/* ─── DAOAML wordmark ────────────────────────────────────────────
 * Font: **JetBrains Mono 700 (Bold)** (free, Apache 2.0).
 * https://www.jetbrains.com/lp/mono/  ·  also on Google Fonts.
 *
 * Lowercase, two-tone (dao dim, aml bright). This is the canonical
 * brand face — JetBrains Mono's signature touch is the **loop-l**:
 * the lowercase `l` has a curl at the bottom-right so it can never
 * be confused with `I` or `1`. That curl is the most-recognised
 * fingerprint of the daoaml wordmark — it's what makes the word
 * read as "daoaml" rather than "daoamI".
 *
 * History: started as JetBrains Mono in v1 admin → briefly swapped
 * to a self-hosted pixel face (Visitor / 04b_03) → then Pixelify
 * Sans → then Tektur during a "match the display tier" experiment.
 * Returned to JetBrains Mono per design ownership, who confirmed
 * the curl-l is the brand mark's defining feature.
 *
 * Class name `.font-visitor` is a legacy holdover from the pixel-
 * font era (Visitor pixel font, 04b_03 — both retired); kept stable
 * so existing markup doesn't need renaming across every shell.js
 * header injection site.
 *
 * The wordmark markup is split into two child spans `.logo-dimmed`
 * (dao) and `.logo-bright` (aml); the two-tone split alone carries
 * the brand-mark personality. */
.font-visitor {
  font-family: 'JetBrains Mono', 'Fira Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 700;
  font-size: 28px;
  line-height: 1;
  letter-spacing: -0.02em;
  text-transform: lowercase;
  display: inline-block;
  position: relative;
  user-select: none;
}

/* ─── Headline rhythm + accent system ───────────────────────────
 * Mixed-colour headlines: the body of every h1-h6 stays in the
 * regular foreground colour (white-ish in dark / dark-ink in light),
 * and a deliberately-wrapped accent span on one rhetorical-centre
 * word picks up the themed accent colour:
 *
 *   • dark theme:  phosphor green  (var(--phosphor) ≈ #7af0a0)
 *   • light theme: rust orange     (#c85820 = color-ochre)
 *
 * UI Designer rule of thumb (2026-05-22): "If the reader sees only
 * one word from this headline, which one tells them what we're
 * selling?" That word gets the accent. Usually a verb of action
 * (check, pay, slipped, fail) or a 2-3-word differentiator phrase
 * (no account, one page, by itself).
 *
 * Two layers:
 *   1. DEFENSIVE LOCK — every <span> inside h1-h6 inherits font-*
 *      and gets text-shadow nuked. Utility classes (font-medium,
 *      text-fgdim, italic) accidentally added to inner spans are
 *      visually no-ops — prevents rhythm breakage.
 *
 *   2. ACCENT ALLOW-LIST — a small set of opt-in class names
 *      (.text-phosphor, .accent, .phosphor, .glow-text) pick up
 *      var(--headline-accent). The allow-list has higher selector
 *      specificity (0,1,1) than the lock (0,0,2) so the colour
 *      wins without !important. Tailwind utility .text-phosphor
 *      (0,1,0) also loses to the allow-list, so the themed colour
 *      is authoritative regardless of which accent class was used.
 *
 * History:
 *   • round 1 (017490f): font-weight inheritance lock
 *   • round 2 (377656e): colour inheritance lock
 *   • round 3 (552a2f3): accent allow-list per-theme — THIS shape
 *   • round 4 (cec03f2): whole-heading accent — rejected, removed
 *   • round 5 (this):    back to mixed pattern + UI Designer's
 *                        per-page accent-word picks rolled into HTML */
h1 > span, h2 > span, h3 > span,
h4 > span, h5 > span, h6 > span {
  font-family: inherit;
  font-weight: inherit;
  font-style:  inherit;
  color:       inherit;
  text-shadow: none;
}

