/* ============================================================
   MagicBlocks component library — shared tokens + page chrome
   Imported by every /components/*.html page.
   Change tokens here; every page reflects the change.
   ============================================================ */

:root {
  /* ------------------------------------------------- colour */
  /* ink/foundation */
  --ink:         #191E32;
  --slate:       #466099;
  --lavender:    #6E90CC;
  --paper:       #FFFFFF;

  /* warm neutrals — the default surface family.
     These are PINNED values: they stay warm in both light and dark
     modes so the brand's cream-paper identity carries through.
     Any component that sets one of these as its own background must
     also scope its type tokens (--fg, --fg-soft, --fg-dim, --hair)
     to ink values so copy stays legible when the theme's --fg flips. */
  --warm-1:      #FBF6F0;  /* lightest — hairline tint on paper */
  --warm-2:      #F9F1E8;  /* light — marketing footer, soft stages */
  --warm-3:      #F4ECE4;  /* default — page background in light mode */
  --warm-5:      #E8DBCB;  /* mid — panel sunken, demo-stage alt */
  --warm-7:      #D2BFAA;  /* deep — ambient blocks, hero shadows */

  /* block quad — pink is hero */
  --pink-300:    #FE84A9;
  --pink-500:    #FF5B8D;
  --pink-700:    #FF3F7A;

  --yellow-300:  #FFD878;
  --yellow-500:  #F9C33E;
  --yellow-700:  #F9AD03;

  --green-300:   #7DF4D0;
  --green-500:   #47DDB2;
  --green-700:   #37BC9B;

  --blue-300:    #5BD9FC;
  --blue-500:    #30C4F2;
  --blue-700:    #1FAAE8;

  /* semantic (warm/light mode — default) */
  --bg:          var(--warm-3);
  --bg-paper:    var(--paper);
  --bg-sunk:     var(--warm-5);
  --bg-sunken:   var(--warm-5);           /* alias of --bg-sunk */
  --bg-warm:     var(--warm-2);            /* light warm tint for subtle surfaces */
  --bg-deep:     var(--warm-7);
  --fg:          var(--ink);
  /* --fg-soft was var(--slate) = #466099 which read as link-blue on body
     paragraphs. Changed to ink at 78% alpha — neutral, ~6 ratio on white,
     passes AA-body. The --slate token is still available where explicitly
     intentional. */
  --fg-soft:     rgba(25, 30, 50, 0.78);
  /* --fg-dim was 0.55 (3.77 ratio = fail AA-body). Bumped to 0.7 = ~5.6.
     --fg-faint was 0.35 (~2 = fail everything). Bumped to 0.6 = ~3.7
     for AA-large on decorative captions/dividers. */
  --fg-dim:      rgba(25, 30, 50, 0.7);
  --fg-faint:    rgba(25, 30, 50, 0.6);
  --hair:        rgba(25, 30, 50, 0.12);
  --hair-soft:   rgba(25, 30, 50, 0.06);
  /* warm-tinted hairline variants — for panels where cool ink-tinted
     borders read slightly muddy on warm-cream ground. Not the default;
     reach for these only when the ink-tinted hair feels off. */
  --hair-warm:      rgba(139, 115, 85, 0.18);
  --hair-warm-soft: rgba(139, 115, 85, 0.10);
  --accent:      var(--pink-700);
  --accent-soft: rgba(255, 63, 122, 0.12);
  --success:     var(--green-700);
  --success-soft: rgba(55, 188, 155, 0.14);
  --warning:     var(--yellow-700);
  --warning-soft: rgba(249, 173, 3, 0.16);
  --info:        var(--blue-700);
  --info-soft:   rgba(31, 170, 232, 0.14);
  --error:       #D64545;
  --error-soft:  rgba(214, 69, 69, 0.12);

  /* Darker semantic TEXT variants — for body/caption text on LIGHT
     backgrounds. The bright brand colors above (--accent, --success,
     --info, --warning) read fine as fills/borders/icons but fail
     WCAG AA when used as text on cream / paper. In dark mode these
     alias back to the brand colors. Use --accent for backgrounds,
     borders, icons; use --accent-text for text. */
  --accent-text:   #B42463;
  --success-text:  #1E6B44;
  --info-text:     #1463A1;
  --warning-text:  #8A5A00;
  --error-text:    var(--error);

  /* ambient brand glow — sits behind the whole page via body::before.
     Subtle in light mode, more pronounced in dark where the dark base
     makes the pink feel lit rather than washed. Shared so every page
     gets the same through-line without heroes needing bespoke gradients. */
  --glow-pink:   rgba(255, 63, 122, 0.06);
  --glow-blue:   rgba(31, 170, 232, 0.04);
  --glow-warm:   rgba(249, 195, 62, 0.03);

  /* neutral hash pattern for demo stages — theme-aware so the texture
     stays visible on both cream and ink backgrounds without overpowering. */
  --stage-hash:  rgba(25, 30, 50, 0.035);

  /* ------------------------------------------------- space */
  --s-1:   4px;
  --s-2:   8px;
  --s-3:   12px;
  --s-4:   16px;
  --s-5:   20px;
  --s-6:   24px;
  --s-7:   32px;
  --s-8:   40px;
  --s-9:   48px;
  --s-10:  64px;
  --s-11:  80px;
  --s-12:  96px;
  --s-13:  128px;

  /* ------------------------------------------------- radii */
  --r-xs:  4px;
  --r-sm:  6px;
  --r-md:  10px;
  --r-lg:  14px;
  --r-xl:  20px;
  --r-2xl: 28px;
  --r-pill: 999px;

  /* ------------------------------------------------- shadow / elevation */
  --sh-0: none;
  --sh-1: 0 1px 2px rgba(25, 30, 50, 0.06), 0 1px 1px rgba(25, 30, 50, 0.04);
  --sh-2: 0 4px 10px rgba(25, 30, 50, 0.08), 0 1px 2px rgba(25, 30, 50, 0.06);
  --sh-3: 0 10px 28px rgba(25, 30, 50, 0.12), 0 2px 4px rgba(25, 30, 50, 0.06);
  --sh-4: 0 24px 56px rgba(25, 30, 50, 0.18), 0 4px 8px rgba(25, 30, 50, 0.08);
  --sh-pink: 0 12px 40px rgba(255, 63, 122, 0.28);
  --sh-focus: 0 0 0 3px rgba(255, 63, 122, 0.28);

  /* ------------------------------------------------- motion */
  --dur-1: 100ms;
  --dur-2: 160ms;
  --dur-3: 240ms;
  --dur-4: 400ms;
  --ease:  cubic-bezier(0.2, 0.8, 0.2, 1);

  /* ------------------------------------------------- type */
  --f-display: "Bricolage Grotesque", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter, sans-serif;
  --f-body:    "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter, sans-serif;
  --f-mono:    "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --f-serif:   "Fraunces", ui-serif, Georgia, "Times New Roman", serif;

  /* ------------------------------------------------- z-index */
  --z-base:    1;
  --z-sticky:  10;
  --z-overlay: 100;
  --z-modal:   200;
  --z-toast:   300;
}

