/* ── Farn — Palette tokens ─────────────────────────────────────────── */
/* Four palettes: Iron Night · Birch Mist · Forest · Bloom                  */

:root {
  /* Iron Night — dark surfaces */
  --in0-void:      #0D1117;   /* Darkest base, primary dark bg             */
  --in1-iron:      #374151;   /* Elevated surfaces, borders                */
  --in2-slate:     #4B5563;   /* Active lines, selections                  */
  --in3-ash:       #6B7280;   /* Comments, placeholders, guides            */

  /* Birch Mist — light surfaces */
  --bm0-sand:      #D5D2C7;   /* Variables, elevated UI (dark)             */
  --bm1-mist:      #E9E6DC;   /* Hover states, active line (light)         */
  --bm2-birch:     #F7F6F3;   /* Primary bg (light) / text (dark)         */

  /* Forest — accent */
  --fo0-glade:     #94C5AF;   /* Light accent; dark-mode primary accent (links, buttons, indicators) */
  --fo1-fern:      #327A59;   /* Primary accent — light-mode buttons, links, CTAs; dark-mode hover  */
  --fo2-forest:    #2D5E4A;   /* Secondary accent; card highlight bg (dark mode)   */
  --fo3-deepwater: #254D5A;   /* Tertiary accent; code block bg + card highlight bg (light mode); featured-surface bg (dark mode) */

  /* Bloom — semantic */
  --bl0-ember:     #C5414C;   /* Errors, deletions                         */
  --bl1-ochre:     #AB5A2B;   /* Warnings, regex, escapes                  */
  --bl2-grain:     #8D6B20;   /* Annotations, decorators                   */
  --bl3-moss:      #567A37;   /* Success, additions, strings               */
  --bl4-heather:   #885DB4;   /* Numbers, uncommon functionality           */
}
/* ── Farn — Typography tokens ─────────────────────────────────────── */
/* Fraunces (display) · Instrument Sans (body) · JetBrains Mono (code)      */
/* IMPORTANT: Fraunces requires font-variation-settings: 'opsz' <size>       */

/* Font loading excluded from dist — self-host WOFF2s (site/public/fonts/) or use Google Fonts with consent. */

:root {
  --font-display: 'Fraunces', Georgia, serif;
  --font-body:    'Instrument Sans', system-ui, sans-serif;
  --font-mono:    'JetBrains Mono', 'Courier New', monospace;

  /* UI text scale — use in component CSS; for prose/heading styles use .text-* utility classes */
  --text-2xs:  0.6875rem;  /* 11px — badge labels, overline captions */
  --text-xs:   0.75rem;    /* 12px — tooltips, metadata, btn-sm, secondary text */
  --text-sm:   0.875rem;   /* 14px — UI text: inputs, labels, buttons, tabs, tables */
  --text-base: 1rem;       /* 16px — body text, accordion content */
}

/*
  Type scale reference:
  ─────────────────────────────────────────────────────────
  Role         Font               Weight  Size          opsz
  ─────────────────────────────────────────────────────────
  Display/H1   Fraunces           800     clamp(56–112) 72 or 36
  H2           Fraunces           700     clamp(28–42)  24
  H3           Fraunces           600     clamp(20–28)  20
  Body         Instrument Sans    400     16px          —
  UI/metadata  Instrument Sans    500–600 11–14px       —
  Code         JetBrains Mono     400–500 12–13px       —
  ─────────────────────────────────────────────────────────
  Rules:
  - Max 3 type sizes per layout
  - Body column max 68 characters per line (68ch)
  - Fraunces minimum size: 16px — never smaller
  - Never use Instrument Sans weight 700+
  - letter-spacing: -0.02em on display; 0 on body
*/
/* ── Farn — Spacing, layout, and radius tokens ──────────────────────── */
/* Base unit: 12px (0.75rem). Scale multiplied from there.                  */

:root {
  /* Spacing scale */
  --space-xs:  0.375rem;   /*  6px */
  --space-sm:  0.75rem;    /* 12px */
  --space-md:  1.5rem;     /* 24px */
  --space-lg:  2.25rem;    /* 36px */
  --space-xl:  3rem;       /* 48px */
  --space-2xl: 3.75rem;    /* 60px */
  --space-3xl: 4.5rem;     /* 72px */
  --space-4xl: 6rem;       /* 96px */

  /* Layout widths */
  --width-content: 1080px;
  --width-prose:   70ch;
  --width-narrow:  640px;

  /* Breakpoints (reference values — CSS custom properties cannot be used in @media directly) */
  --breakpoint-mobile:  640px;
  --breakpoint-tablet:  768px;

  /* Border radius */
  --radius-sm:  4px;
  --radius-md:  6px;
  --radius-lg:  8px;
  --radius-xl:  12px;
  --radius-full: 9999px;

  /* Z-index scale */
  --z-base:    0;
  --z-raised:  1;
  --z-content: 10;    /* sticky sub-nav — above page, below fixed nav */
  --z-nav:     50;    /* fixed top nav bar — above sticky, below dropdowns */
  --z-dropdown: 100;
  --z-sticky:  200;
  --z-overlay: 300;
  --z-modal:   400;
  --z-toast:   500;
}
/* ── Farn — Motion tokens ─────────────────────────────────────────────── */

