/* ─────────────────────────────────────────────────────────────────────────
   RM DESIGN SYSTEM v1 (21 July 2026)
   Measured from elevenlabs.io, adapted under Fred's laws:
   one family (Inter), NO grey typography (all type #000), one line colour.
   Inter substitutes their proprietary Waldenburg at display sizes.
   Documented at /system.html.
   ───────────────────────────────────────────────────────────────────────── */

:root {
  /* Colour */
  --ink: #000000;            /* the only text colour */
  --paper: #ffffff;
  --paper-warm: #f5f3f1;     /* their card/panel bone */
  --paper-warm-2: #ebe8e4;   /* deeper bone, hover fills */
  --line: #eeeeee;           /* every rule and hairline (Fred's lightened value) */
  --ring: rgba(0, 0, 0, 0.08);
  --tint: rgba(41, 37, 36, 0.05);       /* their 5% warm hover tint */
  --ink-hover: #44403b;      /* black buttons warm to charcoal on hover */

  /* Type scale */
  --sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --fs-display: clamp(38px, 5.5vw, 56px);
  --fs-h2: clamp(27px, 4vw, 36px);
  --fs-h3: 21px;
  --fs-body: 16px;
  --fs-small: 15px;
  --fs-micro: 13px;
  --ls-display: -0.02em;
  --ls-body: 0.01em;

  /* Space scale */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px;
  --s6: 32px; --s7: 44px; --s8: 56px; --s9: 80px;

  /* Radius scale */
  --r-sm: 4px; --r-card: 20px; --r-lg: 24px; --r-pill: 9999px;

  /* Shadow (rings, not borders; lifts stay near-invisible) */
  --shadow-ring: inset 0 0 0 0.5px rgba(0, 0, 0, 0.1);
  --shadow-lift: 0 0 0 0.5px rgba(0, 0, 0, 0.08), 0 1.7px 3.4px rgba(0, 0, 0, 0.04);

  /* Motion: one easing, five durations */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --t-micro: 150ms;   /* hovers: colour, background, ring */
  --t-fast: 200ms;    /* small movement, chips */
  --t-med: 300ms;     /* expanders, panel changes */
  --t-slow: 360ms;    /* entrances */
  --t-reveal: 500ms;  /* large reveals only */
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.5;
  letter-spacing: var(--ls-body);
  -webkit-font-smoothing: antialiased;
}
.wrap { max-width: 880px; margin: 0 auto; padding: 0 var(--s6); }

