/* Guide-specific layout and components. */

main { position: relative; z-index: 10; max-width: 1200px; margin: 0 auto; padding: 1.75rem 2rem 2rem; }

/* No horizontal scrollbar on any device. A single wide element (old
   captured-poses table, a too-wide inline code block, etc.) used to
   push the entire viewport sideways on phones — now anything that
   overflows gets clipped at the document edge instead. */
html { overflow-x: clip; }
body { overflow-x: hidden; max-width: 100vw; }

/* ─── universal text-readability backdrop ─────────────────────────────────
   The animated background (grid + nebula + scan-line + noise) sits at
   z-index 0-3. Plain text floating directly over it gets visually
   chopped by the scanlines. Any prose container that doesn't already
   have its own opaque-ish background gets one here. Use a CSS variable
   so individual sections can opt out by overriding it.
   --text-bg: rgba(4, 4, 12, 0.78) → solid-feeling, still glows through */

.topic-content > details.section-collapse,
.topic-content > details.section-collapse > summary,
.topic-content .topic-section,
.topic-content p,
.topic-content ul:not(.module-list):not(.topic-grid):not(.rail-topics):not(.rail-toc):not(.paper-list):not(.software-list):not(.part-list),
.topic-content ol,
.topic-content blockquote,
.topic-content .callout,
.topic-content .vs-card,
.topic-content .example-card,
.topic-content .technique-card,
.topic-content .anim-placeholder,
main > section > p,
main > section > ul,
main > section > ol,
main > .topic-hero {
  /* let already-styled cards keep their own bg; only fall back if none */
}

/* The collapsible section body is the most common offender. */
details.section-collapse > div,
details.section-collapse > p,
details.section-collapse > ul,
details.section-collapse > ol,
details.section-collapse > blockquote,
details.section-collapse > pre,
details.section-collapse > table,
details.section-collapse > .callout,
details.section-collapse > .technique-grid,
details.section-collapse > .topic-grid,
details.section-collapse > .vs-grid,
details.section-collapse > .example-grid {
  position: relative;
}

/* Plain prose inside topic content — wrap each direct text node container
   in a soft backdrop so the scanlines stop chopping the letters. */
.topic-content > .topic-section,
.topic-section .vs-card,
.topic-section .example-card,
.topic-section .technique-card,
.topic-section .callout,
.topic-section .anim-placeholder,
.hero,
.topic-hero {
  background: rgba(4, 4, 12, 0.78);
  border-radius: 6px;
  position: relative;
}
.topic-section { padding: 0 0; }
.topic-section > details.section-collapse { padding: 14px 18px; }

/* The summary needs a backdrop too since it sits at the top of each section. */
details.section-collapse > summary {
  background: rgba(4, 4, 12, 0.85);
  margin-left: -18px;
  margin-right: -18px;
  padding-left: 30px;
  padding-right: 18px;
}

/* Lists rendered as references (paper-list, software-list, part-list) — each li
   already has its own bg. But the outer ul backdrop helps when the list is
   short. */
.paper-list, .software-list, .part-list { background: transparent; }

/* Topic hero / section headings get a fully solid backdrop so the headline
   pops against the nebula + scanlines. */
.topic-hero {
  background: rgba(4, 4, 12, 0.86);
  padding: 1.5rem 1.6rem 2rem;
  border-radius: 8px;
}
.topic-hero h1 { background: transparent; }

/* Top-level page sections (about, glossary, landing) sit on a solid
   backdrop, since they're long-form prose and pages have no rail. */
main > section { background: rgba(4, 4, 12, 0.78); border-radius: 8px; padding: 18px 22px; margin-bottom: 16px; }
main > section h2 { background: transparent; border-bottom-color: rgba(0,224,255,0.25); }
main > section h2:first-child { margin-top: 0; }

/* Glossary list cards already have a left border; give them a backdrop too. */
.glossary-list dd { background: rgba(4,4,12,0.6); padding: 6px 12px 6px 16px; border-radius: 4px; }
.glossary-list dt { padding: 0 6px; }

/* Code spans were a little too transparent — bump them. */
code { background: rgba(0, 0, 0, 0.55); }

/* Featured/recommended block already has its own gradient, just bump opacity. */
.featured-block { background-color: rgba(0, 0, 0, 0.45); }
.featured-block li { background: rgba(0, 0, 0, 0.65); }

/* ───────────── landing hero ───────────── */

.hero {
  padding: 4rem 0 3rem;
  text-align: center;
  position: relative;
}
.hero h1 {
  font-size: clamp(2rem, 5vw, 3.4rem);
  letter-spacing: 0.02em;
  text-shadow: 0 0 24px rgba(168, 85, 247, 0.45),
               0 0 40px rgba(0, 224, 255, 0.18);
}
.hero h1 .glow-cyan { color: var(--accent-cyan); }
.hero h1 .glow-purple { color: var(--accent-purple); }
.hero .subhead {
  font-size: 1.05rem;
  color: var(--text-secondary);
  max-width: 640px;
  margin: 1rem auto;
}
.hero .pill-row {
  display: inline-flex; gap: 8px; flex-wrap: wrap; justify-content: center;
  margin-top: 1.5rem;
}
.hero .pill {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding: 6px 14px;
  border-radius: 14px;
  background: rgba(0, 224, 255, 0.06);
  color: var(--accent-cyan);
  border: 1px solid rgba(0, 224, 255, 0.25);
}

/* ───────────── topic grid ───────────── */

.topic-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
  margin-top: 1.5rem;
}

.topic-card {
  display: block;
  background: var(--bg-panel);
  border: 1px solid var(--border-base);
  border-radius: 8px;
  padding: 1.1rem 1.2rem 1.2rem;
  text-decoration: none;
  color: inherit;
  position: relative;
  overflow: hidden;
  transition: all 280ms cubic-bezier(0.4, 0, 0.2, 1);
  backdrop-filter: blur(12px);
}
.topic-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0; height: 2px;
  background: var(--card-color, linear-gradient(90deg, var(--accent-cyan), var(--accent-purple)));
  opacity: 0.7;
  transition: opacity 280ms;
}
.topic-card:hover {
  border-color: var(--card-color, var(--accent-cyan));
  transform: translateY(-2px);
  box-shadow:
    0 0 0 1px rgba(0, 224, 255, 0.15),
    0 8px 28px -10px var(--card-color, rgba(0, 224, 255, 0.4)),
    0 4px 16px -8px rgba(168, 85, 247, 0.25);
}
.topic-card:hover::before { opacity: 1; }
/* Hex-framed icon holder: the emoji sits inside a rotated square with a
   neon ring in the card's category colour. Pulses on hover so the whole
   card feels alive and obviously interactive. */
.topic-card .icon-frame {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px; height: 54px;
  margin: 0 0 0.7rem;
  clip-path: polygon(50% 0%, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%);
  background:
    linear-gradient(135deg, var(--card-color, var(--accent-cyan)), transparent 75%),
    rgba(8, 12, 20, 0.85);
  border: 1px solid var(--card-color, var(--accent-cyan));
  box-shadow: 0 0 18px -2px var(--card-color, var(--accent-cyan));
  transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1),
              box-shadow 300ms;
}
.topic-card .icon-frame .icon-glow {
  position: absolute; inset: 3px;
  clip-path: inherit;
  background: radial-gradient(circle at 30% 30%,
              var(--card-color, var(--accent-cyan)) 0%,
              transparent 60%);
  opacity: 0.35;
  mix-blend-mode: screen;
  transition: opacity 300ms;
}
.topic-card .icon {
  font-size: 1.7rem;
  line-height: 1;
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
  /* Emoji baselines render ~2px below the geometric middle; nudge up so
     it reads as centred inside the hex. */
  padding-bottom: 2px;
  filter: drop-shadow(0 0 4px var(--card-color, var(--accent-cyan)));
  transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
.topic-card:hover .icon-frame {
  transform: rotate(12deg) scale(1.08);
  box-shadow: 0 0 28px -2px var(--card-color, var(--accent-cyan));
}
.topic-card:hover .icon-frame .icon-glow { opacity: 0.7; }
.topic-card:hover .icon { transform: rotate(-12deg) scale(1.1); }
.topic-card h3 {
  margin: 0 0 0.3rem;
  font-size: 1rem;
  font-weight: 600;
}
.topic-card .subhead {
  font-size: 0.82rem;
  color: var(--text-secondary);
  margin: 0;
}
.topic-card .card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 0.8rem;
}
.topic-card .category-pill {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding: 2px 8px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--text-dim);
  border: 1px solid var(--border-base);
}
/* "open →" affordance — visible at all times so clickability is obvious,
   intensifies on hover. */