:root {
  /* Duration scale */
  --duration-fast:   80ms;   /* Press / active states */
  --duration-base:  120ms;   /* Standard hover interactions */
  --duration-slow:  200ms;   /* Fill, colour, and indicator transitions */
  --duration-enter: 250ms;   /* Enter / exit geometry (drawers, nav hide) */
  --duration-reveal: 400ms;  /* Content reveal and stagger animations */
  --duration-loop:   800ms;  /* Repeating cycle animations — spinner, skeleton shimmer */

  /* Easing */
  --ease-default: ease;
  --ease-out:     ease-out;
  --ease-in-out:  ease-in-out;
  --ease-spring:  cubic-bezier(0.16, 1, 0.3, 1); /* overshoot / spring out */
}
/* ── Farn — Component tokens (Tier 3) ─────────────────────────────────── */
/*                                                                           */
/* Tier-3 tokens sit above the semantic layer and below implementation.      */
/* Override these to retheme a component without touching semantic tokens    */
/* that affect the rest of the system.                                       */

:root {
  /* ── Nav tokens ─────────────────────────────────────────────────────── */
  --nav-height:         64px;
  --nav-link-font-size: var(--text-sm);
  --nav-cta-height:     36px;
  --nav-overlay-bg:     color-mix(in srgb, black 50%, transparent);

  /* ── Footer tokens ──────────────────────────────────────────────────── */
  --footer-padding-top:    var(--space-3xl);
  --footer-padding-bottom: var(--space-xl);

  /* ── Button tokens ──────────────────────────────────────────────────── */
  --btn-radius:           var(--radius-md);
  --btn-disabled-opacity: 0.5;
  --btn-gap:              6px;
  --btn-padding-x:        16px;
  --btn-sm-padding-x:     12px;
  --btn-lg-padding-x:     20px;

  /* Primary/Secondary/Ghost — --btn-p-bg, --btn-p-text, --btn-p-hover-bg,
     --btn-s-bg, --btn-s-text, --btn-s-hover-bg, --btn-s-active-bg,
     --btn-g-text, --btn-g-border, --btn-g-hover-bg are intentionally NOT
     declared here. component-classes.css falls back to their semantic source
     (--color-accent, --color-bg-inset, --color-text, --color-border-strong,
     --color-bg-interactive-hover, etc.) when they're unset, which resolves
     correctly in every theme/surface without needing a redeclaration in each
     one. Declaring a Tier-3 default here would defeat that: browsers resolve
     var() references at the element where the *custom property itself* is
     last declared, not at the element that consumes it — so a default
     declared once here would freeze to whichever context's semantic value
     was in scope there, and leak that into every other context that doesn't
     override it (this exact bug shipped for the featured surface; see
     tokens/dark-light.css's [data-surface="featured"] block history). The
     fallback pattern sidesteps that entirely: a context only needs to
     declare one of these tokens when its correct value genuinely differs
     from the semantic default (e.g. --btn-s-hover-bg needing --in1-iron
     instead of --color-bg-interactive-hover where birch text would fail
     contrast on ash — see the dark-theme block in dark-light.css). You can
     still override any of these on any scope, same as before — set
     e.g. --btn-p-bg directly and it takes precedence over the fallback.
     --btn-g-active-bg is the one exception below: every context needs a
     genuinely different value for it (not a shared default with occasional
     overrides), so it keeps a real Tier-3 default plus per-context overrides. */
  --btn-p-border:   transparent;

  /* Secondary */
  --btn-s-border:   transparent;

  /* Ghost */
  --btn-g-bg:       transparent;

  /* Destructive — theme-invariant everywhere (always near-black hover, for
     emphasis), so it keeps plain Tier-3 aliases like the rest of this file;
     nothing here is ever redeclared per theme/surface, so the fallback
     pattern above wouldn't simplify anything. */
  --btn-d-bg:       var(--color-error);
  --btn-d-text:     var(--color-on-error);
  --btn-d-border:   transparent;
  --btn-d-hover-bg: var(--in0-void);
  --btn-d-active-bg: var(--in0-void); /* same as hover — no darker palette token exists */

  --btn-g-active-bg: var(--color-bg-interactive-active); /* ambient default (light: --bm0-sand); dark ambient and both featured variants override this directly in dark-light.css, since each needs its own distinct value rather than a shared fallback */

  /* ── Link tokens ────────────────────────────────────────────────────── */
  --link-color:         var(--color-accent);
  --link-hover-color:   var(--color-accent-hover);
  --link-visited-color: var(--color-accent);

  /* ── Card tokens ────────────────────────────────────────────────────── */
  --card-bg:             var(--color-bg-panel);
  --card-hover-bg:       var(--color-bg-inset);
  --card-border:         transparent;
  --card-radius:         var(--radius-lg);
  --card-padding:        var(--space-md);
  --card-preview-height: 9rem;
  --card-highlight-bg:     var(--color-card-highlight-bg);
  --card-highlight-border: var(--color-card-highlight-border);
  --card-highlight-text:           var(--color-card-highlight-text);
  --card-highlight-text-secondary: var(--color-card-highlight-text-secondary);
  --card-highlight-text-tertiary:  var(--color-card-highlight-text-tertiary);

  /* ── Layered overlap tokens ─────────────────────────────────────────── */
  --overlap-section-radius:     var(--radius-xl);
  --overlap-section-offset:     60px;
  --overlap-card-radius:        var(--card-radius);
  --overlap-card-offset:        80px;
  --overlap-card-duration:      0.7s;
  --overlap-card-shadow-raised: 0 -4px 32px rgba(0, 0, 0, 0.14);

  /* ── Sine wave tokens ───────────────────────────────────────────────── */
  --wave-height: 80px;

  /* ── Convex arc tokens ──────────────────────────────────────────────── */
  --arc-height: 80px;

  /* ── Organic blob tokens ─────────────────────────────────────────────── */
  --blob-height: 100px;

  /* ── Diagonal cut tokens ─────────────────────────────────────────────── */
  --diagonal-angle: -3deg; /* static display angle; keep between -2deg and -5deg */
                           /* scroll-driven animation always starts from -5deg regardless */

  /* ── Stacked card tokens ─────────────────────────────────────────────── */
  --stack-scale-step: 0.03;             /* scale reduction per depth level */
  --stack-top:        0px;              /* sticky top offset — override to clear a fixed nav */
  --stack-radius:     var(--radius-xl); /* top-corner radius on each section */
  --stack-count:      4;                /* number of .stack-section children; set per instance */
  --stack-height:     100vh;            /* section height; set to 100dvh for dynamic viewport tracking */

  /* ── Input tokens ───────────────────────────────────────────────────── */
  --input-radius:           var(--radius-md);
  --input-bg:               var(--color-bg-panel);
  --input-bg-active:        var(--color-bg-inset);   /* hover + focus */
  --input-border:           var(--color-border);
  --input-border-focus:     var(--color-accent);
  --input-border-error:     var(--color-error);
  --input-focus-shadow:     0 0 0 3px color-mix(in srgb, var(--color-accent) 15%, transparent);
  --input-text:             var(--color-text);
  --input-placeholder:      var(--color-text-tertiary);
  --input-disabled-opacity: 0.4;

  /* ── Accordion tokens ──────────────────────────────────────────────── */
  --accordion-border:           var(--color-border);
  --accordion-radius:           var(--radius-md);
  --accordion-summary-bg:       transparent;
  --accordion-summary-hover-bg: var(--color-bg-interactive-hover);
  --accordion-panel-bg:         transparent;
  --accordion-font-size:        var(--text-base);
  --accordion-toggle-size:      1.25rem;
  --accordion-toggle-rotation:  45deg;

  /* ── Badge tokens ──────────────────────────────────────────────────── */
  --badge-height:          22px;
  --badge-padding:         0 8px;
  --badge-letter-spacing:  0.04em;

  --badge-general-bg:      var(--bm0-sand);
  --badge-general-text:    var(--in0-void);
  --badge-published-bg:    var(--bl3-moss);
  --badge-published-text:  var(--bm2-birch);  /* bloom bg: birch 4.59:1 ✓; void 3.81:1 fail */
  --badge-draft-bg:        var(--bl1-ochre);
  --badge-draft-text:      var(--bm2-birch);  /* bloom bg: birch 4.59:1 ✓; void 3.81:1 fail */
  --badge-archived-bg:     var(--bl0-ember);
  --badge-archived-text:   var(--bm2-birch);  /* bloom bg: birch 4.59:1 ✓; void 3.82:1 fail */
  --badge-beta-bg:         var(--bl4-heather);
  --badge-beta-text:       var(--bm2-birch);  /* bloom bg: birch 4.55:1 ✓; void 3.84:1 fail */
  --badge-research-bg:     var(--bl2-grain);
  --badge-research-text:   var(--bm2-birch);  /* bloom bg: birch 4.57:1 ✓; void 3.84:1 fail */
  --badge-category-bg:     var(--fo2-forest);
  --badge-category-text:   var(--bm2-birch);  /* forest bg: birch 6.91:1 ✓; void 2.53:1 fail */

  /* ── Component typography tokens ────────────────────────────────────── */
  --btn-font-size:        var(--text-xs);
  --btn-sm-font-size:     var(--text-2xs);
  --btn-lg-font-size:     var(--text-sm);
  --label-font-size:      var(--text-sm);
  --input-font-size:      var(--text-sm);
  --badge-font-size:      var(--text-2xs);
  --hint-font-size:       var(--text-sm);
  --breadcrumb-font-size: var(--text-xs);

  /* ── Quote tokens ──────────────────────────────────────────────────────── */
  --quote-border-width:   3px;
  --quote-border-color:   var(--color-accent);
  --quote-text-color:     var(--color-text-secondary);
  --quote-footer-color:     var(--color-text-tertiary);
  --quote-footer-font-size: var(--text-xs);
  --quote-padding:        var(--space-sm) 0 var(--space-sm) var(--space-lg);
  --quote-margin-bottom:  var(--space-lg);
  --quote-opsz:           16;

  /* Pullquote — references separator decorative tokens as single source of truth */
  --quote-pull-rule-width:        var(--separator-decorative-width);
  --quote-pull-rule-height:       var(--separator-decorative-weight);
  --quote-pull-rule-color:        var(--separator-decorative-color);
  --quote-pull-figcaption-size:   var(--text-2xs);

  /* Testimonial card (renamed from .quote-attribution in v0.x — breaking change) */
  /* shell (bg, border-radius, display) comes from .card — add .card to the element */
  --quote-testimonial-border:          var(--color-border-subtle); /* override: .card uses transparent */
  --quote-testimonial-padding:         var(--space-lg);            /* override: .card uses --space-md */
  --quote-testimonial-gap:             var(--space-sm);
  --quote-testimonial-mark-color:      var(--color-accent);
  --quote-testimonial-mark-size:       3rem;
  --quote-testimonial-avatar-size:     2.5rem;
  --quote-testimonial-avatar-bg:       var(--color-bg-inset);
  --quote-testimonial-text-size:       var(--text-base);
  --quote-testimonial-avatar-font:     var(--text-sm); /* initials size */
  --quote-testimonial-name-size:       var(--text-sm);
  --quote-testimonial-role-size:       var(--text-xs);
  --quote-testimonial-attribution-gap: var(--space-sm);
  --quote-testimonial-attribution-top: var(--space-xs);

  /* ── Code block tokens ──────────────────────────────────────────────── */
  --code-bg:          var(--color-bg-inset); /* surface-aware; override with --color-bg-code for always-dark */
  --code-text:        var(--color-text);
  --code-border:      var(--color-border);
  --code-radius:      var(--radius-md);
  --code-font-size:   0.8125rem; /* 13px — midpoint between --text-xs and --text-sm; intentional for code readability */
  --code-copy-size:   32px;
  --code-copy-radius: var(--radius-sm);

  /* ── Tooltip tokens ─────────────────────────────────────────────────── */
  /* --tooltip-bg and --tooltip-text live in dark-light.css (theme-inverse) */
  --tooltip-max-width:  220px;
  --tooltip-radius:     var(--radius-sm);
  --tooltip-padding:    4px 10px;
  --tooltip-font-size:  var(--text-xs);

  /* ── Pagination tokens ──────────────────────────────────────────────── */
  --pagination-active-bg:   var(--color-accent);
  --pagination-active-text: var(--color-accent-text);
  --pagination-hover-bg:    var(--color-bg-interactive-hover);
  --pagination-hover-text:  var(--color-text);
  --pagination-radius:      var(--radius-md);
  --pagination-gap:         var(--space-xs);
  --pagination-font-size:   var(--text-sm);

  /* ── Tab tokens ─────────────────────────────────────────────────────── */
  --tab-idle-text:        var(--color-text-secondary);
  --tab-hover-bg:         var(--color-bg-interactive-hover);
  --tab-active-text:      var(--color-text);
  --tab-indicator:        var(--color-accent);
  --tab-border:           var(--color-border);
  --tab-panel-bg:         transparent;
  --tab-gap:              4px;
  --tab-font-size:        var(--text-sm);
  --tab-disabled-opacity: 0.4;

  /* ── Spinner tokens ─────────────────────────────────────────────────── */
  --spinner-color:     var(--color-accent);
  --spinner-track:     color-mix(in srgb, var(--color-accent) 20%, transparent);
  --spinner-size:      24px;
  --spinner-sm-size:   16px;
  --spinner-lg-size:   40px;
  --spinner-border:    2px;
  --spinner-lg-border: 3px;
  --spinner-duration:  1.2s;

  /* ── Skeleton tokens ─────────────────────────────────────────────────── */
  /* --skeleton-shine lives in dark-light.css — per-theme palette value */
  --skeleton-radius:   var(--radius-sm);
  --skeleton-base:     var(--color-bg-panel);
  --skeleton-duration: 1.6s;

  /* ── Separator tokens ──────────────────────────────────────────────────── */
  --separator-section-weight:    2px;
  --separator-decorative-width:  32px;
  --separator-decorative-weight: 2px;
  --separator-decorative-color:  var(--color-accent);

  /* ── Table tokens ────────────────────────────────────────────────────── */
  --table-border:             var(--color-border);
  --table-header-bg:          var(--color-bg-inset);
  --table-header-text:        var(--color-text);
  --table-header-font-size:   var(--text-sm);
  --table-row-stripe-bg:      var(--color-bg-inset);   /* inset for visible contrast on panel-bg surfaces */
  --table-row-hover-bg:       var(--table-row-stripe-bg);
  --table-font-size:          var(--text-sm);
  --table-cell-padding:       var(--space-sm) var(--space-sm);  /* 12px 12px */
  --table-cell-padding-sm:    4px var(--space-xs);              /* 4px 6px — compact */
  --table-cell-padding-lg:    var(--space-md) var(--space-md);  /* 24px 24px — comfortable */
  --table-radius:             var(--radius-md);        /* apply to a wrapper, not the table */
}
/* ── Farn — Semantic tokens and surface patterns ──────────────────────── */
/*                                                                           */
/* Two-layer architecture:                                                   */
/*   Layer 1 — palette (colors.css): raw color values, never used directly  */
/*   Layer 2 — semantic (this file): purpose-mapped aliases                  */
/*                                                                           */
/* Theme control:                                                             */
/*   Page-level : data-theme="dark" or data-theme="light" on <html>         */
/*   Any element: data-theme="dark|light" — sets background + all tokens    */
/*   Depth      : data-surface="base|layer|overlay|featured" — relative to theme */
/*                                                                           */
/* FOWT prevention: add this inline script before <body>:                    */
/*   const t = localStorage.getItem('farn-theme');                           */
/*   const s = window.matchMedia('(prefers-color-scheme: dark)').matches     */
/*     ? 'dark' : 'light';                                                   */
/*   document.documentElement.setAttribute('data-theme', t ?? s);            */