/* Theme-aware headline accent token. */
:root                  { --headline-accent: var(--phosphor); }
[data-theme="light"]   { --headline-accent: #c85820; }   /* color-ochre */

/* Accent-class allow-list — opts a span into the themed colour. */
h1 > .text-phosphor, h2 > .text-phosphor, h3 > .text-phosphor,
h4 > .text-phosphor, h5 > .text-phosphor, h6 > .text-phosphor,
h1 > .accent,        h2 > .accent,        h3 > .accent,
h4 > .accent,        h5 > .accent,        h6 > .accent,
h1 > .phosphor,      h2 > .phosphor,      h3 > .phosphor,
h4 > .phosphor,      h5 > .phosphor,      h6 > .phosphor,
h1 > .glow-text,     h2 > .glow-text,     h3 > .glow-text,
h4 > .glow-text,     h5 > .glow-text,     h6 > .glow-text {
  color: var(--headline-accent);
}
/* Two-tone only — dao = phosphor brand green (~13.7:1 on warm-
 * charcoal), aml = pure white. The horizontal scanline strip got
 * dropped per UX feedback ("видна и мешает читать") — at any opacity
 * it cut through pixel-font letterforms, breaking legibility for the
 * sake of a CRT decoration. The two-tone split alone carries the
 * brand-mark personality. */
:root {
    --bg: #0a0d0c; --panel: #0f1413; --line: #1d2725;
    --fg: #cfe8d8; --fgdim: #a8c0b6; --mute: #8aa39a; --phosphor: #7af0a0;

    /* Secondary chrome tier — used for table toolbars, search inputs,
     * placeholders. Stayed dark-only in cabinet inline styles until
     * the C2 refactor wave; promoted to tokens so the light override
     * can flip them. */
    --line2:       #28342f;
    --placeholder: #5a6a64;

    /* Semi-transparent panel washes — cabinet pages stack these over
     * the page bg to read as "slightly recessed". On dark theme they
     * are rgba over #0a0d0c (the page bg); on light theme they need
     * to be rgba over #f7eed5 cream so the wash stays an effect, not
     * a near-black scrim painted over cream. 4 percentages cover
     * every cabinet/me-page consumer in the corpus (40/50/60/92). */
    --wash-40:  rgba(10,13,12,.40);
    --wash-50:  rgba(10,13,12,.50);
    --wash-60:  rgba(10,13,12,.60);
    --wash-70:  rgba(10,13,12,.70);
    --wash-92:  rgba(10,13,12,.92);
    --wash-100: rgba(10,13,12,1.00);

    /* Glyph color on the phosphor primary CTA. On dark theme
     * phosphor is a bright #7af0a0 (green), so we paint near-black
     * text on it. On light theme phosphor flips to a warm rust
     * orange #a85220 (admin-v2 cream-paper palette), so text needs
     * to be cream — clears AA at 4.6:1 on the rust surface. */
    --on-phosphor: #06120a;

    /* Risk scale — mirrors admin-v2's risk tokens but lifted to the
     * static-side shell namespace so check.html's JS-generated SVGs
     * can use `var(--risk-*)` instead of hardcoded hex. Dark values
     * stay bright; light values shift darker for AA on cream. */
    --risk-clean:    #7ee787;
    --risk-low:      #c1d756;
    --risk-caution:  #f0c674;
    --risk-suspect:  #f08040;
    --risk-critical: #ff6b6b;
    /* Emphasis variant of risk-critical — slightly brighter pink for
     * error eyebrows / decision-button accents that need to read
     * "alert" against the body text colour. Folds to plain
     * --risk-critical on light theme (no need for a brighter shade
     * on cream — the deep red already reads alert). */
    --risk-critical-emph: #ff8585;
    /* Info / medium-review tier — the "needs human attention" hue.
     * Dark: legacy sky-cyan #7ad7f0 (≈ 9.9:1 on #0a0d0c, well above AA).
     * Light: deep ocean blue #0c6e9c (≈ 4.9:1 on cream, clears AA body).
     * Used for `.r-med` / `.cat-mark.h-med` / `.tag-ens` / decision-
     * button "review" / etc. — see check.html sweep. */
    --risk-info: #7ad7f0;

    /* Wordmark tokens — "dao" accent + "aml" bright pair.
     * Dark: phosphor-green "dao" + white "aml" (legacy CRT vibe).
     * Light: vivid brand-orange #e8814a "dao" + near-black "aml"
     * (Mediterranean terracotta palette). The "dao" mark is treated
     * as a logo per WCAG 1.4.3 — exempt from text contrast minima
     * so we use the brand-vivid hex; the deeper rust #a85220 carries
     * the AA contract elsewhere (--phosphor). */
    --logo-dimmed: var(--phosphor);
    --logo-bright: #ffffff;
  }

  .font-visitor .logo-dimmed { color: var(--logo-dimmed); }
  .font-visitor .logo-bright { color: var(--logo-bright); }

  /* ── .shadow-glow override — Tailwind v4 bakes @theme `--shadow-
   * glow` to literal phosphor hex at build time, so the utility
   * paints dark-phosphor halo on cream paper. Override the utility
   * directly with live color-mix() that re-resolves per theme. */
  .shadow-glow {
    --tw-shadow:
      0 0 0 1px color-mix(in srgb, var(--phosphor) 18%, transparent),
      0 0 24px -6px color-mix(in srgb, var(--phosphor) 35%, transparent);
  }

  /* ── color-mix() fallback layer ────────────────────────────────
   * `color-mix(in srgb, …)` is the modern way to derive transparent
   * tints from a single hue token (added Chrome 111 / Safari 16.2 /
   * Firefox 113 — April 2023). Browsers older than that drop any
   * declaration whose value parses as invalid, including the rules
   * that compose risk-tier alerts, the verdict-card chrome, and the
   * pricing sticky-bar. To keep the ~1.5-3% legacy tail readable
   * (corporate browsers, old iOS, etc.) the rule below feature-
   * gates a dark-only fallback palette ONLY when color-mix() is
   * NOT supported, so the page degrades gracefully to a usable
   * dark theme instead of a broken transparent shell. */
  @supports not (color: color-mix(in srgb, red, blue)) {
    :root {
      /* Pre-resolve the common color-mix shapes used across the
       * codebase to their dark-theme rgba equivalents. Light-theme
       * is OFF for these browsers (we keep them on dark — old
       * browsers + light cream is the rarest combo and not worth
       * the maintenance burden of a second fallback set). */
      --risk-critical-soft: rgba(255,107,107,.10);
      --risk-critical-line: rgba(255,107,107,.40);
      --risk-caution-soft:  rgba(240,198,116,.10);
      --risk-caution-line:  rgba(240,198,116,.40);
      --risk-low-soft:      rgba(122,240,160,.10);
      --risk-low-line:      rgba(122,240,160,.40);
      --phosphor-soft:      rgba(122,240,160,.10);
      --phosphor-line:      rgba(122,240,160,.40);
    }
    /* Force dark theme on color-mix-less browsers so the static
     * hex fallback rgba values in their declarations match the page
     * bg. Users can still toggle to light via the IIFE but the
     * resulting page will have some unstyled fallback components. */
    html:not([data-theme="dark"]) {
      /* no-op selector — kept for documentation; real fallback is
       * the @supports gate above which only injects tokens. */
    }
  }

  /* ────────────────────────────────────────────────────────────────
   * Light theme — warm cream paper. Tokens mirror admin-v2 globals.css
   * (canonical source: frontend/admin-v2/src/styles/globals.css). Apply
   * by setting `data-theme="light"` on <html>. Default (no attribute)
   * stays dark per product spec.
   *
   * Cabinet pages (me/billing.html etc.) embed inline <style> blocks
   * with hardcoded dark hex; we re-declare those class selectors here
   * with token-derived light values so a single attribute flip covers
   * the whole surface graph without touching each cabinet HTML.
   * ──────────────────────────────────────────────────────────────── */
  [data-theme="light"] {
    --bg: #f7eed5;
    --panel: #f0e3c2;
    --line: #c7b48a;
    --line2: #97825e;        /* between line + mute on cream */
    --placeholder: #87785f;  /* readable hint text on cream */
    --fg: #2a2014;
    --fgdim: #5a4a32;
    --mute: #6b5c45;
    /* Brand accent shift on cream — was deep emerald #047857. Now a
     * warm rust orange that mirrors the dark-theme phosphor energy on
     * a Mediterranean terracotta canvas. #a85220 = 4.6:1 on #f7eed5
     * (AA body). The vivid #e8814a sits one tier brighter for the
     * "dao" wordmark and logo SVG where WCAG 1.4.3 exempts logos. */
    --phosphor: #a85220;
    --logo-dimmed: #e8814a;   /* "dao" — vivid brand orange (logo exempt) */
    --logo-bright: #2a2014;   /* "aml" — deep ink for second-tone contrast */
    /* Wash tier — semi-opaque cream so "recessed panel" effect carries
     * over to the light surface without painting dark-on-cream. */
    --wash-40:  rgba(240,227,194,.40);
    --wash-50:  rgba(240,227,194,.50);
    --wash-60:  rgba(240,227,194,.60);
    --wash-70:  rgba(232,217,168,.70);
    --wash-92:  rgba(247,238,213,.94);
    --wash-100: rgba(247,238,213,1.00);
    /* Cream glyph on rust CTA — clears AA at 4.6:1 on #a85220. */
    --on-phosphor: #f7eed5;
    /* Risk scale on cream — shifted darker for AA. Mirrors admin-v2
     * globals.css `[data-theme="light"]` risk block. */
    --risk-clean:    #2d6e2d;
    --risk-low:      #5a7820;
    --risk-caution:  #b88018;
    --risk-suspect:  #c85820;
    --risk-critical: #b8201f;
    --risk-critical-emph: var(--risk-critical);  /* same as base on light */
    --risk-info:     #0c6e9c;                    /* AA-clearing deep ocean blue on cream */

    /* Tailwind v4 generates `text-fg`, `bg-bg`, `border-line` utilities
     * from a separate `--color-*` namespace defined in tailwind.css
     * `:root`. We re-declare those tokens here with the same light
     * palette so every utility class (text-mute, bg-panel, border-line,
     * border-phosphor, text-phosphor, etc.) flips automatically on
     * theme change — no hunt for hardcoded class consumers.
     * Keep in sync with the public `--bg/--fg/...` tokens above. */
    --color-bg:       #f7eed5;
    --color-panel:    #f0e3c2;
    --color-line:     #c7b48a;
    --color-fg:       #2a2014;
    --color-fgdim:    #5a4a32;
    --color-mute:     #6b5c45;
    --color-phosphor: #a85220;
    /* `--color-amber: #b88018` would only hit 2.96:1 on cream — fails
     * WCAG AA body. Drop to #8a5e10 → 4.92:1 (AA body) so the footer
     * column headers, FREE plan-tag, and signup gift-card glyphs stay
     * readable on light. Same hue family, just shifted darker. */
    --color-amber:    #8a5e10;
    --color-danger:   #b8201f;
    /* Extended Tailwind namespace — panel2/line2/phosphor2/violet/
     * ochre tokens declared in tailwind.in.css's @theme block need
     * cream-paper equivalents or `text-line2` / `bg-panel2` Tailwind
     * utilities leak slate-on-cream values. Defined here (not in
     * tailwind.in.css :root) so the override beats the @theme layer. */
    --color-panel2:    #ead6a8;   /* warm-paper muted panel */
    --color-line2:     #97825e;   /* same as --line2 above */
    --color-phosphor2: #6b3713;   /* deeper rust, hover/secondary */
    --color-violet:    #6f4a7a;   /* darker mauve for cream AA */
    --color-ochre:     #c85820;   /* warm orange-brown, AA-clearing */
  }

  /* ── Body decoration layer overrides ────────────────────────────
   * The base `.scanlines / .vignette / .crt-flicker` body classes
   * paint dark-theme gradients (phosphor grid, black vignette,
   * white-screen scanlines). On cream paper a black corner-vignette
   * is jarring — flip every layer to a warm-paper analogue. */
  [data-theme="light"] body {
    /* Light-theme body grid + glow.
     *
     * Was 2.5% phosphor lines + 6% phosphor radial — both barely
     * visible on cream (≈1.06:1 against #f7eed5; eye reads as a
     * single flat colour, not a wireframe canvas). Split the two
     * layers so they carry different jobs:
     *   - Grid lines paint with var(--line) (#c7b48a taupe) at 60%
     *     so the 32×32 grid reads as classic graph paper —
     *     ≈1.39:1 contrast, same perceptual weight as the
     *     dark-theme phosphor grid against warm-charcoal.
     *   - Radial-from-top stays phosphor-tinted (warm rust) at 16%
     *     for the brand glow — a sunset wash above the page.
     *
     * The vignette ramp at the bottom also bumps to 60% line so it
     * acts as a real darkening corner rather than a hint.
     */
    background-image:
      linear-gradient(color-mix(in srgb, var(--line) 60%, transparent) 1px, transparent 1px),
      linear-gradient(90deg, color-mix(in srgb, var(--line) 60%, transparent) 1px, transparent 1px),
      radial-gradient(ellipse 80% 60% at 50% -10%, color-mix(in srgb, var(--phosphor) 16%, transparent), transparent 60%);
  }
  [data-theme="light"] .vignette::after {
    background: radial-gradient(ellipse at center,
                                transparent 55%,
                                color-mix(in srgb, var(--line2) 50%, transparent) 100%);
  }
  /* Scanlines mix `screen` of white over dark — invisible on cream.
   * Drop the pseudo entirely on light (no replacement: cream paper
   * doesn't need a CRT veneer to read as "terminal"). */
  [data-theme="light"] .scanlines::before { display: none; }

  /* Cabinet sub-nav (inline-styled in me/*.html). */
  [data-theme="light"] .subnav { border-bottom-color: var(--line); }
  [data-theme="light"] .subnav a { color: var(--mute); }
  [data-theme="light"] .subnav a:hover { color: var(--fg); }
  [data-theme="light"] .subnav a.is-active {
    color: var(--phosphor); border-bottom-color: var(--phosphor);
  }

  /* Cabinet state strip (inline-styled in me/*.html). */
  [data-theme="light"] .state-strip {
    border-color: var(--line);
    background: rgba(250, 240, 220, 0.5);
    color: var(--mute);
  }
  [data-theme="light"] .state-strip .ss-eyebrow { color: var(--mute); }
  [data-theme="light"] .state-strip .b { color: var(--fg); }
  [data-theme="light"] .state-strip .sep { color: var(--line); }
  [data-theme="light"] .state-strip .plan-tag { color: var(--color-amber); }
  [data-theme="light"] .state-strip .plan-tag.paid { color: var(--phosphor); }


/* ============================================================
 * cabinet v3 utilities — approved by 6-expert review (≥9.5/10)
 * See docs/cabinet-redesign-plan-v3-approved.md + brand-constitution.md
 *
 * Scope: /me/*.html cabinet pages only. Marketing pages keep
 * existing .font-display sizing.
 * ============================================================ */

/* H1 re-scale for cabinet — max 22px vs marketing's 38px.
 * Per UX critique: cabinet ≠ marketing. */
.cabinet-h1 {
  font-size: clamp(1.1rem, 1.8vw, 1.4rem);
}

/* Single-line status strip — replaces oversized .status-card with phosphor
 * glow. Per plan §S1.5: "drop marketing chrome from cabinet." */
.status-line {
  margin: 0 0 1.25rem;
  font-family: 'Fira Mono', ui-monospace, monospace;
  font-size: 13px;
  color: var(--fgdim);
  line-height: 1.6;
}
.status-line-row {
  display: flex;
  align-items: center;
  gap: 0.5em;
  flex-wrap: wrap;
}
.status-line .status-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  color: var(--mute);
  text-transform: lowercase;
  letter-spacing: 0.04em;
  font-size: 12px;
}
.status-line .status-eyebrow .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--phosphor);
  box-shadow: 0 0 6px color-mix(in srgb, var(--phosphor) 60%, transparent);
  flex-shrink: 0;
}
.status-line .status-eyebrow .dot.is-low    { background: var(--risk-caution); box-shadow: 0 0 6px color-mix(in srgb, var(--risk-caution) 60%, transparent); }  /* R-code-review: --amber was undefined; --risk-caution is the existing amber-yellow token */
.status-line .status-eyebrow .dot.is-empty  { background: var(--risk-critical); box-shadow: 0 0 6px color-mix(in srgb, var(--risk-critical) 60%, transparent); }
.status-line .status-sep   { color: var(--line); }
.status-line .status-h1    { color: var(--fg); font-weight: 700; }
.status-line .status-sub-inline { color: var(--fgdim); }
.status-line .status-actions { margin-top: 0.4rem; }
.status-line .status-actions.hidden { display: none; }

