/* recipes.css — reusable component patterns
 *
 * Depends on tokens.css and fonts.css. Each recipe works by
 * applying its class to a single element. See brand/STYLE.md
 * /components for the usage rules that govern these recipes.
 */

/* ============================================================
 * EYEBROW
 * Small label above a section heading. Three variants share a
 * modifier system for colour (.is-ink, .is-gold), alignment
 * (.is-center, .is-right), and a numbered ordinal prefix
 * (.is-numbered). See STYLE.md /components for full usage.
 * ============================================================ */

/* ---------- Default: column-spanning hairline, mono + JP ---- */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-mid);
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 24px;
}
.eyebrow .jp {
  font-family: var(--font-jp);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.05em;
  text-transform: none;
  color: var(--red);
}
.eyebrow::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--ink-faint);
}

/* .eyebrow · alignment */
.eyebrow.is-center { text-align: center; }
.eyebrow.is-center::before {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--ink-faint);
}
.eyebrow.is-right { text-align: right; }
.eyebrow.is-right::after { display: none; }
.eyebrow.is-right::before {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--ink-faint);
}

/* .eyebrow · colour */
.eyebrow.is-ink .jp { color: var(--ink); }
.eyebrow.is-gold { font-weight: 700; }
.eyebrow.is-gold .jp {
  color: var(--gold);
  font-weight: 500;
}

/* ---------- Quiet: voice-only, no stroke, no mark ---------- */
.eyebrow-quiet {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 24px;
}
.eyebrow-quiet .jp {
  font-family: var(--font-jp);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.05em;
  text-transform: none;
  color: var(--red);
}

/* .eyebrow-quiet · alignment */
.eyebrow-quiet.is-center { justify-content: center; text-align: center; }
.eyebrow-quiet.is-right  { justify-content: flex-end; text-align: right; }

/* .eyebrow-quiet · colour */
.eyebrow-quiet.is-ink .jp { color: var(--ink); }
.eyebrow-quiet.is-gold { font-weight: 700; }
.eyebrow-quiet.is-gold .jp {
  color: var(--gold);
  font-weight: 500;
}

/* ---------- Gloss: JP character with italic reading -------- */
.eyebrow-gloss {
  font-family: var(--font-jp);
  font-size: 18px;
  font-weight: 400;
  letter-spacing: 0.08em;
  color: var(--red);
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 24px;
}
.eyebrow-gloss .reading {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  font-style: italic;
  letter-spacing: 0.14em;
  text-transform: lowercase;
  color: var(--ink-mid);
}

/* .eyebrow-gloss · alignment */
.eyebrow-gloss.is-center { justify-content: center; text-align: center; }
.eyebrow-gloss.is-right  { justify-content: flex-end; text-align: right; }

/* .eyebrow-gloss · colour */
.eyebrow-gloss.is-ink  { color: var(--ink); }
.eyebrow-gloss.is-gold {
  color: var(--gold);
  font-weight: 500;
}

/* ---------- Numbered ordinal ---------------------------------
 * The ordinal lives in <span class="num">01 · </span> inside the
 * eyebrow. The span inherits the parent's type family, size,
 * weight, and colour so the ordinal matches the eyebrow style.
 * For .eyebrow-gloss the parent is Mincho; for the other two
 * variants the parent is Mono. No explicit .num styling is
 * required — default inheritance handles it.
 * ----------------------------------------------------------- */


/* ============================================================
 * CARD
 * Eight variants: four colors × two states (raised / sunken).
 * Separate recipes (Architecture B). Shared size modifiers
 * .is-sm / .is-md (default, no class) / .is-lg compose across
 * all variants. Cards are STATIC — no hover states.
 *
 * Cards belong only on --paper, --paper-deep, or --paper-coal
 * surfaces. On --ink backgrounds, cast shadows vanish.
 *
 * See STYLE.md /components Cards for composition rules.
 * ============================================================ */

/* ---------- raised cards (letterpress) ---------- */

/* .card-paper — baseline letterpress verbatim from textures.css.
   This card is the reference; every other raised variant's shadow
   is tuned against it. */
.card-paper {
  background: #F4EFE6;
  border-radius: 6px;
  padding: 32px 40px;
  color: var(--ink);
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.7),
    0 1px 0 rgba(255,251,240,0.5),
    0 4px 12px rgba(40,30,18,0.06),
    0 16px 40px rgba(40,30,18,0.06);
}

/* .card-coal — letterpress tuned for dark surface. Top highlight
   dropped 0.70→0.18 (hot paper-white bleaches the coal body);
   below-edge paper highlight removed (reads wrong on dark); warm
   cast rgba(40,30,18,0.06) replaced with rgba(0,0,0,0.30) both
   layers — the cast needs to be darker + more opaque to separate
   a dark card from the paper body. */
.card-coal {
  background: var(--paper-coal);
  border-radius: 6px;
  padding: 32px 40px;
  color: var(--paper);
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.18),
    0 4px 12px rgba(0,0,0,0.30),
    0 16px 40px rgba(0,0,0,0.30);
}

/* .card-oxblood — letterpress tuned for warm-red surface. Top
   highlight softened 0.70→0.35 (0.70 reads as a hot bleached
   stripe on red-deep); cast deepened 0.06→0.18 both layers so
   the warm-brown cast separates from the warm red body;
   below-edge paper highlight removed. */
.card-oxblood {
  background: var(--red-deep);
  border-radius: 6px;
  padding: 32px 40px;
  color: var(--paper);
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.35),
    0 4px 12px rgba(40,30,18,0.18),
    0 16px 40px rgba(40,30,18,0.18);
}

/* .card-gold — letterpress tuned for ochre surface. Top highlight
   dropped 0.70→0.40 (hot highlight bleaches the gold tone);
   cast deepened 0.06→0.14 both layers so the ceremonial card
   sits visibly proud; below-edge highlight softened 0.50→0.25. */
.card-gold {
  background: var(--gold);
  border-radius: 6px;
  padding: 32px 40px;
  color: var(--ink);
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.40),
    0 1px 0 rgba(255,251,240,0.25),
    0 4px 12px rgba(40,30,18,0.14),
    0 16px 40px rgba(40,30,18,0.14);
}

/* ---------- sunken cards (deboss) ---------- */

/* .card-paper-sunken — baseline deboss verbatim from textures.css.
   Reference for all sunken variants. */
.card-paper-sunken {
  background: var(--paper-deep);
  border-radius: 6px;
  padding: 32px 40px;
  color: var(--ink);
  box-shadow:
    inset 0 2px 4px rgba(40,30,18,0.10),
    inset 0 -1px 0 rgba(255,251,240,0.7),
    0 1px 0 rgba(255,251,240,0.7);
}

/* .card-coal-sunken — deboss tuned for dark surface. Top inset
   raised rgba(40,30,18,0.10)→rgba(0,0,0,0.55) (paper-tone cast
   is invisible on coal; needs black-ish for press-in to carry);
   bottom paper-tone highlights softened to 0.05 and 0.08 — they
   should barely whisper against the dark body.

   Sunken-coal surface: #2E2824 (~20% deeper than --paper-coal
   #3E362F, preserves warm-brown family). Literal (not a token)
   because this is a per-recipe depth, not a standalone palette
   value. */
.card-coal-sunken {
  background: #2E2824;
  border-radius: 6px;
  padding: 32px 40px;
  color: var(--paper);
  box-shadow:
    inset 0 2px 4px rgba(0,0,0,0.55),
    inset 0 -1px 0 rgba(255,251,240,0.08),
    0 1px 0 rgba(255,251,240,0.05);
}

/* .card-oxblood-sunken — deboss tuned for warm-red surface. Top
   inset deepened 0.10→0.40 (needs more bite against the warm-dark
   body); bottom highlights kept but softened to 0.22 and 0.15 —
   full-strength paper highlight reads as a hot lip on red.

   Sunken-oxblood surface: #6B1C12 (~22% deeper than --red-deep,
   stays in crimson family). Literal (not a token) because this
   is a per-recipe depth, not a standalone palette value. */
.card-oxblood-sunken {
  background: #6B1C12;
  border-radius: 6px;
  padding: 32px 40px;
  color: var(--paper);
  box-shadow:
    inset 0 2px 4px rgba(0,0,0,0.40),
    inset 0 -1px 0 rgba(255,251,240,0.22),
    0 1px 0 rgba(255,251,240,0.15);
}

/* .card-gold-sunken — deboss tuned for ochre surface. Top inset
   deepened 0.10→0.24 to read against the warm body; paper-tone
   highlights preserved at 0.55 and 0.40 — they read as clean lit
   lips on deep gold.

   Sunken-gold surface: #8F7128 (~22% deeper than --gold, stays
   in ochre family). Literal (not a token) because this is a
   per-recipe depth, not a standalone palette value.

   Note: gold-sunken illusion is the weakest of the eight card
   variants. Strongest when nested inside a .card-gold parent
   (same-hue deboss). See STYLE.md /components Cards. */
.card-gold-sunken {
  background: #8F7128;
  border-radius: 6px;
  padding: 32px 40px;
  color: var(--ink);
  box-shadow:
    inset 0 2px 4px rgba(40,30,18,0.24),
    inset 0 -1px 0 rgba(255,251,240,0.55),
    0 1px 0 rgba(255,251,240,0.40);
}

/* ---------- size modifiers (compose with any card variant) ---------- */

.is-sm { padding: 20px 24px; }
/* .is-md is the default; no class required */
.is-lg { padding: 48px 56px; }

/* ---------- internal layout helpers (optional, for card content) ---------- */