/* ── No-JS dark mode fallback ───────────────────────────────────────── */
/* Fires only when data-theme has not yet been set (before JS runs or when  */
/* JS is disabled). Once the FOWT inline script sets data-theme on <html>, */
/* the [data-theme="dark"] block below takes over at higher specificity.    */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    background:               var(--color-bg);
    color:                    var(--color-text);
    --color-bg:               var(--in0-void);
    --color-bg-panel:         var(--in1-iron);
    --color-bg-inset:         var(--in2-slate);
    --color-text:             var(--bm2-birch);
    --color-text-secondary:   var(--bm1-mist);
    --color-text-tertiary:    var(--bm0-sand);
    --color-border:           var(--in2-slate);
    --color-border-strong:    var(--bm0-sand);
    --color-border-subtle:    color-mix(in srgb, var(--in2-slate) 25%, transparent);
    --color-ghost-border:     color-mix(in srgb, var(--bm2-birch) 25%, transparent);
    --color-bg-code:          var(--in1-iron);
    --color-accent:           var(--fo0-glade);
    --color-accent-hover:     var(--fo1-fern);
    --color-accent-active:    var(--fo2-forest);
    --color-accent-text:      var(--in0-void);
    --color-wordmark-dot:     var(--fo1-fern); /* fixed brand color — always fern, never follows theme */
    --color-error:            var(--bl0-ember);
    --color-warning:          var(--bl1-ochre);
    --color-success:          var(--bl3-moss);
    --color-on-error:         var(--bm2-birch);
    --color-on-success:       var(--bm2-birch);
    --color-on-warning:       var(--bm2-birch);
    --color-bg-interactive-hover:          var(--in3-ash);
    --color-bg-interactive-active:         var(--in0-void);
    --color-card-highlight-bg:             var(--fo2-forest);
    --color-card-highlight-border:         transparent;
    --color-card-highlight-text:           var(--bm2-birch);
    --color-card-highlight-text-secondary: var(--bm1-mist);
    --color-card-highlight-text-tertiary:  var(--bm0-sand);
    --tooltip-bg:                  var(--bm1-mist);
    --tooltip-text:                var(--in0-void);
    --skeleton-shine:              var(--in2-slate);
    /* Mirrors the [data-theme="dark"] block below: only genuine divergences
       from the --btn-* semantic fallbacks need a value here (see the
       components.css comment above --btn-p-border for why). */
    --btn-p-active-bg:  var(--fo1-fern);   /* collapses active = hover */
    --btn-p-hover-text:  var(--bm2-birch); /* void (resting text) only reaches 3.66:1 on fern — birch clears 4.78:1 */
    --btn-p-active-text: var(--bm2-birch);
    --btn-s-hover-bg:  var(--in1-iron);   /* not --color-bg-interactive-hover (ash): birch text only reaches 4.47:1 on ash; slate would match --btn-s-bg (no visible hover), so darken to iron instead (9.54:1) */
    --btn-g-hover-bg:  var(--in2-slate);  /* ghost rests at transparent, so lightening to slate is safe and clears 6.99:1 (ash only reached 4.47:1) */
    --btn-g-active-bg: var(--in0-void);
    --overlap-card-shadow-raised: 0 -4px 32px rgba(0, 0, 0, 0.40);
    --color-section-featured: var(--bm1-mist);
  }
}