/* Sub-nav with ⋮ more dropdown — per UX critique R2: reports promoted
 * to primary; api/security/referrals moved under ⋮ more. */
.subnav-more {
  position: relative;
  display: inline-block;
  margin-left: 0.5rem;
}
.subnav-more > summary {
  list-style: none;
  cursor: pointer;
  color: var(--mute);
  font-family: 'Fira Mono', ui-monospace, monospace;
  font-size: 13px;
  /* A11y: WCAG 2.2 AA target-size minimum is 24×24px. Was 0.2rem 0.4rem
   * (~22px tall) — failed. Bumped to 0.45rem 0.75rem + min-height. */
  padding: 0.45rem 0.75rem;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  user-select: none;
  -webkit-user-select: none;
}
.subnav-more > summary:focus-visible {
  outline: 2px solid var(--phosphor);
  outline-offset: 2px;
}
.subnav-more > summary::-webkit-details-marker { display: none; }
.subnav-more > summary::marker { content: ''; }
.subnav-more > summary:hover { color: var(--fg); }
.subnav-more[open] > summary { color: var(--phosphor); }
.subnav-more-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 160px;
  background: var(--panel);
  border: 1px solid var(--line);
  z-index: 50;
  display: flex;
  flex-direction: column;
  box-shadow: 0 6px 16px -8px rgba(0,0,0,.4);
}
.subnav-more-menu a {
  /* A11y WCAG 2.2 AA: target ≥24px height. 0.5rem 0.85rem + min-height 32px. */
  padding: 0.5rem 0.85rem;
  min-height: 32px;
  display: flex;
  align-items: center;
  color: var(--fgdim);
  font-family: 'Fira Mono', ui-monospace, monospace;
  font-size: 13px;
  text-decoration: none;
  border-bottom: 1px solid var(--line);
}
.subnav-more-menu a:focus-visible {
  outline: 2px solid var(--phosphor);
  outline-offset: -2px;
}
.subnav-more-menu a:last-child { border-bottom: none; }
.subnav-more-menu a:hover {
  color: var(--phosphor);
  background: color-mix(in srgb, var(--phosphor) 4%, transparent);
}
.subnav-more-menu a.is-active {
  color: var(--phosphor);
}

