/* ============================================================================
   Mode Education - CONVERGED BUTTON SYSTEM
   ----------------------------------------------------------------------------
   One semantic definition for every button on every Mode surface: the public
   front door, the campaign landings, the learner app, the exam simulator and
   the Mode Operations Centre.

   WHY THIS FILE EXISTS
   The public site (.btn / .btn-solid / .btn-outline / .btn-ghost) and the
   console (.mc-btn / .mc-btn--primary / --secondary / --ghost / --danger) grew
   separately but had already converged on the same idea: the mint-to-teal
   gradient, inline-flex with a gap, a 1px press. What differed was arbitrary -
   radius, padding units, focus treatment - and arbitrary difference is drift.
   This defines the semantics ONCE and re-expresses both existing vocabularies
   as thin aliases, so ~769 controls keep working untouched.

   ADOPTED, NOT INVENTED
   Primary keeps the front door's DARK INK on the mint gradient (#05231a). That
   pairing is ~9:1 and was already the best-contrasting button in the codebase.
   The 3.39:1 failure the red team found was white-on-#1D9E75, which appears in
   the journey emails and the join/lead pages written in July 2026 - not in the
   site's own system. Those adopt this treatment; the site did not need saving.

   COLOUR MUST STAY RE-POINTABLE
   Every value below resolves through var() with a fallback. On the public site
   the brand tokens answer; inside the console moc-ui.css answers with its own
   light/dark values. Never hard-code a colour here: the console's light theme
   re-points these variables and a fixed value goes invisible on white.
   ============================================================================ */

