/* Composer Assistant — the theme system. Single source of truth for colour.
   ---------------------------------------------------------------------------
   WHY THIS FILE EXISTS, AND WHY main.css COULD NOT DO IT

   main.css used to name its colours LITERALLY: --ink, --stock, --on-ink,
   --on-stock. A token called "ink" cannot become white. That is not a missing
   button — it is a token layer that structurally cannot hold two themes, which
   is why CA had no light/dark switch and could not grow one.

   Every colour is now named by its JOB (--bg-base, --text-muted,
   --border-subtle), so a theme is simply a different set of values under
   [data-theme]. That is the whole idea, and it is app_cc's, ported:
   static/css/themes/tokens.css there, read on 8 Sep 2026.

   ⚠️ PORTED, NEVER IMPORTED (CLAUDE.md Law One). Nothing here is loaded from
   app_cc; the mechanism was studied and rewritten in CA's own file with CA's
   own palette. What we deliberately did NOT copy:
     · the [data-bs-theme] block — CA has no Bootstrap
     · THEME_RESET_TOKEN, CC's deliberate mass reset of stored preferences —
       CA has zero visitors with a stored choice. Add it the day it is needed.

   THE TWO ACCENTS ARE LOAD-BEARING AND THEY SURVIVE THE FLIP
       brass  = you own this
       signal = this is running and being counted
   Their FILL value is identical in both themes, on purpose: the buy button is
   the anchor of the page and must not move when somebody toggles. Only the
   TEXT variants change, because...

   ⚠️ ...RAW BRASS AND RAW SIGNAL ARE ILLEGIBLE AS TEXT ON WHITE. Measured on
   8 Sep 2026 against #fcfbf9: brass #d19a4e = 2.40:1, signal #46dfc4 = 1.61:1.
   Both fail WCAG AA badly. That is why every accent has two tokens — a FILL
   (--brass) and a TEXT colour (--brass-text) — and why using --brass for a
   label is a bug, not a shortcut. app_cc hit exactly this and solved it the
   same way with --accent-on-light.

   CONTRAST, MEASURED NOT ESTIMATED (8 Sep 2026)
     dark   text-primary 16.5:1 · text-muted 5.9:1 · brass 7.5:1 · signal 11.2:1
     light  text-primary 16.8:1 · text-muted 5.4:1 · brass-text 5.7:1
            signal-text 6.4:1 · danger 5.8:1
   All comfortably past AA. Re-measure before changing any value here.
   --------------------------------------------------------------------------- */


/* ═══════════════════════════════════════════════════════════════════════════
   Theme-INDEPENDENT tokens. These never change between light and dark, and
   nothing under [data-theme] may override them.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Type. Bricolage Grotesque is the display voice, IBM Plex Sans the reading
     voice, IBM Plex Mono every NUMBER — prices and take counts are quantities a
     composer compares down a column, and tabular figures are what line them up.
     Every stack names a real fallback so a blocked font degrades, not breaks. */
  --display: "Bricolage Grotesque", "Helvetica Neue", Arial, sans-serif;
  --body:    "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --data:    "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --measure: 68rem;

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 14px;
  --radius-pill: 999px;

  --transition-fast: .12s ease;
  --transition-base: .15s ease;

  /* ⚠️ THE ACCENT FILLS DO NOT FLIP. A brass button is brass in both themes,
     and the text on it is the same near-black either way (7.0:1 and 9.9:1
     measured). The buy button is the one element that stays put when somebody
     changes theme, and that is deliberate. */
  --brass:     #d19a4e;   /* owned, permanent */
  --signal:    #46dfc4;   /* running, metered */
  --on-brass:  #241703;
  --on-signal: #04241e;

  /* ⚠️ WHICH ACCENT THIS PAGE CARRIES. Brass by default — the owned half of
     the funnel. `.surface-run` in main.css flips all three to signal, and it
     is the ONLY thing that may.

     ⚠️ THIS REPLACES --rule-accent, WHOSE IDEA WAS RIGHT AND WHOSE SCOPE WAS
     WRONG. It reached exactly one element, the masthead rule, while .eyebrow,
     .page__summary and the primary button stayed hardcoded to signal. So the
     five identity pages — sign in, check your email, signed in, plugin
     sign-in, the receipt — rendered TEAL while the checkout rendered BRASS,
     and the design system contradicted its own stated rule (brass = you own
     this, signal = this runs and is metered; an account page is the owned
     half). That is the drift Marc saw on 8 Sep 2026. A component now asks for
     "the accent" and the PAGE says which one it is.

     ⚠️ THREE TOKENS, NOT ONE, for the same reason --brass-text exists above:
     --accent is a FILL and is illegible as text, --accent-text is the legible
     text colour, --on-accent is what goes ON the fill. Reaching for --accent
     to colour a label is the bug, not the shortcut. */
  --accent:      var(--brass);
  --accent-text: var(--brass-text);
  --on-accent:   var(--on-brass);
}


