/* ============================================================
   scryops — Telemetry design system
   Single CSS file: tokens + base + components.
   Load once in the <head>. Dark is default; add class="light"
   on <html> to switch. All components read from the tokens —
   never hard-code a hex below this block.
   ============================================================ */

:root {
  /* ---- color · dark (default) — Telemetry, warm/de-neon (DS Jul-2026) ---- */
  --bg:#141210;             /* warm charcoal — softened near-black (body still ~12.6:1) */
  --surface:#1C1915;        /* card elevation above the page */
  --border:#2B2620;
  --heading:#ECE6D9;
  --text:#D7D0C4;
  --muted:#9B9382;
  --green:#66C892;          /* healthy / values / INFO / brand / CTA (de-neoned) */
  --cyan:#E4DDCE;           /* identifiers / links / edges — warm ink, not a hue */
  --link:#E4DDCE;
  --warn:#C9AE6B;
  --danger:#D98E80;         /* muted terracotta — reads as error, not alarm */
  --violet:#A79E8C;         /* OpenTelemetry topic accent — warm mid ink */

  /* party-gallery.html fixed per-character identity accents (flavor, not
     data — pref-mono already forces .party-card/.party-name/.party-ph-cls
     to neutral ink regardless of these, see the pref-mono block below) */
  --party-monk:#4FD1C5;
  --party-paladin:#F5C542;
  --party-sorcerer:#E55DC8;
  --party-warlock:#8B6CEF;
  --party-artificer:#D98A2B;

  /* obs-mascot.html fixed per-class identity accents — same pattern as
     the party-gallery tokens above (flavor, not data) */
  --mascot-noob:#A99E88;
  --mascot-warrior:#D98166;
  --mascot-wizard:#8FA8C4;
  --mascot-rogue:#7FB37E;
  --mascot-bard:#B0A2D8;
  --mascot-cleric:#D8B85C;
  --mascot-ranger:#6FB39A;
  --mascot-oracle:#A78FE0;
  --mascot-barbarian:#D2894F;

  /* inline code chip */
  --ic-bg:#1E1A14; --ic-text:#E4DDCE; --ic-bd:#241F18;

  /* code well — STAYS DARK in all three themes */
  --code-bg:#100E0B; --code-text:#CEC8BC; --code-bd:#8E8574;
  /* --code-bd is the well's OUTER boundary (needs 3:1, WCAG 1.4.11) — the
     previous #201C16 measured ~1.10:1 against --bg, a silent failure; this
     value (== --mc-ramp-3) clears ~5.1:1. Internal row dividers must stay
     subtle (~1.3:1) — pointing one at --code-bd puts a 5.3:1 hairline under
     every row and the terminal reads as a ruled table. Use --code-rule for
     any internal divider instead. */
  --code-rule:#2A251E;
  /* readout constants — used ON the always-dark code/terminal wells,
     so they must NOT flip with theme (light/calm leave these alone). Anything
     drawn on the well must use these, never --green/--cyan/--warn/--danger:
     those invert with the theme and vanish against the dark surface. */
  --code-hi:#ECE6D9; --code-muted:#8E877A; --code-green:#66C892; --code-cyan:#E4DDCE;
  --code-warn:#C9AE6B; --code-danger:#D98E80; --code-violet:#A79E8C; --code-eco:#8AA97C;
  /* permacomputing — resource-awareness accent (page level; the well uses --code-eco) */
  --eco:#8AA97C; --eco-bright:#A9C79B;

  /* figures */
  --fig-bg:#17130E;
  --fig-grid:linear-gradient(rgba(155,147,130,.06) 1px,transparent 1px),
             linear-gradient(90deg,rgba(155,147,130,.06) 1px,transparent 1px);
  --fig-bd:#2B2620;
  --node-fill:#16120C; --node-stroke:var(--muted); --edge:var(--cyan); --nlab:var(--heading);

  /* callouts — mapped to log levels INFO / WARN / ERROR.
     DERIVED from the semantic accents (not hard-coded), so they follow every
     theme and the monochrome mode automatically. One source of truth. */
  --info-bg:color-mix(in srgb,var(--green) 8%,transparent); --info-bd:var(--green); --info-lb:var(--green);
  --warn-bg:color-mix(in srgb,var(--warn) 10%,transparent); --warn-bd:var(--warn); --warn-lb:var(--warn);
  --dgr-bg:color-mix(in srgb,var(--danger) 10%,transparent); --dgr-bd:var(--danger); --dgr-lb:var(--danger);

  /* tables */
  --th:#211D17; --tborder:#221E18;

  /* ---- type — proportional reading face, monospace chrome ----
     Reading face is the proportional Atkinson Hyperlegible (already loaded);
     Space Mono headings + IBM Plex Mono code/labels keep the terminal voice.
     Courier Prime is retained as an opt-in typewriter face (--font-typewriter). */
  --font-display:'Space Mono', ui-monospace, monospace;
  --font-read:'Atkinson Hyperlegible', system-ui, sans-serif;
  --font-code:'IBM Plex Mono', ui-monospace, monospace;
  /* Pixel voice, split in two: 'scry' is dot-matrix Doto (scrying — discrete
     points you infer across), 'ops' is solid Pixelify Sans (built practice).
     --font-pixel aliases the ops face — it's denser, so it holds at label
     sizes, and it's the workhorse for every pixel label besides the
     wordmark's first half. Press Start 2P is retained only so pages that
     still name it directly keep rendering; new pixel-voice work uses
     --font-pixel-scry / --font-pixel-ops. Both fall back to the same
     monospace stack so a missing file degrades to one uniform word rather
     than splitting the name across two different fallbacks. */
  --font-pixel-scry:'Doto', ui-monospace, monospace;
  --font-pixel-ops:'Pixelify Sans', ui-monospace, monospace;
  --fw-pixel-scry:900;
  --fw-pixel-ops:700;
  --font-pixel:var(--font-pixel-ops);
  --font-typewriter:'Courier Prime', ui-monospace, monospace;
  --font-body:var(--font-read);

  --fs-display:34px; --fs-h1:29px; --fs-h2:20px; --fs-h3:16px;
  --fs-lede:17.5px;  --fs-body:16px; --fs-code:13.5px;   /* body ≥16px per GUIDELINES non-negotiable #3 */
  --fs-label:11px;   --fs-pixel:11px;
  --lh-body:1.75;    --lh-lede:1.72;   --lh-code:1.75;
  --read-track:0;   /* proportional reading face wants no extra tracking (loosens in .pref-spacing) */
  --measure:70ch;

  /* ---- spacing — 4px base ---- */
  --sp-1:4px; --sp-2:8px; --sp-3:14px; --sp-4:22px; --sp-5:32px; --sp-6:52px;

  /* ---- form ---- */
  --radius:6px; --radius-sm:4px; --radius-retro:3px; --radius-pill:999px; --space:8px; --hair:1px;

  /* ---- bridge: repo's evolved (warm-paper) token names → Telemetry ----
     The repo's components were authored against an earlier vocabulary.
     Aliasing those names onto the Telemetry tokens re-skins every existing
     component to the dark-default palette with no per-component edits.
     var() resolves per-theme, so these follow light/calm automatically. */
  --line:var(--border);
  --head:var(--heading);
  --accent:var(--green);            /* brand / wordmark / CTAs → terminal green */
  --accent-hover:var(--cyan);
  --accent-press:var(--green);
  --on-accent:var(--bg);            /* text on an accent fill = page bg */
  --ok:var(--green);
  --pending:var(--warn);
  --alert:var(--danger);
  --info:var(--cyan);
  --num-idle:var(--muted);
  --ac:var(--green);                /* party-gallery card accent */
  --amber:var(--warn);              /* 404 page */
  --amber-deep:var(--warn); --gold:var(--warn);
  --klein:var(--cyan); --klein-mid:var(--cyan); --klein-glow:var(--cyan);
  --font-mono:var(--font-code); --font-sans:var(--font-read);
}

