/* =============================================================================
   _buttons.css — canonical button component (REFERENCE IMPLEMENTATION)

   Self-contained: this one file carries the button's light token defaults
   (@layer tokens), its dark remap (@layer theme), and its rules
   (@layer components). There is NO button entry in _dark.css.

   State model (notes/architecture.md "Unified state model"): every state is one
   selector group bridging the live pseudo-class to the forced `data-state`
   token — :hover/[data-state~="hover"], :active/[~="pressed"],
   :focus-visible/[~="focus"], :disabled/[disabled]/[~="disabled"]. No bespoke
   `.btn--focus` / `.btn--disabled` classes.

   ── CRITICAL: custom-property FREEZING (see pitfalls "token freezing") ──
   A `--btn-*` token must NOT hold `var(--gov-*)` / `var(--color-*)` that is
   remapped under `body[data-theme="dark"]`. Such a token, declared on :root
   (html), resolves the indirection AT THE HTML LEVEL — where the body-scoped
   dark remap does NOT reach — so it captures the LIGHT value and inherits that
   frozen value down forever (this caused the secondary/ghost dark-hover-goes-
   white regression). Two safe patterns, used below:
     1. LITERALS in :root + an explicit literal override in @layer theme
        (primary/danger fills, shadows, halos, the secondary rest bg).
     2. Reference the flipping gov/semantic token DIRECTLY in the component rule
        (secondary/ghost fg/bg/border in every state, the focus-ring spacer,
        disabled) — there it resolves on the .btn element and flips correctly.
   ============================================================================= */

/* ─────────────────────────────────────────────────────────────────────────
   TOKENS — light defaults. ONLY literals + non-flipping values live here.
   (Flip-sensitive colours are referenced directly in the rules instead.)
   ───────────────────────────────────────────────────────────────────────── */
@layer tokens {
  :root {
    /* focus halo — LITERALS (dark literals in @layer theme). The ring SPACER is
       NOT a token — it's inlined as var(--color-bg-surface) in the focus rule so
       it resolves on the element (would freeze to light white as a token). */
    --btn-ring-halo: rgba(35, 98, 162, 0.45);
    --btn-ring-halo-danger: rgba(197, 42, 58, 0.50);

    /* primary — literal fills (dark literals below) */
    --btn-primary-bg: #2362a2;
    --btn-primary-fg: #ffffff;
    --btn-primary-shadow: 0 1px 0 rgba(12,24,56,0.06), 0 2px 4px rgba(12,24,56,0.10);
    --btn-primary-bg-hover: #1e5086;
    --btn-primary-shadow-hover: 0 2px 0 rgba(12,24,56,0.08), 0 4px 8px rgba(35,98,162,0.28);
    --btn-primary-bg-pressed: var(--gov-color-primary-700);  /* light only; theme overrides w/ literal */
    --btn-primary-shadow-pressed: inset 0 1px 2px rgba(0,0,0,0.20);

    /* secondary — only the theme-specific rest bg (white→subtle) + shadow
       literals are tokens; fg/border/hover/pressed COLOURS ride the gov scale
       and are referenced directly in the rules so they flip. */
    --btn-secondary-bg: #ffffff;                                  /* theme → color-bg-subtle */
    --btn-secondary-shadow: 0 1px 0 rgba(12,24,56,0.04);
    --btn-secondary-shadow-hover: 0 2px 0 rgba(12,24,56,0.05), 0 4px 10px rgba(35,98,162,0.15);
    /* pressed: light = darken border+text to primary-700 + a navy inset; dark
       gets a bespoke translucent-white treatment in @layer theme. These have an
       explicit dark override, so the gov-var light defaults can't freeze. */
    --btn-secondary-bg-pressed: var(--gov-color-primary-100);
    --btn-secondary-fg-pressed: var(--gov-color-primary-700);
    --btn-secondary-bd-pressed: var(--gov-color-primary-700);
    --btn-secondary-shadow-pressed: inset 0 1px 2px rgba(12,24,56,0.18);

    /* ghost — shadow literals only (rest/hover colours ride the gov scale in the
       rules; pressed is tokenised so dark can override) */
    --btn-ghost-shadow-hover: 0 1px 3px rgba(12,24,56,0.08);
    --btn-ghost-bg-pressed: var(--gov-color-primary-100);
    --btn-ghost-fg-pressed: var(--gov-color-primary-700);
    --btn-ghost-shadow-pressed: inset 0 1px 2px rgba(12,24,56,0.12);

    /* danger — literal fills (dark literals below) */
    --btn-danger-bg: #c52a3a;
    --btn-danger-fg: #ffffff;
    --btn-danger-shadow: 0 1px 0 rgba(12,24,56,0.06), 0 2px 4px rgba(197,42,58,0.18);
    --btn-danger-bg-hover: #a51e2d;
    --btn-danger-shadow-hover: 0 2px 0 rgba(12,24,56,0.08), 0 4px 8px rgba(197,42,58,0.30);
    --btn-danger-bg-pressed: #8e1120;
    --btn-danger-shadow-pressed: inset 0 1px 2px rgba(0,0,0,0.20);
  }
}

