/* ============================================================
   app.css — Loss of Control · Threat-Model view template
   Clean-room rebuild from Figma "00 Template" (node 115:3363).
   One source of truth for the 5 views under "Loss of Control
   Threat Model". Page chrome is injected by app.js; pages only
   provide eyebrow + headline + the diagram stage.
   ============================================================ */

/* @font-face for "PP" now lives once in components.css (linked first everywhere). */

/* ── Layout tokens specific to the view template ──────────────
   Colour / radius / motion tokens are canonical in components.css. */
:root {
  --red:        #cc3333;   /* diagram accent (diagrams own their own colours) */
  --footer-h:   76px;      /* footer bar height — drives canvas stage inset + control offsets */
  --toc-w:      300px;
  --gutter:     48px;
  --rail-gap:   62px;      /* left-margin = gutter + toc + gap = 410 → content is viewport-centred */
  /* left edge of the centred 1100 header container → eyebrow aligns under the
     logo at every width (= 410 at 1920, the Figma value) */
  --content-left: max(40px, calc(50vw - 550px));
}

/* ── Reset / base ─────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html {
  background-color: var(--surface-page);
  /* Repeatable 16×16 SVG tile: 1px #9C9E9D dot on #F3F5F4 (Figma 115:3568). */
  background-image: url("figures/dot-grid.svg");
  background-repeat: repeat;
  background-size: 16px 16px;
  background-position: 0 -3px;   /* nudge the grid up so the first dot row isn't flush against the fixed header */
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Always reserve the scrollbar gutter so the fixed TOC sits at the same x on
     every page (no 15px jump between scrolling and non-scrolling pages). */
  scrollbar-gutter: stable;
}
/* Mobile: no reserved gutter (overlay scrollbars → it's just an empty strip on
   the right), and clip any horizontal overflow from the desktop-sized diagrams. */
@media (max-width: 768px) {
  html { scrollbar-gutter: auto; overflow-x: hidden; }
}
/* Canvas (diagram) pages ALSO reserve the gutter. It was dropped here to avoid an empty
   strip, but that made the fixed header 15px wider than on scrolling report pages, so the
   navbar jumped ~7.5px when moving between them. Reserving everywhere keeps the header the
   same width on every page → no UI shift (the user's priority). The reserved gutter shows
   the page's own dot-grid, seamless below the header; the bare 15px beside the header is
   browser-chrome space DOM content can't paint into, so it's left as-is (near-invisible
   dot-grid sliver). */