/* Light theme parity */
[data-theme="light"] .subnav-more > summary:hover { color: var(--fg); }
[data-theme="light"] .subnav-more[open] > summary { color: var(--phosphor); }
[data-theme="light"] .subnav-more-menu { background: #fff; border-color: var(--line); }
[data-theme="light"] .subnav-more-menu a:hover { background: color-mix(in srgb, var(--phosphor) 8%, transparent); }
[data-theme="light"] .status-line .status-eyebrow .dot { box-shadow: 0 0 4px color-mix(in srgb, var(--phosphor) 50%, transparent); }
[data-theme="light"] .status-line .status-h1 { color: var(--fg); }


/* ============================================================
 * A11y — skip-to-main link (WCAG 2.4.1 Level A "Bypass Blocks")
 *
 * Inserted by shell.js ensureSkipLink() as the first focusable
 * element on each page. Hidden until focused. Keyboard users
 * Tab→Enter → jump to <main>.
 * ============================================================ */
.sr-only-focusable {
  position: absolute;
  left: 0; top: 0;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0; padding: 0; margin: -1px;
}
.sr-only-focusable:focus,
.sr-only-focusable:active {
  position: fixed;
  z-index: 10000;
  left: 12px; top: 12px;
  width: auto; height: auto;
  overflow: visible;
  clip: auto;
  padding: 8px 16px;
  background: var(--phosphor);
  color: var(--on-phosphor, var(--bg));
  font-family: 'Fira Mono', ui-monospace, monospace;
  font-size: 13px;
  text-decoration: none;
  outline: 2px solid var(--phosphor);
  outline-offset: 2px;
  margin: 0;
}


/* ============================================================
 * A11y — prefers-reduced-motion (WCAG 2.3.3 AAA + 2.2.2 Level A)
 *
 * Per a11y audit R1: shell.css had .fade-up, .crt-flicker, .blink,
 * .marquee, .skel-pulse, hover transforms — none respected reduced
 * motion. Vestibular-sensitive users got CRT flicker + infinite
 * marquee + page-shift hovers.
 *
 * Universal kill-switch via attribute selector. Specific overrides
 * preserve state-meaningful animations (e.g. status-eyebrow .dot
 * pulse on out-of-checks empty state stays — semantic urgency).
 * ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* Specific opt-out: scanlines are decorative, no info value.
   * Marquee is decorative & Level A failure under WCAG 2.2.2 (Pause). */
  .scanlines::before,
  .crt-flicker::before,
  .err-marquee,
  .err-marquee-track {
    animation: none !important;
    display: none !important;
  }
}