/* ── Motion primitives ─────────────────────────────────────────────────── */
@keyframes fade-up {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.enter { animation: fade-up var(--t-slow) var(--ease) both; }

/* Scroll reveals: progressive enhancement, gated on html.js so a visitor with
   no JS or no IntersectionObserver keeps every section visible at rest. */
html.js .reveal { opacity: 0; }
html.js .reveal.in { animation: fade-up var(--t-slow) var(--ease) both; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  html.js .reveal { opacity: 1; }   /* reduced-motion never sees hidden content */
  /* Line tracing off: the static borders and dots render exactly as at rest. */
  html.js section + section, html.js footer { border-top-color: var(--line) !important; }
  html.js .rule-line { display: none !important; }
  html.js section > .wrap::before, html.js section > .wrap::after,
  html.js footer > .wrap::before, html.js footer > .wrap::after {
    opacity: 1 !important;
    transform: none !important;
  }
  /* Trunk and pen off entirely; the static grey frame stands in for them. */
  html.js .ink-trunk, html.js .ink-pen { display: none !important; }
}

/* ── Buttons (pills, weight 400, quiet; three sizes) ───────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  padding: 0 var(--s4);
  border: 0;
  border-radius: var(--r-pill);
  font-family: var(--sans);
  font-size: var(--fs-small);
  font-weight: 400;
  letter-spacing: var(--ls-body);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--t-micro) var(--ease),
              color var(--t-micro) var(--ease),
              box-shadow var(--t-micro) var(--ease);
}
.btn-sm { height: 36px; padding: 0 14px; font-size: 14px; }
.btn-lg { height: 44px; padding: 0 20px; font-size: 16px; }
.btn-primary { background: var(--ink); color: var(--paper); }
.btn-primary:hover { background: var(--ink-hover); }
.btn-secondary { background: var(--paper); color: var(--ink); box-shadow: var(--shadow-ring); }
.btn-secondary:hover { background: var(--tint); }
.btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.btn:active { transform: translateY(0.5px); }

/* Quiet text link (retained for inline use) */
.textlink {
  display: inline-block;
  margin-top: var(--s5);
  color: var(--ink);
  font-size: var(--fs-body);
  text-decoration: underline;
  text-underline-offset: 4px;
  transition: opacity var(--t-micro) var(--ease);
}
.textlink:hover { opacity: 0.66; }

/* ── Cards and panels ──────────────────────────────────────────────────── */
.card {
  background: var(--paper-warm);
  border-radius: var(--r-card);
  padding: var(--s5) 28px;
}
.card-ring {
  background: var(--paper);
  border-radius: var(--r-card);
  padding: var(--s5) 28px;
  box-shadow: var(--shadow-ring);
}
.card p { font-size: var(--fs-body); max-width: 60ch; }
.card p + p { margin-top: var(--s3); }
.card strong { font-weight: 600; }

/* ── Chips (build placeholders keep the dashed identity) ───────────────── */
.placeholder {
  display: inline-block;
  padding: 2px 10px;
  border: 1px dashed var(--line);
  border-radius: var(--r-sm);
  color: var(--ink);
  font-size: var(--fs-micro);
  letter-spacing: 0;
}
.chip {
  display: inline-block;
  padding: 3px 12px;
  background: var(--paper-warm);
  border-radius: var(--r-pill);
  font-size: var(--fs-micro);
  transition: background-color var(--t-micro) var(--ease);
}
.chip:hover { background: var(--paper-warm-2); }

/* ── Inputs (inferred from their pattern: hairline ring, generous height) ─ */
.input {
  width: 100%;
  height: 44px;
  padding: 0 var(--s4);
  border: 0;
  border-radius: 10px;
  background: var(--paper);
  box-shadow: var(--shadow-ring);
  font-family: var(--sans);
  font-size: var(--fs-body);
  color: var(--ink);
  transition: box-shadow var(--t-micro) var(--ease);
}
.input:focus { outline: none; box-shadow: inset 0 0 0 1.5px var(--ink); }

/* ── Nav ───────────────────────────────────────────────────────────────── */
.nav {
  position: sticky; top: 0; z-index: 30; background: var(--paper);
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.nav.scrolled { border-bottom-color: var(--line); box-shadow: var(--shadow-lift); }
.nav-inner {
  max-width: 880px;
  margin: 0 auto;
  padding: 20px var(--s6);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}
.nav-mark {
  font-size: 19px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
}
.nav-links { display: flex; align-items: center; gap: var(--s5); }
.nav-links a {
  color: var(--ink);
  text-decoration: none;
  font-size: var(--fs-small);
  transition: opacity var(--t-micro) var(--ease);
}
.nav-links a:hover { opacity: 0.66; }
.nav-links a.btn-primary { color: var(--paper); }
.nav-links a.btn-primary:hover { opacity: 1; }
.nav-links a[aria-current="page"],
.nav-links a.active { text-decoration: underline; text-underline-offset: 4px; }

main a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }

/* ── The grid frame: hairline columns, crossing rules, dots with halos ──── */
section { padding: 0; }
section > .wrap {
  position: relative;
  padding: var(--s9) var(--s6);
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
}
section + section { border-top: 1px solid var(--line); }
footer { border-top: 1px solid var(--line); }
footer > .wrap {
  position: relative;
  padding: var(--s7) var(--s6) 60px;
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
}
.hero > .wrap { padding-top: 96px; }

section > .wrap::before, section > .wrap::after,
footer > .wrap::before, footer > .wrap::after {
  content: "";
  position: absolute;
  top: -1px;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 0 8px var(--paper);
  z-index: 1;
}
section > .wrap::before, footer > .wrap::before { left: -1px; }
section > .wrap::after, footer > .wrap::after { right: -1px; }

/* ── Line tracing on scroll (progressive enhancement, gated on html.js) ─────
   Every section that follows another, and the footer, carries an injected
   .rule-line. Its static top border goes transparent (the 1px WIDTH stays, so
   nothing shifts) and the line draws itself in as the section enters view; the
   two crossing dots land in sync, the left one as the line sets off, the right
   as it arrives. No JS means no html.js, so the static borders and dots above
   render untouched. */
html.js section, html.js footer { position: relative; }
html.js section + section, html.js footer { border-top-color: transparent; }

html.js .rule-line {
  position: absolute;
  top: -1px;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1200ms var(--ease);
}
html.js .ruled .rule-line { transform: scaleX(1); }
/* Reverse is quick and undramatic. Un-drawing runs at 300ms, not the 1200ms
   forward stroke. The :not(.ruled) selector outranks the base .rule-line
   transition (more elements and classes), so a row that loses .ruled picks up
   the short duration, while a row that still holds .ruled keeps the long one. */
html.js section:not(.ruled) .rule-line,
html.js footer:not(.ruled) .rule-line { transition-duration: 300ms; }

/* The dots carry no positioning transform at rest (they sit on absolute top,
   left and right offsets), so animating scale from 0.4 back to identity lands
   them byte-identical to the static dot: same 2px centre, same 8px paper halo,
   same crossing point. Nothing to multiply, so scale is used outright. */
html.js section > .wrap::before, html.js section > .wrap::after,
html.js footer > .wrap::before, html.js footer > .wrap::after {
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
html.js section:not(.hero):not(.ruled) > .wrap::before,
html.js section:not(.hero):not(.ruled) > .wrap::after,
html.js footer:not(.ruled) > .wrap::before,
html.js footer:not(.ruled) > .wrap::after {
  opacity: 0;
  transform: scale(0.4);
  transition-delay: 0ms;   /* reverse: dots snap back with no stagger */
}
html.js .ruled > .wrap::before { transition-delay: 100ms; }
html.js .ruled > .wrap::after { transition-delay: 1000ms; }

/* ── The ink trunk and its pen (scroll-linked, JS-injected) ─────────────────
   One 1px vertical ink line rides the left grid rail from the first section
   below the hero down to the footer's top edge. Its drawn length is a pure
   transform: scaleY, glued 1:1 to scroll, so redrawing costs nothing and it
   retracts identically on the way back up. A travelling dot, built to the same
   2px ink and 8px paper halo as the grid junctions, rides the tip on a
   translateY tied to the same measurement. Both are JS-injected, so a no-JS
   visitor never meets a broken frame. Both sit above the grey rail so the ink
   covers it along the drawn length, below the nav, and take no pointer events.
   overflow-x on the positioned ancestor clips any stray width. */
html.js main { position: relative; overflow-x: clip; }
html.js .ink-trunk {
  position: absolute;
  width: 1px;
  background: var(--ink);
  transform-origin: top center;
  transform: scaleY(0);
  pointer-events: none;
  z-index: 5;
  will-change: transform;
}
html.js .ink-pen {
  position: absolute;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 0 8px var(--paper);
  pointer-events: none;
  z-index: 6;
  will-change: transform;
}

/* ── Type ──────────────────────────────────────────────────────────────── */
h1, h2 {
  font-weight: 400;
  letter-spacing: var(--ls-display);
  line-height: 1.08;
}
h1 { font-size: var(--fs-display); max-width: 22ch; }
h2 { font-size: var(--fs-h2); max-width: 28ch; }
h1 em, h2 em, .sub em { font-style: italic; }
.sub { margin-top: var(--s5); font-size: clamp(16px, 2vw, 18px); max-width: 56ch; }
.body-block { margin-top: var(--s5); max-width: 58ch; }
.body-block p + p { margin-top: var(--s4); }
.body-block strong { font-weight: 600; }

/* ── Lists ─────────────────────────────────────────────────────────────── */
.list { margin-top: 28px; display: grid; gap: var(--s3); }
.list li {
  list-style: none;
  position: relative;
  padding-left: 32px;
  font-size: var(--fs-body);
  max-width: 60ch;
}
.list li::before { content: "\2022"; position: absolute; left: 8px; top: 0; font-size: 18px; line-height: 1.4; }

/* ── Tiles and blocks ──────────────────────────────────────────────────── */
.styles-grid { margin-top: 48px; display: grid; gap: 48px; }
.style-block { display: grid; gap: var(--s4); }
.style-tile {
  aspect-ratio: 16 / 10;
  border: 1px dashed var(--line);
  border-radius: var(--r-card);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--paper-warm);
  transition: background-color var(--t-fast) var(--ease);
}
.style-tile:hover { background: var(--paper-warm-2); }
.style-block h3 { font-size: var(--fs-h3); font-weight: 500; letter-spacing: -0.01em; }
.style-block p { font-size: var(--fs-body); max-width: 58ch; }

footer p { font-size: var(--fs-micro); color: var(--ink); letter-spacing: 0.02em; }

/* ── Menu table ────────────────────────────────────────────────────────── */
.menu { margin-top: var(--s7); }
.menu-row {
  display: grid;
  grid-template-columns: 56px 1fr auto;
  gap: 18px;
  align-items: baseline;
  padding: var(--s5) 0;
  border-top: 1px solid var(--line);
  color: inherit;
  transition: background-color var(--t-micro) var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.menu .menu-row:last-child { border-bottom: 1px solid var(--line); }
/* Menu halves, 1 August 2026: the menu tells its shape. Build is paid once,
   keep is month to month. Labels sit between menu groups. */
.menu-half { margin-top: var(--s7); font-size: var(--fs-h3); font-weight: 500; letter-spacing: -0.01em; }
.menu-half + .menu { margin-top: var(--s3); }
/* Highlighted row: the free look reads as the page's primary choice. The fill
   bleeds OUTWARD via negative margins while the content keeps the shared grid,
   so numbers, titles, prices and buttons stay aligned with every other row.
   Its own top hairline and the next row's are dropped so neither cuts across
   the rounded fill. */
.menu-row-primary {
  background: var(--paper-warm);
  border-top: 0;
  border-radius: var(--r-card);
  margin: 0 -24px;
  padding: var(--s5) 24px;
}
.menu-row-primary + .menu-row { border-top: 0; }
/* No row-level hover fill: the tint read as a second highlighted card beside
   the primary row, and rows are not controls; the buttons and expanders
   carry their own hover states. */
.menu-row .n { font-size: 24px; font-weight: 400; letter-spacing: -0.01em; }
.menu-row h3 { font-size: var(--fs-h3); font-weight: 500; letter-spacing: -0.01em; }
.menu-row p { font-size: var(--fs-small); margin-top: var(--s1); max-width: 52ch; }
.price { font-size: var(--fs-small); white-space: nowrap; color: var(--ink); }
.price-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  text-align: right;
}
.price-cell .btn { margin-top: 0; }

/* ── Expanders ─────────────────────────────────────────────────────────── */
details.see-more { margin-top: 10px; }
details.see-more summary {
  cursor: pointer;
  display: inline-block;
  font-size: var(--fs-small);
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 4px;
  list-style: none;
  transition: opacity var(--t-micro) var(--ease);
}
details.see-more summary:hover { opacity: 0.66; }
details.see-more summary::-webkit-details-marker { display: none; }
details.see-more summary::after {
  content: "+";
  display: inline-block;
  margin-left: 5px;
  transition: transform var(--t-fast) var(--ease);
}
details.see-more[open] summary::after { transform: rotate(45deg); }
details.see-more .more { margin-top: var(--s4); display: grid; gap: var(--s3); max-width: 58ch; }
details.see-more[open] .more { animation: fade-up var(--t-fast) var(--ease) both; }
details.see-more .more p { font-size: var(--fs-small); }
details.see-more .more .list { margin-top: 0; }
details.see-more .more .list li { font-size: var(--fs-small); }

/* ── Rules panel (adopts the card) ─────────────────────────────────────── */
.rule-box {
  margin-top: var(--s6);
  background: var(--paper-warm);
  border-radius: var(--r-card);
  padding: var(--s5) 28px;
}
.rule-box p { font-size: var(--fs-body); max-width: 60ch; }
.rule-box p + p { margin-top: var(--s3); }
.rule-box strong { font-weight: 600; }

/* ── Intake form (section id="start") ─────────────────────────────────── */
.intake-form { max-width: 560px; display: grid; gap: 14px; }
.intake-form fieldset { border: 0; padding: 0; margin: 0; }
.intake-form legend { font-size: 14px; font-weight: 500; padding: 0; margin-bottom: 10px; }
.intake-form .checks { display: grid; gap: 10px; }
.intake-form .field { display: grid; gap: 6px; }
.intake-form .field > span { font-size: 14px; font-weight: 500; }
.intake-form .btn { justify-self: start; }
.intake-form .form-note { font-size: var(--fs-small); }

.menu-row[id], section[id] { scroll-margin-top: 72px; }

/* ── Responsive frame ──────────────────────────────────────────────────── */
@media (max-width: 944px) {
  section > .wrap, footer > .wrap { margin: 0 var(--s4); }
}
@media (max-width: 560px) {
  section > .wrap, footer > .wrap { margin: 0 var(--s4); }
  section > .wrap { padding: var(--s8) 20px; }
  .hero > .wrap { padding-top: 64px; }
  .wrap { padding: 0 20px; }
  .nav-inner { padding: var(--s4) 20px; gap: 14px; }
  .nav-links { gap: var(--s4); }
  .menu-row { grid-template-columns: 40px 1fr; }
  .menu-row-primary { margin: 0 -12px; padding: var(--s5) 12px; }
  .price-cell { grid-column: 2; align-items: flex-start; text-align: left; gap: var(--s2); }
}

/* ─────────────────────────────────────────────────────────────────────────
   System documentation page (/system.html) layout
   ───────────────────────────────────────────────────────────────────────── */
.sys-shell { display: grid; grid-template-columns: 220px 1fr; max-width: 1160px; margin: 0 auto; }
.sys-nav {
  position: sticky;
  top: 70px;
  align-self: start;
  height: calc(100vh - 70px);
  overflow-y: auto;
  padding: var(--s6) var(--s5);
  border-right: 1px solid var(--line);
}
.sys-nav .nav-mark { display: block; margin-bottom: var(--s5); }
.sys-nav .sys-back { display: none; }
.sys-nav a {
  display: block;
  padding: 6px 10px;
  margin: 2px 0;
  border-radius: var(--r-pill);
  color: var(--ink);
  font-size: var(--fs-small);
  text-decoration: none;
  transition: background-color var(--t-micro) var(--ease);
}
.sys-nav a:hover { background: var(--tint); }
.sys-nav a.active { background: var(--paper-warm); font-weight: 500; }
.sys-main { padding: 0 var(--s7) var(--s9); }
.sys-main section { border: 0; }
.sys-main section + section { border-top: 1px solid var(--line); }
.sys-main section > div { padding: var(--s8) 0; }
.sys-h { font-size: var(--fs-h2); font-weight: 400; letter-spacing: var(--ls-display); }
.sys-sub { margin-top: var(--s2); font-size: var(--fs-small); }
.spec { display: inline-block; margin: 2px 4px 2px 0; padding: 2px 10px; background: var(--paper-warm); border-radius: var(--r-sm); font-size: var(--fs-micro); font-variant-numeric: tabular-nums; }
.demo-row { margin-top: var(--s5); display: flex; flex-wrap: wrap; gap: var(--s4); align-items: center; }
.swatch { width: 132px; }
.swatch .well { height: 72px; border-radius: 10px; box-shadow: var(--shadow-ring); }
.swatch p { margin-top: var(--s2); font-size: var(--fs-micro); }
.type-row { margin-top: var(--s5); display: grid; gap: var(--s2); }
.space-bar { height: 14px; background: var(--paper-warm-2); border-radius: 3px; }
.radius-demo { width: 96px; height: 72px; background: var(--paper-warm); box-shadow: var(--shadow-ring); }
.motion-demo { width: 64px; height: 64px; border-radius: 14px; background: var(--ink); }
.sys-table { margin-top: var(--s5); width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
.sys-table th, .sys-table td { text-align: left; padding: 10px 14px 10px 0; border-bottom: 1px solid var(--line); }
.sys-table th { font-weight: 600; }
@media (max-width: 760px) {
  .nav { position: static; }
  .sys-shell { grid-template-columns: 1fr; }
  .sys-nav {
    position: sticky;
    top: 0;
    height: auto;
    display: flex;
    gap: var(--s1);
    overflow-x: auto;
    border-right: 0;
    border-bottom: 1px solid var(--line);
    padding: var(--s3) var(--s4);
    background: var(--paper);
    z-index: 5;
  }
  .sys-nav .nav-mark { display: none; }
  .sys-nav .sys-back { display: block; font-weight: 500; background: var(--paper-warm); }
  .sys-nav a { white-space: nowrap; }
  .sys-main { padding: 0 20px var(--s8); }
}

/* ─────────────────────────────────────────────────────────────────────────
   APPLICATION LAYER (dashboards), 21 July 2026
   Component taxonomy cross-checked against Material Design; skinned to this
   system. Data palette validated per the dataviz method on surface #ffffff,
   21 Jul 2026: all checks pass; series 3/4/5 sit below 3:1 contrast, so any
   chart using them ships direct labels or a table view (the relief rule).
   Status colours are reserved for state; never a series, never marketing.
   Axis and label text stays black per the no-grey law; hierarchy by size.
   ───────────────────────────────────────────────────────────────────────── */
:root {
  --series-1: #2a78d6; --series-2: #008300; --series-3: #e87ba4; --series-4: #eda100;
  --series-5: #1baf7a; --series-6: #eb6834; --series-7: #4a3aa7; --series-8: #e34948;
  --status-good: #0ca30c; --status-warn: #fab219;
  --status-serious: #ec835a; --status-critical: #d03b3b;
  --grid: var(--line);      /* chart gridlines */
  --axis: #d6d3cd;          /* baselines and axis lines, one step firmer */
}

/* ── App shell: topbar + side rail + content ───────────────────────────── */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s4); height: 56px; padding: 0 var(--s5);
  border-bottom: 1px solid var(--line); background: var(--paper);
}
.topbar .nav-mark { font-size: 17px; }
.topbar-actions { display: flex; align-items: center; gap: var(--s3); }
.shell { display: grid; grid-template-columns: 232px 1fr; min-height: 320px; }
.side {
  border-right: 1px solid var(--line); padding: var(--s4) var(--s3);
  background: var(--paper);
}
.side a {
  display: block; padding: 7px 12px; margin: 2px 0; border-radius: var(--r-pill);
  color: var(--ink); font-size: var(--fs-small); text-decoration: none;
  transition: background-color var(--t-micro) var(--ease);
}
.side a:hover { background: var(--tint); }
.side a.active { background: var(--paper-warm); font-weight: 500; }
.side .side-label { display: block; padding: 14px 12px 4px; font-size: 12px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
.shell-content { padding: var(--s5); background: var(--paper); }
@media (max-width: 760px) { .shell { grid-template-columns: 1fr; } .side { display: flex; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--line); } .side .side-label { display: none; } .side a { white-space: nowrap; } }