/* ── Semantic tokens — light (default) ───────────────────────────────── */
:root,
[data-theme="light"] {
  background:               var(--color-bg);
  color:                    var(--color-text);
  --color-bg:               var(--bm2-birch);
  --color-bg-panel:         var(--bm1-mist);
  --color-bg-inset:         var(--bm0-sand);
  --color-text:             var(--in0-void);
  --color-text-secondary:   var(--in2-slate);
  --color-text-tertiary:    var(--in3-ash);
  --color-border:           var(--in3-ash);
  --color-border-strong:    var(--in1-iron);
  --color-border-subtle:    color-mix(in srgb, var(--in1-iron) 12%, transparent);
  --color-ghost-border:     color-mix(in srgb, var(--in1-iron) 25%, transparent);
  --color-bg-code:          var(--fo3-deepwater);
  --color-accent:           var(--fo1-fern);
  --color-accent-hover:     var(--fo2-forest);
  --color-accent-active:    var(--fo3-deepwater);
  --color-accent-text:      var(--bm2-birch);
  --color-wordmark-dot:     var(--fo1-fern); /* fixed brand color — always fern, never follows theme */
  --color-error:            var(--bl0-ember);
  --color-warning:          var(--bl1-ochre);
  --color-success:          var(--bl3-moss);
  --color-on-error:         var(--bm2-birch);
  --color-on-success:       var(--color-accent-text);
  --color-on-warning:       var(--color-accent-text);
  --color-bg-interactive-hover:          var(--bm1-mist);  /* one step deeper than base bg (birch) */
  --color-bg-interactive-active:         var(--bm0-sand);  /* one step deeper than hover */
  --color-card-highlight-bg:             var(--fo3-deepwater);
  --color-card-highlight-border:         transparent;
  --color-card-highlight-text:           var(--bm2-birch);
  --color-card-highlight-text-secondary: var(--bm1-mist);
  --color-card-highlight-text-tertiary:  var(--bm0-sand);
  --tooltip-bg:                  var(--in0-void);
  --tooltip-text:                var(--bm2-birch);
  --skeleton-shine:              var(--bm2-birch); /* birch (page bg) — lighter than panel (mist) */
  /* No --btn-* overrides needed here: every one of them already matches its
     semantic fallback in light theme (see the components.css comment above
     --btn-p-border) — --btn-g-active-bg is the sole exception, and its light
     value is already the Tier-3 default in components.css. */

  /* Section transition aliases — consumed by divider patterns (T-23–T-28) */
  --color-section:          var(--color-bg);
  /* override --color-section-next on the divider element to match the actual destination section */
  --color-section-next:     var(--color-bg-panel);
  --color-section-base:     var(--color-bg);
  --color-section-layer:    var(--color-bg-panel);
  --color-section-overlay:  var(--color-bg-inset);
  --color-section-featured: var(--in0-void);
}