.topic-card .card-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--card-color, var(--accent-cyan));
  opacity: 0.65;
  transition: opacity 300ms, transform 300ms;
}
.topic-card .card-cta-arrow {
  display: inline-block;
  transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
.topic-card:hover .card-cta { opacity: 1; }
.topic-card:hover .card-cta-arrow { transform: translateX(6px); }
.topic-card { cursor: pointer; }

/* "start here" treatment for the fundamentals topic card */
.topic-card.start-here {
  background:
    linear-gradient(135deg, rgba(255, 107, 157, 0.12), rgba(168, 85, 247, 0.08)),
    var(--bg-panel);
  border-color: rgba(255, 107, 157, 0.45);
}
.topic-card.start-here::before {
  background: linear-gradient(90deg, var(--accent-pink), var(--accent-purple));
  opacity: 1;
  height: 3px;
}
.start-here-pill {
  position: absolute;
  top: 12px; right: 12px;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-pink);
  background: rgba(255, 107, 157, 0.12);
  border: 1px solid rgba(255, 107, 157, 0.45);
  padding: 2px 8px;
  border-radius: 10px;
  text-shadow: 0 0 6px rgba(255, 107, 157, 0.5);
}

/* ─────────── intrinsics-vs-extrinsics page ─────────── */
.vs-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin: 1rem 0 0.5rem;
}
@media (max-width: 720px) { .vs-grid { grid-template-columns: 1fr; } }

.vs-card {
  position: relative;
  background: var(--bg-panel);
  border: 1px solid var(--border-base);
  border-radius: 8px;
  padding: 1.4rem 1.5rem 1.3rem;
  overflow: hidden;
}
.vs-card.vs-int { border-color: rgba(0, 224, 255, 0.4); }
.vs-card.vs-int::before {
  content: '';
  position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent-cyan), transparent);
}
.vs-card.vs-ext { border-color: rgba(168, 85, 247, 0.4); }
.vs-card.vs-ext::before {
  content: '';
  position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent-purple), transparent);
}

.vs-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 2px 10px;
  border-radius: 10px;
  margin-bottom: 0.7rem;
}
.vs-int .vs-tag {
  color: var(--accent-cyan);
  background: rgba(0, 224, 255, 0.1);
  border: 1px solid rgba(0, 224, 255, 0.3);
}
.vs-ext .vs-tag {
  color: var(--accent-purple);
  background: rgba(168, 85, 247, 0.1);
  border: 1px solid rgba(168, 85, 247, 0.3);
}
.vs-card h3 { margin: 0.2rem 0 0.5rem; font-size: 1.05rem; }
.vs-card p { color: var(--text-secondary); }

.example-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
  margin-top: 1rem;
}
.example-card {
  background: var(--bg-panel);
  border: 1px solid var(--border-base);
  border-radius: 6px;
  padding: 1rem 1.15rem;
}
.example-card h3 {
  margin: 0 0 0.4rem;
  font-size: 1rem;
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
}
.example-card p { font-size: 0.86rem; }
.example-card .small { font-size: 0.75rem; }
.example-card ul { padding-left: 1rem; margin: 0.4rem 0; }
.example-card ul li { font-size: 0.82rem; padding: 0.2rem 0; }

.callout {
  padding: 0.85rem 1.1rem;
  border-radius: 6px;
  margin: 1rem 0;
  font-size: 0.92rem;
  border: 1px solid;
}
.callout.callout-amber {
  background: rgba(240, 176, 32, 0.06);
  border-color: rgba(240, 176, 32, 0.4);
  color: var(--text-primary);
}
.callout.callout-amber strong { color: var(--accent-amber); }

/* ─────────── topic page layout ─────────── */

.topic-page { display: grid; grid-template-columns: 220px 1fr; gap: 2rem; }

.topic-rail {
  position: sticky;
  top: 1rem;
  align-self: start;
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: 1rem 0;
  border-right: 1px solid var(--border-base);
}

/* ── Mobile rail-drawer ──────────────────────────────────────────────
   At ≤900px the rail becomes an off-canvas drawer that slides in from
   the left (instead of stacking above the page hero, which ate the
   above-the-fold real estate). `.rail-toggle` in the site header opens
   the drawer, a backdrop dims the content, and the drawer closes on:
     (a) clicking any link inside it,
     (b) clicking the backdrop, or
     (c) pressing Escape.
   On wider screens `.rail-toggle` is hidden and the rail stays as a
   persistent sticky sidebar. */
@media (max-width: 900px) {
  .topic-page { grid-template-columns: 1fr; }
  .rail-toggle { display: inline-flex; }
  .topic-rail, .all-anims-toc {
    position: fixed !important;
    top: 0; left: 0; bottom: 0;
    width: min(320px, 82vw);
    max-height: 100vh !important;
    padding: 4.5rem 1.25rem 2rem;
    background: var(--bg-panel, rgba(4, 4, 12, 0.96));
    border-right: 1px solid var(--border-base);
    box-shadow: 8px 0 40px rgba(0, 0, 0, 0.6);
    z-index: 50;
    transform: translateX(-101%);
    transition: transform 220ms ease;
    /* Explicit auto + touch-action so iOS Safari and Chromium both
       allow scrolling the drawer content vertically even when
       `body { overflow: hidden }` is set (which we do via rail-open
       to lock the page behind the drawer). */
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }
  body.rail-open .topic-rail,
  body.rail-open .all-anims-toc {
    transform: translateX(0);
  }
  /* Backdrop — a REAL sibling element injected by nav.js at body level
     (not a `body::before` pseudo-element). Reason: `main` has
     `position: relative; z-index: 10`, which creates a stacking context
     at z-10 in the root context. The drawer (`.topic-rail`) lives
     inside that context. A pseudo-backdrop on body at z-40 sat in the
     root context ABOVE main(10), eating clicks on drawer links. Having
     the backdrop as a direct child of body lets it sit between main
     (z-10) and the drawer, which nav.js also appends to body on open
     so it joins the root stacking context at z-50 > 40. */
  .rail-backdrop {
    display: none;
    position: fixed; inset: 0;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(2px);
    z-index: 40;
    pointer-events: auto;
  }
  body.rail-open .rail-backdrop { display: block; }
  body.rail-open { overflow: hidden; }
}

/* Section collapsibles (auto-wrapped by js/nav.js) */
details.section-collapse { display: block; }
details.section-collapse > summary {
  cursor: pointer; list-style: none;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--accent-cyan);
  margin: 0 0 0.7rem;
  padding: 0.55rem 0 0.55rem 1.6rem;
  border-bottom: 1px solid var(--border-base);
  position: relative;
  user-select: none;
  transition: color 160ms;
}
details.section-collapse > summary::-webkit-details-marker { display: none; }
/* Cyberpunk chevron: a filled right-pointing neon triangle that rotates
   90° when the section opens. Bigger + more glowing than the plain `▸`
   so the "click to expand" affordance is obvious at a glance. */
details.section-collapse > summary::before {
  content: "";
  position: absolute; left: 0.35rem; top: 50%;
  width: 0; height: 0;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 8px solid var(--accent-purple);
  transform: translateY(-50%);
  filter: drop-shadow(0 0 6px rgba(168, 85, 247, 0.55));
  transition: transform 240ms cubic-bezier(0.4, 0, 0.2, 1),
              border-left-color 200ms, filter 200ms;
}
details.section-collapse[open] > summary::before {
  transform: translateY(-50%) rotate(90deg);
  border-left-color: var(--accent-cyan);
  filter: drop-shadow(0 0 8px rgba(0, 224, 255, 0.7));
}
details.section-collapse > summary:hover {
  color: var(--accent-pink);
}
details.section-collapse > summary:hover::before {
  border-left-color: var(--accent-pink);
  filter: drop-shadow(0 0 10px rgba(255, 107, 157, 0.75));
}
details.section-collapse[open] > summary { border-bottom-color: rgba(0, 224, 255, 0.4); }

/* References sub-collapsibles (rendered by js/citations.js) */
details.ref-collapse {
  background: var(--bg-panel);
  border: 1px solid var(--border-base);
  border-radius: 6px;
  padding: 0.5rem 0.85rem;
  margin: 0.55rem 0;
}
details.ref-collapse > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: var(--text-primary);
  padding: 0.3rem 0 0.3rem 1.2rem;
  position: relative;
  user-select: none;
}
details.ref-collapse > summary::-webkit-details-marker { display: none; }
details.ref-collapse > summary::before {
  content: "▸";
  position: absolute; left: 0; top: 0.3rem;
  color: var(--accent-purple);
  transition: transform 200ms;
}
details.ref-collapse[open] > summary::before { transform: rotate(90deg); }
.ref-label { font-weight: 600; }
.ref-count {
  margin-left: auto;
  color: var(--text-dim);
  font-size: 0.72rem;
  background: rgba(255, 255, 255, 0.04);
  padding: 1px 8px;
  border-radius: 10px;
  border: 1px solid var(--border-base);
}