.card-title {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 14px;
}
.card-body {
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  margin: 0;
}
.card-data {
  font-family: var(--font-mono);
  font-size: 44px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  margin: 0;
}
.card-delta {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.04em;
  margin: 4px 0 0;
}


/* ============================================================
 * EYEBROW · DARK
 * Companion to .eyebrow for use on dark card surfaces
 * (.card-coal, .card-oxblood, .card-gold and their sunken
 * variants). The base .eyebrow recipe uses --ink-mid text and
 * --red JP gloss, both unreadable on dark surfaces; this family
 * swaps in paper-family colors with gold accent as default.
 *
 * Modifier system mirrors .eyebrow exactly:
 *   Color:      (default) / .is-paper / .is-gold / .is-ink
 *   Alignment:  (default left) / .is-center / .is-right
 *   Numbered:   .is-numbered adds ordinal prefix via .num span
 *
 * See STYLE.md /components Eyebrow · Dark for usage rules.
 * ============================================================ */

/* ---------- base ---------- */
.eyebrow.is-dark {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--paper);
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 24px;
}
.eyebrow.is-dark .jp {
  font-family: var(--font-jp);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.05em;
  text-transform: none;
  color: var(--gold);
}
.eyebrow.is-dark::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: rgba(255, 251, 240, 0.25);
}

/* ---------- color modifiers ---------- */

/* .is-paper: monochromatic paper — use when the card carries a
   gold accent elsewhere and the eyebrow should not compete. */
.eyebrow.is-dark.is-paper { color: var(--paper); }
.eyebrow.is-dark.is-paper .jp { color: var(--paper); }

/* .is-gold: gold label, paper JP — reverses the default accent. */
.eyebrow.is-dark.is-gold { color: var(--gold); }
.eyebrow.is-dark.is-gold .jp { color: var(--paper); }

/* .is-ink: ink text, ink JP — ONLY for use on .card-gold where
   ink is the legible color. */
.eyebrow.is-dark.is-ink { color: var(--ink); }
.eyebrow.is-dark.is-ink .jp { color: var(--ink); }

/* ---------- alignment modifiers ---------- */

.eyebrow.is-dark.is-center { justify-content: center; }
.eyebrow.is-dark.is-center::before {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: rgba(255, 251, 240, 0.25);
}

.eyebrow.is-dark.is-right { justify-content: flex-end; }
.eyebrow.is-dark.is-right::after { display: none; }
.eyebrow.is-dark.is-right::before {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: rgba(255, 251, 240, 0.25);
}

/* ---------- numbered modifier ---------- */

.eyebrow.is-dark.is-numbered .num {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  color: inherit;
}


/* ============================================================
 * HANKO
 * Red seal stamp — distinctive Japanese signature element.
 * Inline-flex box holding one or more JP characters in Mincho
 * 700, paper-on-red, axis-aligned, with a soft warm cast.
 *
 * Default size 28px. Size modifiers .is-22 (in cards), .is-28
 * (default inline, explicit class permitted), .is-48 (callouts),
 * .is-72 (hero corner).
 *
 * See STYLE.md /components Hanko for usage rules.
 * ============================================================ */

.hanko {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background: var(--red);
  border-radius: 2px;
  font-family: var(--font-jp);
  font-weight: 700;
  font-size: 14px;
  color: var(--paper);
  line-height: 1;
  /* Warm red-ink drop shadow. rgba(138, 36, 24, ...) matches the
     hex of --red-deep (#8A2418); expressed as an rgba literal
     here because CSS can't take alpha against a token var. */
  box-shadow: 0 2px 6px rgba(138, 36, 24, 0.25);
}

/* ---------- size modifiers ---------- */

.hanko.is-22 { width: 22px; height: 22px; font-size: 11px; }
.hanko.is-28 { width: 28px; height: 28px; font-size: 14px; }
.hanko.is-48 { width: 48px; height: 48px; font-size: 24px; border-radius: 3px; }
.hanko.is-72 {
  width: 72px;
  height: 72px;
  font-size: 36px;
  border-radius: 4px;
  /* Hero scale carries a slightly heavier cast — 0.30 alpha,
     10px blur at 3px offset. Same red-deep rgba family. */
  box-shadow: 0 3px 10px rgba(138, 36, 24, 0.30);
}


/* ============================================================
 * NAV — left rail + top masthead.
 *
 * Brutalist mono-terminal direction. Rail is 64px collapsed by
 * default; expands to 180px on :hover OR when .is-expanded is
 * applied. The expansion is CSS-only and does NOT require JS
 * for the hover behavior.
 *
 * The top masthead's scroll-hide behavior REQUIRES JS in the
 * consuming app — brand ships only the .is-hidden class. See
 * STYLE.md /components Nav "Implementation notes" for the
 * recommended scroll-detection snippet (direction-based,
 * toggles .is-hidden on .nav-masthead).
 *
 * Corner alignment: the rail's right-edge border and the
 * masthead's bottom-edge border meet at a single intersection
 * point. The masthead sits inside the main content column, not
 * above the rail. See STYLE.md /components Nav "Structure" for
 * the canonical markup pattern.
 *
 * Active state: ">" prefix + --red color. No left bar, no
 * background fill. Pick one treatment; never combine.
 *
 * Modifiers:
 *   .is-expanded  on .nav-rail      — lock rail at 180px
 *   .is-drawer    on .nav-rail      — full-width mobile drawer
 *   .is-active    on .nav-item      — current page indicator
 *   .is-hidden    on .nav-masthead  — translate up out of view
 *
 * See STYLE.md /components Nav for full rules.
 * ============================================================ */

/* ---------- composition wrapper (optional) ---------- */

/* .nav-composition is a flex-row wrapper. min-height defaults to 0
   so the composition can be embedded in widget contexts. For full-
   page shell usage, consumers should set their own min-height
   (commonly 100vh) on the page container or on .nav-composition.
   Documented in STYLE.md /components Nav "Usage". */
.nav-composition {
  display: flex;
  position: relative;
  background: var(--paper);
  min-height: 0;
}


/* ---------- rail ---------- */

/* .nav-rail — 64px collapsed by default, expands to 180px on
   :hover or when .is-expanded is applied. 100% in .is-drawer.
   The 64px and 180px widths are structural literals — no token
   equivalent. 64 is wide enough to center the 30px logo mark;
   180 is wide enough for the longest mono route label in the
   approved V1 sandbox without wrapping.

   ANIMATION — width + shadow + background transitions all run
   at 200ms var(--ease-out). The 200ms literal is retained from
   the approved V1 interaction (sandbox/nav-gallery-v2.html).
   --duration-fast (240ms) was considered but felt slightly long
   for the lateral rail reveal. Documented as the recipe's sole
   sub-token duration literal. */
.nav-rail {
  position: relative;
  width: 64px;
  flex-shrink: 0;
  background: var(--paper);
  border-right: 1px solid var(--ink-faint);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  z-index: 2;
  transition:
    width 200ms var(--ease-out),
    box-shadow 200ms var(--ease-out),
    background-color 200ms var(--ease-out);
}

.nav-rail:hover,
.nav-rail.is-expanded {
  width: 180px;
  /* Subtle letterpress — ~50% of textures.css .emboss-letterpress
     opacities. The rail whispers off the page rather than shouts;
     louder presses (sandbox V4 at ~80%) read as "card on rail"
     instead of "rail as chrome". rgba literals because CSS cannot
     express alpha against a var() reference. */
  box-shadow:
    inset 0 1px 0 rgba(255, 251, 240, 0.35),
    0 1px 0 rgba(255, 251, 240, 0.25),
    0 2px 6px rgba(40, 30, 18, 0.03),
    0 8px 20px rgba(40, 30, 18, 0.03);
}

/* .nav-rail.is-drawer — mobile full-width drawer. Consuming app
   toggles this class via JS on a hamburger trigger. All other
   rail mechanics (content visibility, nav items, hover) continue
   to apply. */
.nav-rail.is-drawer { width: 100%; }


/* ---------- rail .mark (brand slot) ---------- */

/* .nav-rail .mark — 48px-tall brand slot at the top of the rail.
   Holds both the mark SVG (shown collapsed) and the lockup SVG
   (shown expanded); opacity crossfades on rail state change.
   Consuming markup includes both children as <img> elements:
     <div class="mark">
       <img class="svg" src="logo-mark-red-pressed.svg" alt="Kujaku" />
       <img class="lockup" src="logo-lockup-red-pressed.svg" alt="Kujaku Investments" />
     </div>                                                      */
/* .mark is 48px tall to match .nav-masthead height.
   The two bottom-edge borders meet at a single Y coordinate,
   creating the crisp "+" corner intersection. */
.nav-rail .mark {
  position: relative;
  height: 48px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  border-bottom: 1px solid var(--ink-faint);
  flex-shrink: 0;
}

/* Both logos absolutely positioned in the same slot, centered
   via top/left/transform so each preserves its natural aspect
   ratio. Crossfade runs at 200ms var(--ease-out) — same literal
   as the rail's width/shadow reveal, for shared rhythm. */
.nav-rail .mark .svg,
.nav-rail .mark .lockup {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: block;
  transition: opacity 200ms var(--ease-out);
}

/* Mark SVG (collapsed state) — 28px square fits the 48px .mark
   slot with 10px breathing room top and bottom. Was 30px when
   .mark was 56px. */
.nav-rail .mark .svg {
  opacity: 1;
  width: 28px;
  height: 28px;
}