/* ── Semantic tokens — dark ─────────────────────────────────────────── */
[data-theme="dark"] {
  background:               var(--color-bg);
  color:                    var(--color-text);
  --color-bg:               var(--in0-void);
  --color-bg-panel:         var(--in1-iron);
  --color-bg-inset:         var(--in2-slate);
  --color-text:             var(--bm2-birch);
  --color-text-secondary:   var(--bm1-mist);
  --color-text-tertiary:    var(--bm0-sand);
  --color-border:           var(--in2-slate);
  --color-border-strong:    var(--bm0-sand);
  --color-border-subtle:    color-mix(in srgb, var(--in2-slate) 25%, transparent);
  --color-ghost-border:     color-mix(in srgb, var(--bm2-birch) 25%, transparent);
  --color-bg-code:          var(--in1-iron);
  --color-accent:           var(--fo0-glade);  /* glade: 9.79:1 on void, 5.33:1 on iron — passes AA on all dark surfaces */
  --color-accent-hover:     var(--fo1-fern);   /* hover; --btn-p-active-bg also collapses to fern — void text only reaches 3.66:1 on fern, so hover/active text flips to birch below */
  --color-accent-active:    var(--fo2-forest);
  --color-accent-text:      var(--in0-void);   /* glade bg is light (L=0.49) — dark text required; badge/success/warning text overrides below use --bm2-birch directly */
  --color-wordmark-dot:     var(--fo1-fern); /* fixed brand color — always fern, never follows theme */
  --color-error:            var(--bl0-ember);
  --color-warning:          var(--bl1-ochre);
  --color-success:          var(--bl3-moss);
  --color-on-error:         var(--bm2-birch);
  --color-on-success:       var(--bm2-birch);  /* bloom-palette bg (moss) needs light text; void = 3.81:1 fail */
  --color-on-warning:       var(--bm2-birch);  /* bloom-palette bg (ochre) needs light text; void = 3.80:1 fail */
  --color-bg-interactive-hover:          var(--in3-ash);   /* ash — lightest dark step, contrasts all dark surfaces */
  --color-bg-interactive-active:         var(--in0-void);  /* darker than ghost hover ash (#6B7280) */
  --color-card-highlight-bg:             var(--fo2-forest);
  --color-card-highlight-border:         transparent;
  --color-card-highlight-text:           var(--bm2-birch);
  --color-card-highlight-text-secondary: var(--bm1-mist);
  --color-card-highlight-text-tertiary:  var(--bm0-sand);
  --tooltip-bg:                  var(--bm1-mist);
  --tooltip-text:                var(--in0-void);
  --skeleton-shine:              var(--in2-slate); /* slate — lighter than panel (iron) */
  /* Only genuine divergences from the --btn-* semantic fallbacks are declared
     here (see the components.css comment above --btn-p-border for why). */
  --btn-p-active-bg:   var(--fo1-fern);   /* collapses active = hover */
  --btn-p-hover-text:  var(--bm2-birch);  /* void (resting text) only reaches 3.66:1 on fern — birch clears 4.78:1 */
  --btn-p-active-text: var(--bm2-birch);
  --btn-s-hover-bg:  var(--in1-iron);   /* not --color-bg-interactive-hover (ash): birch text only reaches 4.47:1 on ash; slate would match --btn-s-bg (no visible hover), so darken to iron instead (9.54:1) */
  --btn-g-hover-bg:  var(--in2-slate);  /* ghost rests at transparent, so lightening to slate is safe and clears 6.99:1 (ash only reached 4.47:1) */
  --btn-g-active-bg: var(--in0-void);  /* darker than ghost hover ash (#6B7280) */
  --overlap-card-shadow-raised: 0 -4px 32px rgba(0, 0, 0, 0.40);
  --color-section-featured: var(--bm1-mist);
}

