/* ui.css — the ONE button system (issue #1313; base + ghost migration #1630).
   Loaded by every layout.js page, after /css/layout.css; the primitives
   below own .btn, .btn-primary and .btn-ghost site-wide so pages no longer
   carry local copies (the guards: server/test/ui-primitives-guard.test.js
   fails the suite if any file outside the deliberate paywalled-sim chrome
   paints .btn-primary or .btn-ghost again, or re-declares the .btn base
   with a bare .btn selector).

   CONTEXTUAL PRIMARY — the #1313 fix in one line: the old `.btn-primary`
   was ink-on-ink (1.29:1) on every dark hero. The default stays the light
   surface's ink fill + lime text; on DARK surfaces (the masthead header,
   the nav band, the dark .pricing section, the guides' dark end-of-article
   cards, and any container opting in via .on-dark) the primary flips to the
   LIME fill + ink text — the strongest-looking control on the surface it
   sits on, clearing the WCAG 1.4.11 3:1 boundary floor on both masthead
   gradient stops (pinned statically and by the pixel-sampled journey in
   server/test/e2e/ui-contrast-journey.test.js).

   Tokens: the shared palette lives on the pages (index.html's :root is the
   source of truth; layout.css keeps the nav-band vars). Only the token this
   system adds itself is declared here. NO @font-face / @import — the fonts
   ride the one canonical css2 URL (#1069); no layout-shifting rules (#1071,
   #1068 must stay green). */

:root{
  /* The button system's palette. Source of truth: index.html's :root
     (solver pages re-declare the pair byte-equal — the #1121 idiom, pinned
     by contrast-guard/ui-primitives-guard). Declared here too so the system
     is self-sufficient on any page that loads it. #1661 added the trio the
     look variants hang off (byte-equal to index.html's :root and
     products.css, which re-declares the same values for the product pages). */
  --ink:#0d1b16;
  --lime:#9be564;
  --cream:#f6f3ea;
  --leaf:#2f6b4f;
  --mist:#e9efe8;
  --ink-10:rgba(13,27,22,.1);
  --focus-ring:0 0 0 3px rgba(155,229,100,.45);
  /* #1745: the danger look's pair, the same self-sufficiency idiom —
     --danger byte-equal to the pages' :root copies (admin, coach-dashboard,
     dashboard all declare #c14b3a); --danger-deep is the hover shade
     dashboard.html's folded rule carried. */
  --danger:#c14b3a;
  --danger-deep:#a83b2d;
}

/* ---- Token scale (#1313 fix 1: the radii + shadow scale declared once).
   Surfaces consume these instead of re-declaring raw values (this file's own
   lift and lime-glow hovers already ride them). The palette above keeps its
   ~22 per-page byte-equal copies — the deliberate #1121 idiom, NOT a fork to
   mass-delete. The scale is its own :root block, independent of the palette
   block above (whose --focus-ring restoration rides #1773), so it applies as
   soon as this sheet parses. */
:root{
  --radius-pill:999px;
  --radius-sm:10px;
  --radius-md:14px;
  --radius-lg:18px;
  --shadow-card:0 10px 30px rgba(13,27,22,.05);
  --shadow-lift:0 10px 24px rgba(13,27,22,.2);
  --shadow-lime:0 10px 26px rgba(155,229,100,.28);
}

/* ---- .btn base ----
   The base declarations ride :where() — ZERO specificity — so ui.css is the
   DEFAULT, never an override: pages whose <style> blocks sit before the link
   block (most of them) keep their own .btn sizing at any specificity
   (coach-dashboard.html:209's 44px touch floor taught this — an
   equal-specificity .btn-sm default here dropped its #deleteProfileBtn to
   40px and the touch-floor journey red-ed). Pages WITHOUT their own .btn
   base get these primitives; pages WITH one lose nothing. The state rules
   below (.btn:focus-visible/:active/:disabled/[aria-busy]) stay at normal
   specificity — pages don't declare those today, so ui.css owns them. */
:where(.btn){
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  min-height:48px;padding:12px 28px;border-radius:var(--radius-pill);border:1.5px solid transparent;
  font-family:inherit;font-weight:700;font-size:15px;line-height:1.2;
  text-decoration:none;cursor:pointer;white-space:nowrap;
  transition:transform .15s ease,box-shadow .15s ease,background .15s ease,border-color .15s ease,color .15s ease;
}
/* #1575: the author display above — even at :where's zero specificity, author
   origin beats the UA — defeats the UA [hidden]{display:none}. trial-hero.js's
   paid-holder branch hides the trial-jump ghost with the hidden attribute, and
   without this counter-rule every paying customer saw a clickable "Try 3
   minutes free" beside "Open … →" (the #1343 defeat interview.css documents). */