html.light {
  --bg:#F6F3EC;
  --surface:#FFFDF7;
  --border:#E6DFD2;
  --heading:#1E1811;
  --text:#2C261E;
  --muted:#6F6556;
  --green:#157A45;
  --cyan:#1E1811;           /* identifiers / links / hover — ink, not a hue */
  --link:#1E1811;           /* darker than body text, plus the underline */
  --warn:#7A6220;
  --danger:#A8483C;
  --violet:#5E5648;

  /* darkened to clear 4.5:1 as text against the cream surface — the dark
     hues at the top of this file read fine on charcoal but fail on cream */
  --party-monk:#22827A;
  --party-paladin:#956F08;
  --party-sorcerer:#D222AD;
  --party-warlock:#7D5AED;
  --party-artificer:#A5671E;

  /* same reasoning as the party-gallery light overrides above */
  --mascot-noob:#80745D;
  --mascot-warrior:#C25330;
  --mascot-wizard:#5578A1;
  --mascot-rogue:#4D814C;
  --mascot-bard:#7E67BF;
  --mascot-cleric:#8E7222;
  --mascot-ranger:#44806A;
  --mascot-oracle:#8260D3;
  --mascot-barbarian:#AA642C;

  --ic-bg:#EDE7DB; --ic-text:#1E1811; --ic-bd:#DED6C7;

  /* code well intentionally NOT overridden — stays dark */

  /* Callout LABELS are nudged toward the heading ink here (rails are left
     on the pure accent). On cream, the accents land at 4.39–4.60:1 against
     the tinted well — under or barely at the 4.5:1 text threshold, since an
     11px/600 label is normal-size text, not large. The rail is a non-text
     UI component (3:1) and already clears ~4.9–5.3:1, so only the text
     moves and the severity hues stay intact. */
  --info-lb:color-mix(in srgb,var(--green) 80%,var(--heading));
  --warn-lb:color-mix(in srgb,var(--warn) 88%,var(--heading));
  --dgr-lb:color-mix(in srgb,var(--danger) 80%,var(--heading));

  --fig-bg:#FFFDF7;
  --fig-grid:linear-gradient(#EDE7DB 1px,transparent 1px),
             linear-gradient(90deg,#EDE7DB 1px,transparent 1px);
  --fig-bd:#E6DFD2;
  --node-fill:#F0EBE0;
  /* node-stroke / edge / nlab and all callout -bg/-bd tokens are derived in :root */

  --th:#EFEAE0; --tborder:#E6DFD2;
}

html.calm {
  --bg:#17140E;
  --surface:#1F1B13;
  --border:#332C20;
  --heading:#F2EAD8;
  --text:#E6DECE;
  --muted:#AA9D84;
  --green:#8FB386;
  --cyan:#EFE7D6;           /* identifiers / links / hover — bright warm ink */
  --link:#EFE7D6;
  --warn:#C9AE7B;
  --danger:#DE9384;
  --violet:#B0A48C;

  /* same as dark, except warlock nudged brighter — the original hue sits
     at 4.48:1 against calm's slightly-lighter card surface, just under
     the 4.5:1 text floor */
  --party-monk:#4FD1C5;
  --party-paladin:#F5C542;
  --party-sorcerer:#E55DC8;
  --party-warlock:#9078F2;
  --party-artificer:#D98A2B;

  /* all clear 4.5:1 against calm's card surface unchanged from dark */
  --mascot-noob:#A99E88;
  --mascot-warrior:#D98166;
  --mascot-wizard:#8FA8C4;
  --mascot-rogue:#7FB37E;
  --mascot-bard:#B0A2D8;
  --mascot-cleric:#D8B85C;
  --mascot-ranger:#6FB39A;
  --mascot-oracle:#A78FE0;
  --mascot-barbarian:#D2894F;

  --ic-bg:#241F15; --ic-text:#EFE7D6; --ic-bd:#3A3324;

  /* code well still dark — keep syntax constant */

  --fig-bg:#1A160F;
  --fig-grid:none;            /* no background pattern — less distraction */
  --fig-bd:#332C20;
  --node-fill:#221D14;
  /* node-stroke / edge / nlab and all callout tokens are derived in :root */

  --th:#1C180F; --tborder:#2A2418;
}

/* Reading prefs — independent, stackable token overrides. */
html.pref-legible{ --fs-body:18px; --fs-lede:19px; --lh-body:1.72; }  /* Atkinson is the default reading face now; this option enlarges it for low-vision & dyslexia */
html.pref-spacing{ --lh-body:2.0; --lh-lede:1.85; --read-track:.03em; }
html.pref-spacing .article > * + *,
html.pref-spacing .prose > * + *{ margin-top:calc(var(--sp-4) + 4px); }
html.pref-reduce *,html.pref-reduce *::before,html.pref-reduce *::after{transition:none!important;animation:none!important;scroll-behavior:auto!important}
@media (prefers-reduced-motion: reduce){*{transition:none!important;animation:none!important}}

/* ------------------------------------------------------------
   MONOCHROME — the charting system's core law, applied whole-system.
   Every semantic hue collapses onto the neutral value ramp, so meaning
   must survive on the redundant channels the components already carry:
   labels (INFO / WARN / ERROR), icon silhouettes, dashes, stroke weight,
   texture, position, and printed values.

   Serves colour-vision deficiency, greyscale print, OS colour filters,
   and readers who want the lowest-stimulation surface available. It is
   also the system's own honesty test: if a component becomes ambiguous
   here, it was leaning on hue and needs another channel.

   Written against --mc-ramp-*, which is already theme-scoped, so this one
   block resolves correctly in dark, light and calm. Also exposed as a
   bare `.pref-mono` class so a single subtree can be shown monochrome
   (used by the redundant-encoding specimen).
   ------------------------------------------------------------ */
html.pref-mono, .pref-mono {
  /* brightest step = the channels that must read first */
  --cyan:var(--mc-ramp-1);
  --link:var(--mc-ramp-1);
  --danger:var(--mc-ramp-1);
  /* second step = brand, values, warnings */
  --green:var(--mc-ramp-2);
  --warn:var(--mc-ramp-2);
  --eco:var(--mc-ramp-2);
  --eco-bright:var(--mc-ramp-1);
  /* third step = topical accents */
  --violet:var(--mc-ramp-3);

  /* the code well stays dark in every theme, so it takes fixed neutrals */
  --code-green:#B9B2A4;
  --code-cyan:#E4DED0;
  --code-warn:#B9B2A4;
  --code-danger:#E4DED0;
  --code-violet:#9C9587;
  --code-eco:#B9B2A4;
  --ic-text:#D8D2C4;

  /* Derived tokens compute in the scope that DECLARES them, so they don't
     re-derive from the overrides above in a subtree. Restate them here — this
     is a no-op for html.pref-mono and required for a .pref-mono subtree.
     Value is monotonic with severity (ERROR brightest → INFO calmest), so
     brightness itself becomes a working redundant channel.

     RAIL vs LABEL are decoupled on purpose: the rail is a non-text UI
     component (WCAG 1.4.11, needs 3:1) so it stays exactly on the ramp step
     that encodes severity; the label is TEXT (1.4.3, needs 4.5:1 — 11px/600
     is normal-size, not large). INFO sits on the faintest of the three
     steps, so its LABEL alone is nudged toward the theme's strongest ink
     until it clears 4.5:1, without moving the rail off the ramp or
     colliding with WARN's value. Mixing against --mc-ink keeps this correct
     in every theme: --mc-ink is bright in dark/calm and near-black in
     light, so the nudge always increases contrast. */
  --info-bg:color-mix(in srgb,var(--mc-ramp-3) 12%,transparent);
  --info-bd:var(--mc-ramp-3);
  --info-lb:color-mix(in srgb,var(--mc-ramp-3) 72%,var(--mc-ink));
  --warn-bg:color-mix(in srgb,var(--mc-ramp-2) 10%,transparent);
  --warn-bd:var(--mc-ramp-2); --warn-lb:var(--mc-ramp-2);
  --dgr-bg:color-mix(in srgb,var(--mc-ramp-1) 10%,transparent);
  --dgr-bd:var(--mc-ramp-1); --dgr-lb:var(--mc-ramp-1);
  --node-stroke:var(--mc-ramp-2); --edge:var(--mc-ramp-1);
}

/* Pixel art is full-colour SVG; desaturate rather than hide it. */
html.pref-mono .scry-cucco__sprite img, html.pref-mono .scry-cucco__sprite svg,
html.pref-mono .scry-cucco__medallion img, html.pref-mono .scry-cucco__medallion svg,
html.pref-mono .scry-cucco__fgframe img, html.pref-mono .scry-cucco__fgframe svg,
html.pref-mono .scry-cucco__solo img, html.pref-mono .scry-cucco__solo svg,
.pref-mono .scry-cucco__sprite img, .pref-mono .scry-cucco__fgframe img {
  filter:grayscale(1);
}

/* Mascot class accents are inline (set per class in JS), so they need an
   explicit override here — the party reads by name + role + stats instead. */
html.pref-mono .scry-cucco__wrap, html.pref-mono .scry-cucco__fg { border-top-color:var(--muted) !important; }
html.pref-mono .scry-cucco__name, html.pref-mono .scry-cucco__plate,
html.pref-mono .scry-cucco__fgnm { color:var(--heading) !important; }
html.pref-mono .scry-cucco__lvl { color:var(--heading) !important; border-color:var(--border) !important; }
html.pref-mono .scry-cucco__fgdot { background:var(--muted) !important; }
html.pref-mono .scry-cucco__fgstat b { color:var(--heading) !important; }
html.pref-mono .scry-cucco__xp > span { background:var(--muted) !important; }
html.pref-mono .scry-cucco__hp > span { color:var(--muted) !important; }

/* party-gallery.html (.party-card) uses the same --ac fixed-identity-accent
   pattern the mascot comment above references — needs the same override. */
html.pref-mono .party-card { border-top-color:var(--muted) !important; }
html.pref-mono .party-name { color:var(--heading) !important; }
html.pref-mono .party-ph-cls { color:var(--muted) !important; }

/* Lite mode (permacomputing Phase 3): drop to system fonts (zero web-font
   bytes) and let the Mermaid runtime be skipped. Auto-applies when the
   browser signals reduced-data. Fonts are the shared block below. */
html.pref-lite{
  --font-display:ui-monospace,'Courier New',monospace;
  --font-read:ui-monospace,'Courier New',monospace;
  --font-code:ui-monospace,'Courier New',monospace;
  --font-body:ui-monospace,'Courier New',monospace;
  --font-pixel:ui-monospace,monospace;
}
@media (prefers-reduced-data: reduce){
  :root{
    --font-display:ui-monospace,'Courier New',monospace;
    --font-read:ui-monospace,'Courier New',monospace;
    --font-code:ui-monospace,'Courier New',monospace;
    --font-body:ui-monospace,'Courier New',monospace;
    --font-pixel:ui-monospace,monospace;
  }
}
/* Mermaid fallback — diagrams are static inline SVG (no JS needed), so no-JS
   visitors get the real diagram. The .mermaid source stays dormant and is
   shown as a readable text block only in Lite/data-saver mode. */
.diagram .mermaid{display:none}
html.pref-lite .diagram .diag-card > svg{display:none}
html.pref-lite .diagram .mermaid{display:block;white-space:pre-wrap;font-family:var(--font-code);font-size:12px;line-height:1.5;color:var(--code-muted);background:var(--code-bg);border:1px solid var(--code-bd);border-radius:var(--radius);padding:14px 16px;overflow-x:auto}
html.pref-lite .diagram .mermaid::before{content:"diagram source";display:block;color:var(--eco);font-size:10px;letter-spacing:.08em;text-transform:uppercase;margin-bottom:8px}

/* No-JS resilience (Permacomputing Phase 4): the footprint badge needs JS to
   fill real numbers — hide its placeholders entirely when JS is off. */
html:not(.js) .scry-fp{display:none}

/* ============================================================
   base
   ============================================================ */
*{box-sizing:border-box}
html{background:var(--bg)}
body{
  margin:0;
  background:var(--bg);
  color:var(--text);
  font-family:var(--font-read);
  font-size:var(--fs-body);
  line-height:var(--lh-body);
  -webkit-font-smoothing:antialiased;
  /* No transition on the mode-switching root: both background and
     color are var-bound, and custom properties can't interpolate —
     transitioning either sticks on the old value (dark-on-dark on
     toggle-back). The mode flip is instant by design. */
}

/* ============================================================
   article shell + measure
   ============================================================ */
.article{max-width:var(--measure);margin:0 auto;padding:0 24px}
.article > * + *{margin-top:var(--sp-4)}
/* Paragraph rhythm for the actual content — .Content renders directly into
   .prose (see single.html), so this is the selector that spaces prose
   siblings; .article's own > * + * above only spans its few structural
   children (single-header / prose / article-end). */
.prose > * + *{margin-top:var(--sp-4)}

/* ============================================================
   headings — Space Mono, lowercase
   ============================================================ */
h1,.h1{font-family:var(--font-display);font-weight:400;font-size:var(--fs-h1);line-height:1.25;letter-spacing:-.01em;color:var(--heading);text-transform:lowercase;margin:0}
h2,.h2{font-family:var(--font-display);font-weight:400;font-size:var(--fs-h2);line-height:1.3;color:var(--heading);text-transform:lowercase;margin:var(--sp-6) 0 0}
h3,.h3{font-family:var(--font-display);font-weight:400;font-size:var(--fs-h3);color:var(--heading);text-transform:lowercase;margin:38px 0 0}
/* A plain element right after a heading gets a tighter step than the general
   34px evidence / 22px paragraph rhythm (--sp-4) — 30px, deliberately off the
   4px scale, per the DS reading-page template. The :not() guards are
   intentional, not decorative: without them, .prose > table (1 class + 1
   type, same as this rule's own 1 class + 1 type) would *tie* it, with the
   winner decided fragilely by file order; .prose > .highlight (2 classes)
   already *outranks* it (1 class + 1 type) regardless of order. The explicit
   :not() exclusion makes both structurally unmatchable here either way, so
   evidence keeps full spacing after a heading regardless of future edits to
   this file. */
.prose > h2 + *:not(table):not(.highlight):not(figure),
.prose > h3 + *:not(table):not(.highlight):not(figure){margin-top:30px}
/* .prose > * + * (line 324) has higher specificity (one class) than the bare
   h2,.h2 / h3,.h3 selectors above (one type selector for a plain <h2>/<h3>),
   so it silently wins margin-top for any heading that isn't .prose's first
   child — i.e. essentially every real heading. These two rules restore the
   intended heading rhythm specifically inside prose content, without
   touching the base h2,.h2/h3,.h3 rule that other, non-.prose headings
   (e.g. card titles) still rely on. */
.prose > h2{margin-top:var(--sp-6)}
.prose > h3{margin-top:38px}
.title{font-family:var(--font-display);font-weight:400;font-size:var(--fs-display);line-height:1.18;letter-spacing:-.01em;color:var(--heading);text-transform:lowercase;margin:0}

/* ============================================================
   prose
   ============================================================ */
p{margin:0;color:var(--text)}
.lede{font-size:var(--fs-lede);line-height:var(--lh-lede);color:var(--text)}

a{color:var(--link);text-decoration:none;border-bottom:1px solid color-mix(in srgb,currentColor 72%,transparent)}
a:hover{border-bottom-color:var(--link)}
a:visited{color:var(--link)}

/* inline code */
:not(pre) > code{
  font-family:var(--font-code);font-size:.85em;
  background:var(--ic-bg);color:var(--ic-text);
  border:1px solid var(--ic-bd);padding:1px 6px;border-radius:var(--radius-sm);
}

/* ============================================================
   code block — dark in both modes (see Chroma CSS for tokens)
   ============================================================ */
.code-tab{font-family:var(--font-code);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin:0 0 8px}
pre,.highlight pre,.chroma{
  font-family:var(--font-code);
  background:var(--code-bg);color:var(--code-text);
  border:1px solid var(--code-bd);border-radius:var(--radius);
  padding:16px 18px 22px;font-size:var(--fs-code);line-height:var(--lh-code);
  overflow-x:auto;tab-size:4;
}
pre code{background:none;border:none;padding:0;color:inherit;font-size:inherit}
/* Evidence gets more vertical air than the paragraph rhythm (34px vs
   --sp-4's 22px — deliberately off the 4px scale, per the DS readme) —
   scoped to a direct child of .prose, which is where .Content actually
   renders, so a code block inside a card isn't double-margined. Bare
   fences (no language tag) get no .highlight wrapper from Hugo, so they
   need the same margin repeated, or they read as tighter to the
   surrounding text than a labeled block right above or below them.
   Targets BOTH .prose > pre (the no-JS/pre-hydration shape, where <pre>
   is still the direct .prose child) and .prose > .code-well (the
   with-JS shape below, where code-copy.js has moved <pre> one level
   deeper and .code-well has taken its place as the direct child) —
   whichever one is actually the direct child at render time is the one
   that needs the margin; the other selector is simply inert. `.layout`
   on both bare-fence branches isn't decorative: see the specificity
   note below. */
.prose > .highlight{margin:34px 0}
.layout .prose > pre,
.layout .prose > .code-well{margin:34px 0}
/* code-copy.js wraps every fenced block's <pre> — labeled or bare — in a
   <div class="code-well">, which is what actually bleeds 19px past its
   own 720px-capped ancestor on each side (width = measure + 38px,
   centred via a negative-ish margin-inline), not <pre> itself. <pre>
   just fills that wrapper at 100% and keeps its own overflow-x:auto for
   scrolling.

   That split matters: an earlier version bled and scrolled the SAME
   element, so the copy button (anchored to it for correct edge
   alignment) scrolled away with the code on any line wider than the
   well — unreachable on exactly the lines worth copying — and, with no
   reserved gutter, sat on top of line 1. .code-well doesn't scroll, so
   the button anchored to it (position:relative here) stays put and
   reachable regardless of horizontal scroll position; padding-top:44px
   on <pre> below reserves the room instead of overlapping.

   max-width:none defeats the generic `.layout .prose > *{max-width:720px}`
   rule, which would otherwise re-clamp the bare-fence branch (.code-well
   sits as a direct .prose child there) back down and silently cancel the
   bleed — confirmed happening in an earlier version, where a bare fence
   measured margin-left:0 and maxWidth:720px against a labeled fence's
   correct -19px/none. The `.layout` prefix on that branch is what wins
   the specificity fight (0,2,1 vs the generic rule's 0,2,0); without it
   max-width:none is present in the rule but loses the cascade anyway.

   Scoped narrower than langswitch on purpose: its Chroma output lives
   several DOM levels inside .langswitch .ls-panels, in its own nested
   context with its own chrome, so this measure-relative bleed formula
   doesn't apply there — langswitch already scrolls on its own <pre>
   correctly via the generic rule above; only tab-size/margin needed to
   be shared, not this width math.

   .layout .prose > pre is also included here: it's the bare-fence
   shape for the brief window before code-copy.js runs and wraps <pre>
   in .code-well (see that script's own comment — without it the code
   "renders fine... just without the measure-flush bleed"). Without
   this line a bare fence flashes at the generic 720px cap and then
   snaps 19px wider the instant JS wraps it; matching the width here up
   front removes that reflow instead of just narrowing its window. */
.prose > .highlight .code-well,
.layout .prose > .code-well,
.layout .prose > pre{
  width:calc(min(100%,720px) + 38px);max-width:none;
  margin-inline:calc(max(0px,(100% - 720px)/2) - 19px) auto;
  position:relative;
}
.prose > .highlight .code-well > pre,
.layout .prose > .code-well > pre{
  width:100%;margin-inline:0;
  border-left:none;border-right:none;
  padding:44px 18px 22px; /* top clears the button; bottom clears the
    horizontal scrollbar, which paints inside the padding box */
}
.prose > .highlight .code-well > pre > code,
.layout .prose > .code-well > pre > code{
  display:block;padding:0;overflow:visible;
}
.code-copy-btn{
  position:absolute;top:10px;right:12px;z-index:1;
  font-family:var(--font-code);font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--code-muted);background:var(--code-bg);border:1px solid var(--code-bd);
  padding:5px 11px;cursor:pointer;border-radius:0;
  transition:color .15s,border-color .12s,background .12s;
}
.code-copy-btn:hover{color:var(--cyan);border-color:var(--cyan)}
.code-copy-btn:active{transform:translateY(1px)}
.code-copy-btn:focus-visible{outline:2px solid var(--cyan);outline-offset:2px}

/* ============================================================
   callouts  —  {{< callout info >}} … {{< /callout >}}
   ============================================================ */
.scry-callout{border-radius:var(--radius);padding:14px 17px;font-size:15px;line-height:1.6;color:var(--text)}
.scry-callout > :first-child{margin-top:0}
.scry-callout > :last-child{margin-bottom:0}
.scry-callout__label{font-family:var(--font-code);font-size:11px;letter-spacing:.1em;font-weight:600;display:flex;align-items:center;gap:8px;margin-bottom:6px}
.scry-callout.info{background:var(--info-bg);border-left:3px solid var(--info-bd)}
.scry-callout.info  .scry-callout__label{color:var(--info-lb)}
.scry-callout.warn{background:var(--warn-bg);border-left:3px solid var(--warn-bd)}
.scry-callout.warn  .scry-callout__label{color:var(--warn-lb)}
.scry-callout.danger{background:var(--dgr-bg);border-left:3px solid var(--dgr-bd)}
.scry-callout.danger .scry-callout__label{color:var(--dgr-lb)}

/* ============================================================
   figures — obs-* shortcodes + mermaid
   ============================================================ */
.obs-fig{
  background:var(--fig-bg);background-image:var(--fig-grid);background-size:26px 26px;
  border:1px solid var(--fig-bd);border-radius:var(--radius);padding:22px 20px 8px;
}
.obs-fig svg{display:block;width:100%;height:auto}
.obs-fig .node{fill:var(--node-fill);stroke:var(--node-stroke)}
.obs-fig .nlab{font-family:var(--font-code);font-size:12px;fill:var(--nlab)}
.obs-fig .edge{stroke:var(--edge);stroke-width:1.5}
.obs-fig .arr{fill:var(--edge)}
figcaption,.obs-cap{font-family:var(--font-code);font-size:12px;line-height:1.45;color:var(--muted);margin:6px 2px 0}

/* mermaid: pre-rendered static SVG, themed via CSS vars; container just frames it */
.mermaid{
  background:var(--fig-bg);background-image:var(--fig-grid);background-size:26px 26px;
  border:1px solid var(--fig-bd);border-radius:var(--radius);padding:18px;
}

/* ============================================================
   tables
   ============================================================ */
table{width:100%;border-collapse:collapse;font-size:14px}
/* Evidence (code, figures, tables) gets more vertical air than the paragraph
   rhythm (34px vs --sp-4's 22px — deliberately off the 4px scale, per the
   DS readme) — a table header band or code well's own fill reads as flush
   against the line above it at plain paragraph spacing. Scoped to direct
   children of .prose (where .Content actually renders) so a table already
   nested inside a figure card (e.g. obs-comparison-table.html's
   .scry-table) isn't double-margined. */
.prose > table{margin:34px 0}
thead th{text-align:left;font-family:var(--font-code);font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);font-weight:500;padding:9px 13px;background:var(--th);border-bottom:1px solid var(--tborder)}
tbody td{padding:10px 13px;color:var(--text);border-bottom:1px solid var(--tborder);line-height:1.5;vertical-align:top}