/* ── Tabs ──────────────────────────────────────────────────────────────── */
.tabs { display: flex; gap: var(--s5); border-bottom: 1px solid var(--line); }
.tab {
  padding: 10px 2px; font-size: var(--fs-small); color: var(--ink);
  text-decoration: none; border-bottom: 2px solid transparent;
  margin-bottom: -1px; transition: opacity var(--t-micro) var(--ease);
}
.tab:hover { opacity: 0.66; }
.tab.active { border-bottom-color: var(--ink); font-weight: 500; }

/* ── Breadcrumbs ───────────────────────────────────────────────────────── */
.crumbs { display: flex; flex-wrap: wrap; gap: var(--s2); font-size: var(--fs-micro); }
.crumbs a { color: var(--ink); text-decoration: none; }
.crumbs a:hover { text-decoration: underline; text-underline-offset: 3px; }
.crumbs .sep { opacity: 0.35; }
.crumbs .here { font-weight: 500; }

/* ── Tables ────────────────────────────────────────────────────────────── */
.table-scroll { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
.table th {
  text-align: left; font-size: var(--fs-micro); font-weight: 600;
  padding: 10px 14px 8px 0; border-bottom: 1px solid var(--axis);
  white-space: nowrap;
}
.table td { padding: 11px 14px 11px 0; border-bottom: 1px solid var(--line); }
.table tr:hover td { background: var(--tint); }
.table .num { text-align: right; font-variant-numeric: tabular-nums; }
.table th.num { text-align: right; }
.table-dense td { padding: 7px 14px 7px 0; }
.table .sort::after { content: " \2193"; font-size: 11px; }
.table .sort.asc::after { content: " \2191"; }

/* ── Stat tiles ────────────────────────────────────────────────────────── */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--s4); }
.stat { background: var(--paper-warm); border-radius: var(--r-card); padding: 18px 22px; }
.stat .stat-label { font-size: var(--fs-micro); font-weight: 500; }
.stat .stat-value { margin-top: 6px; font-size: 32px; letter-spacing: -0.02em; line-height: 1.1; }
.stat .stat-delta { margin-top: 6px; font-size: var(--fs-micro); display: flex; align-items: center; gap: 6px; }