.btn[hidden]{display:none!important}
:where(.btn-sm){min-height:40px;padding:9px 20px;font-size:14px}
/* #1745: the large hero size rides the same zero-specificity default shape
   (folded from products.css's bare .btn-lg; product heroes, the learn lane
   and the cases hub all ask for it in markup). A page needing a different
   large size takes a scoped override (cases.html's .p-hero .hero-actions
   .btn-lg), never a bare re-declaration. */
:where(.btn-lg){padding:17px 34px;font-size:17px}
.btn:focus-visible{outline:none;box-shadow:var(--focus-ring)}
/* #1661: the hover lift is the base state — the tactile standard the
   primary hover already carried (dashboard.html's bare .btn:hover folded
   in). Look hovers below re-declare their own transform where they differ;
   :active must stay AFTER this so the press still wins the tie. */
.btn:hover{transform:translateY(-1px)}
.btn:active{transform:scale(.98)}
.btn:disabled,.btn[aria-busy="true"]{opacity:.6;cursor:default;transform:none;box-shadow:none}
/* #1661: a truly disabled control says so (folded from checkout.html's
   bare .btn:disabled fork); the aria-busy loading state keeps the plain
   cursor via the combined rule above. */
.btn:disabled{cursor:not-allowed}
/* Loading state: set aria-busy="true" on the control while its action is in
   flight — the spinner rides ::after so pages never hand-roll one. */
.btn[aria-busy="true"]::after{
  content:"";width:1em;height:1em;flex:0 0 auto;border-radius:50%;
  border:2px solid currentColor;border-right-color:transparent;
  animation:btn-spin .7s linear infinite;
}
@keyframes btn-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){
  .btn{transition:none}
  .btn:active{transform:none}
  .btn[aria-busy="true"]::after{animation-duration:1.6s}
}

/* ---- Primary: the light-surface default (ink fill, lime text) ---- */
.btn-primary{background:var(--ink);color:var(--lime)}
.btn-primary:hover{transform:translateY(-1px);box-shadow:var(--shadow-lift)}
.btn-primary:disabled{box-shadow:none}

/* ---- Secondary: the ghost — outline in the surface's ink (#1630 face b) ----
   ONE ghost look site-wide: transparent fill + the ink outline on light
   surfaces; the dark scopes below flip it to the cream outline (the same
   behaviour story the primary got). Pages no longer carry local copies —
   the face-(b) census in ui-primitives-guard.test.js fails the suite on any
   ghost look painted outside this file. */
.btn-ghost{background:transparent;color:var(--ink);border:1.5px solid rgba(13,27,22,.2)}
.btn-ghost:hover{border-color:var(--ink);background:rgba(13,27,22,.04)}

/* ---- Tertiary: text link with the trailing arrow ---- */
.btn-link{background:none;border:none;color:inherit;font:inherit;font-weight:700;padding:0;min-height:0;text-decoration:none}
.btn-link::after{content:"→";margin-left:6px}
.btn-link:hover{text-decoration:underline}

/* ---- Contextual primary: dark surfaces carry the lime fill ---- */

/* The masthead header (every `header.hero`/`.top`/`.cv-header`/
   `.partner-hero` page — index, /products/*, auth pages, coaches…) paints
   the --hero-gradient (#0d1b16→#14302a); its primary flips to lime. */
header .btn-primary{background:var(--lime);color:var(--ink)}
header .btn-primary:hover{box-shadow:var(--shadow-lime)}

/* The injected nav band rides the same gradient (layout.css paints it); the
   nav CTA keeps layout.css's geometry pins (line-height:1, 44px tap floor)
   and takes the lime fill — the single source of its colour now. */
nav .links a.btn-primary{background:var(--lime);color:var(--ink);box-shadow:0 4px 14px rgba(0,0,0,.25)}
nav .links a.btn-primary:hover{color:var(--ink);transform:translateY(-2px);box-shadow:0 8px 18px rgba(0,0,0,.3)}

/* The index/gallery dark pricing band (`.pricing{background:var(--ink)}`). */
.pricing .btn-primary{background:var(--lime);color:var(--ink)}
.pricing .btn-primary:hover{box-shadow:var(--shadow-lime)}

/* The guides' dark end-of-article cards (guides.css paints
   .guide-cta/.guide-cta-inline with background:var(--ink)). */
.guide-cta .btn-primary,.guide-cta-inline .btn-primary{background:var(--lime);color:var(--ink)}
.guide-cta .btn-primary:hover,.guide-cta-inline .btn-primary:hover{box-shadow:var(--shadow-lime)}

/* Escape hatch for any other dark container: give the wrapper .on-dark. */
.on-dark .btn-primary{background:var(--lime);color:var(--ink)}
.on-dark .btn-primary:hover{box-shadow:var(--shadow-lime)}