/* Lockup SVG (expanded state) — max-height 28px preserves the
   lockup's natural aspect ratio. max-width leaves 14px inset
   on each side of the 180px expanded rail (calc keeps it in
   sync with any future rail-width change). */
.nav-rail .mark .lockup {
  opacity: 0;
  max-height: 28px;
  width: auto;
  max-width: calc(100% - 28px);
}

/* Crossfade triggers — rail :hover, .is-expanded, or .is-drawer
   hides the mark and reveals the lockup. */
.nav-rail:hover .mark .svg,
.nav-rail.is-expanded .mark .svg,
.nav-rail.is-drawer .mark .svg { opacity: 0; }
.nav-rail:hover .mark .lockup,
.nav-rail.is-expanded .mark .lockup,
.nav-rail.is-drawer .mark .lockup { opacity: 1; }


/* ---------- rail .items (nav sections container) ---------- */

/* .nav-rail .items — flex column holding .nav-section blocks.
   Hidden in collapsed state (opacity 0); fades in on expand.
   ANIMATION — opacity transition 200ms var(--ease-out). */
.nav-rail .items {
  flex: 1;
  padding: 14px 0 8px;
  opacity: 0;
  min-height: 0;
  transition: opacity 200ms var(--ease-out);
}
.nav-rail:hover .items,
.nav-rail.is-expanded .items,
.nav-rail.is-drawer .items { opacity: 1; }


/* ---------- rail .footer (build-info block) ---------- */

/* .nav-rail .footer — optional 3-line mono-faint block at the
   rail bottom. Build-info convention: SHA / layer / last tick.
   Line content is consumer-defined. Hidden collapsed, fades in
   on expand. Scoped under .nav-rail so the generic ".footer"
   class is safe beside a consumer's page-level footer. */
.nav-rail .footer {
  flex-shrink: 0;
  padding: 10px 14px 12px;
  border-top: 1px solid var(--ink-faint);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  color: var(--ink-pale);
  line-height: 1.85;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 200ms var(--ease-out);
}
.nav-rail:hover .footer,
.nav-rail.is-expanded .footer,
.nav-rail.is-drawer .footer { opacity: 1; }


/* ---------- nav sections ---------- */

/* .nav-section — group of a section label + its nav items. The
   .label is the mono uppercase heading (e.g. "SYSTEM", "LOG",
   "STATIC"). */
.nav-section {
  margin: 0 0 10px;
}
.nav-section .label {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-mid);
  padding: 0 18px;
  margin: 0 0 6px;
  white-space: nowrap;
}


/* ---------- nav items ---------- */

/* .nav-item — single nav row. Mono 11px, --ink-mid default,
   --ink on hover. Structure: a <span class="slash">/</span>
   followed by the route label (bare text, or wrapped in
   <span class="label"> for an additional styling hook). The
   18px/28px horizontal paddings are structural literals tuned
   so the "/" slash column aligns across items and the ">"
   active prefix occupies the slash's column without layout
   shift.

   ANIMATION — color transition 80ms var(--ease-out). Fast on
   purpose: hover feedback on dense mono nav rows should feel
   immediate, not leisurely. No background fill on hover — the
   color shift alone carries the affordance. */
.nav-item {
  position: relative;
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-mid);
  text-decoration: none;
  padding: 4px 14px 4px 28px;
  letter-spacing: 0.04em;
  white-space: nowrap;
  transition: color 80ms var(--ease-out);
}
.nav-item:hover { color: var(--ink); }

.nav-item .slash {
  color: var(--ink-mid);
  transition: color 80ms var(--ease-out);
}
.nav-item:hover .slash { color: var(--ink); }

/* .nav-item .label — optional wrapper for the route name; inline
   text after the slash works equally well. The .label scope lets
   a consumer add per-label styling (e.g. a numeric badge or a
   truncation ellipsis) without touching the .nav-item row. */
.nav-item .label { color: inherit; }

/* Active state — single treatment: ">" prefix + --red color.
   Slash hidden via visibility (not display) so the baseline
   stays stable between active and inactive rows. */
.nav-item.is-active { color: var(--red); }
.nav-item.is-active .slash { visibility: hidden; }
.nav-item.is-active::before {
  content: '>';
  position: absolute;
  left: 18px;
  color: var(--red);
  font-weight: 500;
}


/* ============================================================
 * NAV MASTHEAD — ticker strip.
 *
 * 48px-tall masthead. Horizontally scrolling stock-ticker-style
 * carousel with /-prefix symbols borrowed from the rail's route
 * vernacular. Right-aligned nav actions (login, about, etc.).
 *
 * Marquee animation: CSS @keyframes translateX 0 → -50% on
 * .ticker-track. Markup duplicates the ticker list for seamless
 * loop. Animation pauses on hover (:hover on .ticker-track).
 *
 * Hover-swap reveal: each ticker block shows SYMBOL + delta%
 * by default; on hover, delta fades out and price fades in
 * using absolute-positioned siblings. No color coding on delta
 * (ink-mid always); direction implied by +/- sign.
 *
 * Scroll-hide: .is-hidden class translates masthead up via
 * transform: translateY(-100%). Consumer JS toggles the class
 * based on scroll direction (~15 lines, see STYLE.md).
 *
 * Corner alignment: 48px height matches .nav-rail .mark for
 * the crisp "+" intersection at the rail/masthead corner.
 *
 * MARKUP CONTRACT —
 *   <div class="nav-masthead">
 *     <div class="ticker-viewport">
 *       <div class="ticker-track">
 *         <span class="ticker-block">
 *           <span class="symbol">SPX</span>
 *           <span class="delta">+0.18%</span>
 *           <span class="price">5,248.30</span>
 *         </span>
 *         ... block list, then DUPLICATED for seamless loop
 *       </div>
 *     </div>
 *     <div class="actions">
 *       <a href="...">Login</a><a href="...">About</a>
 *     </div>
 *   </div>
 *
 * See STYLE.md /components Nav for full system rules.
 * ============================================================ */

/* Base masthead — 48px height + 1px --ink-faint bottom border
   are the corner-alignment contract with .nav-rail .mark.
   overflow: hidden confines the marquee to the viewport.
   ANIMATION — transform transition var(--duration-fast) (240ms)
   for the .is-hidden slide-up. Slightly slower than the rail's
   200ms because vertical motion over the full 48px reads
   farther than a width reveal. */
.nav-masthead {
  height: 48px;
  display: flex;
  align-items: stretch;
  background: var(--paper);
  border-bottom: 1px solid var(--ink-faint);
  overflow: hidden;
  transition: transform var(--duration-fast) var(--ease-out);
}

/* Ticker region — expands to fill the masthead; the marquee
   track slides inside its clipped bounds. */
.nav-masthead .ticker-viewport {
  flex: 1;
  overflow: hidden;
  display: flex;
  align-items: center;
  position: relative;
}

/* Marquee track — holds the DOUBLED ticker-block list and runs
   a 60-second linear loop. translateX(-50%) halts at the
   midpoint so the second half renders seamlessly from
   translateX(0); consumer markup must repeat the list twice to
   match. 60s is a structural literal chosen for a slow, calm
   scroll; no tokenized duration is long enough for marquee
   work. The 24px gap and 24px side padding are structural
   literals tuned for ticker-block density at 11px mono. */
.nav-masthead .ticker-track {
  display: flex;
  align-items: center;
  white-space: nowrap;
  flex-shrink: 0;
  gap: 24px;
  padding: 0 24px;
  animation: ticker-marquee 60s linear infinite;
}

/* Hover pauses the marquee so a reader can hold the track
   still — and so block-hover can reveal the price without
   the target sliding out from under the pointer. */
.nav-masthead .ticker-track:hover { animation-play-state: paused; }

/* Ticker cell — column stack (symbol on top, delta below).
   position: relative anchors .price for its absolute overlay.
   min-width reserves horizontal space so neighbors don't shift
   when price text (wider) swaps in for delta text (narrower).
   80px is the structural literal — fits the longest ticker
   triplet in the approved V10 dataset at 11px mono. */
.nav-masthead .ticker-block {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  line-height: 1.15;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  min-width: 80px;
}

/* Symbol row — /-prefix in --ink-pale via ::before, echoing
   the rail's nav-item /-slash vernacular so the masthead reads
   as the same typographic system as the rail. */
.nav-masthead .ticker-block .symbol {
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink);
}
.nav-masthead .ticker-block .symbol::before {
  content: "/";
  color: var(--ink-pale);
  font-weight: 400;
  margin-right: 3px;
}

/* Delta row (default visible) and price row (default hidden,
   absolutely positioned over the delta slot). Both carry
   identical typographic weight so the swap reads as a content
   change, not a layout shift. Delta stays --ink-mid always —
   no color coding; direction is implied by the +/- sign. */
.nav-masthead .ticker-block .delta,
.nav-masthead .ticker-block .price {
  font-size: 11px;
  color: var(--ink-mid);
  white-space: nowrap;
  transition: opacity 200ms var(--ease-out);
}
.nav-masthead .ticker-block .price {
  position: absolute;
  left: 0;
  bottom: 0;
  opacity: 0;
  pointer-events: none;
  color: var(--ink);
}

/* Hover swap — delta fades out, price fades in at the same
   slot. 200ms literal matches the nav-rail's width/shadow
   reveal timing so masthead and rail animate in the same
   rhythm. No tokenized duration is 200ms; this is the same
   sub-token literal the rail already carries. */
.nav-masthead .ticker-block:hover .delta { opacity: 0; }
.nav-masthead .ticker-block:hover .price { opacity: 1; }


/* ---------- actions (right edge) ---------- */