/* ── Surface patterns ─────────────────────────────────────────────────── */
/* base/layer/overlay are relative — they adapt to the current data-theme.   */
/* featured is the exception: always dark regardless of page theme.          */
/* Only tokens that differ from the inherited theme values are declared.     */
/* Each relative surface that changes in dark mode has two override selectors:*/
/*   [data-theme="dark"] [data-surface]  — theme on ancestor element         */
/*   [data-surface][data-theme="dark"]   — theme on same element             */
/* featured uses both forms too — see block comment below.                   */

/* base — resets to page-level bg (useful inside deeper surface contexts) */
[data-surface="base"] {
  background: var(--bm2-birch);
  --color-bg: var(--bm2-birch);
}

[data-theme="dark"] [data-surface="base"],
[data-surface="base"][data-theme="dark"] {
  background: var(--in0-void);
  --color-bg: var(--in0-void);
}

/* layer — cards, sidebars, panels */
[data-surface="layer"] {
  background:                   var(--bm1-mist);
  --color-bg:                   var(--bm1-mist);
  --color-bg-panel:             var(--bm2-birch);
  --color-bg-interactive-hover: var(--bm0-sand);  /* go deeper from mist */
  --skeleton-base:              var(--bm0-sand);
  --skeleton-shine:             var(--bm2-birch);
}

[data-theme="dark"] [data-surface="layer"],
[data-surface="layer"][data-theme="dark"] {
  background:                   var(--in1-iron);
  --color-bg:                   var(--in1-iron);
  --color-bg-panel:             var(--in2-slate);
  --color-bg-code:              var(--in2-slate);
  --color-bg-interactive-hover: var(--in3-ash);
  --skeleton-base:              var(--in2-slate);
  --skeleton-shine:             var(--in3-ash);
  --input-border:               var(--in3-ash); /* ash visible on slate panel bg */
}

/* overlay — modals, dropdowns, floating elements */
[data-surface="overlay"] {
  background:                   var(--bm0-sand);
  --color-bg:                   var(--bm0-sand);
  --color-bg-inset:             var(--bm1-mist);   /* sand is the darkest light step — inset goes lighter for contrast */
  --color-bg-interactive-hover: var(--bm2-birch);  /* go lighter — sand is the darkest light step */
  --skeleton-base:              var(--bm1-mist);
  --skeleton-shine:             var(--bm2-birch);
}