:root {
  /* --- semantic button tokens ------------------------------------------- */
  --btn-accent-from: var(--p-mint, var(--c-mint, #3EE7B2));
  --btn-accent-to:   var(--p-teal, var(--c-teal, #1D9E75));
  --btn-accent-ink:  var(--fg-onAccent, #05231a);   /* dark ink on mint: ~9:1 */
  --btn-fg:          var(--fg, var(--c-white, #F8FAFC));
  --btn-fg-quiet:    var(--fg-muted, var(--c-muted, #A6B0BF));
  --btn-line:        var(--border, var(--glass-border, rgba(255,255,255,0.14)));
  --btn-line-strong: var(--border-strong, rgba(255,255,255,0.28));
  --btn-danger-fg:   var(--p-red-200, #ffb4b4);
  --btn-danger-bg:   var(--danger-bg, rgba(180,60,60,0.12));
  --btn-danger-bd:   var(--danger-bd, rgba(220,120,120,0.45));
  --btn-focus:       var(--focus-ring, #5BC8FF);

  /* Density. Public surfaces get room; the console stays compact. Both clear a
     44px touch target at their standard size, which is the accessibility floor
     for anything a learner or visitor taps. */
  --btn-h-compact: 32px;
  --btn-h-base:    44px;
  --btn-h-large:   52px;
  --btn-radius:    var(--r-pill, 999px);
  --btn-radius-flat: 10px;          /* console + exam: rectangular, not pill */
  --btn-motion:    180ms cubic-bezier(.2,.7,.3,1);
}

/* ---------------------------------------------------------------------------
   BASE - shared by every variant and every alias.
   No colour here: colour is the variant's job, so a variant can never be
   accidentally overridden by base specificity.
   ------------------------------------------------------------------------- */
.ms-btn,
.btn,
.mc-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  min-height: var(--btn-h-base);
  padding: 0.7em 1.5em;
  border: 1px solid transparent;
  border-radius: var(--btn-radius);
  font: inherit;
  font-weight: 600;
  font-size: 0.95rem;
  line-height: 1.2;
  letter-spacing: 0.01em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  position: relative;
  transition: background var(--btn-motion), color var(--btn-motion),
              border-color var(--btn-motion), box-shadow var(--btn-motion),
              transform var(--btn-motion);
}

/* A press is the one motion every button keeps: it is feedback, not decoration. */
.ms-btn:active, .btn:active, .mc-btn:active { transform: translateY(1px); }

/* Focus is never removed, never subtle, and never clipped by a sticky header
   or an overflow container - hence the outline rather than a box-shadow ring. */
.ms-btn:focus-visible,
.btn:focus-visible,
.mc-btn:focus-visible {
  outline: 3px solid var(--btn-focus);
  outline-offset: 2px;
}

.ms-btn[disabled], .ms-btn[aria-disabled="true"],
.btn[disabled], .mc-btn[disabled], .mc-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* ---------------------------------------------------------------------------
   VARIANTS
   ------------------------------------------------------------------------- */
.ms-btn--primary, .btn-solid, .mc-btn--primary {
  background: linear-gradient(180deg, var(--btn-accent-from), var(--btn-accent-to));
  color: var(--btn-accent-ink);
  border-color: transparent;
  box-shadow: 0 6px 18px -8px rgba(29,158,117,0.55);
}
.ms-btn--primary:hover, .btn-solid:hover, .mc-btn--primary:hover {
  filter: brightness(1.06);
  box-shadow: 0 10px 24px -8px rgba(29,158,117,0.7);
}

/* Secondary reads as the accent without claiming the accent. */
.ms-btn--secondary, .btn-outline, .mc-btn--secondary {
  background: color-mix(in srgb, var(--btn-accent-to) 8%, transparent);
  border-color: var(--btn-accent-to);
  color: var(--btn-fg);
}
.ms-btn--secondary:hover, .btn-outline:hover, .mc-btn--secondary:hover {
  background: color-mix(in srgb, var(--btn-accent-to) 16%, transparent);
  border-color: var(--btn-accent-from);
}

.ms-btn--ghost, .btn-ghost, .mc-btn--ghost {
  background: color-mix(in srgb, var(--btn-fg) 4%, transparent);
  border-color: var(--btn-line);
  color: var(--btn-fg);
}
.ms-btn--ghost:hover, .btn-ghost:hover, .mc-btn--ghost:hover {
  background: color-mix(in srgb, var(--btn-fg) 9%, transparent);
  border-color: var(--btn-line-strong);
}

/* Destructive is never the loudest thing on screen. It is outlined, not filled,
   so a delete cannot out-shout the safe action beside it - and it never relies
   on colour alone: pair it with an explicit verb ("Delete campaign"). */
.ms-btn--danger, .mc-btn--danger {
  background: var(--btn-danger-bg);
  border-color: var(--btn-danger-bd);
  color: var(--btn-danger-fg);
}
.ms-btn--danger:hover, .mc-btn--danger:hover {
  background: color-mix(in srgb, var(--btn-danger-fg) 16%, transparent);
}

/* A text action for genuinely tertiary choices. Underlined, because a coloured
   word alone is not a discoverable control. */
.ms-btn--link {
  background: none; border: 0; min-height: 0; padding: 0.2em 0;
  color: var(--btn-accent-to); text-decoration: underline; text-underline-offset: 3px;
  border-radius: 4px;
}

/* --- EXAM: deliberately the quietest family in the product -----------------
   Owner decision, 2026-07-27. Under timed conditions a control that animates,
   glows or draws the eye is not polish - it is a distraction, and an unexpected
   control is a fairness problem. So: flat, rectangular, no gradient, no shadow,
   no hover lift, no filter. Only the border responds, and only slightly.
   Submit/Finish/Next/Save/Exit stay visually distinct from one another; never
   merge their treatment for the sake of consistency with the rest of the site. */
.ms-btn--exam {
  background: color-mix(in srgb, var(--btn-fg) 6%, transparent);
  border-color: var(--btn-line-strong);
  color: var(--btn-fg);
  border-radius: var(--btn-radius-flat);
  box-shadow: none;
  font-weight: 600;
}
.ms-btn--exam:hover { border-color: var(--btn-fg-quiet); background: color-mix(in srgb, var(--btn-fg) 10%, transparent); }
.ms-btn--exam:active { transform: none; }          /* no movement under exam conditions */
.ms-btn--exam.is-commit {                           /* the one irreversible action */
  background: linear-gradient(180deg, var(--btn-accent-from), var(--btn-accent-to));
  color: var(--btn-accent-ink);
  border-color: transparent;
}

/* ---------------------------------------------------------------------------
   SIZES + DENSITY
   ------------------------------------------------------------------------- */
.ms-btn--sm, .mc-btn--sm { min-height: var(--btn-h-compact); padding: 0 10px; font-size: 0.82rem; }
.ms-btn--lg, .btn-lg, .mc-btn--lg { min-height: var(--btn-h-large); padding: 0.95em 2em; font-size: 1.02rem; }
.ms-btn--full, .btn-full { width: 100%; }

/* The console is a dense working tool, not a landing page: flatter corners and
   tighter rhythm, while keeping the same semantics and the same focus ring. */
.mc-btn { border-radius: var(--btn-radius-flat); }

/* Icon-only. Square, and it MUST carry an accessible name - there is no visible
   label to fall back on. */
.ms-btn--icon {
  width: var(--btn-h-base); min-width: var(--btn-h-base);
  padding: 0; border-radius: var(--btn-radius-flat);
}
.ms-btn--icon.ms-btn--sm { width: var(--btn-h-compact); min-width: var(--btn-h-compact); }

/* ---------------------------------------------------------------------------
   LOADING - reserve the space, never resize.
   A button that grows when it starts working shifts the layout under the
   pointer, and a button that stays clickable while working double-submits.
   ------------------------------------------------------------------------- */
.ms-btn.is-loading, .btn.is-loading, .mc-btn.is-loading { pointer-events: none; }
.ms-btn.is-loading .ms-btn__label, .btn.is-loading .btn-label { opacity: 0.55; }
.ms-btn .ms-btn__spinner, .btn .spinner {
  width: 1.05em; height: 1.05em; border-radius: 50%;
  border: 2px solid color-mix(in srgb, currentColor 35%, transparent);
  border-top-color: currentColor; display: none;
  animation: ms-btn-spin 0.7s linear infinite;
}
.ms-btn.is-loading .ms-btn__spinner, .btn.is-loading .spinner { display: inline-block; }
@keyframes ms-btn-spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------------------------
   ACCESSIBILITY FLOORS
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .ms-btn, .btn, .mc-btn { transition: none; }
  .ms-btn:active, .btn:active, .mc-btn:active { transform: none; }
  .ms-btn .ms-btn__spinner, .btn .spinner { animation-duration: 1.6s; }
}

/* Windows High Contrast: gradients and translucency vanish, so restore a real
   border and let the system colours through. */
@media (forced-colors: active) {
  .ms-btn, .btn, .mc-btn { border: 1px solid ButtonBorder; background: ButtonFace; color: ButtonText; }
  .ms-btn:focus-visible, .btn:focus-visible, .mc-btn:focus-visible { outline: 3px solid Highlight; }
  .ms-btn[disabled], .btn[disabled], .mc-btn[disabled] { color: GrayText; }
}

/* Long labels and future translation must not clip or force a horizontal
   scroll: wrap rather than overflow, and never set a fixed width. */
.ms-btn, .btn, .mc-btn { max-width: 100%; overflow-wrap: anywhere; }

/* ============================================================================
   CTA BAND legibility fix (owner-reported: "difficult to read, especially the
   word CONTACT").

   Cause: .cta-band's background was TRANSLUCENT - rgba navy over rgba dark - so
   its final colour depended on whatever sat behind it. Where the page behind was
   light, the band resolved to mid-grey, and the mint eyebrow (#3EE7B2) on mid-grey
   falls to roughly 2.5-3:1. Letter-spaced 0.22em uppercase at ~12px is the hardest
   thing on the page to read, so it failed first and worst.

   Fix: make the band's own colour deterministic rather than inherited, and stop
   the eyebrow relying on a mid-tone accent for legibility.
   ============================================================================ */
.cta-band {
  background:
    radial-gradient(80% 120% at 50% 0%, rgba(var(--c-teal-rgb), 0.28), transparent 60%),
    linear-gradient(180deg, #0e2a3f, #0a1c2b) !important;   /* opaque: no backdrop dependency */
  border: 1px solid rgba(var(--c-mint-rgb), 0.28);
}

/* The eyebrow is a label, not decoration: it must be readable before it is pretty.
   Larger, less extreme tracking, and near-white rather than mint - the mint accent
   moves to a short rule beside it, which carries the brand without carrying the
   legibility burden. */
/* Specificity note, so nobody "fixes" this later by adding !important:
   styles.css:866 sets `.section:not(.dark-band) .eyebrow { color:#0f7a54 }` - a DARK GREEN meant for
   LIGHT sections. :not() counts as a class, so that rule is (0,3,0). The CTA band is the exception it
   never anticipated: a DARK panel nested inside a light section, so it inherited a light-background
   colour onto dark navy and landed at 2.77:1.
   The fix matches that specificity exactly (.section .cta-band .eyebrow is also (0,3,0)) and wins on
   SOURCE ORDER because this file loads after styles.css. That is ordinary cascade, not an escalation.
   The systemic fix is a reusable `.on-dark` surface class so any dark panel re-points its own text
   colours regardless of the section it sits in - worth doing when the surface work is tackled. */
.section .cta-band .eyebrow,
.cta-band .eyebrow {
  color: #EAF6F1;
  font-size: 0.82rem;
  letter-spacing: 0.14em;
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
}
.cta-band .eyebrow::before,
.cta-band .eyebrow::after {
  content: "";
  width: 1.6em; height: 2px; border-radius: 2px;
  background: var(--c-mint);
  opacity: 0.9;
}
.section .cta-band h2, .cta-band h2 { color: #fff; }
.section .cta-band p,  .cta-band p  { color: rgba(255,255,255,0.9); }

/* The contact CTA pulsed indefinitely. A permanent animation on a static page is
   noise, and it ignored the fact that the button beside it is the primary action. */
.section .cta-band .btn-outline { animation: none !important; }

/* ============================================================================
   CONTROL-GEOMETRY FIXES (owner audit at 360/390/768/1280/1440, 2026-07-27)

   All four live here, in the shared primitive, not in a page. Every one of these
   controls exists on several surfaces; fixing them per-page is how they drifted
   in the first place.

   SPECIFICITY NOTE - read before editing.
   styles.css defines the same controls at (0,1,0) and, in two places, at (0,2,0):
       .hero__cta .btn-lg { padding-block: 0.85em }      (0,2,0)
       .modal__close      { border-color; background }   (0,1,0), light-theme block
   A plain `.btn-lg` here is (0,1,0) and LOSES to `.hero__cta .btn-lg`. So the
   size rules below are written as `.btn.btn-lg` - also (0,2,0), winning on source
   order because this file loads after styles.css. That is ordinary cascade, not
   an escalation, and it is why none of this needs !important.
   ============================================================================ */

/* --- btn-lg: ONE height, everywhere -----------------------------------------
   It was resolving to 52px in some places and 52.2px in others, because
   .hero__cta .btn-lg overrode padding-block to 0.85em while the primitive said
   0.95em - measured 13.872px vs 15.504px of vertical padding on controls that
   are both btn-lg. Fixing the padding alone would only move the disagreement, so
   the padding is now set low enough that the computed box is always UNDER
   --btn-h-large and min-height is the single thing deciding the height. */
.btn.btn-lg,
.ms-btn.ms-btn--lg,
.mc-btn.mc-btn--lg {
  min-height: var(--btn-h-large);
  padding-block: 0.8em;
  padding-inline: 2em;
  font-size: 1.02rem;
  line-height: 1.2;
}

/* --- btn-lg on phones: stop inflating ---------------------------------------
   Below 480px the large size pushed "Apply for Early Access" onto two lines, so
   the most important control on the site rendered as a ragged two-line block
   next to 44px neighbours. The label is fixed - the rules file requires an
   action to keep the same name through the whole flow - so the BUTTON yields,
   not the words: below 480 the large size simply resolves to the standard one. */
@media (max-width: 480px) {
  .btn.btn-lg,
  .ms-btn.ms-btn--lg,
  .mc-btn.mc-btn--lg {
    min-height: var(--btn-h-base);
    padding-block: 0.7em;
    padding-inline: 0.8em;
    font-size: 0.95rem;
  }
  /* The label keeps the standard 0.95rem size; the horizontal padding and the
     icon gap give up the room instead. At 360 the narrowest host is the CTA
     band, whose content box is 223px against a label that needs ~224px - it was
     missing a single line by under a pixel. These values leave ~8px of headroom
     so a fallback font metric cannot tip it back over. */
  .btn.btn-lg { gap: 0.35em; }
}

/* --- nav links: 44px, like the CTA beside them ------------------------------
   .nav__link was 41.1px (8px padding + a 25.088px inherited line box), and the
   "Knowledge Hub" one was 35.2px because it computes to display:inline, where
   vertical padding does not contribute height at all. inline-flex fixes both:
   it makes the padding count AND lets min-height apply. The nav CTA sitting next
   to these is already 44px, so this makes the row honest as well as tappable. */
.nav__link {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;   /* preserves the existing text-align:left */
  min-height: var(--btn-h-base);
}

/* --- modal close: 44px hit area, 40px chip ----------------------------------
   It was a 40px box (measured 39.2 mid-transition, because .modal starts at
   scale(.98)). The touch target has to clear 44, but the button must not get
   visually heavier - so the BOX grows to 44 and the visible chip moves to a
   ::before inset by 2px, which keeps it at exactly 40px with the same border,
   fill and 50% radius. The 18px icon is untouched. The offset is pulled back by
   the same 2px so the chip stays optically where it always was. */
.modal__close {
  width: var(--btn-h-base);
  height: var(--btn-h-base);
  top: calc(0.9rem - 2px);
  right: calc(0.9rem - 2px);
  border: 0;
  background: none;
  isolation: isolate;            /* keeps the z-index:-1 chip inside the button */
}
.modal__close:hover { background: none; }   /* (0,1,1) - beats the hover fill in styles.css */
.modal__close::before {
  content: "";
  position: absolute;
  inset: 2px;
  z-index: -1;
  border-radius: 50%;
  border: 1px solid rgba(var(--c-navy-rgb), 0.12);
  background: rgba(var(--c-navy-rgb), 0.04);
  transition: background 0.25s var(--ease);
}
.modal__close:hover::before { background: rgba(var(--c-navy-rgb), 0.08); }