/* ink/dark mode — triggered by [data-theme="dark"] on <body> */
body[data-theme="dark"] {
  --bg:          var(--ink);
  --bg-paper:    #232842;
  --bg-sunk:     #141828;
  --bg-sunken:   #141828;
  --bg-warm:     #232842;                  /* dark-mode "warm" reads as raised paper */
  --bg-deep:     #0F1221;
  --fg:          #F4ECE4;
  --fg-soft:     #C9CFE2;
  --fg-dim:      rgba(244, 236, 228, 0.78);  /* was 0.7 — bumped for AA-body across all bgs */
  --fg-faint:    rgba(244, 236, 228, 0.62);  /* was 0.5 — bumped to clear AA-body 4.5+ on bg-paper */
  --hair:        rgba(244, 236, 228, 0.14);
  --hair-soft:   rgba(244, 236, 228, 0.07);
  /* in dark mode the default --hair is already cream-tinted; keep the
     warm variants mapped to a slightly more saturated warm tone so
     components that opt-in stay consistent across themes. */
  --hair-warm:      rgba(210, 191, 170, 0.22);
  --hair-warm-soft: rgba(210, 191, 170, 0.12);
  --accent:      #FF4F87;  /* was #FF6E9D — pushed darker for AA-large compliance */
  --accent-soft: rgba(255, 63, 122, 0.22);
  --success:     var(--green-500);
  --success-soft: rgba(125, 244, 208, 0.16);
  --warning:     var(--yellow-500);
  --warning-soft: rgba(255, 216, 120, 0.18);
  --info:        var(--blue-500);
  --info-soft:   rgba(91, 217, 252, 0.16);
  --error:       #FF7A7A;
  --error-soft:  rgba(255, 120, 120, 0.16);

  /* Dark-mode: brand semantic colors are bright enough to read as text
     on the ink surface — alias the -text tokens back to the brand
     colors so the same rules work in both themes. */
  --accent-text:   var(--accent);
  --success-text:  var(--success);
  --info-text:     var(--info);
  --warning-text:  var(--warning);
  --error-text:    var(--error);

  /* dark mode glows — deeper and slightly more saturated so the brand
     warmth carries through the ink surface without feeling gauzy. */
  --glow-pink:   rgba(255, 110, 157, 0.14);
  --glow-blue:   rgba(91, 217, 252, 0.07);
  --glow-warm:   rgba(255, 216, 120, 0.05);

  /* hash pattern — lift to a light tint so the texture stays visible
     on ink without going full-contrast dots. */
  --stage-hash:  rgba(244, 236, 228, 0.04);
}