/* ============================================================
   table of contents (partial: toc.html)
   ============================================================ */
.toc{position:sticky;top:88px;align-self:start}
.toc-label{font-family:var(--font-code);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);margin-bottom:14px}
/* Reset Hugo's #TableOfContents list — no bullets, no default indent;
   the left rail on each link carries the structure. */
.toc nav,.toc ul{margin:0;padding:0;list-style:none}
.toc li{margin:0}
.toc a{display:block;font-family:var(--font-code);font-size:12.5px;line-height:1.45;color:var(--muted);text-decoration:none;border-bottom:none;padding:6px 0 6px 13px;border-left:2px solid var(--border)}
/* nested h3 entries: indent the TEXT, not the rail — every link keeps the same
   left edge so the rail is one clean continuous line (matches the reference). */
.toc ul ul a{padding-left:26px}
.toc a:hover{color:var(--text)}
.toc a.active{color:var(--link);border-left-color:var(--link)}

/* ============================================================
   chrome — eyebrow, pixel wordmark, mode toggle
   ============================================================ */
.scry-wordmark{font-size:13px;line-height:1;color:var(--heading)}
.scry-wordmark__scry{font-family:var(--font-pixel-scry);font-weight:var(--fw-pixel-scry)}
.scry-wordmark__ops{font-family:var(--font-pixel-ops);font-weight:var(--fw-pixel-ops);color:var(--green)}
.pixel-tag{font-family:var(--font-code);font-size:11px;color:var(--muted)}

.accent-line{height:2px;background:linear-gradient(90deg,var(--green),var(--cyan))}

/* skip link — off-screen until keyboard focus */
.skip-link{position:absolute;left:-9999px;top:0}
.skip-link:focus{left:8px;top:8px;z-index:10;background:var(--surface);color:var(--link);font-family:var(--font-code);font-size:13px;padding:8px 12px;border:1px solid var(--border);border-radius:var(--radius-sm)}
/* Visible keyboard focus for every interactive element (WCAG 2.4.7). --link is
   high-contrast in all three themes (cyan/teal/amber); offset lifts it off the control. */
:focus-visible{outline:2px solid var(--link);outline-offset:2px}

/* ============================================================
   buttons
   ============================================================ */
.scry-btn{font-family:var(--font-code);font-size:13px;line-height:1;display:inline-flex;align-items:center;justify-content:center;gap:8px;border-radius:8px;padding:9px 16px;min-height:40px;cursor:pointer;border:1px solid var(--border);background:transparent;color:var(--text);text-decoration:none;transition:border-color .12s,background .12s,color .12s;white-space:nowrap}
.scry-btn:hover{border-color:var(--cyan);color:var(--heading)}
.scry-btn:active{transform:translateY(1px)}
.scry-btn:focus-visible{outline:2px solid var(--link);outline-offset:2px}
.scry-btn[disabled],.scry-btn[aria-disabled="true"]{opacity:.45;cursor:not-allowed;pointer-events:none}
.scry-btn.sm{font-size:12px;padding:7px 12px;min-height:34px}
.scry-btn.primary{background:var(--green);color:var(--on-accent);border-color:var(--green);font-weight:500}
.scry-btn.primary:hover{background:var(--cyan);border-color:var(--cyan);color:var(--on-accent)}
.scry-btn.ghost{border-color:transparent;color:var(--link);text-decoration:underline;text-underline-offset:3px}
.scry-btn.ghost:hover{color:var(--cyan);background:transparent}

/* ============================================================
   layout: guide template (toc rail + article)
   ============================================================ */
.layout{max-width:820px;margin:0 auto;display:grid;grid-template-columns:minmax(0,1fr);gap:54px;padding:50px 28px 130px}
/* Sidebar layout is CENTRED on the viewport, not left-anchored. A prior
   version gave the TOC its own fixed 200px track and put the only
   flexible track on the right (`200px minmax(0,758px) minmax(0,1fr)`) —
   that pushes the whole grid right by the TOC's width, since surplus
   width only ever collects in the trailing track: measured 59px of
   leftward prose offset from true centre at 1440px, growing with
   viewport width since the flexible track absorbs 100% of the surplus
   on one side only. Centring a fixed-width measure needs flexible
   tracks on BOTH sides, so the TOC now lives inside the left 1fr gutter
   (`justify-self:end`, `width:200px`) instead of owning a dedicated
   track — the gutter still holds it flush to the measure's left edge,
   it just no longer forces the grid off-centre to do it. The TOC
   partial still renders before <article> in single.html (both for this
   grid placement and, at the stacked breakpoint below, so DOM order
   matches reading order for assistive tech too).

   The article track is 758px, not 720: the article width is not a
   reading-width decision, it's the 720px measure PLUS whatever evidence
   is allowed to bleed past it. A code well is deliberately 758px
   (720 + 2x19 — see .code-well below), and with the track at exactly
   720 there was no slack for that bleed, so every code block rendered
   19px outside its own article on each side — confirmed by measuring
   .article at 282-1002 (720px) against a code well at 263-1021 (758px)
   at 1400px viewport. Widening the track to match doesn't change the
   measure itself: `.layout .prose > *{max-width:720px}` still caps
   prose content at 720 regardless of how wide .article's own box is. */
.layout.has-toc{max-width:none;grid-template-columns:minmax(0,1fr) minmax(0,758px) minmax(0,1fr)}
.layout.has-toc > .toc{grid-column:1;grid-row:1;justify-self:end;width:200px;max-width:100%}
.layout.has-toc > .article{grid-column:2;grid-row:1;min-width:0}   /* min-width:0 lets the grid item shrink below wide content (tables/diagrams) so their own overflow-x containers scroll instead of the page */
/* Reading column: prose holds the 720px measure (centered). Evidence
   (code, figures, tables) shares that same measure and aligns flush with
   the prose left/right edges, rather than breaking out wider (GUIDELINES
   #2 — "one measure for prose and evidence alike"). Anything still too
   wide for 720px (a dense comparison table, a wide diagram) scrolls
   inside its own overflow-x:auto container instead of forcing the column
   wider. */
.layout .article{margin:0;padding:0;max-width:none}
.layout .article > .single-header,
.layout .article > .article-end,
.layout .prose > *{max-width:720px;margin-inline:auto}
.site-top{position:sticky;top:0;z-index:5;display:flex;align-items:center;gap:14px;padding:16px 28px;background:var(--bg);border-bottom:1px solid var(--border)}
.site-top .spacer{flex:1}
.site-meta{font-family:var(--font-code);font-size:11px;letter-spacing:.14em;color:var(--muted)}

/* Below 1084 a sidebar can only exist by stealing from the measure. The
   threshold counts BOTH gaps and BOTH paddings for the 3-track grid above:
     28 + 200 + 54 + 720 + 54 + 28 = 1084
   (a naive count using one gap/padding pair, e.g. ~990, understates it and
   leaves a band where the measure silently shrinks below 720 while the
   sidebar still renders — verified against the scryops-design kit, whose
   own history includes finding 1030 insufficient for the same reason.) */
@media (max-width:1083px){
  .layout,.layout.has-toc{max-width:800px;grid-template-columns:1fr;gap:30px;padding:34px 22px 90px}
  /* grid-row set explicitly, not auto: auto lets DOM order win, and if
     the TOC partial is ever moved back after </article> in single.html
     it would drop the TOC to the page bottom instead of stacking it
     above the article as intended. justify-self reset to start: the
     desktop rule now reads end (to hug the centred measure), which
     this breakpoint must not inherit, or the stacked TOC shifts right
     instead of keeping its original left alignment. */
  .layout.has-toc > .toc{grid-column:1;grid-row:1;justify-self:start}
  .layout.has-toc > .article{grid-column:1;grid-row:2}
  .toc{position:static}
  .title{font-size:28px}
}

/* ============================================================
   diagram components  —  obs-* HTML/SVG shortcodes
   Ported from the legacy static/css/style.css (which the
   Telemetry chrome no longer loads) and rewired onto the tokens
   above, so every figure flips dark/light. Palette mapping from
   the old system: amber/brand → --green, klein-blue → --cyan,
   success → --green, danger family → --danger, Commit Mono →
   --font-code, Press Start 2P → --font-pixel. No hard-coded hex
   below this line — components read tokens only.
   ============================================================ */

/* shared figure wrapper + flat diagram card (neutral frame, no chromatic accent) */
figure.diagram,figure.knt-fig,.obs-fig{margin:34px 0}
figure.diagram figcaption,figure.knt-fig figcaption{font-family:var(--font-code);font-size:12px;line-height:1.45;color:var(--muted);margin-top:10px;padding-left:2px}
.diag-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:20px 20px 16px;overflow-x:auto}
/* Hand-built figures carry no inline max-width, so they take the 636px floor.
   Mermaid emits its own inline max-width pinning the SVG to its natural size;
   min-width previously beat that in the cascade and upscaled it (e.g. 277px
   -> 636px, a 2.3x stretch), rendering mermaid's 14px text far larger than
   body copy. Scoping this out lets mermaid render at scale 1.0. */
.diag-card > svg:not([style*="max-width"]){min-width:636px}

/* divider between stacked comparison flows (obs-reactive-loop) */
.flow-divider{height:1px;background:var(--border);margin:19px 0}

/* comparison / two-version tables (obs-comparison-table, obs-monitoring-shifts) */
.scry-table{width:100%;border-collapse:collapse;background:var(--surface);border:1px solid var(--border);font-size:14px}
.scry-table th{background:var(--th);border:1px solid var(--tborder);padding:9px 14px;font-family:var(--font-code);font-size:11px;text-align:left;letter-spacing:.04em;color:var(--text)}
.scry-table th:first-child{color:var(--muted);letter-spacing:.1em;text-transform:uppercase}
.scry-table th.v1{color:var(--muted);border-bottom:2px solid var(--muted)}
.scry-table th.v2{color:var(--cyan);border-bottom:2px solid var(--cyan)}
.scry-table td{border:1px solid var(--tborder);padding:8px 14px;font-size:13px;line-height:1.5;vertical-align:middle;color:var(--text)}
.scry-table td:first-child,.scry-table tbody th[scope="row"],.scry-table tbody th.rowhead{font-family:var(--font-code);color:var(--muted);font-weight:400;font-size:11px;text-transform:uppercase;letter-spacing:.08em;white-space:nowrap;background:var(--th);text-align:left;padding:8px 14px;line-height:1.5;vertical-align:middle}
.scry-table td.v1{color:var(--text)}
.scry-table td.v2{color:var(--cyan)}
.scry-table-wrap{overflow-x:auto}