html:has(body.app-mode-canvas) { scrollbar-gutter: stable; }
body {
  margin: 0;
  padding-top: var(--header-h);
  position: relative;          /* positioning context for the .app-head overlay */
  min-height: 100vh;
  min-height: 100dvh;          /* dvh excludes the mobile URL bar so full-bleed canvas pages don't leave a gap / push controls under it */
  font-family: "PP", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
/* canvas pages don't scroll — the stage is fixed full-bleed */
body.app-mode-canvas { overflow: hidden; }
/* Pages 1–4 (canvas) have no footer, so the stage + bottom controls reclaim
   that space — everything keyed off --footer-h collapses to the bottom edge. */
body.app-mode-canvas { --footer-h: 0px; }
/* doc pages: flex column so the footer sticks to the bottom even when the
   content is short (fixed/absolute chrome stays out of the flex flow). */
body.app-mode-doc { display: flex; flex-direction: column; }
img { display: block; max-width: 100%; }
a { color: inherit; }

/* Header markup + look are shared — see .app-header in components.css. */

/* ============================================================
   Layout — content column + sticky right TOC rail
   left-margin (410) = gutter (48) + toc (300) + gap (62), so the
   content column is centred on the viewport at the Figma width.
   ============================================================ */
/* Every chrome element below is INJECTED by app.js and positioned here.
   Pages only supply their diagram/content. Two modes on <body>:
   .app-mode-canvas (full-bleed diagram, fixed controls, no footer) and
   .app-mode-doc (scrolling article/map + footer). */

/* ── Eyebrow + headline — absolute overlay, IDENTICAL on every page ── */
.app-head {
  /* Flush to the left edge and to the very top of the canvas (right below the
     fixed header — no gap). The 24/32px padding keeps the text off the edges. */
  position: absolute; top: var(--header-h); left: 0;
  width: 420px; max-width: calc(100vw - var(--gutter));
  z-index: 25;
  /* Transparent on every diagram (canvas) page so the diagram keeps the real estate
     the old solid block ate; only the headline carries a box (below).
     pointer-events:none lets the diagram pan/click THROUGH the title area.
     Padding/gap from Figma 73:4950 (pt-32 / pb-24 / px-32, gap-8). */
  background: transparent; padding: 32px 32px 24px; pointer-events: none;
  display: flex; flex-direction: column; gap: 8px;
}
/* type from shared .eyebrow (components.css); keep margin/line-height/colour.
   Figma 73:4950: the eyebrow is NOT boxed — just an 8px inset so its text lines up
   with the headline text inside its box (box padding 8px). */
.app-eyebrow {
  margin: 0; line-height: 1.29; color: var(--ink-muted); padding-left: 8px;
}
.app-headline {
  margin: 0; font-size: 22px; font-weight: 400; line-height: 1.3; letter-spacing: 0;
  color: var(--ink);
}
/* Title-headline box (Figma 73:4950): per-line rounded page-grey backgrounds that hug
   each line's text (box-decoration-break: clone) — ragged right edge, no trailing grey.
   The headline's 1.3 line-height lets the line-boxes overlap slightly so they read as one
   connected shape. bg #f3f5f4 (=--surface-page), 12px radius, no shadow. The eyebrow's
   own chip span stays unstyled (no box). */
.app-eyebrow .app-head-chip { display: inline; }
.app-headline .app-head-chip {
  display: inline;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
  background: var(--surface-page); border-radius: 12px; padding: 4px 10px;
}
/* Lede under the headline (Intro only · Figma 143:1785). Body type + inline
   highlight chips on the two load-bearing phrases. */
.app-lede {
  margin: 24px 0 0; font-size: 16px; font-weight: 400; line-height: 1.65;  /* doubled the headline→lede gap (was 4px ⇒ ~20px visual; now ~40px) */
  letter-spacing: 0.4px; color: var(--ink-body);
}
.app-lede strong { font-weight: 500; color: var(--ink); }   /* bold emphasis in a lede */
.app-lede mark {
  /* Figma highlight: coral text on a soft pink chip, rounded, no clipping at wraps */
  background: #ffe4de; color: #c33; border-radius: 4px; padding: 2px 6px;
  white-space: nowrap; box-decoration-break: clone; -webkit-box-decoration-break: clone;
}

/* ── TOC — fixed right rail, IDENTICAL on every page ──────── */
.app-toc {
  /* Flush to the right edge and to the very top of the canvas (no gap below the
     header). The 24px padding keeps the list off the edges. */
  position: fixed; top: var(--header-h); right: 0;
  width: var(--toc-w); z-index: 40;
  background: var(--surface-page); padding: 24px;
  /* Round the only free corner (top sits under the header, right is flush to the
     screen edge). 20px matches the legend's rounding. */
  border-bottom-left-radius: 20px;
}
.app-toc-list { display: flex; flex-direction: column; gap: 24px; border-left: 1px solid rgba(0,0,0,0.10); }
.app-toc-item {
  display: block; text-decoration: none; color: inherit;
  border-left: 2px solid transparent; margin-left: -1px; padding: 4px 0 4px 16px;
  transition: border-color .18s var(--ease-out), color .18s var(--ease-out);
}
.app-toc-row { display: flex; gap: 6px; align-items: baseline; }
.app-toc-n, .app-toc-t { font-size: 14px; font-weight: 400; line-height: 1.3; letter-spacing: 0.01em; color: var(--ink-2); }
.app-toc-n { flex: 0 0 auto; }
.app-toc-s { margin: 4px 0 0 21px; font-size: 12px; font-weight: 400; line-height: 1.4; letter-spacing: 0.02em; color: var(--ink-muted); }
.app-toc-item:hover .app-toc-n, .app-toc-item:hover .app-toc-t { color: var(--ink); }
.app-toc-item.is-active { border-left-color: var(--ink); cursor: default; }
.app-toc-item.is-active .app-toc-n, .app-toc-item.is-active .app-toc-t { color: var(--ink); font-weight: 500; }

/* ── Controls (Replay / Prev / Next) ──────────────────────── */
.app-controls { display: flex; align-items: center; gap: 12px; z-index: 30; }
.app-controls > * { pointer-events: auto; }
.app-pill {
  display: inline-flex; align-items: center; gap: 6px; padding: 9px 18px;
  border-radius: var(--r-pill); font-family: inherit; font-size: 12.5px; font-weight: 500;
  letter-spacing: 0.02em; text-decoration: none; cursor: pointer; white-space: nowrap;
  /* transparent border in the base state so the hover border can appear without
     shifting layout */
  border: 0.5px solid transparent;
  box-shadow: var(--shadow-pill);
  transition: transform .16s var(--ease-out), background .18s var(--ease-out), border-color .16s var(--ease-out);
}
.app-pill:active { transform: scale(0.97); }
.app-pill--ghost { background: var(--surface-white); color: var(--ink); border-color: rgba(170,170,170,0.3); }
.app-pill--ghost:hover { background: var(--surface-bg); border-color: rgba(120,120,120,0.55); }
.app-pill--dark { background: var(--ink); color: var(--ink-inverse); border-color: transparent; }
.app-pill--dark:hover { background: #000; border-color: rgba(255,255,255,0.28); }
/* Prev/Next are equal width and the same 36px height as the zoom pill, so the
   bottom row (controls centred + zoom right) lines up. */
.app-controls .app-pill { min-width: 110px; height: 36px; justify-content: center; }

/* ── Zoom pill (pages 2,3,4) — grey pill, bottom-right (Figma 89:3083) ── */
/* ── Zoom pill — ONE shared look for every diagram route (grey pill, 36px white
   ± buttons, PP label, hover + press feedback). The three pages that carry a zoom
   pill — visual summary (.app-zoom), detail (.map-controls), standard
   (#mtm-zoom-pill) — share this look and keep ONLY their own position: .app-zoom
   below, .map-controls in threat-map.css, #mtm-zoom-pill in that page. ──────── */
.app-zoom, .map-controls, #mtm-zoom-pill {
  display: flex; align-items: center; height: 36px; padding: 0; z-index: 45;
  background: var(--ink-faint); border: 0; border-radius: var(--r-pill);
  user-select: none; -webkit-user-select: none;
  box-shadow: var(--shadow-pill);
}
.app-zoom button, .map-ctrl-btn, .mtm-zpbtn {
  width: 36px; height: 36px; padding: 0; border: 0; background: transparent; cursor: pointer;
  color: #fff; font: 400 20px Arial, sans-serif; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  transition: background .12s var(--ease-out), transform .12s var(--ease-out);
}
.app-zoom button:hover, .map-ctrl-btn:hover, .mtm-zpbtn:hover { background: rgba(255,255,255,0.12); }
.app-zoom button:active, .map-ctrl-btn:active, .mtm-zpbtn:active { transform: scale(0.96); }
/* Zoom % label — ONE typography for every diagram route (detail .zoom-label,
   visual .app-zoom-label, standard #mtm-zoom-label), matching the Previous/Next
   pill label (12.5px / 500 / 0.02em) so every button label is consistent. */
.app-zoom-label, .zoom-label, #mtm-zoom-label {
  min-width: 40px; text-align: center; color: #fff;
  font-family: "PP", -apple-system, sans-serif; font-size: 12.5px; font-weight: 500; letter-spacing: 0.02em;
  /* Double-click resets the view (handlers per page). Needs pointer-events to
     receive the dblclick directly — only the label resets, NOT the +/− buttons.
     user-select:none so the double-click doesn't highlight the % text. */
  pointer-events: auto; cursor: pointer; user-select: none; -webkit-user-select: none;
}