/* Featured / recommended pick treatment for top-pick items */
.featured-block {
  background: linear-gradient(135deg, rgba(48, 232, 104, 0.08), rgba(0, 224, 255, 0.04));
  border: 1px solid rgba(48, 232, 104, 0.4);
  border-radius: 6px;
  padding: 0.85rem 1rem;
  margin: 0.6rem 0 1rem;
  position: relative;
}
.featured-block::before {
  content: "★ RECOMMENDED";
  position: absolute;
  top: -10px; left: 14px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  color: var(--accent-green);
  background: var(--bg-dark);
  padding: 2px 8px;
  border-radius: 10px;
  border: 1px solid rgba(48, 232, 104, 0.45);
  text-shadow: 0 0 6px rgba(48, 232, 104, 0.5);
}
.featured-block ul { list-style: none; padding: 0; display: grid; gap: 6px; }
.featured-block li {
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(60, 60, 80, 0.35);
  border-radius: 4px;
  padding: 0.5rem 0.8rem;
  font-size: 0.85rem;
}
.featured-block .featured-tag {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 8px;
  background: rgba(0, 224, 255, 0.1);
  color: var(--accent-cyan);
  border: 1px solid rgba(0, 224, 255, 0.3);
}
.featured-block .featured-tag.recent { background: rgba(48, 232, 104, 0.1); color: var(--accent-green); border-color: rgba(48, 232, 104, 0.3); }
.featured-block .featured-tag.seminal { background: rgba(168, 85, 247, 0.1); color: var(--accent-purple); border-color: rgba(168, 85, 247, 0.3); }

/* Richer sidebar */
.topic-rail .rail-block { margin-bottom: 1.5rem; padding-right: 0.8rem; }

/* Main-nav block — visible inside the rail on mobile (when the rail is
   a drawer) and hidden on desktop (where the header's in-place nav
   already shows the site menu). */
.rail-main-nav { display: none; }
@media (max-width: 900px) {
  .rail-main-nav { display: block; }
  .rail-main-nav .rail-toc a[aria-current="page"],
  .rail-main-nav .rail-toc a.current {
    color: var(--accent-cyan);
    border-left-color: var(--accent-cyan);
    background: rgba(0, 224, 255, 0.06);
  }
}
.topic-rail .rail-cap {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--text-dim);
  margin: 0 0 0.5rem;
}
.topic-rail .rail-actions { display: flex; gap: 4px; margin: 0 0 0.5rem; }
.rail-btn {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 10px;
  background: rgba(0, 224, 255, 0.06);
  color: var(--text-secondary);
  border: 1px solid rgba(0, 224, 255, 0.18);
  cursor: pointer;
  transition: all 120ms;
}
.rail-btn:hover { color: var(--accent-cyan); border-color: var(--accent-cyan); background: rgba(0, 224, 255, 0.14); }

.topic-rail .rail-toc { list-style: none; padding: 0; margin: 0; }
.topic-rail .rail-toc a {
  display: block;
  font-size: 0.82rem;
  color: var(--text-secondary);
  padding: 0.28rem 0 0.28rem 0.7rem;
  border-left: 2px solid transparent;
  transition: all 120ms;
  text-decoration: none;
}
.topic-rail .rail-toc a:hover, .topic-rail .rail-toc a.active {
  color: var(--accent-cyan);
  border-left-color: var(--accent-cyan);
  background: linear-gradient(90deg, rgba(0, 224, 255, 0.08), transparent);
}

.topic-rail details.rail-group { margin: 0.4rem 0; }
.topic-rail details.rail-group > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 6px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-secondary);
  padding: 0.35rem 0 0.35rem 1rem;
  border-bottom: 1px solid rgba(60, 60, 80, 0.18);
  position: relative;
}
.topic-rail details.rail-group > summary::-webkit-details-marker { display: none; }
.topic-rail details.rail-group > summary::before {
  content: "▸";
  position: absolute; left: 0; top: 0.35rem;
  color: var(--accent-purple);
  transition: transform 200ms;
}
.topic-rail details.rail-group[open] > summary::before { transform: rotate(90deg); }
.topic-rail details.rail-group .rail-count {
  margin-left: auto;
  color: var(--text-dim);
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  background: rgba(255, 255, 255, 0.03);
  padding: 1px 6px;
  border-radius: 8px;
  border: none;
}
.topic-rail .rail-topics { list-style: none; padding: 0.3rem 0 0.6rem; margin: 0; }
.topic-rail .rail-topics a {
  display: flex; align-items: center; gap: 7px;
  font-size: 0.78rem;
  color: var(--text-secondary);
  padding: 0.22rem 0.4rem;
  border-radius: 4px;
  border-left: 2px solid transparent;
  margin: 1px 0;
  text-decoration: none;
  transition: all 120ms;
}
.topic-rail .rail-topics a:hover { color: var(--text-primary); background: rgba(0, 224, 255, 0.06); }
.topic-rail .rail-topics a.current {
  color: var(--card-color, var(--accent-cyan));
  background: linear-gradient(90deg, rgba(0, 224, 255, 0.1), transparent);
  border-left-color: var(--card-color, var(--accent-cyan));
  font-weight: 600;
}
.topic-rail .rail-icon { font-size: 1rem; flex-shrink: 0; filter: drop-shadow(0 0 4px var(--card-color, transparent)); }
.topic-rail .rail-title { line-height: 1.3; }

.topic-rail .rail-meta {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  display: flex; flex-direction: column; gap: 0.4rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--border-base);
}
.topic-rail .rail-meta a { color: var(--accent-purple); text-decoration: none; }
.topic-rail .rail-meta a:hover { color: var(--accent-pink); }

.topic-content { min-width: 0; }

.topic-hero {
  padding: 1.5rem 0 2rem;
  border-bottom: 1px solid var(--border-base);
  margin-bottom: 1.5rem;
}
.topic-hero .kicker {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--accent-purple);
  margin-bottom: 0.6rem;
}
.topic-hero h1 { margin: 0; font-size: 2.2rem; }
.topic-hero .subhead {
  margin-top: 0.6rem;
  font-size: 1.05rem;
  color: var(--text-secondary);
  max-width: 720px;
}

/* Hero acronym expansion: "MR·CAL GUIDE = Multiple Robot Calibration Guide",
   shown subtly under the main brand so first-time visitors understand the
   name while keeping the "Mr. Cal" personality. */
.hero-expansion {
  margin: 0.5rem 0 0;
  font-family: var(--font-mono);
  font-size: 0.84rem;
  letter-spacing: 0.08em;
  color: var(--text-secondary);
}
.hero-expansion strong { color: var(--accent-cyan); font-weight: 700; }
.hero-expansion em { color: var(--text-dim); font-style: italic; }

/* Hero call-to-action row (Download button etc). */
.topic-hero .hero-actions {
  margin: 1.5rem 0 0.2rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  font-size: 0.95rem;
}
.cta-button {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  font-family: var(--font-mono);
  font-size: 0.84rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 700;
  padding: 0.85rem 1.5rem 0.85rem 1rem;
  border-radius: 6px;
  color: #04040c;
  background: var(--accent-cyan);
  border: 1px solid var(--accent-cyan);
  text-decoration: none;
  box-shadow:
    0 0 24px rgba(0, 224, 255, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.3);
  transition: transform 180ms, box-shadow 180ms, background 180ms;
  position: relative;
  overflow: hidden;
}
/* Soft pulse so the button draws attention on load. */
.cta-button::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  border: 2px solid var(--accent-cyan);
  animation: ctaPulse 2.6s ease-out infinite;
  pointer-events: none;
}
@keyframes ctaPulse {
  0%   { transform: scale(1);    opacity: 0.55; }
  80%  { transform: scale(1.18); opacity: 0; }
  100% { transform: scale(1.22); opacity: 0; }
}
.cta-button:hover {
  transform: translateY(-2px);
  background: #3dedff;
  box-shadow:
    0 0 36px rgba(0, 224, 255, 0.7),
    inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
.cta-button:active { transform: translateY(0); }
.cta-button .cta-icon {
  width: 28px; height: 28px; flex-shrink: 0;
  color: #04040c;
}
.cta-button .cta-tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: rgba(4, 4, 12, 0.85);
  color: var(--accent-cyan);
  font-size: 0.75rem;
  font-weight: 700;
  animation: ctaBounce 1.8s ease-in-out infinite;
}
@keyframes ctaBounce {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(2px); }
}
.cta-sub { color: var(--text-secondary); font-size: 0.85rem; }

.topic-section { margin: 2.5rem 0; scroll-margin-top: 1rem; }

/* ── universal link-hover treatment ─────────────────────────────────
   Every in-prose link gets an animated gradient underline that grows on
   hover, so links are obviously interactive without being visually
   loud in their resting state. Applied to content links; NAV/rail/
   button links opt out via their own classes or explicit `no-underline`. */