/* ═══════════════════════════════════════════════════════════════════════════
   DARK — the scoring stage at rest. Indigo-black, never flat #000.
   This is the palette designed in session 3 and it is unchanged.
   ═══════════════════════════════════════════════════════════════════════════ */

[data-theme="dark"] {
  /* Tells the browser to render native scrollbars, form controls and the
     Stripe iframes' own chrome in dark. Without it they stay light and the
     page looks half-converted. */
  color-scheme: dark;

  --bg-base:   #0f1220;
  --bg-panel:  #161a2b;
  --bg-card:   #191d31;
  --bg-input:  #191d31;

  --text-primary: #f2f1ee;
  --text-muted:   #8a90a6;
  --text-faint:   #6b7185;

  --border-subtle: #2b3149;
  --border-strong: #3a4160;

  --brass-text:  #d19a4e;   /* 7.5:1 on --bg-base — legible as text here */
  --signal-text: #46dfc4;   /* 11.2:1 */

  --danger:    #e2685f;     /* 5.7:1 */
  --danger-bg: rgba(226, 104, 95, .10);

  /* On dark the 1px border already separates a card from the ground, so the
     shadow does nothing but cost paint. */
  --shadow-card: none;

  /* The receipt's celebration mark glows; on the dark ground it can afford to.
     See the light theme for why this is a per-theme value rather than one. */
  --accent-glow: color-mix(in srgb, var(--accent) 30%, transparent);
}


/* ═══════════════════════════════════════════════════════════════════════════
   LIGHT — white and brass. Fede's direction, 8 Sep 2026.

   ⚠️ NOT app_cc's light theme, and the difference starts at the base colour.
   CC uses a COOL off-white (#fbfbfd, Apple lineage). CA's base is WARM
   (#fcfbf9) because CA's accent is warm brass and a cool ground fights it.
   Add the typefaces (Bricolage + Plex against CC's DM Sans + JetBrains Mono)
   and the second accent CC does not have — signal teal — and the two read as
   different houses that happen to share a mechanism.
   ═══════════════════════════════════════════════════════════════════════════ */