/* ─────────────────────────────────────────────────────────────────────────
   THEME — dark = LITERAL token values only (no .btn selectors, no var()
   indirection that could freeze). secondary/ghost gov-scale colours are NOT
   here — they flip automatically because the rules reference the gov scale on
   the element.
   ───────────────────────────────────────────────────────────────────────── */
@layer theme {
  [data-theme="dark"] {
    --btn-ring-halo: rgba(140,190,240,0.60);
    --btn-ring-halo-danger: rgba(240,130,145,0.65);

    --btn-primary-bg: #2362a2;          /* dark fills use the saturated light palette (the "original darker" look) */
    --btn-primary-shadow: 0 1px 0 rgba(0,0,0,0.50), 0 2px 4px rgba(0,0,0,0.45);
    --btn-primary-bg-hover: #1e5086;
    --btn-primary-shadow-hover: 0 2px 0 rgba(0,0,0,0.55), 0 4px 8px rgba(82,142,210,0.40);
    --btn-primary-bg-pressed: #0e3a6e;
    --btn-primary-shadow-pressed: inset 0 1px 3px rgba(0,0,0,0.55), inset 0 0 0 1px rgba(0,0,0,0.30);

    /* secondary / ghost dark pressed — bespoke translucent-white inset (matches
       comp-buttons.html's preset generator; these literals override the light
       gov-based pressed tokens, so nothing freezes). */
    --btn-secondary-bg: var(--color-bg-subtle);  /* declared on body too → resolves dark */
    --btn-secondary-bg-pressed: rgba(255,255,255,0.06);
    --btn-secondary-fg-pressed: #cfe1f5;
    --btn-secondary-bd-pressed: rgba(120,170,220,0.55);
    --btn-secondary-shadow-pressed: inset 0 1px 3px rgba(0,0,0,0.55);
    --btn-ghost-bg-pressed: rgba(255,255,255,0.06);
    --btn-ghost-fg-pressed: #cfe1f5;
    --btn-ghost-shadow-pressed: inset 0 1px 3px rgba(0,0,0,0.45);

    --btn-danger-bg: #c52a3a;
    --btn-danger-shadow: 0 1px 0 rgba(0,0,0,0.50), 0 2px 4px rgba(0,0,0,0.45);
    --btn-danger-bg-hover: #a51e2d;
    --btn-danger-shadow-hover: 0 2px 0 rgba(0,0,0,0.55), 0 4px 8px rgba(220,86,102,0.45);
    --btn-danger-bg-pressed: #7a1020;
    --btn-danger-shadow-pressed: inset 0 1px 3px rgba(0,0,0,0.55), inset 0 0 0 1px rgba(0,0,0,0.30);
  }
}

/* ─────────────────────────────────────────────────────────────────────────
   COMPONENT — theme-agnostic. Literals come from --btn-* tokens; flip-sensitive
   colours reference the gov scale DIRECTLY so they resolve on the element.
   ───────────────────────────────────────────────────────────────────────── */