.topic-content a:not(.topic-link):not(.cta-button):not(.rail-toc a):not(.rail-topics a):not(.cite),
.topic-hero a:not(.cta-button),
.hero a,
main > section p a,
.topic-section p a,
.narration-panel .caption-narration a {
  color: var(--accent-cyan);
  text-decoration: none;
  background-image: linear-gradient(90deg,
    var(--accent-cyan), var(--accent-purple));
  background-size: 0% 1.5px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size 220ms, color 220ms, text-shadow 220ms;
  padding-bottom: 1px;
}
.topic-content a:not(.topic-link):not(.cta-button):not(.rail-toc a):not(.rail-topics a):not(.cite):hover,
.topic-hero a:not(.cta-button):hover,
.hero a:hover,
main > section p a:hover,
.topic-section p a:hover,
.narration-panel .caption-narration a:hover {
  background-size: 100% 1.5px;
  color: #3dedff;
  text-shadow: 0 0 8px rgba(0, 224, 255, 0.45);
}

/* Buttons, summaries, and any element carrying `cursor:pointer` gets a
   subtle lift+glow on hover, so clickable affordance is uniform. */
button:not(:disabled),
summary,
[role="button"],
.card-cta { cursor: pointer; }

button:not(:disabled):hover,
.rail-toggle:hover,
details.section-collapse > summary:hover {
  filter: brightness(1.15);
}

/* Animation chrome stack:
     [.anim-title]  — title bar above (sibling, mounted by nav.js)
     [.anim-host]   — the canvas itself
     [.narration-panel] — captions + voice controls (sibling, by narration.js)
   Everything is a vertically-stacked sibling. The .anim-host has its own
   borders only on the sides + nothing else; the title and panel finish the
   visual frame. */