/* ── Badges and status (always icon or dot + label, never colour alone) ── */
.badge {
  display: inline-flex; align-items: center; gap: 7px; padding: 3px 12px;
  background: var(--paper); border-radius: var(--r-pill);
  box-shadow: var(--shadow-ring); font-size: var(--fs-micro);
}
.dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.dot-good { background: var(--status-good); }
.dot-warn { background: var(--status-warn); }
.dot-serious { background: var(--status-serious); }
.dot-critical { background: var(--status-critical); }

/* ── Selects, menus ────────────────────────────────────────────────────── */
.select {
  appearance: none; height: 40px; padding: 0 40px 0 var(--s4);
  border: 0; border-radius: 10px; background: var(--paper);
  box-shadow: var(--shadow-ring); font-family: var(--sans);
  font-size: var(--fs-small); color: var(--ink); cursor: pointer;
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='black' fill='none' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 16px center;
  transition: box-shadow var(--t-micro) var(--ease);
}
.select:focus { outline: none; box-shadow: inset 0 0 0 1.5px var(--ink); }
details.menu { position: relative; display: inline-block; }
details.menu summary { list-style: none; cursor: pointer; }
details.menu summary::-webkit-details-marker { display: none; }
details.menu[open] > .menu-list { animation: fade-up var(--t-fast) var(--ease) both; }
.menu-list {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 20;
  min-width: 200px; padding: 6px; background: var(--paper);
  border-radius: 14px; box-shadow: var(--shadow-ring), var(--shadow-lift);
}
.menu-list a {
  display: block; padding: 8px 12px; border-radius: 9px;
  color: var(--ink); font-size: var(--fs-small); text-decoration: none;
  transition: background-color var(--t-micro) var(--ease);
}
.menu-list a:hover { background: var(--tint); }
.menu-list hr { border: 0; border-top: 1px solid var(--line); margin: 6px 4px; }