[data-theme="light"] {
  color-scheme: light;

  --bg-base:   #fcfbf9;
  --bg-panel:  #f2efe9;
  --bg-card:   #ffffff;
  --bg-input:  #ffffff;

  --text-primary: #1b1a17;   /* warm near-black, never pure #000 */
  --text-muted:   #6b6862;
  --text-faint:   #8f8b83;   /* placeholders only — 3.3:1, never body text */

  /* ⚠️ rgba, not grey hex, so hairlines layer correctly over white cards and
     over the warm ground without banding. */
  --border-subtle: rgba(27, 26, 23, .12);
  --border-strong: rgba(27, 26, 23, .22);

  --brass-text:  #8a5a12;   /* 5.7:1. NOT --brass, which is 2.40:1 here */
  --signal-text: #10695b;   /* 6.4:1. NOT --signal, which is 1.61:1 here */

  --danger:    #b3372e;     /* 5.8:1 */
  --danger-bg: rgba(179, 55, 46, .07);

  /* ⚠️ On light, a card is only 1.03:1 against the ground — fill alone cannot
     separate them, so depth has to come from a shadow. This is the one
     structural difference between the two themes' components. */
  --shadow-card: 0 1px 2px rgba(27, 26, 23, .04), 0 4px 10px rgba(27, 26, 23, .06);

  /* ⚠️ WEAKER THAN DARK'S, AND FOR THE SAME REASON --shadow-card DIFFERS.
     A 30% brass halo reads as a soft glow against #0f1220 and as a muddy
     smear against #fcfbf9 — glow is depth, and depth is the one thing these
     two themes genuinely have to state differently. CC reached the same
     conclusion independently: its --accent-glow is .30 on dark and .10 on
     light.

     ⚠️ color-mix ON --accent, NOT A FIXED BRASS rgba, so the halo follows
     whichever accent the page carries. A brass glow around a signal-coloured
     mark on a .surface-run page is exactly the kind of half-flip the accent
     triple was built to make impossible. */
  --accent-glow: color-mix(in srgb, var(--accent) 12%, transparent);
}


/* ═══════════════════════════════════════════════════════════════════════════
   The page ground, and the swap
   ═══════════════════════════════════════════════════════════════════════════ */

* { box-sizing: border-box; }

body {
  margin: 0;
  /* The footer sits at the bottom of short pages without any page needing to
     declare min-height itself. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;

  background: var(--bg-base);
  color: var(--text-primary);
  font: 400 16px/1.65 var(--body);
  -webkit-font-smoothing: antialiased;

  /* ⚠️ ONLY body transitions. Descendants are suppressed during the swap by
     .no-transition below, so a theme change does not pay the cost of animating
     a thousand elements. */
  transition: background-color var(--transition-base), color var(--transition-base);
}

a { color: inherit; }

/* ⚠️ THE RING USES --signal-text, NOT --signal. Raw signal on the light ground
   is 1.61:1, well under the 3:1 a non-text indicator needs — the focus ring
   would be decorative rather than visible. --signal-text resolves to the same
   #46dfc4 in dark (11.2:1) and to #10695b in light (6.4:1). */
:focus-visible {
  outline: 2px solid var(--signal-text);
  outline-offset: 3px;
  border-radius: 2px;
}

::selection { background: rgba(209, 154, 78, .28); }

@media (forced-colors: active) {
  :focus-visible { outline: 2px solid CanvasText; outline-offset: 2px; }
}

/* ⚠️ TRANSITION SUPPRESSION DURING A SWAP — Paco Coursey 2020 / next-themes,
   the pattern app_cc calls D18. theme.js adds this to <html>, applies the new
   theme, forces a reflow and removes it a tick later. Without it every
   transitioned property on the page animates at once on each toggle. */
.no-transition,
.no-transition *,
.no-transition *::before,
.no-transition *::after {
  transition: none !important;
  -webkit-transition: none !important;
}


/* ═══════════════════════════════════════════════════════════════════════════
   The toggle itself — a WAI-ARIA radio group of three: Light, Dark, System.
   Lives here rather than in main.css because it is part of the theme system,
   not part of any one page.
   ═══════════════════════════════════════════════════════════════════════════ */

.theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  background: var(--bg-panel);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
}

.theme-toggle__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: var(--radius-pill);
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.theme-toggle__btn:hover { color: var(--text-primary); }

.theme-toggle__btn.active {
  background: var(--bg-card);
  color: var(--brass-text);
  box-shadow: var(--shadow-card);
}

/* Screen-reader-only label for each icon button. The SVGs are aria-hidden, so
   without this the buttons are unnamed. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  body,
  .theme-toggle__btn { transition: none; }
}