.anim-title {
  background: rgba(4, 4, 12, 0.94);
  border: 1px solid var(--border-base);
  border-bottom: 1px solid rgba(168, 85, 247, 0.25);
  border-radius: 8px 8px 0 0;
  padding: 10px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-purple);
}
.anim-title-label {
  font-weight: 700;
  color: var(--accent-cyan);
  text-shadow: 0 0 10px rgba(0, 224, 255, 0.35);
}
.anim-title-beat {
  font-family: var(--font-body);
  font-size: 0.85rem;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--text-secondary);
}
.anim-title-beat:empty::before {
  content: "ready";
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.anim-host {
  background: radial-gradient(ellipse at center, #04080f 0%, #000000 80%);
  border-left: 1px solid var(--border-base);
  border-right: 1px solid var(--border-base);
  border-radius: 0;
  border-top: none;
  border-bottom: none;
  min-height: 540px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
  box-shadow: inset 0 0 32px rgba(0, 224, 255, 0.04);
}
@media (max-width: 720px) {
  .anim-host { min-height: 440px; }
}
/* Portrait-phone canvas height: when the viewport is clearly portrait
   (aspect < 0.9), give the .anim-host 70vh so the orientation-aware
   viewer classifies it as portrait and the Phase 4 portrait variants
   (lidar-extrinsics/portrait.js et al) get the vertical room they
   need for a stacked 3D-scene-above-chart-band layout. The width
   cap keeps desktop browsers with a narrow-but-tall drag-out window
   out of this rule. */
@media (max-aspect-ratio: 9/10) and (max-width: 900px) {
  .anim-host { min-height: 70vh; }
  /* Ecosystem is a six-stage vertical stack (sensor → TF tree) that
     doesn't fit in a 70vh portrait canvas — the top banner / bottom
     TF tree clip on a 9:16 phone. Bumped 25 % so the whole column
     reads without a zoom-out gesture; the tall-host pan/zoom-only
     controls (portrait.js) let the user pan around if they still
     want to inspect individual stages close up. */
  .anim-host-ecosystem { min-height: 87vh; }
}
/* When the viewport is LANDSCAPE (aspect ≥ 1.1), cap .anim-host height
   so a portrait-shaped canvas left over from a previous orientation
   doesn't keep the host stretched tall. Without this cap, flipping
   portrait → landscape leaves the canvas at its portrait height
   (e.g. 896px), which makes host aspect land in the 0.9-1.1 dead
   band and hysteresis refuses to trigger a landscape remount. The
   cap is only active above 900 viewport width so phone rotations
   (where the 70vh rule is wanted) aren't affected. */
@media (min-aspect-ratio: 11/10) and (min-width: 901px) {
  .anim-host { max-height: 65vh; }
  .anim-host > canvas { max-height: 100%; }
}
/* Narrow-phone canvas breakout.
   `main` carries a generous 2rem horizontal padding for prose readability,
   but the animation canvas and its sibling title + narration panels are
   fixed-width HUD-heavy components that need every pixel of horizontal
   room they can get on phone. Negative margins pull them out of the
   prose padding and restore ~64 lost pixels of canvas width at 430-CSS-px
   viewports. The sibling .anim-title and .narration-panel follow the
   host so the visual frame stays visually continuous. */
@media (max-width: 500px) {
  main { padding-left: 0.5rem; padding-right: 0.5rem; }
  .topic-content .anim-title,
  .topic-content .anim-host,
  .topic-content .narration-panel {
    margin-left: -0.5rem;
    margin-right: -0.5rem;
  }
  .anim-host { min-height: 480px; }
}
.anim-host:focus { outline: 2px solid rgba(0, 224, 255, 0.4); outline-offset: -2px; }

/* ─────────────────────────────────────────────────────────────────────
   IMU-family panel split (refactor: 3D + data views as siblings)
   ─────────────────────────────────────────────────────────────────────

   Background: every IMU animation used to render a single full-host
   WebGL canvas with absolute-positioned HUD panels stacked ON TOP of
   the 3D scene. The 3D cube was visible THROUGH the chart panels and
   the orientation reflows fought each other. The fix is to split the
   visualisation into discrete sibling DOM panels arranged by CSS
   flex/grid so landscape + portrait layouts can place them cleanly
   without the 3D cube bleeding behind anything.

   Pattern:
     <div class="anim-host anim-host-<slug>">
       <div class="panel panel-3d"><canvas></div>
       <div class="panel panel-ts"></div>
       <div class="panel panel-allan"></div>
     </div>

   Each shared.js wraps the renderer.domElement (created by mountAnim)
   in a `.panel.panel-3d` AFTER mount and rebuilds its HUD panels as
   sibling `.panel`s instead of absolute overlays. The slug-specific
   modifier class on the host (`anim-host-imu`, etc.) drives the
   grid-template per orientation. */

.anim-host.anim-stage-flex {
  /* When an IMU-family animation overrides the host into stage mode
     (a flex/grid container of panel siblings) the default centring
     flex from .anim-host is replaced — these animations own their
     own layout via a slug-specific rule below (.anim-host-imu, etc.)
     that sets `display: grid`. Padding is reset so each panel can
     pin to the host edge cleanly; the slug rule controls the grid
     template. align-items + justify-items are reset to `stretch` so
     panels fill their grid track instead of inheriting the
     centred-child default from .anim-host. */
  align-items: stretch;
  justify-items: stretch;
  padding: 0;
}

.anim-host .panel {
  /* Base sibling panel — flex item, owns its own positioning context
     for any inner HUD chips, never spills outside its allotted box. */
  position: relative;
  overflow: hidden;
  min-width: 0;   /* let the panel shrink below its content width */
  min-height: 0;
}
.anim-host .panel-3d {
  /* Host the THREE.WebGLRenderer canvas. Background is solid so the
     canvas's transparent-clear renderer doesn't show the parent
     gradient through gaps during a resize. min-height:0 + the absolute
     canvas (rule below) prevents the canvas's intrinsic size from
     pushing the grid track open in a feedback loop — without it the
     ResizeObserver+fitCanvas cycle can grow the panel each frame. */
  background: radial-gradient(ellipse at center, #04080f 0%, #000000 80%);
  min-height: 0;
  min-width: 0;
}
.anim-host .panel-3d > canvas {
  /* Pin the canvas to the panel-3d's content box via absolute
     positioning. position:absolute removes the canvas from the
     panel's intrinsic size calculation — so the panel sizes purely
     from its grid track (or flex basis), not from the canvas's
     <canvas height="X"> backing-buffer attribute. inset:0 keeps it
     flush with the panel edges. The animation's own fitCanvas() then
     drives renderer.setSize to the panel's clientWidth/clientHeight. */
  display: block;
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
}
.anim-host .panel-data {
  background: rgba(2, 4, 10, 0.96);
  border-left: 1px solid rgba(58, 58, 82, 0.7);
}
.anim-host[class*="anim-host-"] .panel + .panel {
  /* Visual separator between sibling panels. Border lives on the
     LATER panel so the 3D panel never shows a stray edge during the
     fitCanvas race. Direction-aware: flex-row places it on the left,
     flex-column on the top — uses inline-start logical edge. */
  border-inline-start: 1px solid rgba(58, 58, 82, 0.7);
}

/* ── anim-host-imu — IMU cube + gyro-z TS + Allan deviation (3 panels)
   Compound selector `.anim-host.anim-host-imu` matches the same
   2-class specificity budget as `.anim-host.anim-stage-flex` so the
   slug rule's `display: grid` outranks the host base's `display:
   flex` instead of tying with it. */
.anim-host.anim-host-imu {
  /* Landscape: 3D fills the LEFT 44% column, TS + Allan stack on
     the right 56% column (TS on top, Allan below — the Allan plot
     is the "main" reading and benefits from the wider vertical
     budget). Portrait: 3D top, TS middle, Allan bottom (vertical
     stack). */
  display: grid;
  grid-template-columns: 44% 56%;
  grid-template-rows: 40% 60%;
  grid-template-areas:
    "p3d ts"
    "p3d allan";
}
.anim-host.anim-host-imu .panel-3d    { grid-area: p3d; }
.anim-host.anim-host-imu .panel-ts    { grid-area: ts; }
.anim-host.anim-host-imu .panel-allan { grid-area: allan; }
@media (max-aspect-ratio: 1/1) {
  .anim-host.anim-host-imu {
    grid-template-columns: 1fr;
    grid-template-rows: 38% 24% 38%;
    grid-template-areas:
      "p3d"
      "ts"
      "allan";
  }
}

/* ── anim-host-imu-six-position — IMU cube + accel chart (2 panels) */
.anim-host.anim-host-imu-six-position {
  /* Landscape: cube on the LEFT 56% (the cube is the focal point
     for this calibration walkthrough; the chart is the readout).
     Portrait: cube on top 55%, chart below. */
  display: grid;
  grid-template-columns: 56% 44%;
  grid-template-rows: 1fr;
  grid-template-areas: "p3d data";
}
.anim-host.anim-host-imu-six-position .panel-3d   { grid-area: p3d; }
.anim-host.anim-host-imu-six-position .panel-data { grid-area: data; }
@media (max-aspect-ratio: 1/1) {
  .anim-host.anim-host-imu-six-position {
    grid-template-columns: 1fr;
    grid-template-rows: 55% 45%;
    grid-template-areas:
      "p3d"
      "data";
  }
}

/* ── anim-host-camera-imu — 3D scene + legend + time-offset readout */
.anim-host.anim-host-camera-imu {
  /* Landscape: 3D scene fills the LEFT 70%, the right 30% column
     stacks legend on top + time-offset readout below. Portrait:
     legend + time-offset stack at the top in a 22%-tall band, 3D
     scene below them. */
  display: grid;
  grid-template-columns: 70% 30%;
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "p3d  legend"
    "p3d  td";
}
.anim-host.anim-host-camera-imu .panel-3d     { grid-area: p3d; }
.anim-host.anim-host-camera-imu .panel-legend { grid-area: legend; }
.anim-host.anim-host-camera-imu .panel-td     { grid-area: td; }
@media (max-aspect-ratio: 1/1) {
  .anim-host.anim-host-camera-imu {
    grid-template-columns: 50% 50%;
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "legend td"
      "p3d    p3d";
  }
}

/* ── anim-host-lidar-imu — 3D rig + dt readout band */
.anim-host.anim-host-lidar-imu {
  /* Landscape: 3D scene fills the LEFT 68%, dt readout panel on the
     right 32% column. Portrait: dt readout in the top 22% band, 3D
     scene below. */
  display: grid;
  grid-template-columns: 68% 32%;
  grid-template-rows: 1fr;
  grid-template-areas: "p3d data";
}
.anim-host.anim-host-lidar-imu .panel-3d   { grid-area: p3d; }
.anim-host.anim-host-lidar-imu .panel-data { grid-area: data; }
@media (max-aspect-ratio: 1/1) {
  .anim-host.anim-host-lidar-imu {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "data"
      "p3d";
  }
}

/* ── narration player (mounted by js/narration.js inside .anim-host) ── */
/* Narration panel — sibling below the .anim-host. Joined visually to
   the canvas (no top border, hard top corners). Now also acts as the
   universal "controls below" container — the play / step / replay
   buttons live in .narration-controls and are centred. */
.narration-panel {
  background: rgba(4, 4, 12, 0.94);
  border: 1px solid var(--border-base);
  border-top: 1px solid rgba(0, 224, 255, 0.18);
  border-radius: 0 0 8px 8px;
  margin-bottom: 1.25rem;
  padding: 14px 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Legacy positioning (still used if mountNarration falls back to
   appending inside the host). New code path uses .narration-panel
   above. */
.narration:not(.narration-panel) {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 5;
  pointer-events: none;
}
.narration-missing {
  position: absolute;
  bottom: 8px; right: 12px;
  z-index: 6;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  color: var(--accent-amber);
  background: rgba(240, 176, 32, 0.1);
  border: 1px solid rgba(240, 176, 32, 0.4);
  border-radius: 12px;
  padding: 2px 10px;
}
.narration-caption {
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid rgba(0, 224, 255, 0.18);
  border-radius: 6px;
  padding: 12px 16px;
  color: var(--text-primary);
  font-size: 1.02rem;
  line-height: 1.45;
  pointer-events: auto;
  transition: border-color 320ms, box-shadow 320ms;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.narration-caption.active {
  border-color: rgba(0, 224, 255, 0.6);
  box-shadow: 0 0 24px rgba(0, 224, 255, 0.12);
}
.narration-caption .caption-text {
  font-weight: 700;
  font-size: 1.08rem;
  color: var(--text-primary);
  letter-spacing: 0.01em;
}
.narration-caption .caption-narration {
  font-size: 0.94rem;
  font-weight: 400;
  color: var(--text-secondary);
  line-height: 1.6;
  min-height: 1em;
  text-align: left;
  /* Show the full narration. No max-height clip — what the user hears
     is what the user sees. */
}
.narration-caption .caption-narration:empty { display: none; }
.narration-caption .caption-narration mark {
  background: rgba(0, 224, 255, 0.18);
  color: var(--accent-cyan);
  padding: 0 2px;
  border-radius: 2px;
  font-weight: 600;
  text-shadow: 0 0 8px rgba(0, 224, 255, 0.4);
}
.narration-caption .caption-narration .spoken { color: var(--text-dim); }
.narration-caption .caption-narration .unspoken { color: var(--text-secondary); }
.narration-controls {
  display: flex;
  align-items: center;
  justify-content: center;       /* centred per user request */
  gap: 10px;
  padding: 4px 4px 0;
  pointer-events: auto;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  flex-wrap: wrap;
}
/* Settings drawer floats to the right inside the centered control row. */
.narration-controls .narr-settings { margin-left: 12px; }
.narration-controls button,
.narration-controls .narr-progress,
.narration-controls .narr-settings > summary {
  background: rgba(4, 4, 12, 0.85);
  color: var(--text-secondary);
  border: 1px solid var(--border-base);
  border-radius: 14px;
  padding: 4px 10px;
  font: inherit;
  cursor: pointer;
  user-select: none;
  transition: all 140ms;
  list-style: none;
}
.narration-controls button:hover,
.narration-controls .narr-settings > summary:hover {
  color: var(--accent-cyan);
  border-color: var(--accent-cyan);
  background: rgba(0, 224, 255, 0.1);
}
.narration-controls .narr-toggle {
  font-weight: 700;
  letter-spacing: 0.04em;
  background: linear-gradient(135deg, rgba(0, 224, 255, 0.15), rgba(168, 85, 247, 0.12));
  border-color: rgba(0, 224, 255, 0.5);
  color: var(--accent-cyan);
  text-shadow: 0 0 8px rgba(0, 224, 255, 0.4);
}
.narration-controls .narr-toggle.speaking {
  background: linear-gradient(135deg, rgba(48, 232, 104, 0.25), rgba(0, 224, 255, 0.2));
  border-color: var(--accent-green);
  color: var(--accent-green);
  text-shadow: 0 0 10px rgba(48, 232, 104, 0.6);
  animation: speakingPulse 1.4s ease-in-out infinite;
}
@keyframes speakingPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(48, 232, 104, 0.45); }
  50%      { box-shadow: 0 0 0 6px rgba(48, 232, 104, 0); }
}
.narration-controls .narr-progress {
  cursor: default;
  pointer-events: none;
  color: var(--text-dim);
  letter-spacing: 0.04em;
}
.narration-controls .narr-settings > summary::-webkit-details-marker { display: none; }
/* Make the settings gear obvious: bigger icon + a text label next to it.
   Was a lone tiny "⚙" with no tooltip that users couldn't see or click. */
.narration-controls .narr-settings > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 4px 12px;
}
.narration-controls .narr-gear {
  font-size: 1.1em;
  line-height: 1;
  filter: drop-shadow(0 0 4px rgba(0, 224, 255, 0.35));
  transition: transform 300ms;
}
.narration-controls .narr-settings[open] > summary .narr-gear,
.narration-controls .narr-settings > summary:hover .narr-gear {
  transform: rotate(60deg);
}
.narration-controls .narr-settings-label {
  font-size: 0.82em;
  letter-spacing: 0.06em;
  text-transform: lowercase;
}
.narration-controls .narr-settings { position: relative; }
.narration-controls .narr-settings[open] > .narr-settings-body {
  position: absolute;
  bottom: 36px; right: 0;
  min-width: 240px;
  background: rgba(4, 4, 12, 0.95);
  border: 1px solid rgba(0, 224, 255, 0.3);
  border-radius: 6px;
  padding: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6),
              0 0 16px rgba(0, 224, 255, 0.15);
}
.narr-settings-body label {
  display: block;
  margin-bottom: 10px;
  color: var(--text-secondary);
  font-size: 0.78rem;
}
.narr-settings-body select,
.narr-settings-body input[type="range"] {
  display: block;
  width: 100%;
  margin-top: 4px;
  background: rgba(0, 0, 0, 0.5);
  color: var(--text-primary);
  border: 1px solid var(--border-base);
  border-radius: 3px;
  padding: 4px 6px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
}
.narr-rate-value {
  display: inline-block;
  margin-left: 6px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--accent-cyan);
}
.narr-tts-warn, .narr-tts-hint {
  margin: 0;
  padding: 6px 8px;
  background: rgba(240, 176, 32, 0.08);
  border: 1px solid rgba(240, 176, 32, 0.3);
  border-radius: 4px;
  color: var(--accent-amber);
  font-size: 0.7rem;
  line-height: 1.3;
}
.narr-tts-hint {
  background: rgba(0, 224, 255, 0.06);
  border-color: rgba(0, 224, 255, 0.25);
  color: var(--text-secondary);
}
.narr-voice-preview {
  margin-left: 6px;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  background: rgba(0, 224, 255, 0.1);
  color: var(--accent-cyan);
  border: 1px solid rgba(0, 224, 255, 0.3);
  border-radius: 10px;
  padding: 2px 8px;
  cursor: pointer;
}
.narr-voice-preview:hover { background: rgba(0, 224, 255, 0.2); }
@media (max-width: 720px) {
  .narration-controls { flex-wrap: wrap; gap: 4px; }
  .narration-caption { font-size: 0.85rem; padding: 8px 10px; }
}
.anim-host::after {
  content: '';
  position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(ellipse 80% 30% at 50% 0%, rgba(0, 224, 255, 0.08), transparent 60%),
    radial-gradient(ellipse 80% 30% at 50% 100%, rgba(168, 85, 247, 0.08), transparent 60%);
}