/* ── Selection controls ────────────────────────────────────────────────── */
.check, .radio { accent-color: var(--ink); width: 16px; height: 16px; cursor: pointer; }
.control-row { display: flex; align-items: center; gap: 10px; font-size: var(--fs-small); }
.switch {
  appearance: none; width: 38px; height: 22px; border-radius: var(--r-pill);
  background: var(--paper-warm-2); position: relative; cursor: pointer;
  transition: background-color var(--t-micro) var(--ease); flex: none;
}
.switch::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px;
  border-radius: 50%; background: var(--paper);
  box-shadow: 0 1px 2px rgba(0,0,0,0.18);
  transition: transform var(--t-micro) var(--ease);
}
.switch:checked { background: var(--ink); }
.switch:checked::after { transform: translateX(16px); }
.switch:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ── Alerts: the conventional pattern (tinted fill + border + icon), per
      Bootstrap/Primer/Material anatomy so users recognise severity at sight.
      Text stays black; the tint, border and icon carry the state. ───────── */
.alert {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 13px 16px; border-radius: 12px;
  border: 1px solid; font-size: var(--fs-small); max-width: 60ch;
  color: var(--ink);
}
.alert strong { font-weight: 600; }
.alert svg { flex: none; margin-top: 1px; }
.alert-success { background: rgba(12, 163, 12, 0.09);  border-color: rgba(12, 163, 12, 0.35); }
.alert-warning { background: rgba(250, 178, 25, 0.13); border-color: rgba(207, 141, 0, 0.4); }
.alert-danger  { background: rgba(208, 59, 59, 0.08);  border-color: rgba(208, 59, 59, 0.35); }
.alert-info    { background: rgba(42, 120, 214, 0.08); border-color: rgba(42, 120, 214, 0.35); }
.alert-dismiss {
  margin-left: auto; border: 0; background: none; cursor: pointer;
  font-size: 16px; line-height: 1; padding: 2px 4px; color: var(--ink);
  border-radius: 6px; transition: background-color var(--t-micro) var(--ease);
}
.alert-dismiss:hover { background: rgba(0, 0, 0, 0.06); }