[data-theme="dark"] [data-surface="overlay"],
[data-surface="overlay"][data-theme="dark"] {
  background:                   var(--in2-slate);
  --color-bg:                   var(--in2-slate);
  --color-bg-panel:             var(--in2-slate); /* slate ceiling — overlay bg is already slate, cap panels here */
  --color-bg-inset:             var(--in1-iron);
  --color-bg-interactive-hover: var(--in3-ash);
  --skeleton-base:              var(--in1-iron);
  --skeleton-shine:             var(--in3-ash);
  --input-border:               var(--in3-ash); /* ash visible on slate bg */
}

/* featured — maximum-contrast section; void in light mode, mist in dark mode.
   In light mode, text/border tokens are set to dark-palette values.
   In dark mode, the full token set flips to light-palette values (text → void,
   bg → mist) so descendants inherit correct contrast in both themes without
   needing data-theme on the element.
   This selector covers only the default (unpinned) light-page case. An
   explicit data-theme="light" pin needs its OWN, later rule (in the
   "Light-theme surface overrides" section below, after the dark-flip block)
   even though the declarations are identical — both that rule and the dark-
   flip block below sit at specificity 0-2-0 for the same-element pin form, so
   whichever comes LAST in the file wins the tie. Folding the light-pin
   selectors into this early rule (as a prior version of this file did) is a
   real bug, not just duplication: it would make the light-pin rule lose that
   tie to the dark-flip block. See the light-pin block's own comment for the
   base/layer/overlay pattern this mirrors.
   The :not([data-theme="dark"]) guard (matching the same guard used on the
   light-pin form of base/layer/overlay/featured below) makes this selector
   mutually exclusive with the same-element dark pin, instead of merely
   losing a specificity tie to it. That's not just cleanliness: without it,
   any --btn-* override this block declares that the dark-flip block DOESN'T
   also declare would leak straight through onto a dark-pinned element, since
   custom properties cascade per-property, not per-rule — a value from a
   "losing" rule still wins for a property the "winning" rule never touches.
   This guard only closes that leak for the same-element pin case, though —
   it does nothing for an unpinned featured surface sitting inside a dark
   *ancestor* (data-theme="dark" on <html>, not on this element), since
   :not() only inspects the element's own attributes. That's why the two
   explicit resets in the dark-flip block below (--btn-s-hover-bg,
   --btn-g-hover-bg) are still required — they close the ancestor-inheritance
   leak, which this guard cannot.
   The dark-flip block right below handles both the ancestor form
   ([data-theme="dark"] [data-surface="featured"]) and the same-element pin
   form ([data-surface="featured"][data-theme="dark"]).
   Button tokens only need a value here where the surface's colors genuinely
   diverge from their semantic fallback (see the components.css comment above
   --btn-p-border) — --color-bg-inset/--color-border-strong/etc. are already
   correctly scoped to this surface, so --btn-s-bg/--btn-g-border/etc. resolve
   correctly here for free via their fallback, without redeclaration. */
[data-surface="featured"]:not([data-theme="dark"]) {
  background:                   var(--in0-void);
  color:                        var(--color-text);
  --color-bg:                   var(--in0-void);
  --color-bg-panel:             var(--in1-iron);
  --color-bg-inset:             var(--in2-slate);
  --color-bg-code:              var(--in1-iron);
  --color-text:                 var(--bm2-birch);
  --color-text-secondary:       var(--bm1-mist);
  --color-text-tertiary:        var(--bm0-sand);
  --color-border:               var(--in2-slate);
  --color-border-strong:        var(--bm0-sand);
  --color-border-subtle:        color-mix(in srgb, var(--in2-slate) 25%, transparent);
  --color-ghost-border:         color-mix(in srgb, var(--bm2-birch) 25%, transparent);
  --color-bg-interactive-hover: var(--in3-ash);
  --skeleton-base:              var(--in1-iron);
  --skeleton-shine:             var(--in2-slate);
  --btn-s-hover-bg:             var(--in1-iron);  /* not --color-bg-interactive-hover (ash): birch reaches only 4.47:1 on ash, and slate would match --btn-s-bg (no visible hover) */
  --btn-g-hover-bg:             var(--in2-slate); /* ghost rests at transparent, so lightening to slate is safe (6.99:1 vs ash's 4.47:1) */
  --btn-g-active-bg:            var(--in2-slate);
}

[data-theme="dark"] [data-surface="featured"],
[data-surface="featured"][data-theme="dark"] {
  background:                   var(--bm1-mist);
  color:                        var(--color-text);
  --color-bg:                   var(--bm1-mist);
  --color-bg-panel:             var(--bm2-birch);
  --color-bg-inset:             var(--bm0-sand);
  --color-bg-code:              var(--fo3-deepwater);
  --color-text:                 var(--in0-void);
  --color-text-secondary:       var(--in2-slate);
  --color-text-tertiary:        var(--in3-ash);
  --color-border:               var(--in3-ash);
  --color-border-strong:        var(--in1-iron);
  --color-border-subtle:        color-mix(in srgb, var(--in1-iron) 12%, transparent);
  --color-ghost-border:         color-mix(in srgb, var(--in1-iron) 25%, transparent);
  --color-bg-interactive-hover: var(--bm0-sand);
  --color-accent:               var(--fo1-fern);
  --color-accent-hover:         var(--fo2-forest);
  --color-accent-text:          var(--bm2-birch);
  --skeleton-base:              var(--bm0-sand);
  --skeleton-shine:             var(--bm2-birch);
  /* --btn-p-active-bg needs a reset too, for a THIRD reason beyond the two
     below: this surface's own rest accent (fern) happens to equal the
     ambient dark theme's --btn-p-active-bg override (also fern, "collapse
     active = hover" there). Left unset here, that ambient value still wins
     (it's genuinely declared, not merely a fallback default, so it beats
     --color-accent-active regardless of what that resolves to) — making a
     press revert to the resting color instead of darkening past hover.
     Collapsing active = hover here too, but to THIS surface's own hover
     (forest, not the ambient's fern) fixes it. */
  --btn-p-active-bg:            var(--fo2-forest);
  /* These two don't diverge from their semantic fallback here — but they DO
     diverge in the light-default featured block below (and in the ambient
     dark theme) and must be reset back to the fallback explicitly: the bare
     [data-surface="featured"] selector still matches a same-element dark pin
     (attribute selectors aren't mutually exclusive), and the ambient dark
     theme's own override inherits down into an unpinned featured surface —
     both would otherwise leak the wrong (birch-targeted, iron/slate) value
     in here even though this surface's void text is fine with the sand
     fallback. */
  --btn-s-hover-bg:             var(--color-bg-interactive-hover);
  --btn-g-hover-bg:             var(--color-bg-interactive-hover);
  --btn-g-active-bg:            var(--bm0-sand);
}