.anim-placeholder {
  text-align: center; max-width: 500px; padding: 2rem;
  color: var(--text-secondary);
  position: relative; z-index: 1;
}
.anim-placeholder .badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-purple);
  background: rgba(168, 85, 247, 0.08);
  border: 1px solid rgba(168, 85, 247, 0.3);
  padding: 4px 10px;
  border-radius: 12px;
  margin-bottom: 1rem;
}
.anim-placeholder strong { display: block; font-size: 1.1rem; color: var(--text-primary); margin-bottom: 0.5rem; }
.anim-placeholder em { display: block; margin-top: 0.8rem; font-size: 0.78rem; color: var(--text-dim); }

/* ─────────── technique cards ─────────── */

.technique-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
  gap: 12px;
}

.technique-card {
  background: var(--bg-panel);
  border: 1px solid var(--border-base);
  border-radius: 6px;
  padding: 1rem 1.15rem;
  position: relative;
}
.technique-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; bottom: 0; width: 3px;
  background: linear-gradient(180deg, var(--accent-cyan), var(--accent-purple));
  border-radius: 6px 0 0 6px;
}
.technique-card h3 { margin: 0 0 0.5rem; font-size: 1rem; }
.technique-card p { font-size: 0.86rem; color: var(--text-secondary); }
.technique-card .meta {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
}

/* ─────────── citation chips ─────────── */

.cite {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  padding: 1px 6px;
  border-radius: 3px;
  cursor: help;
  border: 1px solid transparent;
  transition: all 120ms;
  white-space: nowrap;
}
.cite-paper { background: rgba(0, 224, 255, 0.08); color: var(--accent-cyan); border-color: rgba(0, 224, 255, 0.2); }
.cite-paper::before { content: '📄 '; }
.cite-software { background: rgba(48, 232, 104, 0.08); color: var(--accent-green); border-color: rgba(48, 232, 104, 0.2); }
.cite-software::before { content: '📦 '; }
.cite-part { background: rgba(168, 85, 247, 0.08); color: var(--accent-purple); border-color: rgba(168, 85, 247, 0.2); }
.cite-part::before { content: '🔧 '; }
.cite-excluded { background: rgba(255, 71, 87, 0.08); color: var(--accent-red); border-color: rgba(255, 71, 87, 0.3); }
.cite-excluded::before { content: '⊘ '; }

.cite:hover { filter: brightness(1.3); transform: translateY(-1px); }

/* tooltip card on hover (positioned by JS) */
.cite-tooltip {
  position: absolute;
  z-index: 1500;
  max-width: 380px;
  background: var(--bg-panel);
  border: 1px solid var(--accent-cyan);
  border-radius: 6px;
  padding: 0.85rem 1rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6),
              0 0 16px rgba(0, 224, 255, 0.2);
  font-size: 0.82rem;
  pointer-events: none;
  backdrop-filter: blur(12px);
}
.cite-tooltip strong { display: block; color: var(--text-primary); margin-bottom: 0.25rem; }
.cite-tooltip .meta { color: var(--text-dim); font-family: var(--font-mono); font-size: 0.72rem; }
.cite-tooltip a { color: var(--accent-cyan); }

/* ─────────── tradeoffs table ─────────── */

.tradeoffs-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--bg-panel);
  border: 1px solid var(--border-base);
  border-radius: 6px;
  overflow: hidden;
  font-size: 0.86rem;
}
.tradeoffs-table th {
  background: rgba(0, 0, 0, 0.4);
  padding: 0.7rem 1rem;
  text-align: left;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-dim);
  font-weight: 500;
  border-bottom: 1px solid var(--border-base);
}
.tradeoffs-table td {
  padding: 0.65rem 1rem;
  border-bottom: 1px solid rgba(60, 60, 80, 0.18);
  vertical-align: top;
}
.tradeoffs-table tr:last-child td { border-bottom: none; }
.tradeoffs-table tr:hover td { background: rgba(0, 224, 255, 0.03); }

/* ─────────── parts (hardware) cards ─────────── */

.part-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 12px;
}
.part-card {
  background: var(--bg-panel);
  border: 1px solid var(--border-base);
  border-radius: 6px;
  padding: 0.9rem 1rem;
  font-size: 0.85rem;
}
.part-card .name { font-weight: 600; color: var(--text-primary); }
.part-card .vendor { font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-dim); }
.part-card dl { margin: 0.6rem 0 0; display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 0.78rem; }
.part-card dt { color: var(--text-dim); font-family: var(--font-mono); font-size: 0.72rem; }
.part-card dd { color: var(--text-primary); margin: 0; }
.part-card a.datasheet {
  display: inline-block; margin-top: 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
}

/* ─────────── reference lists ─────────── */

.paper-list, .software-list, .part-list {
  list-style: none; padding: 0;
  display: grid; gap: 6px;
}
.paper-list li, .software-list li, .part-list li {
  padding: 0.55rem 0.85rem;
  background: var(--bg-panel);
  border: 1px solid var(--border-base);
  border-radius: 4px;
  font-size: 0.85rem;
}
.paper-list .meta, .software-list .meta {
  display: block;
  margin-top: 2px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-dim);
}
.software-list .license-pill {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  padding: 1px 6px;
  border-radius: 3px;
  margin-left: 4px;
}
.license-pill.permissive { background: rgba(48, 232, 104, 0.1); color: var(--accent-green); }
.license-pill.copyleft   { background: rgba(255, 71, 87, 0.1); color: var(--accent-red); }
.license-pill.unverified { background: rgba(240, 176, 32, 0.1); color: var(--accent-amber); }

.search-box {
  display: block;
  width: 100%;
  margin-bottom: 0.8rem;
  padding: 0.6rem 0.85rem;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  background: rgba(0, 0, 0, 0.5);
  color: var(--text-primary);
  border: 1px solid var(--border-base);
  border-radius: 4px;
}
.search-box:focus { outline: none; border-color: var(--accent-cyan); box-shadow: 0 0 0 2px rgba(0, 224, 255, 0.2); }