/* ── Overlays ──────────────────────────────────────────────────────────── */
dialog.modal {
  border: 0; border-radius: var(--r-card); padding: 28px;
  max-width: 420px; width: calc(100% - 40px);
  box-shadow: var(--shadow-ring), 0 24px 48px rgba(0,0,0,0.12);
  animation: fade-up var(--t-med) var(--ease) both;
}
dialog.modal::backdrop { background: rgba(0, 0, 0, 0.32); }
dialog.modal h3 { font-size: var(--fs-h3); font-weight: 500; }
dialog.modal p { margin-top: var(--s3); font-size: var(--fs-small); }
dialog.modal .demo-row { margin-top: var(--s5); }
.tip { position: relative; text-decoration: underline; text-underline-offset: 3px; cursor: help; }
.tip::after {
  content: attr(data-tip); position: absolute; bottom: calc(100% + 8px); left: 50%;
  transform: translateX(-50%) translateY(2px);
  padding: 5px 12px; border-radius: var(--r-pill);
  background: var(--ink); color: var(--paper);
  font-size: 12px; white-space: nowrap;
  opacity: 0; pointer-events: none;
  transition: opacity var(--t-micro) var(--ease), transform var(--t-micro) var(--ease);
}
.tip:hover::after { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast {
  display: inline-flex; align-items: center; gap: 12px;
  padding: 12px 18px; border-radius: var(--r-pill);
  background: var(--ink); color: var(--paper); font-size: var(--fs-small);
  animation: fade-up var(--t-slow) var(--ease) both;
}
.toast a { color: var(--paper); }

/* ── Loading and empty ─────────────────────────────────────────────────── */
@keyframes skel-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
.skel { background: var(--paper-warm-2); border-radius: 6px; animation: skel-pulse 1.2s var(--ease) infinite; }
.empty {
  border: 1px dashed var(--line); border-radius: var(--r-card);
  padding: var(--s7) var(--s5); text-align: center;
}
.empty p { font-size: var(--fs-small); max-width: 40ch; margin: 0 auto; }
.empty .btn { margin-top: var(--s4); }
.progress { height: 6px; border-radius: var(--r-pill); background: var(--paper-warm-2); overflow: hidden; }
.progress > span { display: block; height: 100%; border-radius: var(--r-pill); background: var(--ink); transition: width var(--t-med) var(--ease); }

/* ── Chart chrome ──────────────────────────────────────────────────────── */
.chart-axis-text { font-size: 12px; fill: var(--ink); font-family: var(--sans); }
.chart-grid-line { stroke: var(--grid); stroke-width: 1; }
.chart-baseline { stroke: var(--axis); stroke-width: 1.5; }
.legend { display: flex; flex-wrap: wrap; gap: var(--s4); font-size: var(--fs-micro); }
.legend span { display: inline-flex; align-items: center; gap: 7px; }
.legend i { width: 10px; height: 10px; border-radius: 3px; flex: none; }

/* ── Footer (full site footer, framed like every section) ──────────────── */
.foot-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: var(--s6);
  align-items: start;
}
.foot-line { margin-top: 10px; font-size: var(--fs-small); max-width: 30ch; }
.foot-label { display: block; font-size: var(--fs-micro); font-weight: 600; margin-bottom: 10px; }
.foot-grid a:not(.nav-mark) {
  display: block; padding: 3px 0; color: var(--ink);
  font-size: var(--fs-small); text-decoration: none;
  transition: opacity var(--t-micro) var(--ease);
}
.foot-grid a:not(.nav-mark):hover { opacity: 0.66; text-decoration: underline; text-underline-offset: 3px; }
.foot-legal { margin-top: var(--s6); padding-top: var(--s4); border-top: 1px solid var(--line); }
@media (max-width: 760px) {
  .foot-grid { grid-template-columns: 1fr 1fr; gap: var(--s5); }
  .foot-grid > div:first-child { grid-column: 1 / -1; }
}