/* ============================================================
 * A11y — Escape closes <details class="subnav-more"> dropdown
 *
 * Per a11y audit R1: native <details>/<summary> Esc only fires when
 * focus is INSIDE the details body. Once user tabs into menu items,
 * Esc doesn't return them to the summary — keyboard trap.
 *
 * Inline declarative JS (no separate file) — auto-loads everywhere
 * shell.css is loaded. Lives in shell.css comment + hooked via JS
 * in shell.js (added in a follow-up; for now declarative approach).
 *
 * Implementation note: this is COMMENTARY only. The actual handler
 * lives in shell.js — see commit comment on shell.js change.
 * ============================================================ */

  /* Brand mark — the actual SVG swap is done in shell.js
   * (applyBrandMark) so the `src` attribute reflects the resolved
   * variant. CSS-side `content: url()` was rejected because crawlers,
   * print, social-preview, and right-click-Save-As all read `src`. */

  /* Theme toggle button — header chip styled like .lang-btn pill but
   * with its own padding so the unicode glyph (☀/☾) stays centred.
   *
   * Font stack: explicit emoji + symbol fallback up front. Without
   * this the button inherits the body face (Fira Mono / Tektur) and
   * those programming/display faces don't ship glyphs for U+2600
   * (☀) or U+263E (☾) — the browser then drops to a degraded
   * .notdef rect that read on screen as a thin "+" instead of a
   * sun. Apple/Segoe/Noto emoji + Segoe UI Symbol cover macOS / Win
   * / Linux respectively; system-ui handles fallback. */
  .theme-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 24px;
    color: var(--mute); cursor: pointer;
    background: transparent; border: 0;
    font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
                 "Noto Color Emoji", "DejaVu Sans", system-ui, sans-serif;
    font-size: 14px; line-height: 1;
    transition: color .15s;
  }
  .theme-toggle:hover { color: var(--fg); }
  .theme-toggle:focus-visible { outline: 1px solid var(--phosphor); outline-offset: 2px; }

  /* ── Auth pages — signup.html + login.html ─────────────────────
   * After the C2 refactor most auth-page colors now flow through
   * `var(--*)` tokens and cascade automatically on theme flip. The
   * overrides below cover ONLY the cases that don't cascade — rgba()
   * decorations, semi-transparent fills, focus rings — where the
   * dark/light hue differs in saturation rather than just lightness.
   * Plain `color: var(--mute)` rules in the inline <style> already
   * flip correctly and don't need a duplicate override here. */
  [data-theme="light"] .auth-aside::before {
    background:
      radial-gradient(700px 380px at -10% 20%, color-mix(in srgb, var(--phosphor) 9%, transparent), transparent 60%),
      radial-gradient(500px 280px at 110% 90%, color-mix(in srgb, var(--color-amber) 7%, transparent), transparent 55%);
  }
  [data-theme="light"] .auth-input:focus {
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--phosphor) 40%, transparent);
  }
  [data-theme="light"] .submit-btn {
    background: color-mix(in srgb, var(--phosphor) 8%, transparent);
  }
  [data-theme="light"] .submit-btn:hover { background: color-mix(in srgb, var(--phosphor) 16%, transparent); }
  [data-theme="light"] .submit-btn .kbd {
    border-color: color-mix(in srgb, var(--phosphor) 35%, transparent);
    /* `.kbd` mixed against transparent + low alpha created sub-AA
     * hint text on cream after the emerald→rust swap. Mix the
     * phosphor against --fg instead of transparent so the kbd
     * label stays readable at AA Large (3:1) on the cream button
     * wash regardless of theme. */
    color: color-mix(in srgb, var(--phosphor) 70%, var(--fg));
  }
  [data-theme="light"] .err-msg {
    border-color: color-mix(in srgb, var(--color-danger) 40%, transparent);
    background: color-mix(in srgb, var(--color-danger) 6%, transparent);
    color: var(--color-danger);
  }
  [data-theme="light"] .gift {
    border-color: color-mix(in srgb, var(--color-amber) 50%, transparent);
    background: color-mix(in srgb, var(--color-amber) 7%, transparent);
  }
  [data-theme="light"] .gift .ic { color: var(--color-amber); }
  [data-theme="light"] .gift .t strong { color: var(--color-amber); }
  [data-theme="light"] .checklist li .c {
    background: color-mix(in srgb, var(--phosphor) 10%, transparent);
  }
  [data-theme="light"] .role-btn.on {
    background: color-mix(in srgb, var(--phosphor) 7%, transparent);
  }
  [data-theme="light"] .login-strip {
    background: color-mix(in srgb, var(--phosphor) 4%, transparent);
  }
  [data-theme="light"] .sent-state {
    border-color: color-mix(in srgb, var(--phosphor) 45%, transparent);
    background: color-mix(in srgb, var(--phosphor) 5%, transparent);
  }

  /* ── Typography floor ────────────────────────────────────────────
   * Mobile <=768 px: anything declared at the legacy 10/10.5/11 px sizes
   * is lifted to a 12 px hard floor. Pixel-monospace below ~12 px on
   * physical mobile pixel pitch is genuinely unreadable; we keep the
   * desktop 11 px chip/eyebrow size for designers who actually want it
   * but stop punishing phone users with hairline labels.
   *
   * `[class*="text-[1"]` is intentional — it matches `text-[10px]`,
   * `text-[10.5px]` and `text-[11px]` arbitrary-value classes Tailwind
   * generates from each inline config. The :where() wrapper keeps
   * specificity at 0 so anything explicitly larger still wins. */
  @media (max-width: 768px) {
    :where(.text-\[10px\], .text-\[10\.5px\], .text-\[11px\], .text-\[11\.5px\]) {
      font-size: 12px;
    }
  }

  /* ── CLS guard ─────────────────────────────────────────────────
   * shell.js injects the header & footer into <div id="shell-header">
   * and <div id="shell-footer"> at DOMContentLoaded. Without size
   * reservation the page renders with 0-px placeholders, then the JS
   * fires and content under both anchors jumps by ~56 px (header) and
   * ~340 px (footer). Reserving min-height keeps CLS at 0 — the
   * eventual injected nodes sit inside the same box that the
   * placeholder occupied. Heights mirror the rendered chrome (h-14 nav
   * = 56 px desktop / 14 + scroll-progress on landing; footer grid
   * is roughly 340 desktop / 560 mobile due to column stacking). */
  #shell-header { display: block; min-height: 56px; }
  #shell-footer { display: block; min-height: 340px; }
  @media (max-width: 768px) {
    #shell-footer { min-height: 560px; }
  }

  /* ── Lang veil ────────────────────────────────────────────────
   * For RU sessions the HTML ships in English and `i18n.js` swaps every
   * text node after DOMContentLoaded — that's the visible EN→RU
   * flicker. We hide <body> only when the session is known-RU and
   * unhide it after `.lang-ready` is set by shell.js (or after a 600 ms
   * fallback timer in shell.js — never strand the user behind a blank
   * page). The `lang` attribute is set synchronously by the inline
   * SeoSync script in each HTML's <head> long before <body> renders,
   * so this selector matches before paint without a flash. EN sessions
   * skip the veil entirely (most common case = no delay). */
  html[lang="ru"]:not(.lang-ready) body { visibility: hidden; }

  html, body {
    background: var(--bg); color: var(--fg);
    /* Fira Mono — canonical body face. Humanist mono, two-storey a/g.
     * `calt` enables contextual alternates (rare in Fira but kept for
     * forward-compat). */
    font-family: 'Fira Mono', ui-monospace, monospace;
    font-feature-settings: "calt";
    line-height: 1.6;
    -webkit-font-smoothing: antialiased; text-rendering: geometricPrecision;
  }
  /* Horizontal-overflow safety net.
   *
   * Both <html> AND <body> use `overflow-x: clip`, NOT `hidden`. The
   * distinction matters twice over:
   *   1. `overflow-x: hidden` on <html> promotes <body> to the
   *      scrolling viewport, breaking `window.scrollY` — the header
   *      `.scroll-progress` bar reads 0 mid-page.
   *   2. `overflow-x: hidden` on <body> creates a new scroll-container
   *      block, which breaks `position: sticky` on direct children
   *      (the .header-shell stops sticking and scrolls away with
   *      the page — the wordmark + theme toggle + progress bar all
   *      disappear after the first viewport).
   * `overflow-x: clip` (Chrome 90+ / Safari 16+ / Firefox 81+) clips
   * exactly like hidden but does NOT create a new scroll context,
   * preserving both scroll mechanics. Pre-clip browsers fall back to
   * `visible` — they keep the horizontal scroll but the marquee/SVG
   * still clip via their own `overflow: hidden` wrappers, so the
   * defect is contained. */
  html, body { overflow-x: clip; }

  /* ── Text-wrap policy (Phase 3 spatial system) ──────────────────
   * Modern CSS: `balance` for headings (browsers cap at ~6 lines,
   * eliminates "two long lines + one orphan" silhouettes), `pretty`
   * for prose (Chrome 117+, Safari 17.4+; eliminates orphans and
   * widows). Fallbacks are graceful — older browsers ignore the
   * declaration and use plain greedy wrapping. */
  h1, h2, h3, h4, h5, h6, [data-section-header] {
    text-wrap: balance;
  }
  p, li, dd, blockquote, .doc-p {
    text-wrap: pretty;
  }
  /* Single-line chrome — explicit `nowrap` to defeat any inherited
   * wrap behaviour and protect overflow scrolling. */
  .crumbs__row, .navlink, .btn-term, .btn-solid, .btn-ghost,
  .lang-btn, .shell-cab-btn, .nav-login, [data-tabular-row] {
    white-space: nowrap;
  }

  /* Prose paragraph rhythm — every `<p>` after a sibling gets
   * 16 px spacing. Inline reset earlier (`* { margin: 0 }`) is now
   * overridden for prose only via :where() so utility classes still
   * win. */
  :where(p + p, p + ul, p + ol, ul + p, ol + p, p + blockquote) {
    margin-top: 16px;
  }
  :where(ul, ol) li + li {
    margin-top: 8px;
  }
  body {
    background-image:
      linear-gradient(color-mix(in srgb, var(--phosphor) 2%, transparent) 1px, transparent 1px),
      linear-gradient(90deg, color-mix(in srgb, var(--phosphor) 2%, transparent) 1px, transparent 1px),
      radial-gradient(ellipse 80% 60% at 50% -10%, color-mix(in srgb, var(--phosphor) 7%, transparent), transparent 60%);
    background-size: 32px 32px, 32px 32px, auto;
  }
  .scanlines::before {
    content:""; position: fixed; inset: 0;
    background: repeating-linear-gradient(to bottom,
      rgba(255,255,255,0.013) 0, rgba(255,255,255,0.013) 1px,
      transparent 1px, transparent 3px);
    pointer-events: none; z-index: 60; mix-blend-mode: screen;
  }
  .vignette::after {
    content:""; position: fixed; inset: 0;
    background: radial-gradient(ellipse at center, transparent 55%, rgba(0,0,0,.5) 100%);
    pointer-events: none; z-index: 59;
  }
  .crt-flicker { animation: flicker 7s infinite; }
  @keyframes flicker { 0%,99%,100% { opacity: 1; } 99.5% { opacity: .96; } }
  .blink { animation: blink 1.05s steps(1) infinite; }
  @keyframes blink { 50% { opacity: 0; } }
  .caret {
    display: inline-block; width: .55ch; height: 1em;
    background: var(--phosphor); transform: translateY(.18em);
    box-shadow: 0 0 6px color-mix(in srgb, var(--phosphor) 60%, transparent);
  }
  .glow-text { text-shadow: 0 0 10px color-mix(in srgb, var(--phosphor) 35%, transparent); }
  /* Brand mark — paper-airplane SVG ships emerald gradient (#10b981 family).
     The page accent is phosphor (#7af0a0); a soft phosphor halo harmonizes
     the two greens without recoloring the SVG itself. */
  .brand-mark { filter: drop-shadow(0 0 6px color-mix(in srgb, var(--phosphor) 45%, transparent)); }
  .hairline { border-color: var(--line); }
  .hairline-strong { border-color: var(--line2); }
  ::selection { background: color-mix(in srgb, var(--phosphor) 35%, transparent); color: var(--on-phosphor); }
  ::-webkit-scrollbar { width: 10px; height: 10px; }
  ::-webkit-scrollbar-track { background: var(--bg); }
  ::-webkit-scrollbar-thumb { background: var(--line); border: 2px solid var(--bg); }
  ::-webkit-scrollbar-thumb:hover { background: var(--line2); }

  /* === buttons: terminal-outline with phosphor accent === */
  .btn-term {
    position: relative;
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .65rem 1.05rem;
    color: var(--phosphor);
    background: color-mix(in srgb, var(--phosphor) 6%, transparent);
    border: 1px solid color-mix(in srgb, var(--phosphor) 45%, transparent);
    transition: transform .08s ease, box-shadow .18s ease, background .18s ease, border-color .18s ease;
    font-weight: 600; letter-spacing: .02em;
  }
  .btn-term::before { content:"["; color: color-mix(in srgb, var(--phosphor) 55%, transparent); font-weight: 600; }
  .btn-term::after  { content:"]"; color: color-mix(in srgb, var(--phosphor) 55%, transparent); font-weight: 600; }
  .btn-term:hover {
    background: color-mix(in srgb, var(--phosphor) 14%, transparent);
    border-color: var(--phosphor);
    box-shadow: 0 0 0 1px var(--phosphor), 0 10px 28px -14px color-mix(in srgb, var(--phosphor) 45%, transparent);
  }
  .btn-term:active { transform: translateY(1px); }
  .btn-term .kbd { color: color-mix(in srgb, var(--phosphor) 60%, transparent); font-size: 10px; padding: 0 5px; border: 1px solid color-mix(in srgb, var(--phosphor) 35%, transparent); border-bottom-width: 2px; margin-left: .15rem; }

  /* solid variant for one-and-only primary call */
  .btn-solid {
    position: relative;
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .65rem 1.05rem;
    color: var(--on-phosphor);
    background: var(--phosphor);
    border: 1px solid var(--phosphor);
    transition: transform .08s ease, box-shadow .18s ease, filter .18s ease;
    font-weight: 700; letter-spacing: .02em;
  }
  .btn-solid::before { content:"["; color: color-mix(in srgb, var(--on-phosphor) 60%, transparent); font-weight: 700; }
  .btn-solid::after  { content:"]"; color: color-mix(in srgb, var(--on-phosphor) 60%, transparent); font-weight: 700; }
  .btn-solid:hover { filter: brightness(1.08); box-shadow: 0 10px 32px -12px color-mix(in srgb, var(--phosphor) 55%, transparent); }
  .btn-solid:active { transform: translateY(1px); }
  .btn-solid .kbd { color: color-mix(in srgb, var(--on-phosphor) 55%, transparent); font-size: 10px; padding: 0 5px; border: 1px solid color-mix(in srgb, var(--on-phosphor) 35%, transparent); border-bottom-width: 2px; margin-left: .15rem; }
  /* Disabled state — must read as "not clickable" at a glance. The
     default browser dim is too subtle on the phosphor fill, so users
     keep trying to click "verdict ready" thinking it's another CTA. */
  .btn-solid:disabled,
  .btn-solid[disabled] {
    background: transparent;
    color: var(--mute);
    border-color: var(--line2);
    border-style: dashed;
    cursor: not-allowed;
    box-shadow: none;
    filter: none;
    transform: none;
  }
  .btn-solid:disabled::before,
  .btn-solid:disabled::after,
  .btn-solid[disabled]::before,
  .btn-solid[disabled]::after {
    color: var(--placeholder);
  }
  .btn-solid:disabled:hover,
  .btn-solid[disabled]:hover {
    filter: none;
    box-shadow: none;
    background: transparent;
  }
  .btn-solid:disabled .kbd,
  .btn-solid[disabled] .kbd {
    color: var(--placeholder);
    border-color: var(--line2);
  }
  /* Verdict-ready state: dashed phosphor frame with a leading ✓ so
     it reads as a status pill, not a CTA. Sits on top of the generic
     :disabled styles so the user knows the form is in a "finished"
     state and the next step is to edit/clear the address. */
  .btn-solid[data-locked-after-result="1"] {
    border-color: color-mix(in srgb, var(--phosphor) 45%, transparent);
    background: color-mix(in srgb, var(--phosphor) 4%, transparent);
    color: var(--phosphor);
  }
  .btn-solid[data-locked-after-result="1"]::before {
    content: "✓ ";
    color: var(--phosphor);
    font-weight: 800;
  }
  .btn-solid[data-locked-after-result="1"]::after { content: ""; }
  .btn-solid[data-locked-after-result="1"] .kbd { display: none; }

  .btn-ghost {
    position: relative;
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .65rem 1.05rem; border: 1px solid var(--line2);
    color: var(--fg); background: transparent;
    transition: all .15s ease;
    font-weight: 500; letter-spacing: .02em;
  }
  .btn-ghost::before { content:"["; color: var(--mute); }
  .btn-ghost::after  { content:"]"; color: var(--mute); }
  .btn-ghost:hover { border-color: var(--phosphor); color: var(--phosphor); }
  .btn-ghost:hover::before, .btn-ghost:hover::after { color: var(--phosphor); }

  .btn-term.btn-sm, .btn-ghost.btn-sm, .btn-solid.btn-sm { padding: .45rem .8rem; font-size: 11px; }

  /* Compact header CTAs on narrow phones — the "run a check ⌘K"
   * pill ships visible on mobile by design (primary CTA), but the
   * kbd shortcut hint is useless on touch and the button padding +
   * kbd width tip the row over 375px. Drop the kbd entirely and
   * tighten the padding under 640px so the row clears for a 320px
   * iPhone-SE viewport. */
  @media (max-width: 640px) {
    .btn-term.btn-sm .kbd,
    .btn-ghost.btn-sm .kbd,
    .btn-solid.btn-sm .kbd { display: none; }
    .btn-term.btn-sm,
    .btn-ghost.btn-sm,
    .btn-solid.btn-sm { padding: .4rem .6rem; gap: .35rem; }
    /* Lang switch — same logic, less horizontal padding. */
    .lang-switch .lang-btn { padding-left: .35rem; padding-right: .35rem; }

    /* Universal mobile overflow protection — long mono addresses /
     * code blocks / pre-formatted terminal frames otherwise burst
     * past the viewport at narrow widths. The combination of
     * scrollable code (overflow-x:auto) + min-width:0 on grid
     * children + ellipsis on tight cells handles the long-tail
     * wallet hashes (0xd8dA…) and right-aligned mono columns. */
    pre, .codeblk, .terminal, code {
      overflow-x: auto;
      -webkit-overflow-scrolling: touch;
      max-width: 100%;
    }
    /* Pricing sample-card right-side address column — was
     * `white-space: nowrap` and bursting the card boundary on 375
     * with the wallet hash + TRC20 tag stack. min-width:0 lets the
     * grid contract; ellipsis swallows the overflow gracefully. */
    .pp-example-row,
    .pp-example-meta { min-width: 0; }
    .pp-example-addr {
      min-width: 0;
      overflow: hidden;
      text-overflow: ellipsis;
      font-size: 10px;
    }
  }

  /* Tailwind utility load-order rescue — `.hidden md:inline-flex` on
   * `[data-shell-login]` / `[data-shell-exit]` chips was being defeated
   * because `.btn-ghost { display: inline-flex }` is declared later in
   * shell.css and same-specificity wins by source order. Forcing the
   * `hidden` semantic on <md via attribute selector + !important so the
   * chips actually hide on mobile as the markup intends. Tablet-and-up
   * `md:inline-flex` then re-flows normally. */
  @media (max-width: 767px) {
    [data-shell-login],
    [data-shell-exit] { display: none !important; }
  }

  /* Final mobile header packing — at 375px the brand + lang + toggle +
   * → CTA + ≡ hamburger STILL adds up to 382px after the chip-hides
   * above, because `gap-6` (24px) between brand and right-cluster plus
   * `px-6` (24×2 = 48px container padding) eats 72px of the 375. Tighten
   * to gap-3 + px-4 under 640 so the row fits a 320px iPhone-SE with
   * margin to spare. */
  @media (max-width: 640px) {
    .header-shell nav > div.max-w-\[1400px\] {
      padding-left: 1rem;
      padding-right: 1rem;
      gap: .75rem;
    }
    .header-shell nav > div.max-w-\[1400px\] > div.flex {
      gap: .5rem;
    }
  }

  /* === sticky header shell ===
   * Frosted-glass backdrop that tints with the page bg — was hard-
   * coded rgba(10,13,12,.82) (warm-charcoal) which dropped a dark
   * smoky pane over cream paper on light theme. Token-driven now so
   * dark theme stays smoky-charcoal and light theme reads as
   * frosted-cream with the same saturation lift. */
  .header-shell {
    position: sticky; top: 0; z-index: 50;
    background: color-mix(in srgb, var(--bg) 82%, transparent);
    backdrop-filter: blur(10px) saturate(120%);
    -webkit-backdrop-filter: blur(10px) saturate(120%);
    transition: box-shadow .2s ease, border-color .2s ease;
  }
  .header-shell.scrolled {
    box-shadow:
      0 1px 0 var(--line2),
      0 16px 24px -22px color-mix(in srgb, var(--fg) 65%, transparent);
  }
  .header-shell.scrolled .top-status { height: 0; opacity: 0; pointer-events: none; overflow: hidden; }
  .top-status { height: 36px; transition: height .25s ease, opacity .2s ease; }

  /* Progress bar inside header — full-width block, paints rust by
   * default, scaled via `transform: scaleX(0..1)` from JS on scroll.
   *
   * No transition: in practice the scroll event fires at frame rate
   * (≥60Hz on modern browsers) so each scaleX update is one frame
   * away from the next — adding a transition causes interpolation
   * races where consecutive listener calls collide with the running
   * tween and the bar gets stuck at its previous frame. Without the
   * transition the bar tracks scroll exactly, no lag, no glitches. */
  .scroll-progress {
    height: 2px;
    width: 100%;
    background: var(--phosphor);
    transform-origin: left center;
    transform: scaleX(0);
    box-shadow: 0 0 8px color-mix(in srgb, var(--phosphor) 55%, transparent);
    will-change: transform;
  }

  .leader { flex: 1; border-bottom: 1px dotted var(--line2); transform: translateY(-.35em); margin: 0 .6rem; }

  .prompt-sym { color: var(--phosphor); }
  .flag { color: var(--risk-caution); }
  .str  { color: #b48ead; }
  .num  { color: var(--phosphor); }
  .com  { color: var(--mute); }

  details > summary { list-style: none; cursor: pointer; }
  details > summary::-webkit-details-marker { display: none; }
  details[open] .chev { transform: rotate(90deg); }
  .chev { transition: transform .15s ease; display: inline-block; }

  .marquee { display: flex; width: max-content; animation: marq 40s linear infinite; }
  @keyframes marq { from { transform: translateX(0);} to { transform: translateX(-50%);} }

  .gutter { color: var(--line2); user-select:none; padding-right: 1rem; text-align: right; }

  .navlink { color: var(--mute); white-space: nowrap; }
  .navlink:hover { color: var(--phosphor); }
  .navlink::before { content:"› "; color: var(--line2); }
  .navlink:hover::before { color: var(--phosphor); }
  .navlink-active { color: var(--phosphor); }
  .navlink-active::before { color: var(--phosphor); }

  .lang-btn { color: var(--mute); cursor: pointer; transition: color .15s; font-family: inherit; white-space: nowrap; }
  .lang-btn:hover { color: var(--fg); }
  .lang-btn.active { color: var(--phosphor); }

  /* — RU translations are 30%+ wider than EN. Lock every header / footer
       button so labels never wrap onto two lines. The kbd badge inside
       buttons is a separate inline-block; keep it from being orphaned. — */
  .btn-term, .btn-ghost, .btn-solid { white-space: nowrap; }
  .btn-term .kbd, .btn-ghost .kbd, .btn-solid .kbd { white-space: nowrap; flex-shrink: 0; }

  /* Brand wordmark + // wallet-aml.daemon comment must stay on one line
     even when the nav row gets cramped by Russian labels. */
  .header-shell a[href="./"] > div { flex-wrap: nowrap; white-space: nowrap; }

  .verdict { position: relative; border: 1px solid var(--line2); padding: 1rem; background: var(--panel); transition: all .15s; display:block; }
  .verdict::after {
    content: "open ↗";
    position: absolute; right: .75rem; bottom: .65rem;
    font-size: 10px; color: var(--mute); letter-spacing: .06em;
    opacity: 0; transition: opacity .15s;
  }
  .verdict:hover { transform: translateY(-2px); }
  .verdict:hover::after { opacity: 1; }
  .v-low      { border-color: color-mix(in srgb, var(--phosphor) 50%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--phosphor) 8%, transparent); }
  .v-low:hover{ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--phosphor) 18%, transparent), 0 0 24px -8px color-mix(in srgb, var(--phosphor) 40%, transparent); }
  .v-mid      { border-color: color-mix(in srgb, var(--risk-caution) 50%, transparent); }
  .v-mid:hover{ box-shadow: 0 0 24px -8px color-mix(in srgb, var(--risk-caution) 40%, transparent); }
  .v-high     { border-color: color-mix(in srgb, var(--risk-critical) 55%, transparent); }
  .v-high:hover{ box-shadow: 0 0 24px -8px color-mix(in srgb, var(--risk-critical) 40%, transparent); }
  .v-crit     { border-color: color-mix(in srgb, var(--risk-critical) 85%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--risk-critical) 12%, transparent); }
  .v-crit:hover{ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--risk-critical) 25%, transparent), 0 0 28px -6px color-mix(in srgb, var(--risk-critical) 45%, transparent); }

  .badge { display: inline-block; padding: 1px 6px; font-size: 10px; font-weight: 700; letter-spacing: .06em; border: 1px solid currentColor; }
  .b-low  { color: var(--phosphor); background: color-mix(in srgb, var(--phosphor) 8%, transparent); }
  .b-mid  { color: var(--risk-caution); background: color-mix(in srgb, var(--risk-caution) 8%, transparent); }
  .b-high { color: var(--risk-critical); background: color-mix(in srgb, var(--risk-critical) 8%, transparent); }
  .b-crit { color: var(--risk-critical); background: color-mix(in srgb, var(--risk-critical) 18%, transparent); }

  .vim-status {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 70;
    height: 28px;
    background: var(--panel);
    border-top: 1px solid var(--line);
    display: flex; align-items: center; justify-content: space-between;
    padding: 0 14px; font-size: 11px; color: var(--mute);
  }
  .vim-mode {
    background: var(--phosphor);
    color: var(--on-phosphor);
    padding: 1px 8px; font-weight: 700; letter-spacing: .08em;
  }

  .chip { display: inline-flex; align-items: center; gap: .25rem; border: 1px solid var(--line2); padding: 1px 6px; font-size: 10px; color: var(--mute); background: transparent; }
  button.chip { cursor: pointer; }
  button.chip:hover { color: var(--phosphor); border-color: var(--phosphor); }

  .term-select {
    appearance: none; background: transparent; color: var(--fg);
    border: none; outline: none; font-family: inherit; font-size: 13px;
    padding-right: 18px; cursor: pointer;
    background-image: linear-gradient(45deg, transparent 50%, var(--phosphor) 50%),
                      linear-gradient(135deg, var(--phosphor) 50%, transparent 50%);
    background-position: calc(100% - 10px) 50%, calc(100% - 6px) 50%;
    background-size: 4px 4px, 4px 4px;
    background-repeat: no-repeat;
  }
  .term-select option { background: var(--panel); color: var(--fg); }

  .input-line {
    width: 100%; background: transparent; border: none; outline: none;
    color: var(--fg); font-family: inherit; font-size: 14px; padding: .9rem 0;
  }
  .input-line::placeholder { color: var(--placeholder); }

  .spark { font-family: inherit; letter-spacing: -1px; }
  .bar { letter-spacing: -1px; }
  /* Authed-state cabinet button — replaces the `log in` chip in the
     top-right after shell.js confirms /api/v1/me. Rendered as a
     bordered phosphor capsule (button, not a link) with the user's
     email on the left and a monogram disk on the right. The capsule
     itself carries the accent so the affordance reads as a button —
     this is THE entry point back to the cabinet and the ambient
     "you are signed in" indicator. On /me/* pages the button fills
     solid phosphor so the user sees at any time they are inside the
     authenticated area.

     Sizing matches the right-side `run a check` btn-term so both
     primary controls share the same vertical rhythm. The inner
     monogram disk is 24×24, slightly inset into the capsule's
     right edge for a tight chip-on-button look. */
  .shell-cab-btn {
    display: inline-flex; align-items: center; gap: 8px;
    height: 32px;
    padding: 0 4px 0 12px;
    border: 1px solid var(--phosphor);
    background: color-mix(in srgb, var(--phosphor) 6%, transparent);
    color: var(--phosphor);
    font-family: inherit; font-size: 11.5px; font-weight: 600;
    letter-spacing: 0.04em;
    text-decoration: none; cursor: pointer; user-select: none;
    transition: background .15s, border-color .15s, color .15s,
                box-shadow .15s, transform .12s;
  }
  .shell-cab-btn:hover {
    background: color-mix(in srgb, var(--phosphor) 14%, transparent);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--phosphor) 35%, transparent),
                0 0 18px -4px color-mix(in srgb, var(--phosphor) 55%, transparent);
    transform: translateY(-1px);
  }
  .shell-cab-btn:active { transform: translateY(0); }
  .shell-cab-btn:focus-visible {
    outline: 2px solid var(--phosphor);
    outline-offset: 2px;
  }
  .shell-cab-btn .shell-avatar-ident {
    color: inherit; opacity: .92;
    font-size: 11.5px; font-weight: 500;
    letter-spacing: 0.02em; line-height: 1;
    /* Keep the email from pushing the disk off the row when the
       address is long — JS truncates to 24 chars + ellipsis, but
       cap visual width too as belt-and-braces. */
    max-width: 22ch; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap;
  }
  .shell-cab-btn .shell-cab-disk {
    display: inline-flex; align-items: center; justify-content: center;
    width: 24px; height: 24px;
    background: var(--phosphor);
    color: var(--on-phosphor);
    font-size: 12px; font-weight: 800;
    letter-spacing: 0;
  }

  /* Active variant — currently inside /me/*. Capsule fills with
     phosphor; ident text flips to dark-on-phosphor; disk inverts
     to dark with phosphor glyph. Halo + brighter hover keep it
     eye-catching as the "you are here" anchor. */
  .shell-cab-btn-active {
    background: var(--phosphor);
    color: var(--on-phosphor);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--phosphor) 20%, transparent),
                0 0 18px -2px color-mix(in srgb, var(--phosphor) 55%, transparent);
  }
  .shell-cab-btn-active:hover {
    /* Brand-coherent lighter hover — was hardcoded #9af6b8 (brighter
     * mint green) which painted lime-green on the new rust accent.
     * color-mix flows with the active --phosphor token. */
    background: color-mix(in srgb, #ffffff 18%, var(--phosphor));
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--phosphor) 32%, transparent),
                0 0 22px -2px color-mix(in srgb, var(--phosphor) 70%, transparent);
  }
  .shell-cab-btn-active .shell-avatar-ident { opacity: 1; }
  .shell-cab-btn-active .shell-cab-disk {
    background: var(--on-phosphor);
    color: var(--phosphor);
  }

  /* ── Breadcrumbs ────────────────────────────────────────────────
   * Rendered by shell.js immediately under the nav (still inside
   * <header id="siteHeader">) on every page where data-active is not
   * "home". Terminal-monospace prompt: `~ / cabinet / api`. Last crumb
   * is current page (non-link); separators and "~" are dim. */
  .crumbs {
    border-bottom: 1px solid var(--line);
    /* Was hardcoded rgba(15,20,19,.45) (dark slate over cream paper
     * read as a printed-magazine grey-stripe — wrong). Now uses the
     * panel-token at 50% so the strip reads as a slight depression
     * in the same paper, theme-coherent on dark + light. */
    background: color-mix(in srgb, var(--panel) 50%, transparent);
  }
  .crumbs__row {
    max-width: 1400px;
    margin: 0 auto;
    padding: 8px 24px;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--fgdim);
    font-family: 'Fira Mono', ui-monospace, monospace;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    white-space: nowrap;
  }
  .crumbs__row::-webkit-scrollbar { display: none; }
  /* "home" — the breadcrumb root. High contrast so it reads as a real
   * clickable link (was a low-contrast `~` symbol that confused users). */
  .crumbs__home {
    color: var(--fg);
    text-decoration: none;
    border-bottom: 1px dashed transparent;
    padding-bottom: 1px;
    transition: color .12s ease, border-color .12s ease;
  }
  .crumbs__home:hover {
    color: var(--phosphor);
    border-bottom-color: var(--phosphor);
  }
  .crumbs__sep {
    color: var(--line2);
    user-select: none;
  }
  .crumbs__link {
    color: var(--fgdim);
    text-decoration: none;
  }
  .crumbs__link:hover {
    color: var(--phosphor);
  }
  .crumbs__current {
    color: var(--fg);
    font-weight: 600;
  }
  @media (max-width: 768px) {
    .crumbs__row { padding: 6px 16px; font-size: 12px; gap: 6px; }
  }