/* ============================================================ reset + base */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--f-body);
  font-optical-sizing: auto;
  color: var(--fg);
  background: var(--bg);
  line-height: 1.55;
  position: relative;
  transition: background var(--dur-3) var(--ease), color var(--dur-3) var(--ease);
  /* Defensive: prevent rogue 1-2px horizontal overflow at the body level.
     Components that need horizontal scroll opt-in via their own
     overflow-x: auto on the relevant wrapper. */
  overflow-x: hidden;
}
/* ambient brand atmosphere — lives behind every page, never clips.
   Pink in the top-right, cool blue in the bottom-left, and a whisper
   of warm yellow through the middle. Fixed so it doesn't move on
   scroll and lights the whole document like a soft-box. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(60vw 55vh at 88% 8%,  var(--glow-pink), transparent 65%),
    radial-gradient(50vw 50vh at 8% 92%,  var(--glow-blue), transparent 65%),
    radial-gradient(70vw 50vh at 50% 50%, var(--glow-warm), transparent 70%);
  transition: opacity var(--dur-3) var(--ease);
}
/* every page-content root needs to sit above the glow */
body > * { position: relative; z-index: 1; }
img, svg { max-width: 100%; display: block; }
a { color: var(--fg); text-decoration-color: var(--hair); text-underline-offset: 3px; }
a:hover { color: var(--accent-text); text-decoration-color: currentColor; }

/* keyboard focus ring — visible on all focusable elements */
:focus-visible {
  outline: none;
  box-shadow: var(--sh-focus);
  border-radius: var(--r-xs);
}
a:focus-visible, button:focus-visible, [role="button"]:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible,
[tabindex]:focus-visible {
  outline: none;
  box-shadow: var(--sh-focus);
}

/* ============================================================ page chrome */

.page {
  max-width: 1160px;
  margin: 0 auto;
  padding: 0 var(--s-7);
}
@media (max-width: 640px) {
  .page { padding: 0 var(--s-4); }
}

/* top bar */
.topnav {
  position: sticky; top: 0; z-index: var(--z-sticky);
  background: color-mix(in oklab, var(--bg) 88%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--hair);
}
.topnav-inner {
  max-width: 1160px; margin: 0 auto;
  display: flex; align-items: center; gap: var(--s-5);
  padding: var(--s-4) var(--s-7);
}

/* ── brand: real icon + wordmark ─────────────────── */
.topnav .brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--f-display);
  font-weight: 700; font-size: 17px;
  letter-spacing: -0.02em;
  color: var(--fg);
  text-decoration: none;
  flex-shrink: 0;
}
.topnav .brand-mark {
  width: 26px; height: 26px; display: inline-block;
  background: url("./02-icon/svg/magicblocks-icon-color.svg") center / contain no-repeat;
  flex-shrink: 0;
}
.topnav .brand-word {
  font-family: var(--f-display);
  font-weight: 700;
}
.topnav .brand-word em {
  font-family: var(--f-serif); font-style: italic; font-weight: 400;
  color: var(--accent-text); margin-left: 1px;
}
/* legacy dot kept for fallback — invisible unless a page still uses it */
.topnav .brand .dot { display: none; }

/* ── crumb (optional, minimal) ────────────────────── */
.topnav .crumb {
  color: var(--fg-dim);
  font-size: 13px;
  display: flex; align-items: center; gap: var(--s-2);
  flex-shrink: 0;
}
.topnav .crumb .sep { color: var(--fg-faint); }
.topnav .spacer { flex: 1; }

/* ── chapter menu — refactored for v2 ───────────────
   The original 10-link inline list got crowded as the kit grew.
   New pattern: a single "Chapters" trigger that pops a 2-column
   mega-dropdown on click, plus a separate Components CTA. The
   .site-menu wrapper is preserved for the mobile drawer behaviour
   below — on mobile, the dropdown content renders inline. */
.site-menu {
  flex: 1;
  display: flex; align-items: center; gap: var(--s-3); justify-content: flex-end;
  font-family: var(--f-body); font-size: 13px;
  position: relative;
}

/* "Chapters ▾" trigger — pill button */
.nav-chapters {
  position: relative;
}
.nav-chapters-trigger {
  appearance: none; -webkit-appearance: none;
  background: var(--bg-paper);
  border: 1px solid var(--hair);
  border-radius: var(--r-pill);
  padding: 7px 14px 7px 16px;
  font: 500 13px/1 var(--f-body);
  color: var(--fg);
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  transition: border-color var(--dur-2) var(--ease),
              background var(--dur-2) var(--ease);
}
.nav-chapters-trigger:hover { border-color: color-mix(in oklab, var(--accent) 30%, var(--hair)); }
.nav-chapters-trigger:focus-visible { outline: 0; box-shadow: var(--sh-focus); }
.nav-chapters-trigger .nav-chapters-num {
  font: 600 11px/1 var(--f-mono);
  color: var(--fg-dim);
  letter-spacing: 0.04em;
}
.nav-chapters-trigger .nav-chapters-caret {
  width: 10px; height: 10px; flex-shrink: 0;
  transition: transform var(--dur-2) var(--ease);
}
.nav-chapters[aria-expanded="true"] .nav-chapters-trigger,
.nav-chapters.is-open .nav-chapters-trigger {
  background: var(--bg-sunk);
  border-color: var(--accent);
}
.nav-chapters.is-open .nav-chapters-caret { transform: rotate(180deg); }