/* ── Light-theme surface overrides ─────────────────────────────────────── */
/* Without these, data-theme="light" data-surface="x" on an element inside  */
/* a dark page resolves to dark palette values — the ancestor dark selector  */
/* ([data-theme="dark"] [data-surface]) at specificity 0-2-0 beats the      */
/* default light surface rule at 0-1-0. Same-element form (0-2-0) ties on   */
/* specificity; source order here ensures light wins when declared last.     */
/* The descendant form uses :not() (specificity 0-3-0) to beat the dark     */
/* ancestor while excluding elements that are explicitly dark themselves.    */

[data-surface="base"][data-theme="light"],
[data-theme="light"] [data-surface="base"]:not([data-theme="dark"]) {
  background:        var(--bm2-birch);
  --color-bg:        var(--bm2-birch);
  --input-border:    var(--color-border);
}

[data-surface="layer"][data-theme="light"],
[data-theme="light"] [data-surface="layer"]:not([data-theme="dark"]) {
  background:                   var(--bm1-mist);
  --color-bg:                   var(--bm1-mist);
  --color-bg-panel:             var(--bm2-birch);
  --color-bg-code:              var(--fo3-deepwater);
  --color-bg-interactive-hover: var(--bm0-sand);
  --skeleton-base:              var(--bm0-sand);
  --skeleton-shine:             var(--bm2-birch);
  --input-border:               var(--color-border);
}

[data-surface="overlay"][data-theme="light"],
[data-theme="light"] [data-surface="overlay"]:not([data-theme="dark"]) {
  background:                   var(--bm0-sand);
  --color-bg:                   var(--bm0-sand);
  --color-bg-inset:             var(--bm1-mist);
  --color-bg-code:              var(--fo3-deepwater);
  --color-bg-interactive-hover: var(--bm2-birch);
  --skeleton-base:              var(--bm1-mist);
  --skeleton-shine:             var(--bm2-birch);
  --input-border:               var(--color-border);
}

/* featured is the exception elsewhere in this file (always dark, pinned to  */
/* page theme rather than adapting), but a local data-theme="light" pin must */
/* still be able to force the void variant back on inside a dark page — same */
/* specificity problem as base/layer/overlay above, same fix. This repeats   */
/* the bare [data-surface="featured"] block's declarations verbatim; that is */
/* required, not incidental — this rule must win the specificity tie against */
/* the dark-flip block above by coming later in the file, so it can't be     */
/* merged into that earlier rule's selector list (see that block's comment). */
[data-surface="featured"][data-theme="light"],
[data-theme="light"] [data-surface="featured"]:not([data-theme="dark"]) {
  background:                   var(--in0-void);
  --color-bg:                   var(--in0-void);
  --color-bg-panel:             var(--in1-iron);
  --color-bg-inset:             var(--in2-slate);
  --color-bg-code:              var(--in1-iron);
  --color-text:                 var(--bm2-birch);
  --color-text-secondary:       var(--bm1-mist);
  --color-text-tertiary:        var(--bm0-sand);
  --color-border:               var(--in2-slate);
  --color-border-strong:        var(--bm0-sand);
  --color-border-subtle:        color-mix(in srgb, var(--in2-slate) 25%, transparent);
  --color-ghost-border:         color-mix(in srgb, var(--bm2-birch) 25%, transparent);
  --color-bg-interactive-hover: var(--in3-ash);
  --skeleton-base:              var(--in1-iron);
  --skeleton-shine:             var(--in2-slate);
  --btn-s-hover-bg:             var(--in1-iron);  /* not --color-bg-interactive-hover (ash): birch reaches only 4.47:1 on ash, and slate would match --btn-s-bg (no visible hover) */
  --btn-g-hover-bg:             var(--in2-slate); /* ghost rests at transparent, so lightening to slate is safe (6.99:1 vs ash's 4.47:1) */
  --btn-g-active-bg:            var(--in2-slate);
}
/* ── Farn — Base reset and global styles ──────────────────────────────── */

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.7;
  background: var(--color-bg);
  color: var(--color-text);
  transition: background-color var(--duration-slow) var(--ease-default), color var(--duration-slow) var(--ease-default);
}

img {
  max-width: 100%;
  display: block;
}

summary {
  list-style: none;
  display: block;
}

:where(a) {
  color: var(--link-color);
}

:where(a:visited) {
  color: var(--link-visited-color);
}

:where(a:hover) {
  color: var(--link-hover-color);
}

/* ── Focus ─────────────────────────────────────────────────────────────────────── */
:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
  border-radius: inherit;
}

:focus:not(:focus-visible) {
  outline: none;
}

/* ── Reduced motion ────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