/* The veil, 3 August 2026 (v7, research-sourced): progressive blur over the
   bottom of the viewport. Recipe from kennethnym.com/blog/progressive-blur-in-css
   [source]: seven full-size layers, blur doubling 1 to 64px, each masked to an
   overlapping trapezoid band so adjacent layers CROSS-FADE; the overlap is what
   kills banding, and hard-edged strips (the previous version) is what caused it.
   Masking is safe with backdrop-filter because masks apply AFTER filters in all
   browsers [source: joshwcomeau.com/css/backdrop-filter]. The one thing that
   must never return: any mix-blend-mode child inside this container (it
   isolates the group and the blur loses its backdrop). Grain: removed for now,
   Fred's call, blur first. The page-end dissolve fades each layer's OWN
   opacity via --veil-o, never a wrapper's. */
.veil {
  position: fixed; left: 0; right: 0; bottom: 0; height: 34vh;
  pointer-events: none; z-index: 40;
}
.veil i { position: absolute; inset: 0; display: block; opacity: var(--veil-o, 1); }
.veil i:nth-child(1) { backdrop-filter: blur(1px); -webkit-backdrop-filter: blur(1px);
  mask-image: linear-gradient(rgba(0,0,0,0), rgba(0,0,0,1) 10%, rgba(0,0,0,1) 30%, rgba(0,0,0,0) 40%);
  -webkit-mask-image: linear-gradient(rgba(0,0,0,0), rgba(0,0,0,1) 10%, rgba(0,0,0,1) 30%, rgba(0,0,0,0) 40%); }
.veil i:nth-child(2) { backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
  mask-image: linear-gradient(rgba(0,0,0,0) 10%, rgba(0,0,0,1) 20%, rgba(0,0,0,1) 40%, rgba(0,0,0,0) 50%);
  -webkit-mask-image: linear-gradient(rgba(0,0,0,0) 10%, rgba(0,0,0,1) 20%, rgba(0,0,0,1) 40%, rgba(0,0,0,0) 50%); }
.veil i:nth-child(3) { backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  mask-image: linear-gradient(rgba(0,0,0,0) 15%, rgba(0,0,0,1) 30%, rgba(0,0,0,1) 50%, rgba(0,0,0,0) 60%);
  -webkit-mask-image: linear-gradient(rgba(0,0,0,0) 15%, rgba(0,0,0,1) 30%, rgba(0,0,0,1) 50%, rgba(0,0,0,0) 60%); }
.veil i:nth-child(4) { backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  mask-image: linear-gradient(rgba(0,0,0,0) 20%, rgba(0,0,0,1) 40%, rgba(0,0,0,1) 60%, rgba(0,0,0,0) 70%);
  -webkit-mask-image: linear-gradient(rgba(0,0,0,0) 20%, rgba(0,0,0,1) 40%, rgba(0,0,0,1) 60%, rgba(0,0,0,0) 70%); }
.veil i:nth-child(5) { backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  mask-image: linear-gradient(rgba(0,0,0,0) 40%, rgba(0,0,0,1) 60%, rgba(0,0,0,1) 80%, rgba(0,0,0,0) 90%);
  -webkit-mask-image: linear-gradient(rgba(0,0,0,0) 40%, rgba(0,0,0,1) 60%, rgba(0,0,0,1) 80%, rgba(0,0,0,0) 90%); }
.veil i:nth-child(6) { backdrop-filter: blur(32px); -webkit-backdrop-filter: blur(32px);
  mask-image: linear-gradient(rgba(0,0,0,0) 60%, rgba(0,0,0,1) 80%);
  -webkit-mask-image: linear-gradient(rgba(0,0,0,0) 60%, rgba(0,0,0,1) 80%); }
.veil i:nth-child(7) { backdrop-filter: blur(64px); -webkit-backdrop-filter: blur(64px);
  mask-image: linear-gradient(rgba(0,0,0,0) 70%, rgba(0,0,0,1) 100%);
  -webkit-mask-image: linear-gradient(rgba(0,0,0,0) 70%, rgba(0,0,0,1) 100%); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .veil i:nth-child(7) { background: linear-gradient(to bottom, transparent, rgba(245,243,241,0.92)); mask-image: none; -webkit-mask-image: none; }
}

/* The top veil, 3 August 2026: the bottom veil mirrored behind the nav, same
   seven-layer cross-faded recipe and the same grain, gradients flipped so the
   frost is heaviest at the screen's top edge and content melts upward as it
   slides under the bar. Sits BELOW the nav (z 25/26 vs the nav's 30) and does
   not dissolve with --veil-o: the bar needs its frost at every scroll depth.
   Pairs with .nav-glass, which strips the nav's solid paint so the veil shows. */
.veil-top, .veil-top-grain-wrap {
  position: fixed; left: 0; right: 0; top: 0; height: 170px;
  pointer-events: none;
}
.veil-top { z-index: 25; }
.veil-top-grain-wrap { z-index: 26; }
.veil-top i { position: absolute; inset: 0; display: block; }
.veil-top i:nth-child(1) { backdrop-filter: blur(1px); -webkit-backdrop-filter: blur(1px);
  mask-image: linear-gradient(to top, rgba(0,0,0,0), rgba(0,0,0,1) 10%, rgba(0,0,0,1) 30%, rgba(0,0,0,0) 40%);
  -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,0), rgba(0,0,0,1) 10%, rgba(0,0,0,1) 30%, rgba(0,0,0,0) 40%); }