/* mega-dropdown panel */
.nav-chapters-panel {
  position: absolute;
  top: calc(100% + 10px); right: 0;
  width: min(560px, calc(100vw - var(--s-7) * 2));
  background: var(--bg-paper);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  padding: var(--s-5);
  box-shadow: 0 24px 48px -20px color-mix(in oklab, var(--ink) 50%, transparent),
              0 8px 16px -8px color-mix(in oklab, var(--ink) 25%, transparent);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-5);
  opacity: 0; transform: translateY(-6px) scale(0.98);
  transform-origin: top right;
  pointer-events: none;
  transition: opacity 200ms var(--ease), transform 200ms var(--ease);
  z-index: 10;
}
.nav-chapters.is-open .nav-chapters-panel {
  opacity: 1; transform: translateY(0) scale(1);
  pointer-events: auto;
}
.nav-chapters-group {
  display: flex; flex-direction: column; gap: 2px;
}
.nav-chapters-group .nav-chapters-eyebrow {
  font: 600 10px/1 var(--f-mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--fg-dim);
  padding: 0 10px var(--s-2);
}
.nav-chapters-panel a {
  display: grid;
  grid-template-columns: 28px 1fr;
  align-items: baseline;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  text-decoration: none;
  transition: background var(--dur-1) var(--ease);
}
.nav-chapters-panel a:hover { background: var(--bg-warm); }
.nav-chapters-panel a[aria-current="page"] {
  background: var(--accent-soft);
}
.nav-chapters-panel a .nav-chapters-num {
  font: 600 11.5px/1 var(--f-mono);
  color: var(--fg-dim);
}
.nav-chapters-panel a[aria-current="page"] .nav-chapters-num { color: var(--accent-text); }
.nav-chapters-panel a .nav-chapters-name {
  font: 600 14px/1.2 var(--f-display);
  color: var(--fg);
  letter-spacing: -0.005em;
}
.nav-chapters-panel a[aria-current="page"] .nav-chapters-name { color: var(--accent-text); }
.nav-chapters-panel a .nav-chapters-sub {
  display: block;
  font: 400 11.5px/1.3 var(--f-body);
  color: var(--fg-soft);
  margin-top: 2px;
}

/* Components CTA — pink-on-white pill, separate from the dropdown.
   Bumped specificity (.site-menu .nav-cta) so the legacy .site-menu > a
   rule below doesn't win and override the colour to fg-dim. The text
   colour is hard-pinned to white in BOTH themes — accent in dark mode is
   pink-300, still high-contrast against pure white. */
.site-menu .nav-cta {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 16px;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: #FFFFFF;
  font: 600 12.5px/1 var(--f-body);
  letter-spacing: 0.005em;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--dur-2) var(--ease),
              transform var(--dur-2) var(--ease),
              box-shadow var(--dur-2) var(--ease);
  box-shadow: 0 6px 18px -8px color-mix(in oklab, var(--accent) 60%, transparent);
}
.site-menu .nav-cta:hover {
  background: var(--pink-700);
  color: #FFFFFF;
  transform: translateY(-1px);
  box-shadow: 0 10px 24px -10px color-mix(in oklab, var(--accent) 70%, transparent);
}
.site-menu .nav-cta:focus-visible { outline: 0; box-shadow: var(--sh-focus); }
.site-menu .nav-cta .nav-cta-arrow { transition: transform var(--dur-2) var(--ease); }
.site-menu .nav-cta:hover .nav-cta-arrow { transform: translateX(2px); }

/* legacy inline-link styles kept as a fallback for any page that
   still ships the old pattern; will fade out once every page migrates */
.site-menu > a {
  color: var(--fg-dim);
  text-decoration: none;
  padding: 6px 10px;
  border-radius: var(--r-pill);
  transition: color var(--dur-2) var(--ease), background var(--dur-2) var(--ease);
  white-space: nowrap;
}
.site-menu > a:hover { color: var(--fg); background: var(--bg-sunk); }
.site-menu > a[aria-current="page"] {
  color: var(--fg); background: var(--bg-paper);
  box-shadow: var(--sh-1);
  font-weight: 600;
}
.site-menu > a.is-cta {
  color: var(--accent-text);
  font-weight: 500;
}
.site-menu > a.is-cta:hover { color: var(--fg); background: var(--accent-soft); }