/* ---- Contextual ghost: dark surfaces carry the cream outline (#1630) ---- */

/* The masthead heroes (header.hero/.top — index, the auth pages, coaches…)
   and the /products/* + cases hub heroes (products.css paints the same
   gradient on a bare .p-hero section there, not always under the header). */
header .btn-ghost,.p-hero .btn-ghost{color:var(--cream);border-color:rgba(246,243,234,.35)}
header .btn-ghost:hover,.p-hero .btn-ghost:hover{border-color:var(--lime);color:var(--lime);background:rgba(246,243,234,.06)}

/* Coming-soon heroes are ink-on-paper (products.css .p-soon) — the ghost
   restores the light look (two classes beat the header scope). */
.p-soon .btn-ghost{color:var(--ink);border-color:rgba(13,27,22,.25)}
.p-soon .btn-ghost:hover{border-color:var(--ink);color:var(--ink);background:rgba(13,27,22,.05)}

/* The guides' dark CTA surfaces: the .inline-cta mid-article strip and the
   .guide-cta / .guide-cta-inline end-of-article cards (guides.css paints
   them background:var(--ink)). */
.inline-cta .btn-ghost,.guide-cta .btn-ghost,.guide-cta-inline .btn-ghost{color:var(--cream);border-color:rgba(246,243,234,.3)}
.inline-cta .btn-ghost:hover,.guide-cta .btn-ghost:hover,.guide-cta-inline .btn-ghost:hover{background:rgba(246,243,234,.08)}

/* Escape hatch, mirroring the primary: give any other dark wrapper .on-dark. */
.on-dark .btn-ghost{color:var(--cream);border-color:rgba(246,243,234,.35)}
.on-dark .btn-ghost:hover{border-color:var(--lime);color:var(--lime);background:rgba(246,243,234,.06)}

/* ---- Look variants (#1661): the product-page pair, folded from products.css ----

   .btn-dark — the filled "get the bundle" look (leaf fill, white text, the
   leaf-tinted lift shadow). .btn-inkline — the outlined alternative CTA
   (transparent fill, ink border tint). Both were products.css locals; the
   look census in ui-primitives-guard.test.js now fails the suite on any
   painter outside this file (excluded sim chrome excepted). */
.btn-dark{background:var(--leaf);color:#fff;box-shadow:0 8px 22px rgba(47,107,79,.28)}
.btn-dark:hover{transform:translateY(-2px);box-shadow:0 14px 32px rgba(47,107,79,.34)}
.btn-inkline{background:transparent;color:var(--ink);border-color:var(--ink-10)}
.btn-inkline:hover{border-color:var(--leaf);color:var(--leaf);background:var(--mist)}

/* ---- Secondary (#1661): the quiet filled look, folded from
   coach-dashboard.html — mist fill, ink text, a darker mist on hover. The
   dark scopes below carry index.html's cream-outline pricing skin. */
.btn-secondary{background:var(--mist);color:var(--ink)}
.btn-secondary:hover{background:rgba(13,27,22,.1)}

/* ---- Danger (#1745): the destructive-action look, folded from
   coach-dashboard.html and dashboard.html — the one .btn-danger fill
   site-wide (danger red, white text; hover deepens to --danger-deep, the
   shade dashboard.html carried). The base .btn:hover lift and the
   .btn:disabled contract above cover the remaining states; the look census
   in ui-primitives-guard.test.js fails the suite on any painter outside
   this file (excluded sim chrome excepted).
   #1885: the variant is ELEMENT-QUALIFIED on purpose. The class-only fold
   (0,1,0) lost to dashboard.html's own base painter `button.btn`
   (0,1,1, background:#fff) at any load order, leaving #deleteBtn on the
   white base face at rest — red only on hover. The qualified compound
   (0,2,1) strictly outranks every consuming page's base shape (both
   dashboard.html's button.btn/a.btn (0,1,1) and .acct-card .btn (0,2,0))
   with no reliance on sheet order; the hover qualifies equally so it keeps
   its shade over the rest rule. The specificity pin in the guard's #1885
   block computes the real rankings against every consuming page. */
button.btn.btn-danger{background:var(--danger);color:#fff}
button.btn.btn-danger:hover{background:var(--danger-deep)}

/* ---- Contextual secondary (#1661): dark surfaces carry index.html's
   cream-outline skin (the pricing band's "Go to your dashboard" utility
   CTA); .on-dark is the escape hatch, mirroring the primary. */
.pricing .btn-secondary,.on-dark .btn-secondary{background:transparent;color:var(--cream);border:1.5px solid rgba(246,243,234,.25)}
.pricing .btn-secondary:hover,.on-dark .btn-secondary:hover{background:rgba(246,243,234,.08);border-color:var(--lime);color:var(--lime)}