@layer components {
  .btn {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 9px 16px; border-radius: 6px;
    font: 500 14px var(--font-sans);
    line-height: 1.2; cursor: pointer;
    /* Buttons are pure controls — rapid/double clicks must never text-select
       the label (system-wide rule, see notes/decisions.md "Non-selectable
       controls"). */
    user-select: none; -webkit-user-select: none;
    border: 1px solid var(--_bd, transparent);
    color: var(--_fg);
    background: var(--_bg);
    box-shadow: var(--_shadow, none);
    --_ring-halo: var(--btn-ring-halo);   /* literal token (flips via theme); danger overrides */
    /* background intentionally NOT transitioned — gradient↔solid can't
       interpolate (flashes through transparent). See pitfalls. */
    transition: box-shadow 140ms ease-out, border-color 140ms ease-out, color 140ms ease-out;
  }

  /* Variants. --_depth = resting shadow re-used UNDER the focus ring. */
  .btn--primary {
    --_bg: var(--btn-primary-bg); --_fg: var(--btn-primary-fg);
    --_bd: transparent; --_shadow: var(--btn-primary-shadow);
    --_depth: var(--btn-primary-shadow);
  }
  .btn--secondary {
    --_bg: var(--btn-secondary-bg);
    --_fg: var(--gov-color-primary-500);          /* direct → flips on element */
    --_bd: var(--gov-color-primary-500);
    --_shadow: var(--btn-secondary-shadow);
  }
  .btn--ghost {
    --_bg: transparent;
    --_fg: var(--gov-color-primary-500);          /* direct → flips */
    --_bd: transparent; --_shadow: none;
  }
  .btn--danger {
    --_bg: var(--btn-danger-bg); --_fg: var(--btn-danger-fg);
    --_bd: transparent; --_shadow: var(--btn-danger-shadow);
    --_depth: var(--btn-danger-shadow);
    --_ring-halo: var(--btn-ring-halo-danger);
  }

  /* ── STATE: hover (live + forced share one rule) ── */
  .btn--primary:hover,
  .btn--primary[data-state~="hover"] {
    --_bg: var(--btn-primary-bg-hover); --_shadow: var(--btn-primary-shadow-hover);
  }
  .btn--secondary:hover,
  .btn--secondary[data-state~="hover"] {
    --_bg: var(--gov-color-primary-50);           /* direct → dark primary-50 in dark */
    --_fg: var(--gov-color-primary-700);
    --_bd: var(--gov-color-primary-600);
    --_shadow: var(--btn-secondary-shadow-hover);
  }
  .btn--ghost:hover,
  .btn--ghost[data-state~="hover"] {
    --_bg: var(--gov-color-primary-50);           /* direct → flips */
    --_fg: var(--gov-color-primary-700);
    --_shadow: var(--btn-ghost-shadow-hover);
  }
  .btn--danger:hover,
  .btn--danger[data-state~="hover"] {
    --_bg: var(--btn-danger-bg-hover); --_shadow: var(--btn-danger-shadow-hover);
  }

  /* ── STATE: pressed ── (--_depth: 0 0 #0000 — a valid empty shadow layer, so a
     pressed+focus combo keeps a valid list; never `none` inside a comma list) ── */
  .btn--primary:active,
  .btn--primary[data-state~="pressed"] {
    --_bg: var(--btn-primary-bg-pressed); --_shadow: var(--btn-primary-shadow-pressed); --_depth: 0 0 #0000;
  }
  .btn--secondary:active,
  .btn--secondary[data-state~="pressed"] {
    --_bg: var(--btn-secondary-bg-pressed);
    --_fg: var(--btn-secondary-fg-pressed);
    --_bd: var(--btn-secondary-bd-pressed);
    --_shadow: var(--btn-secondary-shadow-pressed); --_depth: 0 0 #0000;
  }
  .btn--ghost:active,
  .btn--ghost[data-state~="pressed"] {
    --_bg: var(--btn-ghost-bg-pressed);
    --_fg: var(--btn-ghost-fg-pressed);
    --_shadow: var(--btn-ghost-shadow-pressed); --_depth: 0 0 #0000;
  }
  .btn--danger:active,
  .btn--danger[data-state~="pressed"] {
    --_bg: var(--btn-danger-bg-pressed); --_shadow: var(--btn-danger-shadow-pressed); --_depth: 0 0 #0000;
  }

  /* ── STATE: focus — ONE rule, ALL variants, BOTH themes ──
     spacer = var(--color-bg-surface) INLINE (resolves on element → flips), halo
     variant-tinted + theme-flipped, layered in front of the variant depth. */
  .btn:focus-visible,
  .btn[data-state~="focus"] {
    outline: none;
    transition: box-shadow 220ms cubic-bezier(0.16, 1, 0.3, 1),
                border-color 140ms ease-out, color 140ms ease-out;
    --_shadow:
      0 0 0 2px var(--color-bg-surface),
      0 0 0 5px var(--_ring-halo),
      var(--_depth, 0 0 #0000);
  }

  /* ── STATE: disabled — native pseudo is canonical; token form for non-form
     elements. gov refs INLINE so they flip. The `!important` is GONE (Jun 2026):
     comp-buttons.html's generator now writes only `--btn-*` TOKEN assignments
     into @layer tweaks (no unlayered `.btn--primary{background…!important}`), so
     this rule wins on its own — within @layer components `.btn:disabled` (0,2,0)
     out-specifies `.btn--variant` (0,1,0), and the tweak layer never sets the
     `background`/`box-shadow` properties directly anymore (only their token
     values, which this rule overrides outright). ── */
  .btn:disabled,
  .btn[disabled],
  .btn[data-state~="disabled"] {
    background: var(--gov-color-neutral-200);
    color: var(--gov-color-neutral-500);
    border-color: transparent;
    box-shadow: none;
    cursor: not-allowed;
  }

  /* Sizes */
  .btn--sm { padding: 6px 12px; font-size: 13px; }
  .btn--lg { padding: 12px 20px; font-size: 15px; }

  /* ── Active-tinted surface (.on-active) ───────────────────────────────────
     A primary-50 "active" container — a hovered catalogue card, a selected
     row, a highlighted panel. Secondary / ghost buttons placed here CAMOUFLAGE:
     their normal hover fill IS primary-50 (the surface colour), so the feedback
     vanishes, and the transparent ghost reads weakly against the tint. On this
     surface we (a) pop the secondary rest to a solid surface fill so it lifts
     off the tint, and (b) deepen every hover / pressed a step (primary-100 →
     -200) with a firmer edge, so the state change stays legible against the
     already-blue background. gov/semantic refs resolve ON the .btn element →
     flip correctly in dark (never frozen as :root tokens — see header note).
     Consumers that tint their OWN surface on a state (e.g. a doc card's hover)
     re-point their inner buttons to this treatment in their own file. ──────── */
  .on-active { background: var(--gov-color-primary-50); border-radius: var(--radius-sm); }

  .on-active .btn--secondary { --_bg: var(--color-bg-surface); }   /* solid → pops on the tint */
  .on-active .btn--secondary:hover,
  .on-active .btn--secondary[data-state~="hover"] {
    --_bg: var(--gov-color-primary-100);                            /* a step DEEPER than the surface */
    --_fg: var(--gov-color-primary-700);
    --_bd: var(--gov-color-primary-600);
  }
  .on-active .btn--secondary:active,
  .on-active .btn--secondary[data-state~="pressed"] {
    --_bg: var(--gov-color-primary-200);
    --_fg: var(--gov-color-primary-700);
    --_bd: var(--gov-color-primary-700);
  }

  .on-active .btn--ghost:hover,
  .on-active .btn--ghost[data-state~="hover"] {
    --_bg: var(--gov-color-primary-100);
    --_fg: var(--gov-color-primary-700);
  }
  .on-active .btn--ghost:active,
  .on-active .btn--ghost[data-state~="pressed"] {
    --_bg: var(--gov-color-primary-200);
    --_fg: var(--gov-color-primary-700);
  }
}