/* insight callout (insight shortcode) */
.scry-insight{display:flex;gap:14px;align-items:flex-start;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:14px 18px;margin:24px 0}
.scry-insight.lightbulb{border-left:3px solid var(--green)}
.scry-insight.bookmark{border-left:3px solid var(--cyan)}
.scry-insight__icon{flex-shrink:0;margin-top:3px;width:16px;height:16px}
.scry-insight.lightbulb .scry-insight__icon{color:var(--green)}
.scry-insight.bookmark .scry-insight__icon{color:var(--cyan)}
.scry-insight__body{font-family:var(--font-read);font-size:14.5px;line-height:1.66;color:var(--text)}
.scry-insight__body strong{display:block;font-weight:700;margin-bottom:4px}
.scry-insight.lightbulb .scry-insight__body strong{color:var(--green)}
.scry-insight.bookmark .scry-insight__body strong{color:var(--cyan)}
.scry-insight__body p{margin:0;color:var(--text)}

/* ============================================================
   site chrome — nav menu, homepage, listings, cards, tags, Q&A,
   subscribe, footer. Ported from the retired static/css/style.css
   onto the tokens above (via the legacy aliases) so every page
   flips dark/light. Reading pages use .layout/.article (above);
   these styles cover everything else.
   ============================================================ */

/* page container for non-reading pages */
.wrap{max-width:1100px;margin:0 auto;padding:46px 28px 96px}

/* base lists inside reading/content flow (telemetry base omitted these) */
.article ul,.article ol,.prose ul,.prose ol{margin:14px 0 14px 1.4rem}
.article li,.prose li{margin:4px 0}

/* top-bar main menu (added to site-top.html) */
.top-nav{display:flex;gap:18px;flex-wrap:wrap;align-items:center}
.top-nav a{font-family:var(--font-code);font-size:12px;text-transform:uppercase;letter-spacing:.12em;color:var(--muted);padding:7px 0;display:inline-block}
.top-nav a:hover,.top-nav a[aria-current="page"]{color:var(--cyan)}

/* terminal identity strip (homepage hero line) */
.site-identity{display:flex;align-items:center;gap:.6rem;padding:.85rem 0;border-bottom:1px solid var(--border);font-size:.88rem;flex-wrap:wrap;row-gap:.25rem;font-family:var(--font-code)}
.prompt{color:var(--green);flex-shrink:0;user-select:none}
.cmd{color:var(--text)}
.si-sep{color:var(--green);user-select:none;flex-shrink:0}
.si-desc{color:var(--muted)}
.cursor{display:inline-block;width:9px;height:1em;background:var(--green);vertical-align:text-bottom;animation:scry-blink 1.1s step-end infinite;margin-left:2px}
@keyframes scry-blink{0%,100%{opacity:1}50%{opacity:0}}
@media (prefers-reduced-motion:reduce){.cursor{animation:none;opacity:1}}

/* two-column hero: featured + topics */
.hero-grid{display:grid;grid-template-columns:1fr 220px;gap:0 3.5rem;padding:2.8rem 0 3rem;border-bottom:1px solid var(--border);margin-bottom:3rem;align-items:start}
.featured-article{display:block;padding-right:2rem;border-right:1px solid var(--border);text-decoration:none}
.featured-article:hover .featured-title{color:var(--cyan)}
.featured-meta{display:flex;align-items:center;gap:.6rem;margin-bottom:1.1rem;flex-wrap:wrap}
.featured-date{font-family:var(--font-code);font-size:.78rem;color:var(--muted);margin-left:auto}
.featured-title{font-family:var(--font-display);font-size:1.6rem;font-weight:400;line-height:1.2;color:var(--heading);margin-bottom:1rem;letter-spacing:-.01em;text-transform:lowercase}
.featured-excerpt{font-family:var(--font-read);font-size:.92rem;line-height:1.8;color:var(--muted);margin-bottom:1.4rem}
.featured-cta{font-family:var(--font-code);font-size:.8rem;color:var(--green);text-transform:uppercase;letter-spacing:.1em}

.hero-topics{padding-top:0}
.topic-all{display:block;flex-basis:100%;margin-top:1rem;font-family:var(--font-code);font-size:.75rem;color:var(--muted);opacity:.7}
.topic-all:hover{color:var(--cyan);opacity:1}

/* section label + rule */
.section-head{display:flex;align-items:center;gap:1rem;margin-bottom:.5rem}
.section-label{font-family:var(--font-code);font-size:.6875rem;color:var(--green);text-transform:uppercase;letter-spacing:.18em;white-space:nowrap}
.section-rule{flex:1;height:1px;background:var(--border)}

/* article feed (list/term) + cards (was .article — renamed .art-card to avoid
   colliding with the reading column .article) */
.feed{margin-bottom:4rem}
.scry-artcard{display:grid;grid-template-columns:2.8rem 1fr;gap:1rem;padding:1.6rem 0;border-bottom:1px solid var(--border);cursor:pointer;transition:background .12s;text-decoration:none}
.scry-artcard:first-child{border-top:1px solid var(--border)}
.scry-artcard:hover{background:color-mix(in srgb,var(--cyan) 4%,transparent)}
.scry-artcard__num{font-family:var(--font-pixel);font-size:.63rem;color:var(--muted);padding-top:.4rem;line-height:1.8}
.scry-artcard:hover .scry-artcard__num{color:var(--cyan)}
.scry-artcard__meta{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin-bottom:.45rem}
.scry-artcard__title{font-family:var(--font-display);font-size:1.15rem;font-weight:400;line-height:1.35;margin-bottom:.4rem;color:var(--heading);text-transform:lowercase}
.scry-artcard:hover .scry-artcard__title{color:var(--cyan)}
.scry-artcard__excerpt{font-family:var(--font-read);font-size:.95rem;color:var(--text);line-height:1.7;margin-top:.5rem}

/* ── M3 section listing ──────────────────────────────────────────────── */

/* page header */
.lhead{display:flex;align-items:flex-end;gap:16px;padding:40px 0 22px;border-bottom:1px solid var(--border);margin-bottom:26px}
.lh-l{flex:1}
.scry-eyebrow{font-family:var(--font-code);font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--muted);margin-bottom:11px}
.scry-eyebrow.brand{color:var(--green)}
.lh-title{font-family:var(--font-display);font-weight:400;font-size:32px;line-height:1.1;color:var(--heading);text-transform:lowercase;margin:0}
.lh-sub{font-family:var(--font-read);font-size:15px;line-height:1.6;color:var(--text);max-width:60ch;margin:14px 0 0}
.cnt{font-family:var(--font-code);font-size:11.5px;color:var(--muted);border:1px solid var(--border);border-radius:999px;padding:5px 12px;white-space:nowrap;flex-shrink:0}

@media(max-width:840px){
  .lh-title{font-size:27px}
  .lhead{flex-wrap:wrap;align-items:flex-start}
}

/* ── M3 section listing ──────────────────────────────────────────────── */

/* content-type tags (palette constrained to tokens: identifiers=cyan,
   how-to=green, Q&A=neutral) */
.scry-tag{font-family:var(--font-code);font-size:.6875rem;text-transform:uppercase;letter-spacing:.09em;color:var(--cyan);border:1px solid var(--cyan);padding:.08rem .4rem;background:color-mix(in srgb,var(--cyan) 8%,transparent);border-radius:3px;display:inline-block;line-height:1.5;white-space:nowrap}
.scry-tag.guide,.scry-tag.trends,.scry-tag.article{color:var(--cyan);border-color:var(--cyan)}
.scry-tag.howto{color:var(--green);border-color:var(--green);background:color-mix(in srgb,var(--green) 8%,transparent)}
.scry-tag.qa{color:var(--muted);border-color:var(--border);background:var(--surface)}
.read-time{font-family:var(--font-code);font-size:.75rem;color:var(--muted)}

/* Q&A list */
.qa-section{margin-bottom:4rem;background:var(--surface);border:1px solid var(--border);border-top:3px solid var(--cyan);padding:1.6rem 2rem 1.8rem}
.qa-item{padding:1.4rem 0;border-bottom:1px solid var(--border)}
.qa-item:first-child{border-top:1px solid var(--border)}
.qa-q{font-family:var(--font-display);font-size:.95rem;margin-bottom:.4rem;display:flex;gap:.6rem;color:var(--heading)}
.qa-q::before{content:'Q:';color:var(--green);font-family:var(--font-code);font-size:.6875rem;padding-top:.35rem;flex-shrink:0}
.qa-a{font-family:var(--font-read);font-size:.85rem;color:var(--muted);font-style:italic;padding-left:2.1rem;line-height:1.55}
.qa-a::before{content:'A → ';color:var(--muted);font-style:normal}
.ask-cta{margin-top:1.5rem;display:inline-block;font-family:var(--font-code);font-size:.8rem;text-transform:uppercase;letter-spacing:.1em;color:var(--green);border:1px solid var(--green);padding:.5rem 1.1rem}
.ask-cta:hover{background:var(--green);color:var(--bg)}

/* tag cloud (taxonomy) */
.tags-section{margin-bottom:4rem}
.tag-cloud{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:1rem}
.scry-tagpill{font-family:var(--font-code);font-size:.75rem;color:var(--muted);border:1px solid var(--border);border-radius:var(--radius-pill);padding:0 .9rem;letter-spacing:.02em;display:inline-flex;align-items:center;min-height:44px}
.scry-tagpill::before{content:"#";color:var(--green);font-weight:700;margin-right:.15rem}
.scry-tagpill:hover{color:var(--green);border-color:var(--green);background:color-mix(in srgb,var(--green) 6%,transparent)}

/* single-header (qa/single) + about page */
.single-header{margin-bottom:2.5rem;padding-bottom:1.5rem;border-bottom:1px solid var(--border)}
.single-header h1{font-family:var(--font-display);font-size:1.9rem;font-weight:400;line-height:1.25;margin-bottom:.8rem;color:var(--heading);text-transform:lowercase}
.about-content{font-family:var(--font-read);font-size:.95rem;line-height:1.75;color:var(--text)}
.about-content p{margin-bottom:.8rem}
.about-content strong{color:var(--heading)}
.about-content a{color:var(--link);text-decoration:underline;text-underline-offset:2px}

/* subscribe */
.scry-sub{margin-bottom:4rem;border:1px solid var(--border);border-left:3px solid var(--green);padding:1.6rem 2rem;background:var(--surface);border-radius:var(--radius)}
.scry-sub__label{font-family:var(--font-display);font-size:1.05rem;color:var(--heading);margin-bottom:.4rem;text-transform:lowercase}
.scry-sub__desc{font-family:var(--font-read);font-size:.9rem;color:var(--muted);margin-bottom:1rem;line-height:1.6}
.scry-sub__form{display:flex;gap:.6rem;flex-wrap:wrap}
.scry-sub__input{font-family:var(--font-code);font-size:.85rem;background:var(--bg);border:1px solid var(--muted);color:var(--text);padding:.55rem .9rem;flex:1;min-width:200px;border-radius:var(--radius-sm)}
.scry-sub__input::placeholder{color:var(--muted)}
.scry-sub__input:focus{border-color:var(--green)}
.scry-sub__btn{font-family:var(--font-code);font-size:.82rem;text-transform:uppercase;letter-spacing:.1em;color:var(--on-accent);background:var(--green);border:none;padding:.55rem 1.2rem;cursor:pointer;white-space:nowrap;border-radius:var(--radius-sm)}
.scry-sub__btn:hover{background:var(--cyan)}
.scry-sub__btn[disabled]{opacity:.55;cursor:not-allowed}
/* Success/error is a green/coral pair — the exact confusion case for ~8%
   of men — so each state also carries a distinct glyph silhouette, not
   just colour (see redundant-encoding law in the DS readme). */
.scry-sub__msg{font-family:var(--font-code);font-size:.82rem;margin-top:.75rem;line-height:1.5;display:flex;align-items:baseline;gap:.45rem}
.scry-sub__msg .g{font-size:.75rem;line-height:1;flex:none}
.scry-sub__msg.success{color:var(--green)}
.scry-sub__msg.error{color:var(--danger)}
.scry-sub__msg.loading{color:var(--muted)}

/* footer */
.site-footer{border-top:1px solid var(--border);padding:2.5rem 2rem;text-align:center}
.foot-logo{font-size:.65rem;color:var(--muted);margin-bottom:.8rem}
.foot-logo__scry{font-family:var(--font-pixel-scry);font-weight:var(--fw-pixel-scry)}
.foot-logo__ops{font-family:var(--font-pixel-ops);font-weight:var(--fw-pixel-ops);color:var(--green)}
.site-footer p{font-family:var(--font-code);font-size:.8rem;color:var(--muted)}
.site-footer a{color:var(--cyan)}
.site-footer a:hover{text-decoration:underline}

@media (max-width:720px){
  .hero-grid{grid-template-columns:1fr;gap:2rem 0;padding:1.8rem 0}
  .featured-article{padding-right:0;border-right:none;border-bottom:1px solid var(--border);padding-bottom:2rem}
  .featured-title{font-size:1.3rem}
  .wrap{padding:30px 20px 70px}
  .scry-sub__form{flex-direction:column}
  .top-nav{gap:12px}
}