/* ── hamburger (mobile only) ───────────────────────── */
.nav-toggle {
  display: none;
  appearance: none; -webkit-appearance: none; background: transparent;
  border: 1px solid var(--hair); border-radius: var(--r-md);
  width: 36px; height: 36px; padding: 0;
  flex-direction: column; justify-content: center; align-items: center; gap: 4px;
  cursor: pointer;
  color: var(--fg);
  margin-left: auto;
}
.nav-toggle-bar {
  display: block; width: 16px; height: 1.75px; background: currentColor;
  border-radius: 1px;
  transition: transform var(--dur-2) var(--ease), opacity var(--dur-2) var(--ease);
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) {
  transform: translateY(5.75px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) {
  transform: translateY(-5.75px) rotate(-45deg);
}

/* ── responsive ────────────────────────────────────── */
@media (max-width: 960px) {
  .topnav-inner { gap: var(--s-4); }
  .nav-toggle { display: inline-flex; }
  .site-menu {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: var(--s-3);
    background: var(--bg);
    border-bottom: 1px solid var(--hair);
    padding: var(--s-5);
    transform: translateY(-8px); opacity: 0; pointer-events: none;
    transition: transform var(--dur-2) var(--ease), opacity var(--dur-2) var(--ease);
    box-shadow: 0 20px 40px -20px rgba(20, 25, 55, 0.18);
  }
  .site-menu.is-open {
    transform: translateY(0); opacity: 1; pointer-events: auto;
  }
  .site-menu > a {
    padding: 10px 12px; font-size: 14px;
    border-bottom: 1px solid var(--hair-soft); border-radius: 0;
  }
  .site-menu > a:last-child { border-bottom: 0; }
  .site-menu > a[aria-current="page"] { box-shadow: none; background: var(--bg-sunk); }
  .topnav .crumb { display: none; }

  /* mobile: dropdown becomes inline (no popover) */
  .nav-chapters { width: 100%; }
  .nav-chapters-trigger { width: 100%; justify-content: center; }
  .nav-chapters-panel {
    position: static;
    width: 100%;
    grid-template-columns: 1fr;
    box-shadow: none;
    border-color: var(--hair-soft);
    margin-top: var(--s-3);
    /* always shown on mobile inside the drawer */
    opacity: 1; transform: none; pointer-events: auto;
  }
  .nav-cta { justify-content: center; width: 100%; padding: 12px 16px; font-size: 14px; }
}
@media (max-width: 640px) {
  .topnav-inner { gap: var(--s-3); padding: var(--s-3) var(--s-4); }
  .topnav .brand { font-size: 15px; }
  .topnav .brand-mark { width: 22px; height: 22px; }
  .theme-toggle button { padding: 4px 9px; font-size: 11.5px; }
  .theme-toggle button svg { display: none; }
}

/* light / dark toggle */
.theme-toggle {
  display: inline-flex; align-items: center; gap: 0;
  background: var(--bg-sunk);
  border: 1px solid var(--hair);
  border-radius: var(--r-pill);
  padding: 3px;
  font-family: var(--f-body);
  font-size: 12px;
  font-weight: 500;
}
.theme-toggle button {
  appearance: none; -webkit-appearance: none;
  background: transparent; border: none;
  color: var(--fg-dim);
  padding: 5px 12px;
  border-radius: var(--r-pill);
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 5px;
  transition: color var(--dur-2) var(--ease), background var(--dur-2) var(--ease);
}
.theme-toggle button.is-active {
  background: var(--bg-paper);
  color: var(--fg);
  box-shadow: var(--sh-1);
}
.theme-toggle button svg { width: 13px; height: 13px; }

/* chapter header */
.chapter-head {
  padding: var(--s-11) 0 var(--s-9);
  border-bottom: 1px solid var(--hair);
}
.chapter-eyebrow {
  font-family: var(--f-mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 0 0 var(--s-4);
}
.chapter-title {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: clamp(36px, 5vw, 56px);
  line-height: 1.05;
  letter-spacing: -0.025em;
  margin: 0 0 var(--s-5);
  max-width: 22ch;
}
.chapter-title em {
  font-family: var(--f-serif);
  font-style: italic;
  font-weight: 400;
  color: var(--accent);
  font-variation-settings: "SOFT" 80;
}
.chapter-lede {
  font-size: 19px;
  line-height: 1.6;
  color: var(--fg-soft);
  max-width: 62ch;
  margin: 0 0 var(--s-6);
}

/* section divider (per-subsection) */
.section {
  padding: var(--s-11) 0;
  border-bottom: 1px solid var(--hair);
}
.section:last-of-type { border-bottom: 0; }
.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-6); margin-bottom: var(--s-6);
  flex-wrap: wrap;
}
.section-title {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 28px;
  letter-spacing: -0.01em;
  line-height: 1.2;
  margin: 0;
  display: flex; align-items: baseline; gap: var(--s-3);
}
.section-title .sn {
  font-family: var(--f-mono);
  font-size: 13px;
  color: var(--fg-faint);
  font-weight: 500;
}

/* section permalink — every .section gets a hash anchor next to its title.
   Shows on hover/focus; click copies the URL. JS adds the button; this
   styles it. */