/* Visual-summary zoom pill — position only (look shared above). */
.app-zoom { position: fixed; bottom: calc(var(--footer-h) + 20px); right: 24px; }

/* The zoom controls are pointer-oriented; on touch/mobile layouts pinch-zoom
   covers it, so hide the pill (visual summary, detail, standard). */
@media (max-width: 768px) {
  .app-zoom, .map-controls, #mtm-zoom-pill { display: none; }
}

/* ── Map legend (shared) ──────────────────────────────────────
   ONE legend component for both diagram routes that carry one: the detail map
   and the standard view. Both pages drop the same `.map-legend / .legend__*`
   markup (different content) + an inline toggle script; this is the single CSS
   source. Bottom-LEFT, collapsed to a ghost pill (like the Previous button),
   opening UPWARD via column-reverse so the "Legend" label stays put. */
.map-legend {
  position: absolute; bottom: 24px; left: 24px;
  z-index: 7;
  display: flex; flex-direction: column-reverse;
  width: 280px;
  max-height: calc(100% - 104px); overflow-y: auto;
  padding: 12px 14px;
  font-family: "PP", -apple-system, sans-serif;
  background: rgba(255,255,255,0.92);
  backdrop-filter: blur(8px);
  border: 0.5px solid rgba(170,170,170,0.3);
  /* Match the collapsed pill's corner radius (a ~39px-tall capsule ≈ 19.5px)
     so the bottom bar's corners don't jump between the open and closed states. */
  border-radius: 20px;
  box-shadow: var(--shadow-pill);
  transition: border-color .16s var(--ease-out), background .18s var(--ease-out);
}
.legend__topbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.legend__topbar .legend__head { margin-bottom: 0; }
/* Expanded: small gap between the revealed body (above) and the pill (below).
   The whole bottom bar is the click target to collapse (not just the chevron). */