/* let the top bar wrap when the menu + meta + toggle don't fit one row */
.site-top{flex-wrap:wrap;row-gap:10px}

/* quote_with_author shortcode */
.scry-quote{margin:24px 0;border-left:3px solid var(--green);padding:4px 0 4px 1.2rem}
.scry-quote blockquote{border:none;padding:0;margin:0 0 .8rem;color:var(--text);font-style:italic;font-family:var(--font-read);font-size:.95rem;line-height:1.65}
.scry-quote blockquote p{margin:0}
.scry-quote blockquote p::before{content:'\201C';color:var(--green);font-style:normal}
.scry-quote blockquote p::after{content:'\201D';color:var(--green);font-style:normal}
.scry-quote__attr{display:flex;align-items:center;gap:.7rem}
.scry-quote__avatar{width:32px;height:32px;border-radius:50%;border:1px solid var(--border);object-fit:cover;flex-shrink:0}
.scry-quote__avatar.pixel{width:56px;height:56px;border-radius:7px;object-fit:contain;background:var(--surface);padding:1px;image-rendering:pixelated;image-rendering:crisp-edges}
.scry-quote__initials{width:32px;height:32px;border-radius:50%;border:1px solid var(--border);background:var(--surface);display:flex;align-items:center;justify-content:center;font-family:var(--font-pixel);font-weight:var(--fw-pixel-ops);font-size:.625rem;color:var(--green);flex-shrink:0}
.scry-quote__name{display:block;font-family:var(--font-code);font-size:.8rem;font-weight:700;color:var(--green)}
.scry-quote__role{display:block;font-family:var(--font-code);font-size:.75rem;color:var(--muted)}

/* ── Front page (layouts/index.html) — split hero + terminal feed ────────
   Identity statement + CTA left; the latest pieces as shell output in a
   terminal window on the always-dark code well, so the feed reads the same
   in dark / light / calm. Collapses to one column < 820px. */
.front{max-width:1080px;margin:0 auto;padding:0 28px 90px;display:grid;grid-template-columns:1fr 1fr;gap:44px;align-items:center;min-height:62vh}
.front-hero{display:flex;flex-direction:column;gap:18px;padding:48px 0}
.landing-statement{font-family:var(--font-display);font-weight:400;font-size:clamp(32px,5vw,46px);line-height:1.12;letter-spacing:-.02em;color:var(--heading);text-transform:lowercase;margin:0;max-width:18ch}
.landing-statement b{color:var(--green);font-weight:400}
.landing-lede{font-family:var(--font-read);font-size:var(--fs-lede);line-height:var(--lh-lede);letter-spacing:var(--read-track);color:var(--text);max-width:60ch;margin:0}
.topics{display:flex;gap:8px;flex-wrap:wrap;margin:0}
.topic-chip{font-family:var(--font-code);font-size:12px;color:var(--text);border:1px solid var(--border);border-radius:999px;padding:6px 13px}
.topic-chip b{color:var(--cyan);font-weight:400}
.landing-cta{display:flex;gap:12px;flex-wrap:wrap;align-items:center;margin:6px 0 0}
.landing-cta .scry-btn{text-decoration:none}

.front-feed{padding:24px 0}
.scry-feed{background:var(--code-bg);border:1px solid var(--code-bd);border-radius:var(--radius);overflow:hidden}
.scry-feed__hdr{font-family:var(--font-code);font-size:11.5px;color:var(--code-muted);padding:12px 15px;border-bottom:1px solid var(--code-bd)}
.scry-feed__hdr .fp{color:var(--code-green)}
.scry-feed__hdr .fa{color:var(--code-cyan)}
.scry-feed__cursor{display:inline-block;width:7px;height:13px;background:var(--code-green);vertical-align:-2px;margin-left:3px;animation:scry-blink 1.1s step-end infinite}
@media (prefers-reduced-motion:reduce){.scry-feed__cursor{animation:none}}
.scry-feed__row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:11px;align-items:baseline;padding:10px 15px;border-bottom:1px solid var(--code-bd);text-decoration:none}
.scry-feed__row:last-child{border-bottom:none}
.scry-feed__row .scry-feed__glyph{font-family:var(--font-code);font-size:13px;width:15px;text-align:center;line-height:1}
.scry-feed__row .scry-feed__title{font-family:var(--font-code);font-size:13px;color:var(--code-text)}
.scry-feed__row:hover .scry-feed__title{color:var(--code-cyan)}
.scry-feed__row .scry-feed__meta{font-family:var(--font-code);font-size:10.5px;color:var(--code-muted);white-space:nowrap}
.scry-tp-trace{color:var(--cyan)}.scry-tp-metric{color:var(--green)}.scry-tp-prof{color:var(--warn)}.scry-tp-log{color:var(--muted)}.scry-tp-otel{color:var(--violet)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

@media (max-width:820px){
  .front{grid-template-columns:1fr;gap:26px;min-height:0}
  .front-hero{padding:36px 0 8px}
  .front-feed{padding:0 0 8px}
}

/* ── Reading-preferences panel (chrome) ─────────────────────────────── */
.scry-prefs__btn{font-family:var(--font-code);font-size:12px;color:var(--text);background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:7px 13px;cursor:pointer;transition:border-color .15s}
.scry-prefs__btn:hover{border-color:var(--cyan)}
.scry-prefs__btn b{color:var(--cyan);font-weight:400}
.scry-prefs__panel{position:fixed;top:64px;right:24px;z-index:60;width:290px;background:var(--surface);border:1px solid var(--border);border-radius:13px;padding:18px;box-shadow:0 20px 50px -20px rgba(0,0,0,.7)}
.scry-prefs__panel[hidden]{display:none}
.scry-prefs__panel h2{font-family:var(--font-code);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);margin:0 0 13px}
.scry-prefs__group{margin-bottom:16px}
.scry-prefs__group > .scry-prefs__glabel{font-family:var(--font-code);font-size:11px;color:var(--heading);margin-bottom:9px}
.scry-prefs__seg{display:flex;border:1px solid var(--border);border-radius:8px;overflow:hidden}
.scry-prefs__seg button{flex:1;font-family:var(--font-code);font-size:11.5px;color:var(--muted);background:transparent;border:none;padding:8px 4px;cursor:pointer}
.scry-prefs__seg button[aria-pressed="true"]{background:var(--bg);color:var(--heading)}
.scry-prefs__row{display:flex;align-items:center;gap:11px;padding:9px 0;cursor:pointer;border:none;background:transparent;width:100%;text-align:left;border-bottom:1px solid var(--border)}
.scry-prefs__row:last-child{border-bottom:none}
.scry-prefs__row .scry-prefs__l{flex:1}
.scry-prefs__row .scry-prefs__l .scry-prefs__name{font-family:var(--font-code);font-size:12px;color:var(--text)}
.scry-prefs__row .scry-prefs__l .scry-prefs__desc{font-family:var(--font-code);font-size:10px;color:var(--muted);margin-top:2px}
.scry-prefs__sw{width:38px;height:21px;border-radius:999px;background:var(--border);border:1px solid var(--muted);flex:none;position:relative;transition:background .15s}
.scry-prefs__sw::after{content:"";position:absolute;top:1px;left:1px;width:17px;height:17px;border-radius:50%;background:var(--muted);transition:transform .15s,background .15s}
.scry-prefs__row[aria-checked="true"] .scry-prefs__sw{background:var(--green)}
.scry-prefs__row[aria-checked="true"] .scry-prefs__sw::after{transform:translateX(17px);background:var(--on-accent)}

/* ── Permacomputing · Phase 2 — footprint badge + colophon ──────────────
   Terminal readouts that live on the always-dark code well, so the
   living-green eco signal reads identically in warm-paper AND soft-dark.
   footprint.js fills the real numbers via [data-footprint] + [data-fp-*]. */
.scry-fp{font-family:var(--font-code);font-size:12px;line-height:1.85;background:var(--code-bg);border:1px solid var(--code-bd);border-radius:var(--radius);padding:12px 14px;color:var(--code-text)}
.scry-fp .scry-fp__pr{color:var(--code-eco)}
.scry-fp .scry-fp__ar{color:var(--code-cyan)}
.scry-fp .scry-fp__hi{color:var(--code-hi)}
.scry-fp .scry-fp__eco{color:var(--code-eco)}
.scry-fp .scry-fp__status{color:var(--code-eco)}
.scry-fp.over .scry-fp__status{color:var(--code-danger)}
.scry-fp__bar{height:7px;border-radius:4px;background:rgba(127,176,105,.14);overflow:hidden;margin:8px 0 4px}
.scry-fp__fill{height:100%;width:0;background:linear-gradient(90deg,var(--code-eco),var(--code-eco));transition:width .4s ease}
.scry-fp.over .scry-fp__fill{background:linear-gradient(90deg,var(--code-danger),var(--code-warn))}
.scry-fp__note{font-family:var(--font-read);font-size:10.5px;color:var(--code-muted)}
.scry-fp__method{color:var(--code-cyan);text-decoration:none;border-bottom:1px solid transparent}
.scry-fp__method:hover{border-bottom-color:var(--code-cyan)}
@media (prefers-reduced-motion:reduce){.scry-fp__fill{transition:none}}

/* In the site footer the badge stays compact and centered. */
footer .scry-fp{max-width:440px;margin:0 auto;text-align:left}
.scry-fp__noscript{font-family:var(--font-code);font-size:11.5px;line-height:1.6;color:var(--muted);max-width:440px;margin:10px auto 0;text-align:left}
.scry-fp__noscript a{color:var(--cyan)}

.scry-colophon{font-family:var(--font-code);font-size:12.5px;line-height:1.7;background:var(--code-bg);border:1px solid var(--code-bd);border-radius:var(--radius);padding:16px 18px;color:var(--code-text);max-width:var(--measure)}
.scry-colophon .scry-colophon__cmd{color:var(--code-muted);margin-bottom:8px}
.scry-colophon .scry-colophon__cmd b{color:var(--code-eco);font-weight:400}
.scry-colophon .scry-colophon__row{display:grid;grid-template-columns:130px 1fr;gap:14px;padding:7px 0;border-bottom:1px solid var(--code-rule)}
.scry-colophon .scry-colophon__row:last-child{border-bottom:none}
.scry-colophon .scry-colophon__k{color:var(--code-muted)}
.scry-colophon .scry-colophon__v{color:var(--code-hi)}
.scry-colophon .scry-colophon__v .eco{color:var(--code-eco)}
.scry-colophon .scry-colophon__v a{color:var(--code-cyan);text-decoration:none}
.scry-colophon .scry-colophon__v a:hover{text-decoration:underline}

/* ── Mascot ("the Cucco") — pixel-art RPG chicken party, Phase 3c ────────
   Structural chrome reads Telemetry tokens so it recolors across
   dark/light/calm. --ac (set once per rendered instance) carries the
   fixed per-class identity accent through every variant — same pattern
   .party-card already uses. HP hearts read --danger, not the accent. */
.scry-cucco{margin:2.5rem 0 2rem;font-family:var(--font-code)}
.scry-cucco__wrap{display:flex;gap:16px;align-items:stretch;background:var(--surface);border:1px solid var(--border);border-top:2px solid var(--ac);border-radius:var(--radius-retro);padding:16px;overflow:hidden}
@media(max-width:560px){.scry-cucco__wrap{flex-direction:column;text-align:center}}
.scry-cucco__sprite{width:104px;flex-shrink:0;align-self:center}
.scry-cucco__sprite img{width:100%;height:auto;display:block;image-rendering:pixelated}
.scry-cucco__bubble{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.scry-cucco__name{font-family:var(--font-pixel);font-size:.68rem;line-height:1.5;color:var(--ac)}
.scry-cucco__role{font-size:.72rem;color:var(--muted);margin-bottom:6px}
.scry-cucco__quip{font-family:var(--font-read);font-size:.9rem;line-height:1.55;color:var(--heading);margin:0}
.scry-cucco__quip::before{content:'\201C'}
.scry-cucco__quip::after{content:'\201D'}
.scry-cucco__stats{display:flex;align-items:center;gap:10px;margin-top:10px;flex-wrap:wrap}
.scry-cucco__lvl{font-family:var(--font-pixel);font-size:.625rem;border:1px solid var(--ac);color:var(--ac);padding:4px 6px;line-height:1}
.scry-cucco__hp{letter-spacing:1px;font-size:.8rem}
.scry-cucco__hp .scry-cucco__heart--filled{color:var(--danger)}
.scry-cucco__hp .scry-cucco__heart--empty{color:var(--muted)}
.scry-cucco__xplabel{font-family:var(--font-pixel);font-size:.625rem;color:var(--muted)}
.scry-cucco__xp{position:relative;flex:1;min-width:60px;max-width:130px;height:8px;background:var(--bg);border:1px solid var(--border);overflow:hidden}
.scry-cucco__xp>span{position:absolute;left:0;top:0;bottom:0;display:block;background:var(--ac)}
.scry-cucco__cap{font-size:12px;line-height:1.45;color:var(--muted);font-style:italic;margin-top:10px}
.scry-cucco__badge{display:inline-flex;flex-direction:column;align-items:center;gap:8px;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-retro);padding:14px 16px;text-align:center}
.scry-cucco__medallion{width:88px;height:88px;display:flex;align-items:center;justify-content:center;background:var(--bg);border:1px solid var(--border);border-radius:50%;overflow:hidden}
.scry-cucco__medallion img{width:78%;height:auto;image-rendering:pixelated}
.scry-cucco__plate{font-family:var(--font-pixel);font-size:.625rem;color:var(--ac)}
.scry-cucco__sub{font-size:.68rem;color:var(--muted)}
.scry-cucco__solo{width:120px}
.scry-cucco__solo img{width:100%;height:auto;image-rendering:pixelated}
.scry-cucco__fg{display:flex;gap:15px;align-items:center;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:15px}
@media(max-width:560px){.scry-cucco__fg{flex-direction:column;text-align:center}}
.scry-cucco__fgframe{width:88px;flex:none;align-self:center;background:var(--bg);border:1px solid var(--border);border-radius:7px;padding:7px}
.scry-cucco__fgframe img{width:100%;height:auto;image-rendering:pixelated;display:block}
.scry-cucco__fgbody{min-width:0}
.scry-cucco__fgnm{display:flex;align-items:center;gap:9px;font-family:var(--font-pixel);font-size:.625rem;line-height:1.4;color:var(--heading)}
.scry-cucco__fgdot{width:9px;height:9px;border-radius:50%;flex:none;background:var(--ac)}
.scry-cucco__fgrole{font-family:var(--font-code);font-size:.72rem;color:var(--muted);margin:6px 0 9px}
.scry-cucco__fgquip{font-family:var(--font-read);font-size:.88rem;color:var(--text);line-height:1.55;margin:0 0 11px}
.scry-cucco__fgstat{font-family:var(--font-code);font-size:.73rem;color:var(--muted);letter-spacing:.02em}
.scry-cucco__fgstat b{font-weight:600;color:var(--ac)}
.scry-cucco__fgsep{opacity:.5;margin:0 7px}