.section-anchor {
  appearance: none;
  background: transparent;
  border: 0; padding: 0 var(--s-2);
  color: var(--fg-faint);
  font-family: var(--f-mono);
  font-size: 16px;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
  margin-left: var(--s-2);
  border-radius: var(--r-xs);
}
.section-anchor:hover,
.section:hover .section-anchor,
.section-anchor:focus-visible {
  opacity: 1;
  color: var(--accent-text);
}
.section-anchor.is-copied {
  opacity: 1;
  color: var(--success-text);
}
.section-anchor::before { content: '#'; }
.section-anchor.is-copied::before { content: '✓ copied'; font-size: 11px; }
/* keep the ID target visually off the sticky topnav when scrolled to */
.section { scroll-margin-top: 80px; }
.section-desc {
  color: var(--fg-soft);
  font-size: 16px;
  max-width: 60ch;
  line-height: 1.65;
  margin: 0 0 var(--s-7);
}

/* element block: the standard component slab */
.el {
  margin-bottom: var(--s-9);
}
.el-head {
  display: flex; align-items: baseline; gap: var(--s-4);
  flex-wrap: wrap;
  margin-bottom: var(--s-2);
}
.el-name {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: 18px;
  letter-spacing: -0.005em;
  margin: 0;
}
.el-tag {
  font-family: var(--f-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--fg-dim);
  padding: 2px 7px;
  background: var(--bg-sunk);
  border-radius: var(--r-sm);
  border: 1px solid var(--hair-soft);
}
.el-desc {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--fg-soft);
  margin: 0 0 var(--s-4);
  max-width: 68ch;
}
/* empty descriptions (generated in bulk) were adding ~40px of dead space
   above every demo — collapse them so spacing stays consistent. */
.el-desc:empty, .section-desc:empty { display: none; }

/* the render + code panel */
.demo {
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--bg-paper);
}
.demo-stage {
  padding: var(--s-7);
  display: flex; flex-wrap: wrap;
  gap: var(--s-5);
  align-items: flex-start;
  background:
    linear-gradient(var(--bg-paper), var(--bg-paper)),
    repeating-linear-gradient(
      45deg,
      transparent 0 6px,
      var(--stage-hash) 6px 7px
    );
  background-blend-mode: normal;
}
.demo-stage.center { justify-content: center; }
.demo-stage.vert { flex-direction: column; align-items: stretch; }
.demo-stage.plain { background: var(--bg-paper); }
/* .warm and .ink are deliberate surface variants — they pin to a specific
   tonal treatment regardless of theme so the component demo always reads
   the way the brand intends. In dark mode we nudge each one slightly so
   it stays visually separated from the surrounding page. */
.demo-stage.warm { background: var(--warm-3); color: var(--ink); }
.demo-stage.ink {
  background: var(--ink); color: var(--warm-3);
  --fg: var(--warm-3); --fg-soft: #C9CFE2; --hair: rgba(244,236,228,.14);
}
body[data-theme="dark"] .demo-stage.ink {
  /* lift off the page bg (also ink) with a subtle highlight ring */
  background: #1F2338;
  box-shadow: inset 0 0 0 1px rgba(244, 236, 228, 0.06);
}
body[data-theme="dark"] .demo-stage.warm {
  /* slightly richer warm so it feels intentional against the ink page */
  background: #E6D6C3;
}

/* code tabs */
.demo-tabs {
  border-top: 1px solid var(--hair);
  display: flex; align-items: stretch;
  background: var(--bg-sunk);
  gap: 0;
  font-family: var(--f-mono); font-size: 12px;
}
.demo-tabs button {
  appearance: none; background: transparent; border: 0;
  padding: var(--s-3) var(--s-5);
  color: var(--fg-dim); cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--s-2);
  border-right: 1px solid var(--hair);
  font-family: inherit; font-size: inherit;
}
.demo-tabs button.is-active { color: var(--fg); background: var(--bg-paper); }
.demo-tabs .spacer { flex: 1; }
.demo-tabs .copy {
  border-left: 1px solid var(--hair); border-right: 0;
  padding: 0 var(--s-5);
  color: var(--fg-dim);
}
.demo-tabs .copy:hover { color: var(--accent-text); }
.demo-tabs .copy.is-copied { color: var(--success-text); }