.veil-top i:nth-child(2) { backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
  mask-image: linear-gradient(to top, rgba(0,0,0,0) 10%, rgba(0,0,0,1) 20%, rgba(0,0,0,1) 40%, rgba(0,0,0,0) 50%);
  -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,0) 10%, rgba(0,0,0,1) 20%, rgba(0,0,0,1) 40%, rgba(0,0,0,0) 50%); }
.veil-top i:nth-child(3) { backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  mask-image: linear-gradient(to top, rgba(0,0,0,0) 15%, rgba(0,0,0,1) 30%, rgba(0,0,0,1) 50%, rgba(0,0,0,0) 60%);
  -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,0) 15%, rgba(0,0,0,1) 30%, rgba(0,0,0,1) 50%, rgba(0,0,0,0) 60%); }
.veil-top i:nth-child(4) { backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  mask-image: linear-gradient(to top, rgba(0,0,0,0) 20%, rgba(0,0,0,1) 40%, rgba(0,0,0,1) 60%, rgba(0,0,0,0) 70%);
  -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,0) 20%, rgba(0,0,0,1) 40%, rgba(0,0,0,1) 60%, rgba(0,0,0,0) 70%); }
.veil-top i:nth-child(5) { backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  mask-image: linear-gradient(to top, rgba(0,0,0,0) 40%, rgba(0,0,0,1) 60%, rgba(0,0,0,1) 80%, rgba(0,0,0,0) 90%);
  -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,0) 40%, rgba(0,0,0,1) 60%, rgba(0,0,0,1) 80%, rgba(0,0,0,0) 90%); }
.veil-top i:nth-child(6) { backdrop-filter: blur(32px); -webkit-backdrop-filter: blur(32px);
  mask-image: linear-gradient(to top, rgba(0,0,0,0) 60%, rgba(0,0,0,1) 80%);
  -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,0) 60%, rgba(0,0,0,1) 80%); }
.veil-top i:nth-child(7) { backdrop-filter: blur(64px); -webkit-backdrop-filter: blur(64px);
  mask-image: linear-gradient(to top, rgba(0,0,0,0) 70%, rgba(0,0,0,1) 100%);
  -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,0) 70%, rgba(0,0,0,1) 100%); }
.veil-top-grain {
  position: absolute; inset: 0; display: block;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
  mix-blend-mode: multiply;
  opacity: 0.52;
  mask-image: linear-gradient(to top,
    transparent 0%, rgba(0,0,0,0.08) 25%, rgba(0,0,0,0.22) 45%,
    rgba(0,0,0,0.45) 65%, rgba(0,0,0,0.72) 82%, #000 100%);
  -webkit-mask-image: linear-gradient(to top,
    transparent 0%, rgba(0,0,0,0.08) 25%, rgba(0,0,0,0.22) 45%,
    rgba(0,0,0,0.45) 65%, rgba(0,0,0,0.72) 82%, #000 100%);
}
/* Glass nav: the solid paint goes, the veil does the elevation work. */
.nav-glass { background: transparent; }
.nav-glass.scrolled { border-bottom-color: transparent; box-shadow: none; }

/* The grain, 3 August 2026 (researched: css-tricks.com/grainy-gradients +
   freecodecamp SVG-filter grain guide [sources]): one feTurbulence fractal
   noise tile (baseFrequency 0.8 = fine film grain, stitchTiles for seamless
   tiling, small 160px tile for paint performance), one layer, multiply blend,
   smooth multi-stop mask ramping with the blur. Lives in its OWN fixed
   container: a blend-mode child isolates its parent, and an isolated parent
   would starve any backdrop-filter sharing it, so the grain and the blur must
   never share a tree. Dissolves with the same --veil-o as the blur. */
.veil-grain-wrap {
  position: fixed; left: 0; right: 0; bottom: 0; height: 34vh;
  pointer-events: none; z-index: 41;
}
.veil-grain {
  position: absolute; inset: 0; display: block;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
  mix-blend-mode: multiply;
  opacity: calc(0.52 * var(--veil-o, 1));
  mask-image: linear-gradient(to bottom,
    transparent 0%, rgba(0,0,0,0.08) 25%, rgba(0,0,0,0.22) 45%,
    rgba(0,0,0,0.45) 65%, rgba(0,0,0,0.72) 82%, #000 100%);
  -webkit-mask-image: linear-gradient(to bottom,
    transparent 0%, rgba(0,0,0,0.08) 25%, rgba(0,0,0,0.22) 45%,
    rgba(0,0,0,0.45) 65%, rgba(0,0,0,0.72) 82%, #000 100%);
}
/* The glass nav must stay sticky at ALL widths: the mobile rule that makes
   .nav static (a menu-era space saver) also voids its z-index, dropping the
   bar underneath the fixed top veil. Declared after that rule so it wins. */
.nav-glass { position: sticky; }

/* Mobile glass nav, 3 August 2026: the Apple product-bar pattern. On phones
   the bar is exactly two things on one row: wordmark left, CTA right. The two
   anchor links are desktop conveniences; on a one-pager, scrolling is the
   navigation and both targets sit two swipes away (and in the footer). Tap
   research: 44px minimum hit areas (Apple HIG 44pt, Material 48dp), so the
   pill and the wordmark both get 44px-class targets here. */
@media (max-width: 760px) {
  .nav-glass .nav-links a:not(.btn) { display: none; }
  .nav-glass .nav-inner { flex-wrap: nowrap; }
  .nav-glass .nav-links .btn-sm { height: 44px; padding: 0 20px; }
  .nav-glass .nav-mark { padding: 10px 0; }
}