/* Right-aligned action links. 1px --ink-faint divider separates
   the ticker region from actions. Actions stay static while the
   ticker marquees beneath. */
.nav-masthead .actions {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  height: 100%;
  padding: 0 20px;
  border-left: 1px solid var(--ink-faint);
}
.nav-masthead .actions a {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-mid);
  text-decoration: none;
  transition: color var(--duration-fast) var(--ease-out);
}
.nav-masthead .actions a:hover { color: var(--red); }
.nav-masthead .actions a + a { margin-left: 24px; }


/* ---------- marquee keyframes ---------- */

/* translateX(0 → -50%) pairs with the doubled markup contract
   above for a seamless loop. */
@keyframes ticker-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}


/* ---------- modifier: hidden (scroll-down) ---------- */

/* .is-hidden translates the masthead out of view. Transition
   is defined on the base rule above (transform var(--duration-fast)). */
.nav-masthead.is-hidden {
  transform: translateY(-100%);
}


/* ============================================================
 * INDICATORS — stat / numeral / delta primitives.
 *
 * Four recipes for Kujaku's observational-finance voice:
 *   .indicator-row      — dashboard atom (label / num / delta
 *                         on one grid line). Ships with
 *                         .is-stacked for narrow KPI cells.
 *   .indicator-tabular  — period-column comparison (1M/3M/YTD).
 *                         Uses tabular-nums for digit alignment.
 *   .indicator-gloss    — JP kanji bookend + label + num + delta.
 *                         Editorial callout. .is-dark flips the
 *                         JP red → gold.
 *   .indicator-trend    — numeral + 1px --ink sparkline with
 *                         filled --red end-dot r=2. Echoes
 *                         /graphs rule 4 at miniature scale.
 *
 * Shared: .is-sm, default, .is-lg size modifiers on all four.
 * .is-dark modifier on all four for coal/oxblood surfaces.
 *
 * Width: indicators are content-sized by default. Consumers
 * add `width: 100%` at their site when they want fill (e.g. a
 * dashboard stack where deltas should right-align across rows).
 *
 * See STYLE.md /components Indicator for full spec.
 * See STYLE.md /graphs sparkline micro-chart for the sparkline
 * stroke + end-dot convention.
 * ============================================================ */


/* ---------- shared base ---------- */

/* Core tokens for label / num / delta. Recipes override on top
   of these; .is-dark flips to paper-family on all three. */
.indicator {
  display: block;
  font-family: var(--font-mono);
}
.indicator .label {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-mid);
  line-height: 1.2;
}
.indicator .num {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 500;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.indicator .delta {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-mid);
  font-variant-numeric: tabular-nums;
}

/* Shared .is-dark — applies on --paper-coal, --red-deep, --ink
   surfaces. rgba literals encode alpha against paper tones
   because CSS can't express alpha against a var() reference. */
.indicator.is-dark .label { color: rgba(241,236,224,0.55); }
.indicator.is-dark .num   { color: var(--paper); }
.indicator.is-dark .delta { color: rgba(241,236,224,0.7); }


/* ---------- .indicator-row — dashboard atom ---------- */

/* Single-period label / numeral / delta on one grid line. The
   `1fr` on the middle column resolves to remaining space when a
   consumer gives the row a width; collapses to 0 when it doesn't,
   so the row reads compact in narrow cells. .is-stacked flips
   the layout to a flex-column for KPI strips or any cell that
   can't hold three horizontal columns. */
.indicator-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: 14px;
}
.indicator-row .num   { font-size: 14px; }
.indicator-row .delta { text-align: right; }

/* Size ladder — horizontal form */
.indicator-row.is-sm { gap: 10px; }
.indicator-row.is-sm .label { font-size: 9px; letter-spacing: 0.14em; }
.indicator-row.is-sm .num   { font-size: 11px; }
.indicator-row.is-sm .delta { font-size: 9px; }

.indicator-row.is-lg { gap: 20px; }
.indicator-row.is-lg .label { font-size: 11px; letter-spacing: 0.18em; }
.indicator-row.is-lg .num   { font-size: 22px; }
.indicator-row.is-lg .delta { font-size: 11px; }

/* .is-stacked — flex-column variant. Composes with .is-sm /
   .is-lg. Drops the horizontal-grid right-align on .delta
   (a stacked form is all-left by convention). */
.indicator-row.is-stacked {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}
.indicator-row.is-stacked .delta { text-align: left; }
.indicator-row.is-stacked.is-sm { gap: 3px; }
.indicator-row.is-stacked.is-lg { gap: 6px; }


/* ---------- .indicator-tabular — period comparison ---------- */

/* Outer label + N rows. Each .row is a nested grid of
   period / val / delta with tabular-nums locking digit
   alignment across rows. The val column's `1fr` resolves
   against the outer container width — scenes that want a
   full-width ledger add `width: 100%` at the site. The period
   column widens 28 → 36 → 48px across the size ladder so digit
   alignment survives larger val font-sizes. */
.indicator-tabular {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.indicator-tabular .label { margin-bottom: 4px; }
.indicator-tabular .row {
  display: grid;
  grid-template-columns: 36px 1fr auto;
  gap: 14px;
  align-items: baseline;
  font-variant-numeric: tabular-nums;
}
.indicator-tabular .row .period {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-pale);
}
.indicator-tabular .row .val {
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
  text-align: right;
}
.indicator-tabular .row .d {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-mid);
}

/* Size ladder — steps period column width, outer gap, and all
   three child font-sizes. */
.indicator-tabular.is-sm { gap: 5px; }
.indicator-tabular.is-sm .label { font-size: 9px; letter-spacing: 0.14em; }
.indicator-tabular.is-sm .row { grid-template-columns: 28px 1fr auto; gap: 10px; }
.indicator-tabular.is-sm .row .period { font-size: 8px; }
.indicator-tabular.is-sm .row .val    { font-size: 12px; }
.indicator-tabular.is-sm .row .d      { font-size: 9px; }

.indicator-tabular.is-lg { gap: 12px; }
.indicator-tabular.is-lg .label { font-size: 11px; letter-spacing: 0.18em; }
.indicator-tabular.is-lg .row { grid-template-columns: 48px 1fr auto; gap: 20px; }
.indicator-tabular.is-lg .row .period { font-size: 10px; }
.indicator-tabular.is-lg .row .val    { font-size: 24px; }
.indicator-tabular.is-lg .row .d      { font-size: 12px; }

/* .is-dark — recipe-specific children override base .is-dark
   because .row > .period / .val / .d aren't the shared
   .label / .num / .delta. */
.indicator-tabular.is-dark .row .period { color: rgba(241,236,224,0.45); }
.indicator-tabular.is-dark .row .val    { color: var(--paper); }
.indicator-tabular.is-dark .row .d      { color: rgba(241,236,224,0.7); }


/* ---------- .indicator-gloss — editorial callout ---------- */

/* JP kanji bookend + Latin label, then numeral, then delta.
   Follows the .eyebrow-gloss convention established in the
   eyebrow subsystem. align-items: flex-start keeps children at
   their natural widths so the gloss reads as a pull-quote, not
   a full-bleed block.

   .is-dark flips the red JP character to --gold (matching the
   .eyebrow.is-dark precedent). IMPORTANT: this flip CLAIMS the
   page's one-gold-per-page budget — no other gold element may
   appear on a page that uses .indicator-gloss.is-dark. */
.indicator-gloss {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}
.indicator-gloss .label-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.indicator-gloss .jp {
  font-family: var(--font-jp);
  font-weight: 400;
  font-size: 14px;
  color: var(--red);
  letter-spacing: 0.06em;
  line-height: 1;
}
.indicator-gloss .num { font-size: 22px; }

/* .is-sm — complete ladder: steps outer gap, label-row gap,
   jp, label, num, delta. */
.indicator-gloss.is-sm { gap: 6px; }
.indicator-gloss.is-sm .label-row { gap: 8px; }
.indicator-gloss.is-sm .jp    { font-size: 11px; }
.indicator-gloss.is-sm .label { font-size: 9px; letter-spacing: 0.14em; }
.indicator-gloss.is-sm .num   { font-size: 16px; }
.indicator-gloss.is-sm .delta { font-size: 10px; }

/* .is-lg — complete ladder for ceremonial / section-anchor
   use. 44px numeral reads as a declarative headline. */
.indicator-gloss.is-lg { gap: 12px; }
.indicator-gloss.is-lg .label-row { gap: 14px; }
.indicator-gloss.is-lg .jp    { font-size: 24px; }
.indicator-gloss.is-lg .label { font-size: 11px; letter-spacing: 0.18em; }
.indicator-gloss.is-lg .num   { font-size: 44px; }
.indicator-gloss.is-lg .delta { font-size: 12px; }

.indicator-gloss.is-dark .jp { color: var(--gold); }


/* ---------- .indicator-trend — sparkline trend ---------- */

/* Numeral + inline sparkline + delta. The .main-row is a TIGHT
   CLUSTER: flex + 10px gap, NO `justify-content: space-between`,
   NO forced width — otherwise the sparkline gets thrown to the
   opposite edge of the container. align-items: flex-start on
   the parent keeps the cluster from stretching full-width when
   the recipe sits inside a flex or grid cell.

   The sparkline is a 1px --ink polyline with a filled --red
   end-dot (r=2 default, r=3 at .is-lg). The stroke / dot split
   echoes /graphs rule 4 (filled red end-point marker) at
   miniature scale — the line carries structure, the dot carries
   the brand signal. See STYLE.md /graphs sparkline micro-chart
   subsection.

   Sparkline dimensions (52 / 84 / 220) are structural literals
   tuned to the size ladder. Stroke-widths (1 / 1 / 1.25) and
   endpoint radii (2 / 2 / 3) step one notch at .is-lg so the
   hero figure reads at scale. */