/* ─────────── glossary ─────────── */

/* Glossary v2: filter chips + sidebar hierarchy + compact cards with
   collapsible resources. Renderer in js/common/glossary-renderer.js;
   data in /data/glossary.json. The legacy `.glossary-list` (dl/dt/dd)
   rules remain below for any deep-linked embed that still uses that
   shape. */

.glossary-page { max-width: 1240px; }

.glossary-chrome {
  display: flex; flex-direction: column; gap: 0.8rem;
  margin: 1rem 0 1.2rem;
}
.glossary-filters {
  display: flex; flex-wrap: wrap; gap: 0.4rem;
  align-items: center;
}
.gl-chip {
  --chip-color: var(--accent-cyan);
  background: rgba(4, 8, 16, 0.7);
  color: var(--text-secondary);
  border: 1px solid rgba(120, 160, 210, 0.28);
  border-radius: 999px;
  padding: 0.35rem 0.85rem;
  font: 600 0.82rem/1.2 var(--font-mono, ui-monospace, Menlo, Consolas, monospace);
  letter-spacing: 0.04em;
  cursor: pointer;
  user-select: none;
  transition: background 160ms, color 160ms, border-color 160ms, box-shadow 160ms;
}
.gl-chip:hover {
  color: var(--text-primary);
  border-color: var(--chip-color);
}
.gl-chip.is-active {
  color: #04080e;
  background: var(--chip-color);
  border-color: var(--chip-color);
  box-shadow: 0 0 18px rgba(0, 224, 255, 0.18);
}
.gl-count {
  opacity: 0.75;
  margin-left: 0.35rem;
  font-size: 0.74rem;
}
.glossary-search {
  width: 100%; max-width: 520px;
  padding: 0.55rem 0.8rem;
  background: rgba(4, 8, 16, 0.8);
  color: var(--text-primary);
  border: 1px solid rgba(120, 160, 210, 0.3);
  border-radius: 6px;
  font: 500 0.9rem/1.2 var(--font-body, ui-sans-serif, system-ui, sans-serif);
}
.glossary-search:focus {
  outline: none;
  border-color: var(--accent-cyan);
  box-shadow: 0 0 0 2px rgba(0, 224, 255, 0.25);
}

/* Main column only — per-topic jump navigation now lives in the
   site-wide rail (see `.rail-gl-list` below). Keeping a second
   sidebar inside the main column produced two vertically-scrolling
   TOCs that looked independent to the reader. */
.glossary-body { display: block; }

/* Rail's "Browse glossary" block — injected by glossary-renderer.js
   into the site rail on /glossary.html. Matches the visual style of
   the existing rail's "On this page" + "Browse topics" blocks. */
.rail-gl-list {
  max-height: calc(100vh - 260px);
  overflow-y: auto;
  padding-right: 0.25rem;
}
.rail-gl-group { margin-bottom: 0.25rem; }
.rail-gl-group > summary {
  cursor: pointer;
  font: 600 0.72rem/1.3 var(--font-mono, ui-monospace, monospace);
  color: var(--text-primary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.35rem 0.35rem;
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  list-style: none;
}
.rail-gl-group > summary::-webkit-details-marker { display: none; }
.rail-gl-group > summary::before {
  content: "▸";
  display: inline-block;
  color: rgba(120, 160, 210, 0.55);
  transition: transform 160ms;
}
.rail-gl-group[open] > summary::before { transform: rotate(90deg); }
.rail-gl-group > summary:hover { background: rgba(120, 160, 210, 0.08); }
.rail-gl-dot {
  width: 8px; height: 8px; border-radius: 50%;
  display: inline-block;
}
.rail-gl-count {
  margin-left: auto;
  color: var(--text-muted, rgba(200, 220, 240, 0.5));
  font-weight: 400;
  font-size: 0.72rem;
}
.rail-gl-group ul {
  list-style: none;
  padding: 0 0 0.3rem 1.25rem;
  margin: 0.15rem 0 0;
}
.rail-gl-group li { margin: 0.12rem 0; }
.rail-gl-group a {
  color: var(--text-secondary);
  text-decoration: none;
  padding: 0.15rem 0.35rem;
  border-radius: 3px;
  display: block;
  font-size: 0.82rem;
  line-height: 1.3;
  transition: background 120ms, color 120ms;
}
.rail-gl-group a:hover {
  background: rgba(0, 224, 255, 0.08);
  color: var(--text-primary);
}

.glossary-list {
  display: grid;
  gap: 0.9rem;
}
.gl-card {
  background: rgba(4, 8, 16, 0.65);
  border: 1px solid rgba(120, 160, 210, 0.22);
  border-radius: 8px;
  padding: 0.85rem 1rem;
  scroll-margin-top: 96px;
  transition: background 200ms, border-color 200ms, box-shadow 200ms;
}
.gl-card.is-anchored {
  border-color: var(--accent-cyan);
  background: rgba(0, 224, 255, 0.06);
  box-shadow: 0 0 20px rgba(0, 224, 255, 0.12);
}
.gl-card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
  margin-bottom: 0.35rem;
}
.gl-card-head h3 {
  font-size: 1.02rem;
  margin: 0;
  color: var(--text-primary);
  font-weight: 700;
}
.gl-anchor {
  color: rgba(120, 160, 210, 0.35);
  text-decoration: none;
  margin-right: 0.4rem;
  font-weight: 400;
  font-family: var(--font-mono, monospace);
}
.gl-anchor:hover { color: var(--accent-cyan); }
.gl-pills { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.gl-pill {
  --pill-color: var(--accent-cyan);
  font: 600 0.68rem/1.2 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  color: var(--pill-color);
  background: color-mix(in srgb, var(--pill-color) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--pill-color) 35%, transparent);
}
.gl-def {
  margin: 0.2rem 0 0.4rem;
  color: var(--text-secondary);
  font-size: 0.94rem;
  line-height: 1.5;
}