/* ── Accessible monochrome charting tokens, Phase 5 ───────────────────
   Ported verbatim from the DS bundle (.claude/skills/scryops-design/
   tokens/charts.css), itself ported from the "Accessible monochrome
   chart templates" handoff. Hue is NEVER the sole carrier of meaning —
   every category, rank and relationship is encoded through value
   (lightness), texture, stroke treatment, shape or position too.
   Light theme uses the handoff's values verbatim; dark/calm value-invert
   the ramp (brightest = highest rank) so ordering survives on a dark
   ground. */
:root {
  --mc-surface:var(--surface);
  --mc-inverse:#ECE6D9;
  --mc-on-inverse:#141210;

  --mc-ink:var(--heading);
  --mc-ink-secondary:var(--text);
  --mc-ink-muted:var(--muted);
  --mc-border:var(--border);
  --mc-axis:var(--heading);
  --mc-conditional:#8E8574;

  --mc-ramp-1:#ECE6D9;   /* highest */
  --mc-ramp-2:#BDB3A0;
  --mc-ramp-3:#8E8574;
  --mc-ramp-4:#635C4F;
  --mc-ramp-5:#413B32;   /* lowest */
  --mc-tint:#2A251D;

  /* stroke widths — theme-independent, identical everywhere */
  --mc-stroke-axis:1.5px;
  --mc-stroke-gridline:1px;
  --mc-stroke-shape-outline:1px;   /* outline on EVERY filled/patterned mark */
  --mc-stroke-node:1.6px;
  --mc-stroke-node-primary:3.5px;  /* entry point */
  --mc-stroke-edge:1.8px;
  --mc-stroke-edge-conditional:1.6px;

  /* type — theme-independent */
  --mc-font-sans:var(--font-read);
  --mc-font-mono:var(--font-code);
  --mc-text-h2:26px;
  --mc-text-chart-title:15px;      /* weight 500 */
  --mc-text-node:15px;
  --mc-text-body:14.5px;
  --mc-text-label:14px;            /* axis category labels — HARD FLOOR on screen */
  --mc-text-caption:13.5px;
  --mc-text-value:13px;            /* mono, data values */
  --mc-text-tick:12px;             /* mono, axis ticks */
  --mc-text-eyebrow:11px;          /* mono, uppercase, tracking .14em */
  --mc-text-node-caption:11px;

  /* geometry — theme-independent */
  --mc-radius-card:4px;
  --mc-radius-chip:3px;
  --mc-chart-max:100%;             /* charts fill their column (viewBox is 640 units) */
  --mc-shadow:none;                /* the system uses no shadows */
  --mc-gradient:none;              /* and no gradients, ever */
  --mc-motion:none;                /* charts do not animate */

  /* texture — theme-independent */
  --mc-pattern-period:8px;         /* minimum tile — below this it shimmers */
  --mc-pattern-hatch-width:3.4px;
  --mc-pattern-dot-radius:2.4px;
  --mc-pattern-grid-width:1.6px;
}

html.light {
  --mc-surface:#FFFDF8;
  --mc-inverse:#1F1E1B;
  --mc-on-inverse:#F4F2EC;

  --mc-ink:#1F1E1B;
  --mc-ink-secondary:#3C3A35;
  --mc-ink-muted:#6E6A62;
  --mc-border:#DBD7CD;
  --mc-axis:#1F1E1B;
  --mc-conditional:#5C5850;

  --mc-ramp-1:#1F1E1B;   /* highest */
  --mc-ramp-2:#4F4C45;
  --mc-ramp-3:#7C786F;
  --mc-ramp-4:#ABA79D;
  --mc-ramp-5:#D5D1C7;   /* lowest */
  --mc-tint:#EAE7DF;
}

html.calm {
  --mc-inverse:#F2EAD8;
  --mc-on-inverse:#17140E;
  --mc-conditional:#9C8F74;

  --mc-ramp-1:#F2EAD8;
  --mc-ramp-2:#C9BC9E;
  --mc-ramp-3:#9C8F74;
  --mc-ramp-4:#6E6450;
  --mc-ramp-5:#453E30;
  --mc-tint:#2A2418;
}