.indicator-trend {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}
.indicator-trend .main-row {
  display: flex;
  align-items: center;
  gap: 10px; /* literal: tight cluster between numeral and sparkline */
}
.indicator-trend .num { font-size: 22px; }
.indicator-trend .spark {
  display: inline-block;
  width: 84px;
  height: 24px;
  flex-shrink: 0;
  stroke: var(--ink);
  fill: none;
  stroke-width: 1;
  overflow: visible;
}
.indicator-trend .spark .endpoint {
  fill: var(--red);
  stroke: none;
}

/* .is-sm — compact for peripheral ticker grids. Cluster gap
   tightens to 6px; sparkline drops to 52×14. */
.indicator-trend.is-sm { gap: 3px; }
.indicator-trend.is-sm .main-row { gap: 6px; }
.indicator-trend.is-sm .label { font-size: 9px; letter-spacing: 0.14em; }
.indicator-trend.is-sm .num   { font-size: 13px; }
.indicator-trend.is-sm .delta { font-size: 9px; }
.indicator-trend.is-sm .spark { width: 52px; height: 14px; }

/* .is-lg — hero single-instrument treatment. 44px numeral,
   220×44 sparkline, stroke-width 1.25 for scale, endpoint r=3. */
.indicator-trend.is-lg { gap: 10px; }
.indicator-trend.is-lg .main-row { gap: 14px; }
.indicator-trend.is-lg .label { font-size: 11px; letter-spacing: 0.18em; }
.indicator-trend.is-lg .num   { font-size: 44px; }
.indicator-trend.is-lg .delta { font-size: 12px; }
.indicator-trend.is-lg .spark { width: 220px; height: 44px; stroke-width: 1.25; }
.indicator-trend.is-lg .spark .endpoint { r: 3; }

/* .is-dark — spark stroke flips to --paper; end-dot stays
   --red (reads as a filled bead against both coal and oxblood
   per the Scene 13 dark-surface test). */
.indicator-trend.is-dark .spark { stroke: var(--paper); }
.indicator-trend.is-dark .spark .endpoint { fill: var(--red); }


/* ============================================================
 * BUTTONS — press-mechanic primitives.
 *
 * Every button uses the same core mechanic:
 *   REST   → raised (letterpress shadow)
 *   HOVER  → deboss (pressed IN via inset shadow)
 *   ACTIVE → identical to HOVER deepened
 * Touch users see the press animation on tap. Desktop users
 * hold pressed-in while hovering. No scale, no rotation.
 *
 * Shadow stacks are ~50% of .emboss-letterpress offsets
 * (textures.css) — sized for button scale rather than card
 * scale. Alpha-literal shadows (rgba inline) encode the
 * highlight (rgba(255,251,240, X)) + inset-shadow (rgba(40,30,18, X))
 * pair; CSS can't express alpha-on-var(). Same precedent as
 * .hanko and .nav-rail.
 *
 * Surface modifiers:
 *   (default)  .btn — paper-warm surface (#F4EFE6, matches .card-paper)
 *   .is-primary — red CTA
 *   .is-ink — paper-coal (rare "dark CTA" treatment)
 *   .is-oxblood — red-deep ceremonial (+ optional .jp gold slot)
 *   .is-outline — bordered ghost (1px --ink border)
 *   .is-dark — for buttons INSIDE dark cards (transparent
 *                 fill, paper border; press lives in border +
 *                 background-fill, not shadow stack).
 *
 * Semantic modifier:
 *   .is-route — button navigates somewhere. Rendered with a
 *               leading "/" via ::before, plus lowercase +
 *               tighter tracking to read as a path. No slash
 *               in the markup text — the pseudo supplies it.
 *               NO .is-route = button performs an action
 *               (Submit, Cancel, Confirm, Save).
 *               Slash vernacular matches .nav-item .slash and
 *               .nav-masthead .ticker-block .symbol::before.
 *
 * Size modifiers: .is-sm / default / .is-lg — compose with
 * any surface modifier.
 *
 * State: :disabled or [aria-disabled="true"] → --ink-pale text,
 * flat shadow, cursor: not-allowed.
 *
 * Forbidden composition: .is-primary + .is-oxblood (red on
 * red-deep unreadable). .is-primary inside .card-oxblood or
 * .card-coal also fails — use .is-dark instead.
 *
 * See STYLE.md /components Button for the full spec.
 * ============================================================ */

/* ---------- .btn base (paper-warm surface) ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border: none;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 12px 26px;
  background: #F4EFE6; /* paper-warm, same literal as .card-paper */
  color: var(--ink);
  border-radius: 3px;
  line-height: 1;
  user-select: none;
  text-decoration: none;
  /* REST — raised letterpress */
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.7),
    0 1px 0 rgba(255,251,240,0.5),
    0 2px 6px rgba(40,30,18,0.06),
    0 8px 20px rgba(40,30,18,0.06);
  transition:
    box-shadow var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}
/* HOVER — pressed in (deboss) */
.btn:hover {
  background: var(--paper-deep);
  box-shadow:
    inset 0 2px 4px rgba(40,30,18,0.12),
    inset 0 -1px 0 rgba(255,251,240,0.6);
}
/* ACTIVE — same direction as hover, deeper inset */
.btn:active {
  background: var(--paper-deep);
  box-shadow:
    inset 0 3px 5px rgba(40,30,18,0.16),
    inset 0 -1px 0 rgba(255,251,240,0.6);
}
.btn:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}
.btn:disabled,
.btn[aria-disabled="true"] {
  color: var(--ink-pale);
  box-shadow: none;
  cursor: not-allowed;
  pointer-events: none;
}


/* ---------- .btn.is-primary — red pressed CTA ---------- */
.btn.is-primary {
  background: var(--red);
  color: var(--paper);
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.25),
    0 2px 6px rgba(138,36,24,0.25),
    0 8px 20px rgba(138,36,24,0.12);
  /* rgba(138,36,24) encodes alpha against --red-deep;
     CSS can't express alpha-on-var(). */
}
.btn.is-primary:hover {
  background: var(--red-deep);
  box-shadow:
    inset 0 2px 4px rgba(40,20,12,0.30),
    inset 0 -1px 0 rgba(255,251,240,0.14);
  /* rgba(40,20,12) — warm-dark inset for depth on red surface */
}
.btn.is-primary:active {
  background: var(--red-deep);
  box-shadow:
    inset 0 3px 5px rgba(40,20,12,0.38),
    inset 0 -1px 0 rgba(255,251,240,0.12);
}
.btn.is-primary:disabled,
.btn.is-primary[aria-disabled="true"] {
  color: var(--ink-pale);
  box-shadow: none;
  cursor: not-allowed;
  pointer-events: none;
}


/* ---------- .btn.is-ink — paper-coal dark CTA ---------- */
.btn.is-ink {
  background: var(--paper-coal);
  color: var(--paper);
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.14),
    0 2px 6px rgba(0,0,0,0.18),
    0 8px 20px rgba(0,0,0,0.10);
}
.btn.is-ink:hover {
  background: var(--ink);
  box-shadow:
    inset 0 2px 4px rgba(0,0,0,0.30),
    inset 0 -1px 0 rgba(255,251,240,0.08);
}
.btn.is-ink:active {
  background: var(--ink);
  box-shadow:
    inset 0 3px 5px rgba(0,0,0,0.40),
    inset 0 -1px 0 rgba(255,251,240,0.08);
}


/* ---------- .btn.is-oxblood — red-deep ceremonial ---------- */
/* Optional .jp slot claims the page's one-gold budget
   (STYLE.md /colors one-gold rule). Use sparingly. */
.btn.is-oxblood {
  background: var(--red-deep);
  color: var(--paper);
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.14),
    0 2px 6px rgba(40,10,8,0.28),
    0 10px 24px rgba(40,10,8,0.14);
  /* rgba(40,10,8) — warmer-dark inset for oxblood depth */
}
.btn.is-oxblood:hover {
  background: #6B1C12; /* literal — one step deeper than --red-deep;
                          matches .card-oxblood sunken precedent */
  box-shadow:
    inset 0 2px 4px rgba(20,6,4,0.40),
    inset 0 -1px 0 rgba(255,251,240,0.10);
}
.btn.is-oxblood:active {
  background: #6B1C12;
  box-shadow:
    inset 0 3px 5px rgba(20,6,4,0.50),
    inset 0 -1px 0 rgba(255,251,240,0.10);
}
.btn.is-oxblood .jp {
  font-family: var(--font-jp);
  font-weight: 400;
  color: var(--gold);
  letter-spacing: 0.04em;
  margin-right: 10px;
  font-size: 13px;
  line-height: 1;
}


/* ---------- .btn.is-outline — bordered ghost ---------- */
.btn.is-outline {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--ink);
  padding: 11px 25px; /* -1px per side to account for border */
  box-shadow:
    0 1px 0 rgba(255,251,240,0.4),
    0 2px 4px rgba(40,30,18,0.04);
}
.btn.is-outline:hover {
  background: var(--paper-deep);
  box-shadow:
    inset 0 2px 4px rgba(40,30,18,0.10),
    inset 0 -1px 0 rgba(255,251,240,0.6);
}
.btn.is-outline:active {
  background: var(--paper-deep);
  box-shadow:
    inset 0 3px 5px rgba(40,30,18,0.14),
    inset 0 -1px 0 rgba(255,251,240,0.6);
}