.demo-code {
  display: none;
  margin: 0;
  padding: var(--s-5) var(--s-6);
  background: var(--ink);
  color: #F4ECE4;
  font-family: var(--f-mono);
  font-size: 12.5px;
  line-height: 1.65;
  /* overflow-x: auto only works when width is constrained — pair with
     max-width:100% + min-width:0 so long lines scroll instead of widening
     the parent grid track. */
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
  white-space: pre;
  tab-size: 2;
  -moz-tab-size: 2;
}
.demo-code.is-active { display: block; }
.demo-code code { display: block; min-width: 0; }
/* tiny syntax hints inside .demo-code */
.demo-code .t { color: #FF9AB8; }  /* tags */
.demo-code .a { color: #FFD878; }  /* attr */
.demo-code .s { color: #7DF4D0; }  /* strings */
.demo-code .c { color: rgba(244,236,228,0.4); font-style: italic; } /* comment */
.demo-code .p { color: #5BD9FC; }  /* property */

/* anatomy callouts */
.anatomy {
  position: relative;
  border: 1px dashed var(--hair);
  border-radius: var(--r-lg);
  padding: var(--s-10) var(--s-10);
  margin-top: var(--s-4);
  background:
    linear-gradient(var(--bg-paper), var(--bg-paper)) padding-box,
    linear-gradient(135deg, rgba(255,63,122,0.3), rgba(31,170,232,0.3)) border-box;
  border: 1px dashed transparent;
}
.anatomy-legend {
  list-style: none; padding: 0; margin: var(--s-6) 0 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--s-3) var(--s-5);
  font-family: var(--f-mono); font-size: 12px;
  color: var(--fg-soft);
}
.anatomy-legend li {
  display: flex; gap: var(--s-3); align-items: baseline;
}
.anatomy-legend .n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex: 0 0 20px;
  border-radius: 50%;
  background: var(--accent); color: #fff;
  font-weight: 600; font-size: 10px;
}
.anatomy-chip {
  position: absolute;
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--accent); color: #fff;
  font-family: var(--f-mono); font-weight: 600; font-size: 10px;
  box-shadow: 0 0 0 3px var(--bg-paper);
  pointer-events: none;
  z-index: 2;
}

/* ============================================================ utilities */

.row { display: flex; gap: var(--s-4); flex-wrap: wrap; align-items: center; }
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s-6); }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-6); }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s-5); }
.grid-auto { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--s-5); }
@media (max-width: 720px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
}

.mono  { font-family: var(--f-mono); }
.small { font-size: 12px; }

/* chapter TOC (side nav on every page) */
.toc {
  position: sticky; top: 72px;
  font-family: var(--f-mono);
  font-size: 12px;
  line-height: 1.8;
  padding: var(--s-5) 0;
}
.toc h4 {
  font-family: var(--f-body);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--fg-faint);
  margin: 0 0 var(--s-3);
}
.toc a {
  display: block; color: var(--fg-soft);
  text-decoration: none; padding: 2px 0;
  border-left: 2px solid transparent;
  padding-left: var(--s-3);
  margin-left: calc(-1 * var(--s-3));
}
.toc a:hover { color: var(--accent-text); }
.toc a.is-active { color: var(--fg); border-left-color: var(--accent); }

/* layout: two-col with toc on left.
   NOTE: minmax(0, 1fr) (not just 1fr) on the content column is critical —
   grid tracks default to minmax(auto, 1fr), which lets intrinsic content
   (wide <pre> blocks inside .demo-code) push the column past its share
   and break the page width. min-width:0 on .content is belt-and-braces. */