/* ── Print: prepare for the worst — a copy that reads on paper, no power required ── */
@media print {
  :root { color-scheme: light; }
  html, body { background: #fff; }
  body { color: #111; font-size: 11pt; line-height: 1.5; }

  /* Drop interactive + navigational chrome. */
  .site-top, .accent-line, .toc, .site-footer, .scry-fp,
  .ask-cta, .featured-cta { display: none !important; }

  /* Single-column, full-bleed article. */
  .layout { display: block; }
  .article { max-width: none; width: auto; margin: 0; padding: 0; }

  /* Ink-economical type. */
  h1, h2, h3, .h1, .h2, .h3, .title, .heading { color: #000; }
  a { color: #000; text-decoration: underline; }

  /* Preserve external link targets on paper. */
  .article a[href^="http"]::after {
    content: " (" attr(href) ")"; font-size: .85em; color: #333; word-break: break-all;
  }

  /* Don't split figures, tables, or code across pages; keep headings with bodies. */
  figure, table, pre, .scry-callout, .scry-insight__body, .obs-fig, .scry-table { page-break-inside: avoid; break-inside: avoid; }
  h1, h2, h3 { page-break-after: avoid; }

  /* Legible boxes without color fills. */
  pre, code, .scry-callout, table, th, td {
    border-color: #999 !important; background: transparent !important; color: #111 !important;
  }
}
/* ============================================================
   scryops — parameterised figure shortcodes
   Append to themes/scryops/assets/css/telemetry.css.

   The shortcodes emit MARKUP ONLY and read their styling from here, so a
   page with six figures ships one copy of these rules instead of six.

   Every rule below encodes rank on a non-colour channel. Nothing in this
   block references --cyan / --warn / --danger / --green: those collapse
   under html.pref-mono. Ramp steps are referenced directly.
   ============================================================ */

/* shared glyph — the Callout silhouette set, used by every figure */
.obs-g{width:12px;height:12px;flex:none;display:block}

/* ---- ranked rows: rail value + rail width + glyph ---- */
.obs-rank{display:flex;flex-direction:column;gap:12px;font-family:var(--font-code)}
.obs-rank__row{display:grid;grid-template-columns:auto minmax(0,1fr);gap:12px;align-items:start;
  background:var(--surface);border:1px solid var(--mc-border);border-radius:var(--mc-radius-chip);padding:13px 16px}
/* rank-ladder escalation (0.5px increments) has no canonical charts.css
   equivalent — it's a 4-step severity scale, not a single named role like
   --mc-stroke-node. Left literal on purpose rather than force one of the
   four onto --mc-stroke-node-primary just because 3.5px happens to match. */
.obs-rank__row[data-rank="0"]{border-left:1.5px solid var(--mc-ramp-3)}
.obs-rank__row[data-rank="1"]{border-left:2.5px solid var(--mc-ramp-2)}
.obs-rank__row[data-rank="2"]{border-left:3.5px solid var(--mc-ramp-1)}
.obs-rank__row[data-rank="3"]{border-left:4px solid var(--mc-ramp-1)}
.obs-rank__g{margin-top:3px}
.obs-rank__head{font-size:var(--mc-text-value);line-height:1.5;color:var(--mc-ink);font-weight:600}
.obs-rank__act{font-family:var(--font-read);font-size:var(--mc-text-label);line-height:1.55;color:var(--mc-ink-secondary);margin:4px 0 0}

/* ---- decision stem ---- */
.obs-dt{font-family:var(--font-code);container-type:inline-size}
.obs-dt__hd{font-family:var(--font-code);font-weight:600;font-size:var(--mc-text-value);line-height:1.5;color:var(--mc-ink);margin-bottom:9px}
.obs-dt__sub{font-size:var(--mc-text-tick);color:var(--mc-ink-muted);margin-bottom:20px}
.obs-dt__body{display:grid;grid-template-columns:minmax(0,178px) 56px minmax(0,1fr);align-items:center}
.obs-dt__body.noStem{grid-template-columns:minmax(0,1fr)}
.obs-dt__stem{display:flex;flex-direction:column}
.obs-dt__node{background:var(--surface);border:var(--mc-stroke-node) solid var(--mc-ink);border-radius:var(--mc-radius-chip);padding:11px 15px;text-align:center}
.obs-dt__node.entry{border-width:var(--mc-stroke-node-primary)}
.obs-dt__node.tint{background:var(--mc-tint,var(--surface))}
.obs-dt__nm{font-size:var(--mc-text-node);line-height:1.35;color:var(--mc-ink)}
.obs-dt__cap{display:block;font-size:var(--mc-text-node-caption);color:var(--mc-ink-muted);line-height:1.4;margin-top:4px}
.obs-dt__link{display:flex;flex-direction:column;align-items:center;gap:2px;padding:7px 0;color:var(--mc-ink);font-size:var(--mc-text-node-caption)}
.obs-dt__link span{color:var(--mc-ink-muted)}
.obs-dt__fan{display:flex;align-items:center;justify-content:center;color:var(--mc-ink)}
@container (max-width:520px){
  .obs-dt__body{grid-template-columns:1fr}
  .obs-dt__fan{display:none}
}

/* ---- gauge: extent + segmentation + state-on-the-spent-portion ---- */
.obs-gauge{font-family:var(--font-code);display:block}
.obs-gauge__top{display:flex;align-items:baseline;gap:10px;margin-bottom:7px}
.obs-gauge__label{font-size:var(--mc-text-eyebrow);letter-spacing:.1em;text-transform:uppercase;color:var(--mc-ink-muted)}
.obs-gauge__val{margin-left:auto;font-size:var(--mc-text-value);color:var(--mc-ink);font-weight:600;display:inline-flex;align-items:center;gap:7px}
.obs-gauge__track{display:flex;gap:2px;padding:3px;border:var(--mc-stroke-shape-outline) solid var(--mc-border);background:var(--surface);position:relative}
/* warn/critical border escalation is its own 2-step severity scale, same
   reasoning as the rank-ladder above — 1.8px coincides with --mc-stroke-edge
   but 2.5px (critical) has no canonical match, so both stay literal rather
   than tokenize one step and not the other. */
.obs-gauge__track[data-state="warn"]{border-width:1.8px}
.obs-gauge__track[data-state="critical"]{border-width:2.5px}
.obs-gauge__cell{flex:1;height:22px;min-width:3px;background:var(--mc-ramp-1)}
/* filled cells stay SOLID — they are the value. State escalates on the spent
   portion, so every channel increases monotonically with severity. */
.obs-gauge__cell.off{background:transparent;border:var(--mc-stroke-shape-outline) solid var(--mc-border)}
.obs-gauge__track[data-state="warn"] .obs-gauge__cell.off{
  background-image:repeating-linear-gradient(45deg,var(--mc-ramp-4) 0 3px,transparent 3px 9px)}
.obs-gauge__track[data-state="critical"] .obs-gauge__cell.off{
  background-image:repeating-linear-gradient(45deg,var(--mc-ramp-3) 0 4px,transparent 4px 9px)}
.obs-gauge__tick{position:absolute;top:-4px;bottom:-4px;width:2px;background:var(--mc-ink)}
.obs-gauge__note{font-size:var(--mc-text-node-caption);color:var(--mc-ink-muted);margin-top:7px;line-height:1.5}
.obs-gauge__pips{display:inline-flex;gap:4px;align-items:center}
.obs-gauge__pip{width:13px;height:13px;flex:none;background:var(--mc-ramp-1)}
.obs-gauge__pip.off{background:transparent;border:var(--mc-stroke-shape-outline) solid var(--mc-border)}
.obs-gauge__pipnum{font-size:var(--mc-text-node-caption);color:var(--mc-ink-muted);margin-left:6px}

/* ---- ranked bars (template 01): length + ramp value + printed figure ---- */
.obs-bars{font-family:var(--font-code);display:flex;flex-direction:column;gap:10px}
.obs-bars__row{display:grid;grid-template-columns:minmax(0,150px) minmax(0,1fr) auto;gap:12px;align-items:center}
.obs-bars__lab{font-family:var(--font-read);font-size:var(--mc-text-label);color:var(--mc-ink);text-align:right}
.obs-bars__track{height:30px;position:relative}
.obs-bars__fill{height:100%;border:var(--mc-stroke-shape-outline) solid var(--mc-ink)}
.obs-bars__val{font-size:var(--mc-text-value);color:var(--mc-ink-secondary);white-space:nowrap}
.obs-bars__row.on .obs-bars__fill{border-width:var(--mc-stroke-node-primary)}
.obs-bars__row.on .obs-bars__lab,.obs-bars__row.on .obs-bars__val{color:var(--mc-ink);font-weight:600}

/* ---- series (template 03b): stroke weight + dash + marker, per series ----
   Sizes are set here rather than as SVG attributes so they follow the type
   floor. The chart's 640-unit viewBox renders at the card's content width, so
   a declared size is multiplied by renderedWidth/640 — at a typical 636px card
   that is 0.994, which pushed a declared 12px to 11.93px rendered, just under
   the 11px floor's nearest step. Sizes carry a small margin for that: ticks
   and captions 12.5px, x labels 13.5px, end labels 14.5px. Never lower them
   without re-measuring RENDERED size (computedFontSize x scale). */
.obs-ser{width:100%;height:auto;display:block;font-family:var(--font-code)}
.obs-ser__hd{font-family:var(--font-read);font-size:var(--mc-text-chart-title);font-weight:500;color:var(--mc-ink);margin-bottom:4px}
.obs-ser__sub{font-family:var(--font-code);font-size:var(--mc-text-tick);color:var(--mc-ink-muted);margin-bottom:14px}
/* tick/thr/ev are SVG text in this chart's 640-unit viewBox (see the
   render-scaling comment above) — 12.5px was deliberately measured to
   survive that scaling; canonical --mc-text-tick is 12px declared, which
   would reopen the exact bug this session already fixed. Left literal
   until the canonical token itself accounts for viewBox scaling. */
.obs-ser__tick{font-size:12.5px;fill:var(--mc-ink-muted)}
.obs-ser__xlab{font-family:var(--font-read);font-size:var(--mc-text-caption);fill:var(--mc-ink)}
.obs-ser__end{font-family:var(--font-read);font-size:var(--mc-text-body);font-weight:500;fill:var(--mc-ink)}
.obs-ser__thr{font-size:12.5px;fill:var(--mc-ink-muted)}
.obs-ser__ev{font-size:12.5px;fill:var(--mc-ink)}

/* ---- column (template 01b): vertical sibling of obs-ranked-bars, log scale ----
   Same viewBox-scaling note as obs-ser above: tick/y-label text stays at
   the measured-safe 12.5px rather than canonical --mc-text-tick (12px);
   value/label text (13/14px canonical) already clears the floor with
   margin at this scale, so those reference the tokens directly. */
.obs-col{width:100%;height:auto;display:block;font-family:var(--font-code)}
.obs-col__hd{font-family:var(--font-read);font-size:var(--mc-text-chart-title);font-weight:500;color:var(--mc-ink);margin-bottom:4px}
.obs-col__sub{font-family:var(--font-code);font-size:var(--mc-text-tick);color:var(--mc-ink-muted);margin-bottom:14px}
.obs-col__tick{font-size:12.5px;fill:var(--mc-ink-muted)}
.obs-col__val{font-family:var(--font-code);font-size:var(--mc-text-value);fill:var(--mc-ink-secondary)}
.obs-col__val.on{fill:var(--mc-ink)}
.obs-col__lab{font-family:var(--font-code);font-size:var(--mc-text-label);fill:var(--mc-ink-secondary)}
.obs-col__lab.on{fill:var(--mc-ink)}
.obs-col__cap{font-size:12.5px;fill:var(--mc-ink-muted)}

/* ---- waterfall (template 08): span timeline, self-time vs waiting ----
   Same viewBox-scaling note as obs-ser/obs-col above: tick/name/value text
   (all SVG fill:, not HTML color:) stays at the measured-safe 12.5px
   rather than canonical --mc-text-tick (12px). hd/sub are plain HTML divs
   with no scaling risk, so those reference the tokens directly. */
.obs-wf{width:100%;height:auto;display:block;font-family:var(--font-code)}
.obs-wf__hd{font-family:var(--font-read);font-size:var(--mc-text-chart-title);font-weight:500;color:var(--mc-ink);margin-bottom:4px}
.obs-wf__sub{font-size:var(--mc-text-tick);color:var(--mc-ink-muted);margin-bottom:14px}
.obs-wf__tick{font-size:12.5px;fill:var(--mc-ink-muted)}
.obs-wf__nm{font-size:12.5px;fill:var(--mc-ink-secondary)}
.obs-wf__nm.on{fill:var(--mc-ink);font-weight:600}
.obs-wf__val{font-size:12.5px;fill:var(--mc-ink-muted)}
.obs-wf__val.on{fill:var(--mc-ink);font-weight:600}
.obs-wf__key{display:flex;gap:18px;flex-wrap:wrap;margin-top:13px;padding-top:11px;
  border-top:1px solid var(--mc-border);font-size:var(--mc-text-node-caption);color:var(--mc-ink-muted)}
.obs-wf__key span{display:inline-flex;align-items:center;gap:6px}
.obs-wf__sw{width:22px;height:11px;flex:none;border:1px solid var(--mc-ink)}
.obs-wf__sw.auto{background:var(--mc-ramp-3)}
.obs-wf__sw.manual{background:var(--mc-ramp-2);border-width:2px}
.obs-wf__sw.err{background:var(--mc-ramp-1);border-style:dashed}
.obs-wf__sw.hatch{background:repeating-linear-gradient(45deg,var(--mc-ink) 0 3px,var(--surface) 3px 9px)}
.obs-wf__sw.heavy{background:var(--mc-ramp-1);border-width:3px}

/* ---- state machine (template 07): glyph rank + entry border + return lane ---- */
.obs-sm{font-family:var(--font-code);container-type:inline-size}
.obs-sm__hd{font-family:var(--font-code);font-weight:600;font-size:var(--mc-text-value);line-height:1.5;color:var(--mc-ink);margin-bottom:9px}
.obs-sm__sub{font-size:var(--mc-text-tick);color:var(--mc-ink-muted);margin-bottom:20px}
.obs-sm__row{display:flex;align-items:stretch;flex-wrap:nowrap}
.obs-sm__st{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;gap:7px;
  background:var(--surface);border:var(--mc-stroke-node) solid var(--mc-ink);border-radius:var(--mc-radius-chip);padding:14px 12px;text-align:center}
.obs-sm__st.entry{border-width:var(--mc-stroke-node-primary)}
.obs-sm__st.tint{background:var(--mc-tint,var(--surface))}
.obs-sm__nm{font-size:var(--mc-text-node);line-height:1.3;color:var(--mc-ink)}
.obs-sm__cap{font-size:var(--mc-text-node-caption);color:var(--mc-ink-muted);line-height:1.4}
.obs-sm__edge{flex:none;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  padding:0 11px;min-width:74px;color:var(--mc-ink)}
.obs-sm__arrow{font-size:16px;line-height:1}
.obs-sm__trig{font-size:var(--mc-text-node-caption);color:var(--mc-ink-muted);text-align:center;line-height:1.35}
/* returns: a dashed lane, so the forward path stays readable instead of
   carrying crossing arrows back across the row */
.obs-sm__returns{margin-top:16px;display:flex;flex-direction:column;gap:9px}
.obs-sm__ret{display:grid;grid-template-columns:auto minmax(0,1fr);gap:11px;align-items:center;
  border-top:1px dashed var(--mc-border);padding-top:9px}
.obs-sm__retg{font-size:var(--mc-text-label);line-height:1;color:var(--mc-ink)}
.obs-sm__rett{font-size:var(--mc-text-tick);color:var(--mc-ink-secondary);line-height:1.5}
.obs-sm__rett b{color:var(--mc-ink);font-weight:600}
@container (max-width:520px){
  .obs-sm__row{flex-direction:column}
  .obs-sm__edge{padding:8px 0;min-width:0}
}

/* ---- flow (template 05): one-direction flow, DOM boxes not SVG ----
   Ported from the handoff's FlowDiagram.jsx. One meaning per channel:
   border weight = rank (entry), fill = kind (paper/tint/grid/terminal),
   dash = conditionality. Never wraps a row — below ~520px it re-flows to
   the vertical arrangement (arrows swap to down) instead of scrolling. */
.obs-flow-wrap{container-type:inline-size}
.obs-flow__hd{font-family:var(--font-code);font-weight:600;font-size:var(--mc-text-value);line-height:1.5;color:var(--mc-ink);margin-bottom:9px}
.obs-flow__sub{font-size:var(--mc-text-tick);color:var(--mc-ink-muted);margin-bottom:20px}
/* row label for stacked-comparison usage (obs-reactive-loop): a plain
   mono tag, deliberately the SAME neutral tone for every row — the old
   .flow-version.v2{color:var(--cyan)} split had no meaning to carry, it
   just tinted the "new model" row for no reason other than novelty */
.obs-flow__rowlabel{font-family:var(--font-code);font-size:11px;letter-spacing:.08em;color:var(--mc-ink-muted);margin-bottom:9px}
.obs-flow{display:flex;align-items:stretch;flex-wrap:nowrap;overflow-x:auto;font-family:var(--mc-font-sans)}
.obs-flow.stack{flex-direction:column;align-items:stretch;overflow-x:visible}
.obs-flow__node{flex:1 1 0;min-width:86px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;
  background:var(--mc-surface);border:var(--mc-stroke-node) solid var(--mc-ink);border-radius:var(--mc-radius-chip);padding:15px 12px;text-align:center}
.obs-flow__node.entry{border-width:var(--mc-stroke-node-primary)}
.obs-flow__node.tint{background:var(--mc-tint)}
.obs-flow__node.grid{
  background-image:linear-gradient(var(--mc-ink) 1.6px,transparent 1.6px),linear-gradient(90deg,var(--mc-ink) 1.6px,transparent 1.6px);
  background-size:9px 9px;background-color:var(--mc-surface)}
.obs-flow__node.terminal{background:var(--mc-inverse);border-color:var(--mc-inverse)}
.obs-flow__node.conditional{border-style:dashed}
.obs-flow__nm{font-size:var(--mc-text-node);font-weight:500;line-height:1.3;color:var(--mc-ink)}
.obs-flow__cap{font-family:var(--mc-font-mono);font-size:var(--mc-text-node-caption);color:var(--mc-ink-muted);line-height:1.3}
.obs-flow__text{display:flex;flex-direction:column;align-items:center;gap:6px}
/* text over ANY pattern fill sits on one contiguous surface-coloured band,
   so no pattern lines run between the label and its caption */
.obs-flow__node.grid .obs-flow__text{background:var(--mc-surface);border-radius:2px;padding:4px 8px}
.obs-flow__node.terminal .obs-flow__nm{color:var(--mc-on-inverse)}
.obs-flow__node.terminal .obs-flow__cap{color:var(--mc-on-inverse);opacity:.72}
.obs-flow__edge{flex:none;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:0 10px;min-width:32px;color:var(--mc-ink)}
.obs-flow__edge.cond{color:var(--mc-conditional)}
.obs-flow__arrow{font-size:16px;line-height:1}
.obs-flow__arrow .a-col{display:none}
.obs-flow__elabel{font-family:var(--mc-font-mono);font-size:var(--mc-text-node-caption);color:var(--mc-ink-muted);text-align:center;max-width:66px;line-height:1.3}
.obs-flow.stack .obs-flow__edge{padding:8px 0}
.obs-flow.stack .obs-flow__arrow .a-row{display:none}
.obs-flow.stack .obs-flow__arrow .a-col{display:inline}
.obs-flow.stack .obs-flow__elabel{max-width:none}
/* a row needs ~520px for 4 nodes plus edge labels; below that, flow DOWN
   rather than scroll — vertical is a first-class direction here */
@container (max-width:520px){
  .obs-flow:not(.stack){flex-direction:column;align-items:stretch;overflow-x:visible}
  .obs-flow:not(.stack) .obs-flow__edge{padding:8px 0}
  .obs-flow:not(.stack) .obs-flow__arrow .a-row{display:none}
  .obs-flow:not(.stack) .obs-flow__arrow .a-col{display:inline}
  .obs-flow:not(.stack) .obs-flow__elabel{max-width:none}
}

/* Mermaid state diagrams. Painted here rather than relying on baked
   attributes: the tokenizer strips mermaid's stylesheet, and state-diagram
   theme variables were absent from the sentinel palette, so these figures
   rendered with browser defaults (black on black). Every value is a
   neutral figure token — no --cyan / --warn / --danger, which collapse
   under html.pref-mono. */
.statediagram .node rect,
.statediagram .node circle,
.statediagram .node polygon{fill:var(--node-fill);stroke:var(--node-stroke);stroke-width:1.6px}
.statediagram .node.state-start circle{fill:var(--mc-ramp-1);stroke:none}
.statediagram .node .label-container{fill:var(--node-fill);stroke:var(--node-stroke)}
.statediagram .nodeLabel,
.statediagram .nodeLabel tspan{fill:var(--nlab);font-family:var(--font-code);font-size:13px}
.statediagram .transition{stroke:var(--edge);stroke-width:1.8px;fill:none}
.statediagram .edgeLabel rect{fill:var(--fig-bg);stroke:none}
.statediagram .edgeLabel,
.statediagram .edgeLabel tspan{fill:var(--mc-ink-secondary);font-family:var(--font-code);font-size:12px}
.statediagram marker path,
.statediagram .marker{fill:var(--edge);stroke:var(--edge)}

/* ---- migrated from shortcode inline <style> blocks ---- */

/* obs-about-sections.html */
.about-sections {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
  margin: 1.4rem 0 0.4rem;
}
.about-sec-card {
  display: flex;
  flex-direction: column;
  background: var(--fig-bg);
  border: 1px solid var(--border);
  padding: 1.2rem 1.2rem 1rem;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s, background 0.15s;
}
.about-sec-article { border-top: 3px solid var(--cyan); }
.about-sec-guide   { border-top: 3px solid var(--cyan); }
.about-sec-howto   { border-top: 3px solid var(--warn); }
.about-sec-qa      { border-top: 3px solid var(--violet); }
.about-sec-card:hover { background: var(--warn-bg); }
.about-sec-article:hover { border-color: var(--cyan); }
.about-sec-guide:hover   { border-color: var(--cyan); }
.about-sec-howto:hover   { border-color: var(--warn); }
.about-sec-qa:hover      { border-color: var(--violet); }
.about-sec-tag {
  font-family: var(--font-code);
  font-size:0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 0.7rem;
  display: block;
}
.about-sec-article .about-sec-tag { color: var(--cyan); }
.about-sec-guide   .about-sec-tag { color: var(--cyan); }
.about-sec-howto   .about-sec-tag { color: var(--warn); }
.about-sec-qa      .about-sec-tag { color: var(--violet); }
.about-sec-title {
  font-family: var(--font-code);
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--heading);
  margin-bottom: 0.5rem;
}
.about-sec-desc {
  font-size: 0.82rem;
  line-height: 1.65;
  color: var(--muted);
  flex: 1;
  margin-bottom: 1rem;
}
.about-sec-cta {
  font-size: 0.75rem;
  color: var(--warn);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-top: auto;
}
.about-sec-card:hover .about-sec-cta { color: var(--warn); }
@media (max-width: 700px) {
  .about-sections { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 420px) {
  .about-sections { grid-template-columns: 1fr; }
}

/* obs-alert-fatigue-stats.html */
.af-wrap{background:var(--fig-bg);border:1px solid var(--border);border-top:3px solid var(--mc-ink);padding:1.4rem 1.4rem 1.2rem;font-family:var(--font-code);}
.af-hdr{font-family:var(--font-code);font-size:.6875rem;color:var(--mc-ink-muted);letter-spacing:.1em;text-align:center;margin-bottom:1.3rem;}
.af-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:1.6rem;}
@media(max-width:640px){.af-grid{grid-template-columns:repeat(2,1fr);}}
.af-card{background:var(--bg);border:1px solid var(--border);border-top:3px solid;display:flex;flex-direction:column;align-items:center;text-align:center;gap:.35rem;padding:1rem .8rem .85rem;}
.af-glyph{width:14px;height:14px;margin-bottom:.15rem;}
.af-num{font-size:2.3rem;font-weight:700;line-height:1;letter-spacing:-.02em;}
.af-desc{font-size:.78rem;color:var(--mc-ink-muted);line-height:1.5;flex:1;}
.af-bars-hdr{font-family:var(--font-code);font-size:0.6875rem;color:var(--mc-ink-muted);letter-spacing:.08em;margin-bottom:.5rem;}
.af-div{height:1px;background:var(--border);margin-bottom:1rem;}
.af-row{display:grid;grid-template-columns:190px 1fr;align-items:center;gap:.8rem;margin-bottom:.7rem;}
@media(max-width:640px){.af-row{grid-template-columns:110px 1fr;}}
.af-lbl{font-size:.8rem;color:var(--mc-ink-muted);text-align:right;line-height:1.35;}
@media(max-width:640px){.af-lbl{font-size:.68rem;}}
.af-track{background:var(--bg);border:1px solid var(--border);height:30px;position:relative;overflow:hidden;}
.af-bar{height:100%;display:flex;align-items:center;justify-content:flex-end;}
.af-bar span{font-size:.8rem;font-weight:700;padding-right:.5rem;}
.af-axis{display:flex;justify-content:space-between;margin-left:calc(190px + .8rem);font-size:.72rem;color:var(--mc-ink-muted);padding-top:.2rem;}
@media(max-width:640px){.af-axis{margin-left:calc(110px + .8rem);font-size:.64rem;}}
.af-src{margin-top:1.1rem;font-family:var(--font-code);font-size:0.6875rem;line-height:1.7;color:var(--mc-ink-muted);letter-spacing:.03em;}
figure.af-fig{margin:2.5rem 0 2rem;}
figure.af-fig figcaption{font-size:.7rem;color:var(--mc-ink-muted);font-style:italic;margin-top:.6rem;padding-left:.2rem;}

/* obs-alert-routing.html */
.rt-wrap{background:var(--fig-bg);border:1px solid var(--border);border-top:3px solid var(--mc-ink);padding:1.4rem 1.4rem 1.2rem;font-family:var(--font-code);}
.rt-hdr{font-family:var(--font-code);font-size:.6875rem;color:var(--mc-ink-muted);letter-spacing:.1em;text-align:center;margin-bottom:1.3rem;}
.rt-cols{display:grid;grid-template-columns:104px 1fr 1fr 132px;gap:.8rem;padding:0 .2rem .4rem;font-family:var(--font-code);font-size:.6875rem;color:var(--mc-ink-muted);letter-spacing:.06em;}
.rt-cols span:last-child{text-align:right;}
@media(max-width:640px){.rt-cols{display:none;}}
.rt-lane{background:var(--surface);border:1px solid var(--border);border-left-style:solid;display:grid;grid-template-columns:104px 1fr 1fr 132px;gap:.8rem;align-items:center;padding:.95rem .8rem;margin-bottom:.7rem;}
@media(max-width:640px){.rt-lane{grid-template-columns:1fr;gap:.55rem;}}
.rt-badge{display:flex;flex-direction:column;gap:.25rem;}
.rt-p{display:flex;align-items:center;gap:.45rem;font-size:1.5rem;font-weight:700;line-height:1;color:var(--mc-ink);}
.rt-g{width:14px;height:14px;flex:none;display:block;}
.rt-burn{font-size:.6rem;color:var(--mc-ink-muted);letter-spacing:.04em;}
.rt-cell{font-size:.82rem;color:var(--mc-ink-secondary);line-height:1.45;}
.rt-cell b{color:var(--mc-ink);font-weight:700;}
.rt-cell small{display:block;color:var(--mc-ink-muted);font-size:.72rem;margin-top:.15rem;}
.rt-route{font-size:.82rem;color:var(--mc-ink-secondary);line-height:1.45;}
.rt-route small{display:block;color:var(--mc-ink-muted);font-size:.72rem;margin-top:.15rem;}
.rt-route::before{content:"\2192";color:var(--mc-ink-muted);margin-right:.4rem;font-weight:700;}
@media(max-width:640px){.rt-route::before{content:"\2192 ";}}
.rt-tag{justify-self:end;font-family:var(--font-code);font-size:.6875rem;letter-spacing:.04em;padding:.45rem .55rem;border-style:solid;text-align:center;line-height:1.4;color:var(--mc-ink);}
@media(max-width:640px){.rt-tag{justify-self:start;}}
.rt-foot{margin-top:1rem;padding-top:.9rem;border-top:1px solid var(--border);font-size:.8rem;color:var(--mc-ink-muted);line-height:1.5;}
.rt-foot b{color:var(--mc-ink);}
figure.rt-fig{margin:2.5rem 0 2rem;}
figure.rt-fig figcaption{font-size:.7rem;color:var(--mc-ink-muted);font-style:italic;margin-top:.6rem;padding-left:.2rem;}

/* obs-knowledge-tiers.html */
.knt-wrap{background:var(--fig-bg);border:1px solid var(--border);border-top:3px solid var(--mc-ink);padding:1.4rem 1.4rem 1.2rem;font-family:var(--font-code);}
.knt-hdr{font-family:var(--font-code);font-size:.6875rem;color:var(--mc-ink-muted);letter-spacing:.1em;text-align:center;margin-bottom:1.3rem;}
.knt-lane{background:var(--surface);border:1px solid var(--border);border-left-style:solid;display:grid;grid-template-columns:26px 180px 1fr 148px;gap:.8rem;align-items:center;padding:.95rem .8rem;margin-bottom:.7rem;}
@media(max-width:640px){.knt-lane{grid-template-columns:22px 1fr;gap:.55rem;}}
.knt-glyph{width:14px;height:14px;}
.knt-lp{font-family:var(--font-code);font-size:0.6875rem;font-weight:700;line-height:1.5;}
.knt-ls{font-family:var(--font-code);font-size:0.6875rem;color:var(--mc-ink-muted);letter-spacing:.06em;margin-top:.3rem;}
.knt-desc{font-size:.82rem;color:var(--mc-ink-secondary);line-height:1.5;}
.knt-desc b{color:var(--mc-ink);}
.knt-desc small{display:block;color:var(--mc-ink-muted);font-size:.72rem;margin-top:.2rem;}
.knt-tag{font-family:var(--font-code);font-size:0.6875rem;letter-spacing:.04em;padding:.45rem .55rem;border:1px solid;text-align:center;line-height:1.6;justify-self:end;}
@media(max-width:640px){.knt-tag{justify-self:start;grid-column:2;}}
.knt-foot{margin-top:1rem;padding-top:.9rem;border-top:1px solid var(--border);font-size:.8rem;color:var(--mc-ink-muted);line-height:1.5;}
.knt-foot b{color:var(--mc-ramp-1);}

/* obs-stats-chart.html */
.obs-chart-wrap{background:var(--fig-bg);border:1px solid var(--border);border-top:3px solid var(--warn);padding:1.4rem 1.4rem 1.2rem;font-family:var(--font-code);}
.obs-chart-hdr{font-family:var(--font-code);font-size:.6875rem;color:var(--muted);letter-spacing:.1em;text-align:center;margin-bottom:1.2rem;}
.obs-stat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:1.6rem;}
@media(max-width:640px){.obs-stat-grid{grid-template-columns:repeat(2,1fr);}}
.obs-stat-card{background:var(--bg);border:1px solid var(--border);border-top:3px solid;display:flex;flex-direction:column;align-items:center;text-align:center;gap:.3rem;padding:1rem .8rem .8rem;}
.obs-stat-card svg.obs-stat-glyph{width:13px;height:13px;display:block;}
.obs-stat-num{font-size:2.4rem;font-weight:700;line-height:1;letter-spacing:-.02em;}
.obs-stat-desc{font-size:.78rem;color:var(--muted);line-height:1.5;flex:1;}
.obs-stat-src{font-family:var(--font-code);font-size:.6875rem;color:var(--muted);letter-spacing:.04em;margin-top:.4rem;}
.obs-mttd-hdr{font-family:var(--font-code);font-size:.6875rem;color:var(--muted);letter-spacing:.1em;margin-bottom:.5rem;}
.obs-mttd-div{height:1px;background:var(--border);margin-bottom:1rem;}
.obs-mttd-row{display:grid;grid-template-columns:160px 1fr auto;align-items:center;gap:.8rem;margin-bottom:.7rem;}
@media(max-width:640px){.obs-mttd-row{grid-template-columns:90px 1fr auto;}}
.obs-mttd-lbl{font-size:.8rem;color:var(--muted);text-align:right;word-break:break-word;line-height:1.4;}
@media(max-width:640px){.obs-mttd-lbl{font-size:.7rem;}}
.obs-mttd-track{background:var(--bg);border:1px solid var(--border);height:28px;position:relative;overflow:hidden;}
.obs-mttd-bar{height:100%;width:0;transition:width .9s cubic-bezier(.25,.46,.45,.94);position:relative;display:flex;align-items:center;}
@media(prefers-reduced-motion:reduce){.obs-mttd-bar{transition:none;}}
.obs-mttd-bar-fill{position:absolute;inset:0;opacity:.22;}
.obs-mttd-bar-border{position:absolute;inset:0;border:1.5px solid;}
.obs-mttd-val{font-size:.8rem;font-weight:700;white-space:nowrap;padding-left:.4rem;}
.obs-mttd-badge{font-size:.8rem;font-weight:700;white-space:nowrap;text-align:right;min-width:80px;}
.obs-mttd-badge small{display:block;font-size:.7rem;font-weight:400;color:var(--muted);}
.obs-mttd-lbl svg.obs-mttd-glyph{width:12px;height:12px;flex:none;display:inline-block;vertical-align:-1.5px;margin-right:.4rem;}
.obs-mttd-axis{display:flex;justify-content:space-between;padding:.3rem 0 0;margin-left:calc(160px + .8rem);font-size:.75rem;color:var(--muted);}
@media(max-width:640px){.obs-mttd-axis{margin-left:calc(90px + .8rem);font-size:.7rem;}}
.obs-src{margin-top:1.2rem;font-family:var(--font-code);font-size:.6875rem;color:var(--muted);letter-spacing:.04em;}
figure.obs-fig{margin:2.5rem 0 2rem;}
figure.obs-fig figcaption{font-size:.7rem;color:var(--muted);font-style:italic;margin-top:.6rem;padding-left:.2rem;}

/* party-gallery.html */
.party-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:1.1rem;margin:1.5rem 0;}
.party-card{margin:0;background:var(--surface);border:1px solid var(--border);border-top:3px solid var(--ac);border-radius:3px;overflow:hidden;display:flex;flex-direction:column;}
.party-art{background:var(--bg);aspect-ratio:1/1;display:flex;align-items:center;justify-content:center;}
.party-art img{width:100%;height:100%;object-fit:contain;image-rendering:pixelated;display:block;}
.party-ph{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;width:88%;height:88%;border:2px dashed var(--border);border-radius:3px;color:var(--muted);}
.party-ph-cls{font-family:'Press Start 2P',monospace;font-size:.7rem;color:var(--ac);opacity:.8;}
.party-ph-sub{font-family:var(--font-code);font-size:.7rem;letter-spacing:.06em;}
.party-meta{padding:.9rem 1rem 1.1rem;font-family:var(--font-code);}
.party-name{display:block;font-family:'Press Start 2P',monospace;font-size:.66rem;line-height:1.5;margin-bottom:.35rem;}
.party-cls{display:block;font-size:.72rem;color:var(--muted);margin-bottom:.55rem;}
.party-quip{margin:0;font-size:.86rem;line-height:1.55;color:var(--text);}