/* ---------- .btn.is-dark — buttons placed inside dark-surface
 * cards (.card-coal, .card-oxblood, .card-ink). NOTE: Uses a
 * different press grammar than other .is-dark primitives —
 * border-darkens on hover instead of debossing, because a
 * transparent button on a dark fill can't deboss. Semantic
 * naming unified with eyebrow/indicator/table/chart .is-dark
 * convention per cleanup cycle. */
.btn.is-dark {
  background: transparent;
  color: var(--paper);
  border: 1px solid rgba(241,236,224,0.4);
  padding: 11px 25px;
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.08),
    0 1px 2px rgba(0,0,0,0.12);
  /* rgba(241,236,224) encodes alpha against --paper;
     CSS can't express alpha-on-var(). */
}
.btn.is-dark:hover {
  border-color: var(--paper);
  background: rgba(241,236,224,0.08);
  box-shadow: inset 0 2px 4px rgba(0,0,0,0.20);
}
.btn.is-dark:active {
  background: rgba(241,236,224,0.14);
  box-shadow: inset 0 3px 5px rgba(0,0,0,0.28);
}


/* ---------- .btn.is-route — slash-prefix route semantic ----------
 * The button navigates. Text switches to lowercase + tight
 * tracking so it reads as a path. Slash via ::before mirrors
 * .nav-item .slash and .nav-masthead .ticker-block .symbol::before
 * conventions — consistency across every nav primitive.
 * DO NOT include a literal "/" in the markup text; the pseudo
 * supplies the slash. */
.btn.is-route {
  text-transform: none;
  letter-spacing: 0.04em;
}
.btn.is-route::before {
  content: "/";
  color: var(--ink-pale);
  margin-right: 4px;
  font-weight: 400;
  transition: color var(--duration-fast) var(--ease-out);
}
.btn.is-route:hover::before { color: var(--red); }

/* Route slash colors on filled surfaces — paper-family dim
   that pops on hover. rgba(241,236,224) = --paper with alpha. */
.btn.is-route.is-primary::before { color: rgba(241,236,224,0.55); }
.btn.is-route.is-primary:hover::before { color: var(--paper); }

.btn.is-route.is-ink::before { color: rgba(241,236,224,0.45); }
.btn.is-route.is-ink:hover::before { color: var(--paper); }

.btn.is-route.is-oxblood::before { color: rgba(241,236,224,0.5); }
.btn.is-route.is-oxblood:hover::before { color: var(--gold); }

.btn.is-route.is-outline::before { color: var(--ink-pale); }
.btn.is-route.is-outline:hover::before { color: var(--red); }


/* ---------- .btn.is-sm — small (composes with any surface) ---------- */
.btn.is-sm {
  font-size: 10px;
  letter-spacing: 0.14em;
  padding: 8px 18px;
  border-radius: 2px;
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.7),
    0 1px 0 rgba(255,251,240,0.4),
    0 1px 3px rgba(40,30,18,0.06),
    0 4px 10px rgba(40,30,18,0.06);
}
.btn.is-sm:hover {
  box-shadow:
    inset 0 1px 3px rgba(40,30,18,0.10),
    inset 0 -1px 0 rgba(255,251,240,0.6);
}
.btn.is-sm:active {
  box-shadow:
    inset 0 2px 4px rgba(40,30,18,0.14),
    inset 0 -1px 0 rgba(255,251,240,0.6);
}
.btn.is-sm.is-outline { padding: 7px 17px; }


/* ---------- .btn.is-lg — hero scale ---------- */
.btn.is-lg {
  font-size: 13px;
  letter-spacing: 0.18em;
  padding: 16px 34px;
  border-radius: 4px;
  box-shadow:
    inset 0 1px 0 rgba(255,251,240,0.7),
    0 1px 0 rgba(255,251,240,0.5),
    0 4px 12px rgba(40,30,18,0.08),
    0 16px 40px rgba(40,30,18,0.08);
}
.btn.is-lg:hover {
  box-shadow:
    inset 0 3px 6px rgba(40,30,18,0.14),
    inset 0 -1px 0 rgba(255,251,240,0.6);
}
.btn.is-lg:active {
  box-shadow:
    inset 0 4px 8px rgba(40,30,18,0.18),
    inset 0 -1px 0 rgba(255,251,240,0.6);
}
.btn.is-lg.is-outline { padding: 15px 33px; }


/* ============================================================
 * TABLES — tabular data primitive.
 *
 * Hairline-only structural base. Mono-caps left-aligned headers
 * (1px --ink bottom rule). tabular-nums on every cell. Row
 * dividers are 1px --ink-faint on paper surfaces; on dark
 * surfaces (via .is-dark) they shift to rgba-paper alpha.
 * Hover shifts row background to --paper-deep (240ms).
 *
 * Architecture — two modifier categories:
 *   SURFACE  (.is-*)  assert a visual treatment and do NOT
 *                     compose with each other.
 *                     .is-dense / .is-article / .is-dark /
 *                     .is-slash / .is-eyebrow-header.
 *   CAPABILITY (.has-*) are feature flags. Compose freely with
 *                     each other AND with surface modifiers.
 *                     .has-sort / .has-totals / .has-hanko /
 *                     .has-trend / .has-expandable.
 *
 * Preset:
 *   .is-ledger — expands with td.balance + th.balance-h styling
 *                (hairline separator + weight 500).
 *
 * Cross-recipe composition:
 *   - .has-trend cells host an inline .spark SVG using the
 *     .indicator-trend .spark convention verbatim (1px --ink
 *     polyline + filled --red endpoint r=2).
 *   - .has-hanko cells host a .hanko.is-22 inline.
 *   - .is-slash first-column prefix matches .nav-rail /
 *     .nav-masthead .ticker-block .symbol / .btn.is-route pattern.
 *   - Disabled pagination (.pages a.is-disabled) reuses the
 *     .btn:disabled convention: --ink-pale + pointer-events:none.
 *
 * Delta signs are +/- in mono --ink-mid — NEVER color-coded by
 * direction. Matches /graphs + .indicator .delta conventions.
 *
 * rgba() literals on dark surfaces encode alpha against --paper;
 * CSS can't express alpha-on-var(). Same precedent as .hanko,
 * .nav-rail, .btn.is-dark.
 *
 * See STYLE.md /components Table for the full spec.
 * ============================================================ */

/* ---------- base ---------- */
.tbl {
  border-collapse: collapse;
  width: auto; /* consumer sets width: 100% scene-locally when
                  fill is wanted. Same precedent as .indicator-*. */
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.tbl th,
.tbl td {
  text-align: left;
  font-weight: 400;
  vertical-align: middle;
  padding: 12px 0;
}
.tbl th + th,
.tbl td + td { padding-left: 28px; }

.tbl thead th {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-mid);
  border-bottom: 1px solid var(--ink);
  white-space: nowrap;
  padding-bottom: 12px;
}
.tbl tbody td { border-bottom: 1px solid var(--ink-faint); }
.tbl tbody tr:last-child td { border-bottom: none; }
.tbl tbody tr {
  transition: background-color var(--duration-fast) var(--ease-out);
}
.tbl tbody tr:hover td { background: var(--paper-deep); }

/* ---------- cell-role helpers ---------- */
.tbl td.num,
.tbl td.pct,
.tbl td.wt,
.tbl td.delta,
.tbl th.right,
.tbl td.right { text-align: right; }
.tbl td.sym { font-weight: 500; letter-spacing: 0.02em; }
.tbl td.name {
  font-family: var(--font-body);
  font-size: 14px;
  font-variant-numeric: normal;
}
.tbl td.muted { color: var(--ink-mid); }
.tbl td.pale  { color: var(--ink-pale); }


/* ---------- SURFACE modifier — .is-dense ----------
 * Dashboard density. 8/0 padding, 12px body, 9px caps header. */
.tbl.is-dense { font-size: 12px; }
.tbl.is-dense th,
.tbl.is-dense td { padding: 8px 0; }
.tbl.is-dense th + th,
.tbl.is-dense td + td { padding-left: 20px; }
.tbl.is-dense thead th {
  font-size: 9px;
  letter-spacing: 0.16em;
  padding-bottom: 10px;
}
.tbl.is-dense td.name { font-size: 13px; }


/* ---------- SURFACE modifier — .is-article ----------
 * Narrow editorial embed. Sparse padding, paragraph-friendly.
 * Opts in to width:100% within the article column. */
.tbl.is-article {
  font-size: 13px;
  margin: 24px 0;
  width: 100%;
}
.tbl.is-article th,
.tbl.is-article td { padding: 10px 0; }
.tbl.is-article th + th,
.tbl.is-article td + td { padding-left: 32px; }


/* ---------- SURFACE modifier — .is-dark ----------
 * Paper text on --paper-coal / --red-deep / --ink surfaces.
 * rgba(241,236,224) encodes --paper with alpha (CSS can't
 * express alpha-on-var). Same precedent as .btn.is-dark. */
.tbl.is-dark { color: var(--paper); }
.tbl.is-dark thead th {
  color: rgba(241,236,224,0.68);
  border-bottom-color: rgba(241,236,224,0.3);
}
.tbl.is-dark tbody td {
  border-bottom-color: rgba(241,236,224,0.12);
  color: var(--paper);
}
.tbl.is-dark td.muted { color: rgba(241,236,224,0.6); }
.tbl.is-dark td.name  { color: var(--paper); }
.tbl.is-dark tbody tr:hover td { background: rgba(241,236,224,0.06); }