.gl-resources {
  margin-top: 0.45rem;
  border-top: 1px dashed rgba(120, 160, 210, 0.18);
  padding-top: 0.4rem;
}
.gl-resources summary {
  cursor: pointer;
  font: 600 0.76rem/1.3 var(--font-mono, monospace);
  color: var(--text-secondary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.25rem 0.2rem;
  border-radius: 4px;
  user-select: none;
  list-style: none;
}
.gl-resources summary::before {
  content: "▸";
  display: inline-block;
  margin-right: 0.4rem;
  transition: transform 160ms;
  color: rgba(120, 160, 210, 0.55);
}
.gl-resources[open] summary::before { transform: rotate(90deg); }
.gl-resources summary:hover { color: var(--text-primary); }
.gl-res-body {
  padding: 0.4rem 0.3rem 0.2rem 1.25rem;
  display: grid; gap: 0.6rem;
}
.gl-res-section h4 {
  margin: 0 0 0.25rem;
  font: 600 0.72rem/1.3 var(--font-mono, monospace);
  color: var(--text-muted, rgba(200, 220, 240, 0.55));
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.gl-res-list {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: 0.28rem;
}
.gl-res-list li {
  font-size: 0.88rem;
  color: var(--text-secondary);
  display: flex;
  gap: 0.45rem;
  align-items: baseline;
}
.gl-res-list a {
  color: var(--accent-cyan);
  text-decoration: none;
  border-bottom: 1px dotted rgba(0, 224, 255, 0.45);
}
.gl-res-list a:hover { border-bottom-color: var(--accent-cyan); }
.gl-res-kind {
  font-size: 0.8rem;
  opacity: 0.7;
}

/* Legacy dl/dt/dd for older glossary embeds (kept working). */
.glossary-list dl { display: grid; gap: 0.75rem; }
.glossary-list dt {
  font-weight: 700; color: var(--text-primary);
  font-size: 1.05rem;
  margin-top: 0.4rem;
  scroll-margin-top: 96px;
  transition: background 200ms, box-shadow 200ms;
  border-radius: 4px;
}
.glossary-list dt.is-anchored {
  background: rgba(0, 224, 255, 0.10);
  box-shadow: inset 3px 0 0 0 var(--accent-cyan);
}
.glossary-list dd { color: var(--text-secondary); margin: 0 0 0.4rem; padding-left: 0.4rem; border-left: 2px solid var(--accent-purple); }

/* ─────────── glossary auto cross-reference (core design language) ───────────
   Authors don't manually annotate jargon — js/glossary-link.js walks
   every page on mount, finds glossary terms in plain text, and wraps
   each match in a `.glossary-term` span. The visual treatment below
   is the project's universal "this word has a definition" affordance:
   a subtle dotted underline + cursor:help, with a custom popover on
   hover/focus and click-to-glossary. See
   docs/architecture/design-language.md. */

.glossary-term {
  /* Dotted underline as a low-noise affordance. Color inherits so
     long passages of jargon don't visually "speckle" — only the
     underline differentiates these from regular text. */
  text-decoration: underline dotted rgba(168, 85, 247, 0.55);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  cursor: help;
  outline: none;
  border-radius: 2px;
  transition: background 120ms, text-decoration-color 120ms;
}
.glossary-term:hover,
.glossary-term:focus-visible {
  text-decoration-color: var(--accent-cyan);
  background: rgba(0, 224, 255, 0.06);
}
.glossary-term:focus-visible {
  outline: 2px solid var(--accent-cyan);
  outline-offset: 1px;
}

/* Popover card — positioned by JS. Mirrors .cite-tooltip so the page
   has one consistent "definition card" visual. */
.glossary-tooltip {
  position: absolute;
  z-index: 1500;
  max-width: 360px;
  background: var(--bg-panel);
  border: 1px solid var(--accent-cyan);
  border-radius: 6px;
  padding: 0.85rem 1rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6),
              0 0 16px rgba(0, 224, 255, 0.18);
  font-size: 0.82rem;
  pointer-events: none;
  backdrop-filter: blur(12px);
  animation: glossaryTooltipFade 140ms ease-out;
}
.glossary-tooltip strong {
  display: block;
  color: var(--text-primary);
  margin-bottom: 0.35rem;
  font-size: 0.92rem;
}
.glossary-tooltip p {
  color: var(--text-secondary);
  margin: 0 0 0.55rem;
  line-height: 1.45;
}
.glossary-tooltip-link {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent-cyan);
}
@keyframes glossaryTooltipFade {
  from { opacity: 0; transform: translateY(-2px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .glossary-tooltip { animation: none; }
  .glossary-term { transition: none; }
}

/* Print: drop the underline (paper readers don't need it). */
@media print {
  .glossary-term {
    text-decoration: none;
    background: transparent;
    cursor: auto;
  }
  .glossary-tooltip { display: none; }
}

/* ─────────── about sub-page cards ─────────── */

.about-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1rem;
  margin: 0.5rem 0 1rem;
}
.about-card {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 1rem 1.1rem;
  background: rgba(8, 16, 28, 0.7);
  border: 1px solid rgba(120, 160, 210, 0.28);
  border-radius: 10px;
  text-decoration: none;
  color: inherit;
  transition: background 160ms, border-color 160ms, transform 160ms;
}
.about-card:hover {
  background: rgba(0, 224, 255, 0.05);
  border-color: rgba(0, 224, 255, 0.55);
  transform: translateY(-1px);
}
.about-card[aria-current="page"] {
  border-color: rgba(168, 85, 247, 0.65);
  background: rgba(168, 85, 247, 0.07);
}
.about-card-icon {
  font-size: 1.5rem;
  line-height: 1;
}
.about-card h3 {
  margin: 0;
  font-size: 1.05rem;
  color: var(--text-primary);
}
.about-card p {
  margin: 0;
  color: var(--text-secondary);
  font-size: 0.92rem;
  line-height: 1.45;
}
.about-card-cta {
  margin-top: auto;
  font: 600 0.72rem/1.2 var(--font-mono, monospace);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-cyan);
}
.about-card[aria-current="page"] .about-card-cta {
  color: var(--accent-purple);
}

/* ─────────── testing explainer + test-reports shared chrome ─────────── */

.test-suite-badge {
  display: inline-block;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  font: 600 0.72rem/1.3 var(--font-mono, monospace);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border: 1px solid transparent;
}
.test-suite-badge.pass {
  color: rgba(48, 232, 104, 0.9);
  background: rgba(48, 232, 104, 0.12);
  border-color: rgba(48, 232, 104, 0.4);
}
.test-suite-badge.warn {
  color: rgba(240, 176, 32, 0.95);
  background: rgba(240, 176, 32, 0.12);
  border-color: rgba(240, 176, 32, 0.4);
}
.test-suite-badge.fail {
  color: rgba(255, 107, 157, 0.95);
  background: rgba(255, 107, 157, 0.12);
  border-color: rgba(255, 107, 157, 0.45);
}
.test-suite-badge.idle {
  color: rgba(180, 195, 215, 0.9);
  background: rgba(120, 160, 210, 0.08);
  border-color: rgba(120, 160, 210, 0.25);
}

.test-suite-card {
  background: rgba(4, 8, 16, 0.55);
  border: 1px solid rgba(120, 160, 210, 0.22);
  border-radius: 10px;
  padding: 1rem 1.1rem;
  margin: 0.8rem 0 1rem;
}
.test-suite-card h3 {
  margin: 0 0 0.3rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.test-suite-card .suite-summary {
  color: var(--text-secondary);
  font-size: 0.92rem;
  margin: 0 0 0.6rem;
}
.test-suite-card .suite-stats {
  display: flex;
  gap: 0.8rem;
  flex-wrap: wrap;
  font: 500 0.82rem/1.3 var(--font-mono, monospace);
  color: var(--text-secondary);
  margin: 0.5rem 0;
}
.test-suite-card .suite-stats .stat-label {
  opacity: 0.65;
}
.test-suite-card .suite-artefacts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 0.6rem;
  margin-top: 0.8rem;
}
.test-suite-card .suite-artefact {
  background: rgba(4, 8, 16, 0.55);
  border: 1px solid rgba(120, 160, 210, 0.18);
  border-radius: 6px;
  overflow: hidden;
}
.test-suite-card .suite-artefact img {
  display: block;
  width: 100%;
  height: auto;
}
.test-suite-card .suite-artefact .artefact-caption {
  padding: 0.4rem 0.6rem;
  font: 500 0.78rem/1.3 var(--font-mono, monospace);
  color: var(--text-secondary);
  border-top: 1px solid rgba(120, 160, 210, 0.15);
}
.test-suite-card details.suite-details {
  margin-top: 0.6rem;
}
.test-suite-card details.suite-details > summary {
  cursor: pointer;
  font: 600 0.78rem/1.3 var(--font-mono, monospace);
  letter-spacing: 0.06em;
  color: var(--text-secondary);
  list-style: none;
}
.test-suite-card details.suite-details > summary::before {
  content: "▸";
  display: inline-block;
  margin-right: 0.4rem;
  transition: transform 160ms;
  color: rgba(120, 160, 210, 0.55);
}
.test-suite-card details.suite-details[open] > summary::before {
  transform: rotate(90deg);
}
.test-suite-card details.suite-details > *:not(summary) {
  margin-top: 0.5rem;
}

.test-anim-host {
  background: radial-gradient(ellipse at center, #04080f 0%, #000000 80%);
  border: 1px solid rgba(120, 160, 210, 0.2);
  border-radius: 8px;
  min-height: 260px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
  margin: 0.6rem 0;
}
.test-anim-host canvas { display: block; width: 100%; height: 100%; }

/* Test-reports page — chart + table layout. */
.suite-chart-row {
  display: flex;
  gap: 1.2rem;
  align-items: flex-start;
  flex-wrap: wrap;
  margin: 0.4rem 0 0.8rem;
}
.suite-chart-body {
  flex: 1 1 340px;
  min-width: 280px;
}
.suite-chart-title {
  font: 600 0.78rem/1.3 var(--font-mono, monospace);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 0.35rem;
}
.rollup-chips {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 0.6rem 1rem;
  margin-top: 0.4rem;
}
.rollup-chip {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.6rem;
  background: rgba(4, 8, 16, 0.6);
  border: 1px solid rgba(120, 160, 210, 0.22);
  border-left: 3px solid var(--chip-color, rgba(120, 160, 210, 0.5));
  border-radius: 6px;
  flex-wrap: wrap;
}
.rollup-chip strong {
  font: 700 1.35rem/1 var(--font-mono, monospace);
  color: #cfe4ff;
}
.rollup-chip .chip-hint {
  flex: 1 1 100%;
  font-size: 0.74rem;
  color: var(--text-secondary);
  letter-spacing: 0.02em;
  line-height: 1.3;
  margin-top: 0.1rem;
}
.suite-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 0.6rem;
  font-size: 0.88rem;
}
.suite-table thead {
  background: rgba(120, 160, 210, 0.06);
  border-bottom: 1px solid rgba(120, 160, 210, 0.18);
}
.suite-table th {
  padding: 0.5rem 0.6rem;
  font: 600 0.78rem/1.3 var(--font-mono, monospace);
  letter-spacing: 0.06em;
  color: var(--text-secondary);
}
.suite-table td {
  padding: 0.4rem 0.6rem;
  border-bottom: 1px solid rgba(120, 160, 210, 0.08);
}
.suite-table td code {
  color: #cfe4ff;
}

/* ─────────── responsive ─────────── */

@media (max-width: 720px) {
  main { padding: 1rem 1rem 2rem; }
  .topic-grid { grid-template-columns: 1fr; }
  h1 { font-size: 1.6rem; }
}