.map-legend:not(.is-collapsed) .legend__topbar { margin-top: 10px; cursor: pointer; }

/* Collapsed = a ghost pill that matches .app-pill--ghost (the Previous btn):
   solid white (not the frosted fill the open panel uses), same border/shadow,
   so the bottom row reads as one consistent button set. */
.map-legend.is-collapsed {
  width: auto; overflow: visible; cursor: pointer;
  border-radius: var(--r-pill); padding: 8px 16px;
  background: var(--surface-white); backdrop-filter: none;
}
.map-legend.is-collapsed:hover { background: var(--surface-bg); border-color: rgba(120,120,120,0.55); }
/* Open: sit above the Prev/Next controls (z 30) so the panel cleanly overlays
   them instead of the buttons bleeding through it. */
.map-legend:not(.is-collapsed) { z-index: 31; }

.legend__toggle {
  background: transparent; border: none; cursor: pointer;
  width: 20px; height: 20px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-3); border-radius: 4px;
  transition: background 0.12s var(--ease-out), color 0.12s var(--ease-out), transform 0.12s var(--ease-out);
}
.legend__toggle svg { width: 12px; height: 12px; display: block; }
.legend__toggle:hover { background: rgba(0,0,0,0.05); color: #333; }
.legend__toggle:active { transform: scale(0.92); }

/* The body fades + slides IN on open (@starting-style supplies the from-state).
   Close is INSTANT (display:none) on purpose: animating the close kept the body in
   layout for 0.2s while the container already had the round pill radius + width:auto,
   which flashed a big rounded blob for a frame (see Alex's bug report). */
.legend__body {
  opacity: 1; transform: translateY(0); transform-origin: bottom left;
  transition: opacity 0.2s var(--ease-out), transform 0.2s var(--ease-out);
}
.map-legend.is-collapsed .legend__body {
  display: none; opacity: 0; transform: translateY(8px);
}
@starting-style {
  .map-legend:not(.is-collapsed) .legend__body { opacity: 0; transform: translateY(8px); }
}
.legend__row {
  display: flex; align-items: center; gap: 10px;
  font-size: 11.5px; font-weight: 400; color: var(--ink-muted); margin-bottom: 9px;
}
.legend__row:last-child { margin-bottom: 0; }
/* Card-type rows are clickable: each opens the results drawer listing every node
   of that type. Reset the <button> chrome and add a quiet hover/press affordance
   that reads as a row, not a button. The negative margin + matching padding let
   the hover fill bleed to the panel edges without shifting the text. */
.legend__row--cat {
  appearance: none; -webkit-appearance: none; font: inherit; text-align: left;
  background: transparent; border: 0; cursor: pointer; width: calc(100% + 12px);
  margin-left: -6px; margin-right: -6px; padding: 5px 6px; border-radius: 8px;
  transition: background 0.14s var(--ease-out);
}
.legend__row--cat:hover { background: rgba(0,0,0,0.045); }
.legend__row--cat:active { background: rgba(0,0,0,0.07); }
.legend__row--cat:focus-visible { outline: 2px solid var(--mint-deep); outline-offset: 1px; }
.legend__text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.legend__title { font-size: 12.5px; font-weight: 500; color: var(--ink); line-height: 1.25; }
.legend__sub   { font-size: 12.5px; font-weight: 500; color: var(--ink-3); line-height: 1.3; }
/* The "Legend" label is identical open + closed — the collapsed pill is the
   reference (12.5px / 500 / #1a1a1a / 0.02em), matching the Previous/Next pills. */
.legend__head {
  font-size: 12.5px; font-weight: 500; letter-spacing: 0.02em; color: var(--ink); margin-bottom: 9px;
}
.legend__head + .legend__head { margin-top: 10px; }
/* Section sub-heads ("Card types" / "Connection types") keep the small all-caps
   tracked style so they read distinctly from the "Legend" title. */
.legend__section-head { /* type from shared .eyebrow--sm */
  color: var(--ink-2); margin-bottom: 9px;
}
/* On phones the legend sits just above the bottom controls row. */
/* Mobile: Legend shares the bottom row with Prev/Next (right-aligned), so it
   sits at the same baseline bottom-left instead of floating mid-air above them. */
@media (max-width: 600px) { .map-legend { bottom: calc(14px + env(safe-area-inset-bottom)); left: 12px; } }

/* ── Canvas mode — full-bleed diagram (Overview, Visual Summary, Standard) ── */
/* absolute (not fixed) so it does NOT create a stacking context — lets the
   detail sidebar (z 70) layer above the TOC (z 40). Body is overflow:hidden on
   canvas pages, so absolute is visually identical to fixed. */
.app-mode-canvas .app-stage { position: absolute; inset: var(--header-h) 0 var(--footer-h) 0; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.app-mode-canvas .app-stage > svg { display: block; width: 100%; max-width: 1080px; height: auto; }
.app-mode-canvas .app-controls { position: fixed; left: 0; right: 0; bottom: calc(var(--footer-h) + 20px); justify-content: center; pointer-events: none; }

/* ── Doc mode — scrolling page + footer (Detail, Intro) ───── */
.app-mode-doc .app-doc {
  margin-left: var(--content-left);
  margin-right: calc(var(--toc-w) + var(--gutter) + var(--rail-gap));
  padding-top: 32px;      /* box sits at y96, level with the TOC */
  padding-bottom: 48px;
}
.app-mode-doc .app-controls { margin: 0 0 64px var(--content-left); justify-content: flex-start; }

/* ── Content box (Intro/page 5) — opaque fill masks the dotted grid so the
   text reads cleanly (Figma 89:3090). Carries its own 32px title. ── */
.app-box {
  max-width: 700px;
  background: var(--surface-page);
  padding: 24px 32px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 24px;
}
.app-box-head { display: flex; flex-direction: column; align-items: flex-start; gap: 16px; }
.app-box-eyebrow { margin: 0; line-height: 1.29; color: #8d7acc; } /* type from shared .eyebrow */
.app-title { margin: 0; font-size: 32px; font-weight: 400; line-height: 1.2; letter-spacing: 0; color: var(--ink); }
.app-box > p { margin: 0; font-size: 16px; font-weight: 400; line-height: 1.65; letter-spacing: 0.025em; color: var(--ink-body); }
.app-box-actions { display: flex; gap: 12px; align-items: center; }
.app-box-actions .app-pill { padding: 9px 18px; }

/* ============================================================
   Footer — positioning only (look lives in components.css).
   ------------------------------------------------------------
   Canvas pages: fixed at the viewport bottom, z below the
   detail/search panel (70) so a sliding panel covers it cleanly.
   Doc pages: rides the normal flow and sticks to the bottom (body
   is a min-height:100vh flex column).
   ============================================================ */
.app-mode-canvas .app-footer { position: fixed; left: 0; right: 0; bottom: 0; z-index: 46; }
.app-mode-doc .app-footer { position: static; margin-top: auto; }

/* ============================================================
   Responsive
   ============================================================ */
/* Contents toggle — hidden on desktop (the rail shows instead). */
.app-toc-toggle { display: none; }

@media (max-width: 1080px) {
  /* TOC rail → collapsible "Contents" menu, top-right below the header, so the
     section nav stays reachable instead of disappearing. */
  .app-toc {
    top: var(--header-h); right: 0; width: auto; padding: 24px 12px 12px;   /* 24px top → Contents toggle sits 24px below the header, matching the search bar */
    background: transparent; z-index: 50; display: flex; justify-content: flex-end;
  }
  .app-toc-toggle {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 16px; border-radius: var(--r-pill);
    background: var(--surface-white); border: 0.5px solid rgba(170,170,170,0.3); color: var(--ink);
    font: 500 12.5px/1 "PP", -apple-system, sans-serif; letter-spacing: 0.02em; cursor: pointer;
    box-shadow: var(--shadow-pill);
  }
  .app-toc-caret { width: 12px; height: 12px; transition: transform .18s var(--ease-out); }
  .app-toc.is-open .app-toc-caret { transform: rotate(180deg); }
  .app-toc-list {
    display: none; position: absolute; top: calc(100% - 2px); right: 12px;
    flex-direction: column; gap: 18px;
    background: var(--surface-white); border: 0.5px solid rgba(170,170,170,0.3); border-radius: 16px;
    box-shadow: 0 12px 28px rgba(16,24,40,0.16);
    padding: 18px 20px; min-width: 248px; max-width: calc(100vw - 24px);
    max-height: 72vh; overflow-y: auto;
  }
  .app-toc.is-open .app-toc-list { display: flex; }
  .app-head { max-width: calc(100vw - 150px); }   /* leave room for the Contents toggle */
  .app-mode-doc .app-doc { margin-left: var(--gutter); margin-right: var(--gutter); }
}
@media (max-width: 560px) {
  .app-header-inner { padding: 0 20px; }
  /* nav layout + Download PDF are handled by the mobile hamburger sheet
     (components.css); don't hide the PDF or re-gap the nav here. */
  .app-head { width: 100%; }
  .app-headline { font-size: 17px; }
  /* Doc pages (Intro): the 48px desktop gutters waste most of a phone's width.
     Pull the box near the edges and trim its inner padding so the text fills
     the column instead of sitting in a narrow strip. */
  .app-mode-doc .app-doc { margin-left: 16px; margin-right: 16px; }
  .app-box { padding: 24px 20px; }
  /* If the two action pills don't fit on one row, wrap them as whole pills
     (each label stays on one line — see .app-pill white-space: nowrap). */
  .app-box-actions { flex-wrap: wrap; }
}

/* ── Mobile diagram fallback (basic) ───────────────────────────
   The diagram canvases are desktop-oriented; on phones we keep them pannable
   but stop the bottom controls from overlapping and flag that full exploration
   is a desktop experience. (Map-specific control repositioning lives in
   threat-map.css.) */
.app-head-mobile-note { display: none; }
@media (max-width: 600px) {
  /* Prev/Next sit on the bottom row, right-aligned, leaving the bottom-left for
     the Legend pill (zoom pill is hidden on mobile) — one clean toolbar row.
     Specificity must match .app-mode-canvas .app-controls to win in-cascade. */
  /* +safe-area so the bottom toolbar clears the iOS home indicator / notch insets. */
  .app-mode-canvas .app-controls { bottom: calc(14px + env(safe-area-inset-bottom)); gap: 8px; justify-content: flex-end; padding-right: 12px; }
  .app-controls .app-pill { min-width: 84px; height: 34px; padding: 8px 12px; font-size: 12px; }
  .app-head-mobile-note {
    display: block; margin-top: 8px;
    font-size: 11.5px; font-weight: 500; letter-spacing: 0.01em; color: var(--ink-muted);
  }
}

/* ============================================================
   Reduced motion — see components.css (shared across all pages).
   ============================================================ */