/* ---------- SURFACE modifier — .is-slash ----------
 * First-column slash-prefix via ::before. Mirrors the
 * .nav-rail .nav-item .slash, .nav-masthead .ticker-block
 * .symbol::before, and .btn.is-route::before vernacular.
 * Consumer markup text does NOT include a literal "/". */
.tbl.is-slash tbody td:first-child { position: relative; }
.tbl.is-slash tbody td:first-child::before {
  content: "/";
  color: var(--ink-pale);
  margin-right: 4px;
  font-weight: 400;
  transition: color var(--duration-fast) var(--ease-out);
}
.tbl.is-slash tbody tr:hover td:first-child::before { color: var(--red); }


/* ---------- SURFACE modifier — .is-eyebrow-header ----------
 * <caption> renders as an eyebrow-gloss banner: JP bookend +
 * Sentient title + mono gloss, separated by a 1px --ink rule
 * from the thead. Gold JP claims the page's one-gold budget
 * (see /colors + Eyebrow cross-references). */
.tbl.is-eyebrow-header caption {
  caption-side: top;
  text-align: left;
  padding: 0 0 16px;
}
.tbl.is-eyebrow-header caption .eyebrow-line {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--ink);
}
.tbl.is-eyebrow-header caption .jp {
  font-family: var(--font-jp);
  font-weight: 500;
  font-size: 18px;
  color: var(--gold);
  letter-spacing: 0.06em;
}
.tbl.is-eyebrow-header caption .title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 22px;
  color: var(--ink);
  letter-spacing: -0.01em;
  flex: 1;
}
.tbl.is-eyebrow-header caption .gloss {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-mid);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}


/* ---------- CAPABILITY flag — .has-sort ----------
 * Sortable headers with monochrome carets. Inactive ▲▼ in
 * --ink-pale; active single arrow in --ink via state classes
 * .is-sorted-asc / .is-sorted-desc. Consumer supplies the
 * caret glyph(s) inside the header cell. */
.tbl.has-sort thead th.is-sortable {
  cursor: pointer;
  padding-right: 22px;
  position: relative;
  transition: color var(--duration-fast) var(--ease-out);
}
.tbl.has-sort thead th.is-sortable:hover { color: var(--ink); }
.tbl.has-sort thead th.is-sortable .caret {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--ink-pale);
  font-size: 9px;
  line-height: 1;
  transition: color var(--duration-fast) var(--ease-out);
}
.tbl.has-sort thead th.is-sorted-asc  .caret,
.tbl.has-sort thead th.is-sorted-desc .caret { color: var(--ink); }


/* ---------- CAPABILITY flag — .has-totals ----------
 * tfoot.totals row sits beneath the last data row with a
 * 1px --ink top rule (stronger than --ink-faint data hairlines).
 * td.label switches to mono-caps tracked --ink-mid. */
.tbl.has-totals tfoot.totals td {
  border-top: 1px solid var(--ink);
  border-bottom: none;
  padding-top: 14px;
  padding-bottom: 4px;
  font-weight: 500;
  color: var(--ink);
}
.tbl.has-totals tfoot.totals td.label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-mid);
  font-weight: 500;
}


/* ---------- CAPABILITY flag — .has-hanko ----------
 * Reserves a 36px leading cell for an inline .hanko marker.
 * 36px literal tuned to .hanko.is-22 (22px seal + breathing).
 * Header equivalent th.cell-hanko-h holds the column width. */
.tbl.has-hanko td.cell-hanko {
  width: 36px;
  padding-left: 0;
  padding-right: 0;
}
.tbl.has-hanko th.cell-hanko-h {
  width: 36px;
  padding-left: 0;
  padding-right: 0;
}
.tbl.has-hanko td.cell-hanko + td,
.tbl.has-hanko th.cell-hanko-h + th { padding-left: 16px; }


/* ---------- CAPABILITY flag — .has-trend ----------
 * Reserves a cell for an inline sparkline. Uses the
 * .indicator-trend .spark convention verbatim: 1px --ink
 * polyline (no fill) + filled --red endpoint r=2.
 * On dark surfaces via .is-dark, polyline stroke flips to
 * --paper; endpoint stays --red (brand signal color). */
.tbl.has-trend td.cell-trend { width: 100px; }
.tbl.has-trend td.cell-trend .spark {
  display: inline-block;
  width: 84px;
  height: 18px;
  stroke: var(--ink);
  fill: none;
  stroke-width: 1;
  overflow: visible;
  vertical-align: middle;
}
.tbl.has-trend td.cell-trend .spark .endpoint {
  fill: var(--red);
  stroke: none;
}
.tbl.is-dark.has-trend td.cell-trend .spark { stroke: var(--paper); }


/* ---------- CAPABILITY flag — .has-expandable ----------
 * Per-row detail drawer. Parent row uses .row.is-expandable;
 * toggled-open state adds .is-open; sibling row holds the
 * drawer as .row-detail. The +/− indicator is ::before on
 * the parent's first cell. Drawer background uses the
 * .emboss-deboss inset-shadow vocabulary.
 *
 * State toggle (.is-open) requires ~5 lines of consumer JS,
 * or the CSS :checked hidden-input pattern if pure-CSS is
 * required. Brand ships the visual affordance only. */
.tbl.has-expandable .row.is-expandable td:first-child { cursor: pointer; }
.tbl.has-expandable .row.is-expandable td:first-child::before {
  content: "+";
  color: var(--ink-pale);
  margin-right: 10px;
  font-weight: 400;
  display: inline-block;
  width: 10px;
  transition: color var(--duration-fast) var(--ease-out);
}
.tbl.has-expandable .row.is-expandable.is-open td:first-child::before {
  content: "−";
  color: var(--red);
}
.tbl.has-expandable .row-detail td {
  background: var(--paper-deep);
  box-shadow: inset 0 2px 4px rgba(40,30,18,0.06);
  padding: 20px 0 22px;
  font-size: 12px;
  color: var(--ink-soft);
  line-height: 1.6;
  border-bottom: 1px solid var(--ink-faint);
}
.tbl.has-expandable .row-detail .detail-grid {
  display: grid;
  grid-template-columns: repeat(4, auto);
  gap: 8px 40px;
  font-family: var(--font-mono);
}
.tbl.has-expandable .row-detail .detail-grid dt {
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mid);
  margin: 0;
}
.tbl.has-expandable .row-detail .detail-grid dd {
  margin: 0;
  font-size: 12px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.tbl.has-expandable .row-detail .detail-prose {
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 0 0 14px;
  max-width: 72ch;
}


/* ---------- PRESET — .is-ledger ----------
 * Convention: expects columns date / description / symbol /
 * debit / credit / balance. Preset styles the balance column:
 * 1px --ink-faint left separator + 24px left padding +
 * weight 500 so the running balance reads as the spine. */
.tbl.is-ledger td.balance {
  font-weight: 500;
  border-left: 1px solid var(--ink-faint);
  padding-left: 24px;
}
.tbl.is-ledger th.balance-h {
  border-left: 1px solid var(--ink-faint);
  padding-left: 24px;
}


/* ---------- children — .cell-action / .reveal ----------
 * Trailing action cell. The .reveal child fades in on row
 * hover (opacity 0→1, color --ink-pale→--red). */
.tbl td.cell-action { width: 48px; text-align: right; }
.tbl td.cell-action .reveal {
  color: var(--ink-pale);
  opacity: 0;
  transition: opacity var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}
.tbl tbody tr:hover td.cell-action .reveal {
  opacity: 1;
  color: var(--red);
}


/* ---------- children — .pagination-bar ----------
 * Mono-caps pagination footer. Lives inside tfoot.pagination >
 * td (colspan=all) or standalone beneath the table. Disabled
 * Prev/Next match the .btn:disabled convention: --ink-pale
 * text + pointer-events: none. */
.tbl tfoot.pagination td {
  border-bottom: none;
  padding: 16px 0 0;
}
.tbl .pagination-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 0 0;
  margin-top: 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mid);
  border-top: 1px solid var(--ink-faint);
}
.tbl .pagination-bar .pages a {
  color: var(--ink);
  text-decoration: none;
  margin-left: 18px;
  transition: color var(--duration-fast) var(--ease-out);
}
.tbl .pagination-bar .pages a:hover { color: var(--red); }
.tbl .pagination-bar .pages a.is-disabled {
  color: var(--ink-pale);
  pointer-events: none;
}


/* ============================================================
 * BADGE — small inline severity/status tag.
 *
 * Standalone primitive. Used in table cells, log entries,
 * incident rows, and inline prose to mark status. Severity
 * encoded by INK WEIGHT, never by color. Matches /graphs +
 * .indicator .delta conventions: "never a second red, never
 * green or amber."
 *
 * Variants (surface stays identical — only border + text +
 * weight step):
 *   .badge       default — informational baseline
 *                (--ink-mid text + --ink-faint border, weight 500)
 *   .badge.is-low  quietest  (--ink-pale text + border)
 *   .badge.is-med  elevated  (--ink-mid text + --ink-mid border)
 *   .badge.is-high loudest   (--ink text + --ink border, weight 600)
 *
 * Font-variant-numeric reset to normal so a badge placed
 * inside a tabular-nums context (e.g. .tbl) renders its
 * label with normal spacing.
 *
 * See STYLE.md /components Badge for full spec.
 * ============================================================ */
.badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 2px;
  border: 1px solid var(--ink-faint);
  color: var(--ink-mid);
  font-variant-numeric: normal;
  line-height: 1.4;
}
.badge.is-low  { border-color: var(--ink-pale); color: var(--ink-pale); }
.badge.is-med  { border-color: var(--ink-mid);  color: var(--ink-mid); }
.badge.is-high { border-color: var(--ink);      color: var(--ink);      font-weight: 600; }


/* ============================================================
 * CHARTS — line + bar full-size data visualization.
 *
 * Single .chart recipe with three chart-type modifiers and
 * composable capability flags. Continuity with .indicator-trend
 * .spark — sparklines are charts that chose to be quiet.
 *
 * Chart-type modifiers (pick one):
 *   .is-line-single  — single-series line, .has-gridlines default OFF
 *   .is-line-multi   — multi-series line, end-point labels not legend
 *   .is-bar-grouped  — grouped bar, gridlines ON via markup
 *
 * Surface modifier:
 *   .is-dark         — paper stroke + rgba-paper axes on
 *                      coal/oxblood surfaces. Red end-dot stays red
 *                      (brand signal). rgba(241,236,224) encodes
 *                      alpha against --paper; CSS can't express
 *                      alpha-on-var(). Same precedent as .tbl.is-dark,
 *                      .indicator-trend.is-dark, .btn.is-dark.
 *
 * Capability flags (stack freely):
 *   .has-gridlines       — 1px --ink-faint horizontal rules
 *   .has-reference-line  — dashed --ink-pale horizontal reference
 *   .has-value-labels    — bar values above each bar (bar-grouped)
 *   .has-annotations     — pointer lines + mono labels at points
 *
 * Sizes: .is-sm / default / .is-lg — step max-width, stroke-width,
 * tick font-size, endpoint radius.
 *
 * Stroke vocabulary (continuity with sparkline):
 *   Sparkline: 1px    --ink polyline, filled --red endpoint r=2
 *   Chart:     1.25px --ink polyline, filled --red endpoint r=3.5
 *   .is-lg:    1.5px  --ink polyline, filled --red endpoint r=4
 *
 * Multi-series color tiers (NEVER color-code direction):
 *   Primary   --ink      1.25px solid
 *   Secondary --ink-soft 1px solid
 *   Tertiary  --ink-mid  1px dashed 3-2
 *   Red reserved for ONE end-dot on primary series only.
 *
 * Interactivity: add data-chart-interactive to the <svg> to opt in
 * to brand's charts.js helper (hover crosshair + tooltip + multi-
 * series dim-to-0.3). Brand ships the affordance only; consumer
 * owns the data. Same contract as .nav-masthead .is-hidden.
 *
 * See STYLE.md /graphs Line chart + Bar chart subsections for the
 * full spec.
 * ============================================================ */

/* ---------- base container ---------- */
.chart {
  display: block;
  width: 100%;
  max-width: 640px; /* default; .is-sm / .is-lg override */
}

/* ---------- shared SVG children ---------- */
.chart .axis-line  { stroke: var(--ink);       stroke-width: 1px; fill: none; }
.chart .axis-soft  { stroke: var(--ink-faint); stroke-width: 1px; fill: none; }
.chart .gridline   { stroke: var(--ink-faint); stroke-width: 1px; fill: none; }
.chart .reference-line {
  stroke: var(--ink-pale);
  stroke-width: 1px;
  stroke-dasharray: 4 3; /* literal — forecast/reference dash vocabulary */
  fill: none;
}
.chart .axis-tick {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  fill: var(--ink-mid);
  font-variant-numeric: tabular-nums;
}
.chart .axis-title {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  fill: var(--ink-mid);
  font-weight: 500;
}
.chart .end-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  fill: var(--ink-mid);
  font-variant-numeric: tabular-nums;
}
.chart .annotation-label {
  font-family: var(--font-mono);
  font-size: 9px;
  fill: var(--ink);
  font-variant-numeric: tabular-nums;
}
.chart .annotation-pointer { stroke: var(--ink-faint); stroke-width: 1px; fill: none; }

/* ---------- .is-line-single ---------- */
.chart.is-line-single polyline.series {
  stroke: var(--ink);
  stroke-width: 1.25px; /* literal — continuity with sparkline .is-lg */
  fill: none;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.chart.is-line-single circle.endpoint {
  fill: var(--red);
  stroke: none;
  r: 3.5; /* literal — full-chart endpoint, vs sparkline r=2 */
}
/* gridlines OFF by default — opt in via .has-gridlines + markup */

/* ---------- .is-line-multi ---------- */
.chart.is-line-multi polyline.series {
  fill: none;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.chart.is-line-multi polyline.series.is-primary {
  stroke: var(--ink);
  stroke-width: 1.25px;
}
.chart.is-line-multi polyline.series.is-secondary {
  stroke: var(--ink-soft);
  stroke-width: 1px;
}
.chart.is-line-multi polyline.series.is-tertiary {
  stroke: var(--ink-mid);
  stroke-width: 1px;
  stroke-dasharray: 3 2; /* literal — tertiary-series dash pattern,
                            distinct from forecast 4-3 and
                            reference-line 4-3 */
}
.chart.is-line-multi circle.endpoint {
  fill: var(--red); /* one red end-dot on primary series only */
  stroke: none;
  r: 3.5;
}

/* ---------- .is-bar-grouped ---------- */
.chart.is-bar-grouped rect.bar { stroke: none; }
.chart.is-bar-grouped rect.bar.is-primary   { fill: var(--red); }
.chart.is-bar-grouped rect.bar.is-secondary { fill: var(--ink-soft); }
.chart.is-bar-grouped rect.bar.is-tertiary  { fill: var(--ink-mid); }
/* gridlines ON by default for bar charts — include .gridline
   elements in markup. Bars need them for magnitude comparison. */

/* ---------- capability flags ---------- */
.chart.has-value-labels .value-label {
  font-family: var(--font-mono);
  font-size: 9px;
  fill: var(--ink);
  text-anchor: middle;
  font-variant-numeric: tabular-nums;
}

/* ---------- .is-dark (surface modifier) ---------- */
.chart.is-dark .axis-line      { stroke: rgba(241,236,224,0.6); }
.chart.is-dark .axis-soft      { stroke: rgba(241,236,224,0.3); }
.chart.is-dark .axis-tick      { fill:   rgba(241,236,224,0.7); }
.chart.is-dark .axis-title     { fill:   rgba(241,236,224,0.6); }
.chart.is-dark .gridline       { stroke: rgba(241,236,224,0.08); }
.chart.is-dark .reference-line { stroke: rgba(241,236,224,0.3); }
.chart.is-dark .end-label      { fill:   rgba(241,236,224,0.7); }
.chart.is-dark .annotation-label   { fill: var(--paper); }
.chart.is-dark .annotation-pointer { stroke: rgba(241,236,224,0.3); }

.chart.is-dark.is-line-single polyline.series { stroke: var(--paper); }
.chart.is-dark.is-line-multi polyline.series.is-primary   { stroke: var(--paper); }
.chart.is-dark.is-line-multi polyline.series.is-secondary { stroke: rgba(241,236,224,0.6); }
.chart.is-dark.is-line-multi polyline.series.is-tertiary  { stroke: rgba(241,236,224,0.4); }
.chart.is-dark circle.endpoint { fill: var(--red); /* red signal stays red on dark */ }
.chart.is-dark.is-bar-grouped rect.bar.is-secondary { fill: rgba(241,236,224,0.55); }
.chart.is-dark.is-bar-grouped rect.bar.is-tertiary  { fill: rgba(241,236,224,0.3); }
.chart.is-dark.has-value-labels .value-label { fill: var(--paper); }

/* ---------- sizes ---------- */
.chart.is-sm { max-width: 360px; }
.chart.is-sm .axis-tick,
.chart.is-sm .end-label { font-size: 8px; }
.chart.is-sm polyline.series { stroke-width: 1px; }
.chart.is-sm polyline.series.is-primary { stroke-width: 1.25px; }
.chart.is-sm circle.endpoint { r: 3; }

.chart.is-lg { max-width: 960px; }
.chart.is-lg .axis-tick,
.chart.is-lg .end-label { font-size: 10px; }
.chart.is-lg .axis-title { font-size: 11px; }
.chart.is-lg polyline.series { stroke-width: 1.25px; }
.chart.is-lg polyline.series.is-primary { stroke-width: 1.5px; }
.chart.is-lg circle.endpoint { r: 4; }

/* ---------- interactivity (charts.js) ----------
 * Styling for the crosshair line and tooltip element injected
 * by brand/dist/charts.js. Consumer loads charts.js via
 *   <script src=".../brand/dist/charts.js" defer></script>
 * and opts in per-chart with
 *   <svg class="chart ..." data-chart-interactive>
 * See STYLE.md /graphs Interactivity for the full JS contract. */
.chart-crosshair {
  stroke: var(--ink-faint);
  stroke-width: 1px;
  stroke-dasharray: 4 3;
  pointer-events: none;
}
.chart-tooltip {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--ink-faint);
  border-radius: 2px;
  padding: 6px 10px; /* literal — mono-tight padding matching .badge rhythm */
  white-space: nowrap;
  z-index: 10;
  font-variant-numeric: tabular-nums;
}
/* Dark-surface tooltip: when an interactive chart is nested
   inside a .card-coal / .card-oxblood, the tooltip reads as a
   paper pill lifted off the dark surface. Parent selector keeps
   the tooltip's own paper bg (it's a callout, not a background
   flip) and adjusts only the shadow. */
.card-coal .chart-tooltip,
.card-oxblood .chart-tooltip {
  box-shadow: 0 2px 6px rgba(40,30,18,0.28);
}