.layout {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: var(--s-9);
  padding: var(--s-6) 0 var(--s-13);
}
.layout > .content { min-width: 0; }
@media (max-width: 960px) {
  .layout { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .toc { display: none; }
}

/* prev/next chapter footer */
.page-nav {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: var(--s-5);
  /* self-cap to page width — on 01-05/07/08/index the nav sits at body-
     level with no wrapper; on 06 it's nested inside .page, which is
     already capped, so the overrides below cancel the double-inset. */
  max-width: 1160px;
  margin: var(--s-11) auto var(--s-13);
  padding-inline: var(--s-7);
}
.page .page-nav,
.page-inner .page-nav { padding-inline: 0; }
@media (max-width: 640px) {
  .page-nav { padding-inline: var(--s-4); }
  .page .page-nav, .page-inner .page-nav { padding-inline: 0; }
}
.page-nav a {
  display: block; padding: var(--s-6);
  border: 1px solid var(--hair); border-radius: var(--r-lg);
  background: var(--bg-paper);
  text-decoration: none; color: var(--fg);
  transition: border-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
.page-nav a:hover { border-color: var(--accent); transform: translateY(-1px); }
.page-nav .dir {
  font-family: var(--f-mono); font-size: 11px; text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--fg-faint); margin-bottom: 6px;
}
.page-nav .title {
  font-family: var(--f-display); font-weight: 600; font-size: 18px;
}
.page-nav .next { text-align: right; }
@media (max-width: 720px) {
  .page-nav { grid-template-columns: 1fr; }
  .page-nav .next { text-align: left; }
}

/* footer */
.foot {
  padding: var(--s-9) 0;
  border-top: 1px solid var(--hair);
  color: var(--fg-dim);
  font-size: 13px;
  /* kept on .foot so pages with no .foot-inner wrapper (e.g. 06-media)
     still lay out their two children horizontally. When a .foot-inner
     IS present, this flex sees one child taking 100% width and the
     real layout is done by .foot-inner below. */
  display: flex; justify-content: space-between; gap: var(--s-6);
  flex-wrap: wrap;
}
.foot-inner {
  width: 100%;
  max-width: 1160px;
  margin: 0 auto;
  padding: 0 var(--s-7);
  display: flex; justify-content: space-between; gap: var(--s-6);
  flex-wrap: wrap;
}
.foot-inner .links { display: flex; gap: var(--s-5); flex-wrap: wrap; }
.foot-inner .links a { color: var(--fg-soft); text-decoration: none; }
.foot-inner .links a:hover { color: var(--accent-text); }
@media (max-width: 640px) {
  .foot-inner { padding: 0 var(--s-4); }
}
.foot .mono { font-size: 12px; }

/* ============================================================
   Floating page utilities — back-to-top + section nav
   Auto-injected by _shared.js on any page with 3+ sections.
   Lives on the left edge so it never sits over reading content;
   the popover slides in from the same edge. Pills stack vertically.
   Hides itself on print and respects prefers-reduced-motion. */
.mb-float {
  position: fixed; left: 20px; bottom: 20px; z-index: 70;
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  pointer-events: none;
  font-family: var(--sans, var(--f-body, system-ui));
}
.mb-float button,
.mb-float a {
  pointer-events: auto;
  appearance: none; -webkit-appearance: none;
  font: 600 11.5px/1 var(--mono, var(--f-mono, ui-monospace, "JetBrains Mono", monospace));
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--fg);
  background: var(--bg-paper);
  border: 1px solid var(--hair);
  border-radius: 999px;
  padding: 10px 14px;
  display: inline-flex; align-items: center; gap: 6px;
  box-shadow: 0 12px 28px -16px rgba(25, 30, 50, 0.45),
              0 4px 10px -4px rgba(25, 30, 50, 0.25);
  cursor: pointer;
  text-decoration: none;
  transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1),
              opacity 200ms ease,
              background 160ms ease,
              border-color 160ms ease,
              color 160ms ease;
  opacity: 0; transform: translateY(8px) scale(0.96);
}
.mb-float.is-visible button,
.mb-float.is-visible a {
  opacity: 1; transform: translateY(0) scale(1);
}
.mb-float button:hover,
.mb-float a:hover {
  background: var(--accent);
  color: var(--paper);
  border-color: transparent;
  transform: translateY(-1px);
}
.mb-float .mb-float-top svg,
.mb-float .mb-float-toc svg {
  width: 14px; height: 14px;
  stroke: currentColor; fill: none;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}

/* expandable section list — opens upward + to the right of the pill,
   anchored to the left edge so it never escapes the viewport */
.mb-float-pop {
  pointer-events: auto;
  position: absolute; left: 0; bottom: 100%;
  margin-bottom: 10px;
  width: min(280px, calc(100vw - 40px));
  max-height: 60vh;
  overflow-y: auto;
  background: var(--bg-paper);
  border: 1px solid var(--hair);
  border-radius: 14px;
  box-shadow: 0 24px 48px -20px rgba(25, 30, 50, 0.50),
              0 8px 16px -8px rgba(25, 30, 50, 0.25);
  padding: 8px;
  opacity: 0; transform: translateY(8px) scale(0.96);
  transform-origin: bottom left;
  pointer-events: none;
  transition: opacity 180ms ease, transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
}
.mb-float.is-open .mb-float-pop {
  opacity: 1; transform: translateY(0) scale(1);
  pointer-events: auto;
}
.mb-float-pop .mb-float-pop-title {
  font: 600 10.5px/1 var(--mono, var(--f-mono, ui-monospace, "JetBrains Mono", monospace));
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--fg-dim);
  padding: 8px 10px 6px;
}
.mb-float-pop a {
  display: flex; align-items: baseline; gap: 8px;
  padding: 8px 10px;
  border-radius: 8px;
  font: 500 13px/1.35 var(--sans, var(--f-body, system-ui));
  color: var(--fg-soft);
  text-transform: none;
  letter-spacing: normal;
  border: 0;
  background: transparent;
  box-shadow: none;
  opacity: 1;
  transform: none;
}
.mb-float-pop a .num {
  font: 500 11px/1 var(--mono, var(--f-mono, ui-monospace, "JetBrains Mono", monospace));
  color: var(--fg-dim);
  flex-shrink: 0; min-width: 28px;
}
.mb-float-pop a:hover {
  background: var(--bg-warm);
  color: var(--fg);
  transform: none;
  border-color: transparent;
}
.mb-float-pop a.is-active {
  background: var(--accent-soft);
  color: var(--accent-text);
}
.mb-float-pop a.is-active .num { color: var(--accent-text); }

/* hide on print */
@media print { .mb-float { display: none !important; } }
@media (prefers-reduced-motion: reduce) {
  .mb-float button, .mb-float a, .mb-float-pop {
    transition: none !important;
  }
}
@media (max-width: 480px) {
  .mb-float { left: 14px; bottom: 14px; gap: 8px; }
  .mb-float button, .mb-float a { padding: 9px 12px; font-size: 11px; }
}
