/* Project pages: a sequence of scroll chapters (docs/chapters.md), plus the interactive showcases.
   Each page is <section data-chapter class="p-chapter"> elements that are direct children of <main>.
   Tokens only (tokens.css). Shared components (.frame .sheet .button .prose pre) live in base.css.
   The chapter engine (chapters.css) supplies the full-screen snap, the header offset and the fades. */

[hidden] { display: none !important; }

/* ---------- Chapter frame ---------- */
.p-chapter { --gap: var(--space-5); }
.p-chapter > * + * { margin-top: var(--gap); }
.p-h2 { font-size: clamp(1.75rem, 1.1rem + 2.6vw, 3.5rem); letter-spacing: -0.04em; max-width: 22ch; }
.p-h2 + * { margin-top: var(--space-4); }
.p-lead { font-size: var(--step-lead); line-height: 1.3; max-width: 44ch; }
.p-text .p-lead { max-width: 52ch; }
.p-chapter h3 { font-size: var(--step-lead); letter-spacing: -0.02em; line-height: 1.15; }
.muted { color: var(--muted); }
.note { font-size: var(--step-small); color: var(--ink); max-width: var(--measure); }
.p-text > * + * { margin-top: var(--space-4); }
.fig-cap {
  font-size: var(--step-small); font-weight: 600; line-height: 1.4; margin-top: var(--space-2); max-width: var(--measure);
}

/* ---------- Chapter 1: header, widget, then the facts ----------
   The widget starts inside the first screen: a one-line title block, then the widget itself. */
.p-first, #crosswalk, #query-console, #topology, #diagram { --gap: var(--space-4); }
.p-head { display: grid; gap: var(--space-1); }
.back-link {
  display: inline-block; font-size: var(--step-small); font-weight: 600;
  text-decoration-color: var(--accent); text-decoration-thickness: 2px;
  padding-block: var(--space-1);
}
.p-head h1 {
  font-size: clamp(1.875rem, 1rem + 3.6vw, 3.75rem);
  letter-spacing: -0.045em; line-height: 0.98; max-width: 24ch;
}
.p-head .lead { font-size: var(--step-body); line-height: 1.3; max-width: 62ch; margin-top: var(--space-2); }
.notice {
  margin-top: var(--space-3); background: var(--surface); padding: var(--space-3) var(--space-4);
  font-weight: 600; font-size: var(--step-small); max-width: var(--measure);
}
.p-widget > h2 { font-size: var(--step-lead); letter-spacing: -0.02em; line-height: 1.15; }
.p-widget > .p-lead { font-size: var(--step-small); line-height: 1.4; max-width: 62ch; margin-top: var(--space-1); color: var(--muted); }
.p-widget > .p-lead + * { margin-top: var(--space-4); }
.facts {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4) var(--gutter);
  font-size: var(--step-small); line-height: 1.4; margin-top: var(--space-6);
}
.facts dt { font-weight: 600; }
.facts dd { margin: 2px 0 0; color: var(--muted); }
@media (min-width: 768px) {
  .facts { grid-template-columns: 2fr 2fr 5fr 3fr; }
  /* Course, Tools and Timeframe in one row, from the left. */
  .facts--three { grid-template-columns: max-content minmax(0, max-content) max-content; column-gap: var(--space-7); }
}
@media (max-width: 767px) { .p-head .lead { font-size: var(--step-small); } }

/* ---------- Overview and two-column chapters ---------- */
.p-pair { display: grid; gap: var(--space-6) var(--gutter); align-items: center; }
.pair-fig .frame { aspect-ratio: 4 / 3; width: 100%; }
@media (min-width: 1024px) {
  .p-pair { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .p-pair > :first-child { grid-column: 1 / 7; }
  .p-pair > :last-child { grid-column: 8 / -1; }
}
.p-two { display: grid; gap: var(--space-6) var(--gutter); align-items: start; }
.p-two h3 { margin-bottom: var(--space-3); }
.p-two .p-lead { max-width: 48ch; }
@media (min-width: 1024px) { .p-two { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-7); } }
.p-ground { display: grid; gap: var(--space-5); margin-top: var(--space-7); padding-top: var(--space-5); border-top: 2px solid var(--surface-2); }
.p-ground-title { font-size: var(--step-small); font-weight: 700; letter-spacing: 0; color: var(--muted); margin-bottom: var(--space-4); }
.p-ground-note { margin-top: var(--space-5); }
.p-widget-note { color: var(--muted); margin-top: var(--space-4); }

/* Scroll cue: a soft chevron (round caps and joins, muted colour) centred at the bottom of the first chapter,
   just above its bottom edge. It keeps sliding down through that edge and back in from above, and links to the
   next chapter (desktop only, where the first chapter has room for it). Its name, "Scroll for more", is for screen
   readers only. Paused when its chapter is off screen; still under reduced motion. */
.scroll-cue { display: none; }
@media (min-width: 1024px) {
  .scroll-cue { position: absolute; bottom: 0; left: 50%; translate: -50% 0; display: block; color: var(--muted); }
  .scroll-cue:hover { color: var(--ink); }
}
.scroll-cue-track { position: relative; display: block; width: 64px; height: 44px; overflow: hidden; }
.scroll-cue-arrow {
  position: absolute; left: 0; bottom: 2px; width: 64px; height: auto; overflow: visible;
  fill: none; stroke: currentColor; stroke-width: 4.5; stroke-linecap: round; stroke-linejoin: round;
  filter: drop-shadow(0 3px 4px color-mix(in srgb, var(--ink) 40%, transparent));
  transition: color var(--dur-fast) var(--ease);
  animation: cue-slide 6.86s cubic-bezier(.45, 0, .2, 1) infinite;
}
/* 6.86s loop: slide in from above (1s), rest (5s: the old 1s hold plus a 4s pause), slide out downward (0.86s). */
@keyframes cue-slide {
  0%            { transform: translateY(-100%); opacity: 0; }
  14.58%, 87.46% { transform: translateY(0); opacity: 1; }
  100%          { transform: translateY(100%); opacity: 0; }
}
.chapters-live [data-chapter]:not(.is-current) .scroll-cue-arrow { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) { .scroll-cue-arrow { animation: none; } }

/* IoT first chapter on desktop: the lights left and the Serial Monitor right; under the lights the timing note
   and the facts in one row, under the monitor the one-line intro. The scroll cue takes the bottom right corner.
   The whole chapter fits one laptop screen. */
@media (min-width: 1024px) {
  #crosswalk .p-widget {
    display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); row-gap: var(--space-4);
    align-items: start;
  }
  #crosswalk .xw:not([hidden]) { display: contents; }
  #crosswalk .xw-board { grid-column: 1 / 8; grid-row: 1; }
  #crosswalk .xw-serial { grid-column: 8 / -1; grid-row: 1; }
  #crosswalk .xw .note { grid-column: 1 / 8; grid-row: 2; }
  #crosswalk .xw-static { grid-column: 1 / 8; grid-row: 1 / span 2; }
  #crosswalk .p-widget-note { grid-column: 8 / -1; grid-row: 2; margin-top: 0; }
  #crosswalk .facts { grid-column: 1 / 11; grid-row: 3; margin-top: var(--space-2); }
  #crosswalk .p-head .lead { max-width: none; }
}

/* Frame used as a link to the larger image */
.zoom { cursor: zoom-in; }
.frame--shot { background: var(--surface); }
.frame--shot img { object-fit: contain; }
a.frame:focus-visible { outline-offset: 2px; }

/* ---------- Photo drawers: <details data-smooth> with a .details-body (chapters.css animates them) ---------- */
.drawer summary {
  display: flex; justify-content: space-between; align-items: center; gap: var(--space-4);
  min-height: 44px; padding: var(--space-2) var(--space-4);
  background: var(--surface); font-size: var(--step-small); font-weight: 600; cursor: pointer; list-style: none;
}
.drawer summary::-webkit-details-marker { display: none; }
.drawer summary::after { content: "+"; font-weight: 800; font-size: 1.25em; line-height: 1; }
.drawer[open] summary::after { content: "\2212"; }
.drawer summary:hover { background: var(--surface-2); }
.drawer summary:active { background: color-mix(in srgb, var(--surface-2) 82%, var(--ink)); }
.drawer .details-body { padding-block: var(--space-3) var(--space-1); }
/* Thumbnails in a drawer are small: the lightbox opens them large */
.drawer .sheet-frames > * { height: 88px; }
.drawer .sheet-frames .is-wide { aspect-ratio: 16 / 9; }
.sheet-frames > li > .frame { width: 100%; height: 100%; }
.sheet-frames > li:has(> .is-square) { aspect-ratio: 1; }
.sheet-frames > li:has(> .is-tall) { aspect-ratio: 3 / 4; }
.sheet-frames > li:has(> .is-wide) { aspect-ratio: 16 / 9; }
.sheet-frames { align-items: flex-start; }
@media (max-width: 599px) { .drawer .sheet-frames > * { height: auto; width: calc(33.333% - var(--space-2)); } }

/* ---------- Ordered build steps ---------- */
.steps { list-style: none; padding: 0; margin: 0; }
.steps > li + li { margin-top: var(--space-5); }
.steps :is(h3, h4) { font-size: var(--step-lead); letter-spacing: -0.02em; line-height: 1.15; }
.steps p { margin-top: var(--space-2); max-width: var(--measure); }
.steps .drawer { margin-top: var(--space-3); }
@media (min-width: 1024px) {
  .steps--grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-6) var(--space-7); }
  .steps--grid > li + li { margin-top: 0; }
}
.steps--numbered { list-style: decimal; padding-left: 1.4em; }
.steps--numbered > li::marker { font-weight: 800; }

/* ---------- Tabs / stepper (widgets/tabs.js) ---------- */
.tablist { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }
.tab {
  min-height: 44px; padding: var(--space-2) var(--space-4);
  background: var(--surface); color: var(--ink); border: 0; border-radius: 0;
  font-weight: 600; font-size: var(--step-small); text-align: left; line-height: 1.25;
  transition: background-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.tab:hover { background: var(--surface-2); }
.tab:active { transform: translateY(1px); background: color-mix(in srgb, var(--surface-2) 82%, var(--ink)); }
.tab[aria-selected="true"]:active { background: color-mix(in srgb, var(--accent) 72%, var(--ink)); }
.tab[aria-selected="true"] { background: var(--accent); color: var(--accent-ink); }
.tab-panel + .tab-panel { margin-top: var(--gap); }
[data-tabs].is-live .tab-panel + .tab-panel { margin-top: 0; }
.tab-panel:focus-visible { outline-offset: 6px; }
.stepper-nav { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); margin-top: var(--space-4); }
/* A stepper that carries its own heading: on desktop the stage tabs sit beside the heading's lead, above the
   stage text, and Previous / Next sit beside the photo thumbnails (tabs.js moves them into the panel). */
.stepper-head { margin-bottom: var(--space-5); }
@media (min-width: 1024px) {
  .stepper--headed.is-live {
    display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); align-items: end;
  }
  .stepper--headed.is-live > * { grid-column: 1 / -1; }
  .stepper--headed.is-live > .stepper-head { grid-column: 1 / 6; margin-bottom: 0; }
  .stepper--headed.is-live > .tablist { grid-column: 6 / -1; margin-bottom: 0; }
  .stepper--headed.is-live > .stages { margin-top: var(--space-5); }
  .stage-media:has(> .stepper-nav) { display: flex; flex-wrap: wrap; align-items: flex-start; column-gap: var(--space-4); }
  .stage-media:has(> .stepper-nav) > .frame { flex: 1 0 100%; }
  .stage-media > .stepper-nav { margin-top: var(--space-2); margin-left: auto; }
}
/* Never `disabled`: an end-of-range button keeps focus and just looks dimmed. */
.button[aria-disabled="true"] { opacity: 0.45; cursor: default; transform: none; }
/* Focus stays fully visible on a disabled control (the ring would otherwise drop to about 2:1). */
.button[aria-disabled="true"]:focus-visible { opacity: 1; }

/* A stage: photo left, words and code right */
.stage { display: grid; gap: var(--space-5) var(--gutter); }
.stage-media .frame { aspect-ratio: 4 / 3; }
.stage-media .frame--shot { aspect-ratio: auto; background: var(--surface); padding: var(--space-3); }
.stage-thumbs { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); list-style: none; padding: 0; }
.stage-thumbs .frame { height: 72px; aspect-ratio: 4 / 3; }
.stage-thumbs .frame--shot { aspect-ratio: 1; padding: 0; }
.stage-text p { margin-top: var(--space-3); max-width: var(--measure); }
.stage-text pre { margin-top: var(--space-4); max-height: 11em; overflow: auto; }
@media (min-width: 1024px) {
  .stage { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: start; }
  .stage-media { grid-column: 1 / 6; }
  .stage-text { grid-column: 6 / -1; }
  /* The photo never runs past the screen; the code box grows to sit level with it. */
  .stage-media > .frame:not(.frame--shot) { max-height: 56vh; }
  .stage-text pre { max-height: 22em; }
}

/* ---------- Crosswalk simulator (widgets/crosswalk.js) ---------- */
.xw { display: grid; gap: var(--space-4) var(--gutter); }
.xw-board { background: var(--surface); padding: var(--space-5); display: grid; gap: var(--space-4); align-content: start; }
.xw-sets { display: flex; flex-wrap: wrap; gap: var(--space-4) var(--space-6); align-items: flex-end; }
.xw-set { margin: 0; }
@media (min-width: 600px) {
  .xw-sets { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .xw-set { justify-self: center; }
}
.xw-leds { display: flex; gap: var(--space-2); }
.xw-set figcaption { margin-top: var(--space-2); font-size: var(--step-small); font-weight: 600; line-height: 1.3; }
.xw-pins { display: block; font-weight: 400; color: var(--muted); font-variant-numeric: tabular-nums; }
.led {
  --c: var(--led-fill-red);
  display: block; width: 36px; height: 36px; border-radius: 50%;
  background: var(--surface-2);
  /* A ring so an unlit LED still reads as a position (3:1 against the panel). */
  box-shadow: inset 0 0 0 2px var(--muted);
  transition: background-color 120ms linear;
}
.led--yellow { --c: var(--led-fill-yellow); }
.led--green { --c: var(--led-fill-green); }
.led--blue { --c: var(--led-fill-blue); }
.led.is-on { background: var(--c); }
.xw-controls { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); }
.xw-controls .button { min-width: 44px; }
.xw-board .button--quiet { background: var(--bg); }
.xw-board .button--quiet:hover { background: var(--surface-2); }
.toggle[aria-pressed="true"], .xw-board .toggle[aria-pressed="true"] { background: var(--ink); color: var(--bg); }
.xw-walk {
  font-size: var(--step-lead); font-weight: 800; letter-spacing: -0.02em; line-height: 1.1;
  font-variant-numeric: tabular-nums; min-height: 1.2em;
}
.xw-walk.is-walk { color: var(--led-green); }
.xw-serial h3, .console-out h3 { font-size: var(--step-small); font-weight: 600; margin-bottom: var(--space-2); letter-spacing: 0; }
.serial { height: 14.2em; overflow-y: auto; }
.serial code { white-space: pre; }
@media (min-width: 1024px) {
  .xw { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: start; }
  .xw-board { grid-column: 1 / 8; }
  .xw-serial { grid-column: 8 / -1; }
  .xw .note { grid-column: 1 / -1; }
}
/* Phone: the lights, the buttons and the Serial Monitor share one screen. */
@media (max-width: 599px) {
  .xw-board { padding: var(--space-4); gap: var(--space-3); }
  .xw-sets { flex-wrap: nowrap; justify-content: space-between; gap: var(--space-3); }
  .xw-leds { gap: var(--space-1); }
  .led { width: 26px; height: 26px; }
  .xw-set figcaption { font-size: 0.8125rem; }
  .xw-pins { display: none; }
  .xw-controls { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
  .xw-controls .button { white-space: normal; padding-inline: var(--space-3); text-align: center; }
  .serial { height: 9.6em; }
  .xw .note { font-size: 0.8125rem; }
}

/* ---------- Query console (widgets/query-console.js) ---------- */
.query h3 { font-size: var(--step-lead); letter-spacing: -0.02em; }
.query > p { margin-top: var(--space-2); max-width: var(--measure); }
.query-io { display: grid; gap: var(--space-3) var(--gutter); margin-top: var(--space-3); }
.query-io pre.out { max-height: 15em; overflow: auto; }
.query-run { margin-top: var(--space-3); }
.query .drawer { margin-top: var(--space-3); max-width: 480px; }
.query .drawer .frame { max-width: 440px; }
@media (min-width: 1024px) { .query-io { grid-template-columns: 5fr 7fr; align-items: start; } }

/* ---------- Plot switcher ---------- */
.plot { display: grid; gap: var(--space-5) var(--gutter); }
.plot .frame { aspect-ratio: auto; background: var(--surface); padding: var(--space-3); }
.plot img { max-height: 56vh; width: auto; margin-inline: auto; }
@media (min-width: 1024px) {
  .plot { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: start; }
  .plot > figure { grid-column: 1 / 8; }
  .plot > div { grid-column: 8 / -1; }
}
.plot > div p + pre, .plot > div pre + p { margin-top: var(--space-4); }

/* ---------- Topology (widgets/topology.js) ---------- */
.topo { display: grid; gap: var(--space-5) var(--gutter); }
.topo-map { background: var(--surface); padding: var(--space-4); }
.topo-map svg { width: 100%; height: auto; overflow: visible; }
.topo-map--tall { display: block; }
.topo-map--wide { display: none; }
@media (min-width: 768px) {
  .topo-map--tall { display: none; }
  .topo-map--wide { display: block; }
}
@media (min-width: 1200px) {
  .topo { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: start; }
  .topo-map { grid-column: 1 / 8; position: sticky; top: calc(var(--header-h, 72px) + var(--space-5)); }
  .topo-detail { grid-column: 8 / -1; }
}
/* Short laptop screens: the map shrinks a little so the facts row stays on the first screen. */
@media (min-width: 1024px) and (max-height: 780px) {
  #topology .topo-map svg { max-height: 340px; }
  .p-chapter > .facts--three { margin-top: var(--space-5); }
}
.t-group { fill: var(--bg); }
.t-group-2 { fill: var(--surface-2); }
.t-label { fill: var(--muted); font: 600 18px var(--font-sans); letter-spacing: 0; }
.t-wire { stroke: var(--muted); stroke-width: 2; fill: none; }
.t-wire--dash { stroke-dasharray: 6 5; }
.t-arrow { fill: var(--muted); }
.t-node .t-box { fill: var(--bg); transition: fill var(--dur-fast) var(--ease); }
.t-node text { fill: var(--ink); font: 600 20px var(--font-sans); letter-spacing: 0; pointer-events: none; }
.t-node .t-sub { font-weight: 400; font-size: 18px; fill: var(--muted); }
.t-node { cursor: pointer; outline: none; }
.t-node:hover .t-box { fill: var(--surface-2); }
.t-group-2 ~ a .t-box { fill: var(--bg); }
.t-node[aria-current="true"] .t-box { fill: var(--accent); }
.t-node[aria-current="true"] text, .t-node[aria-current="true"] .t-sub { fill: var(--accent-ink); }
/* Focus is its own ring, 6px outside the node, so it never depends on (or hides inside) the selected fill.
   3px of --focus against the page ground is at least 3:1 in every palette. */
.t-node .t-ring { fill: none; stroke: none; pointer-events: none; }
.t-node:focus-visible .t-ring { stroke: var(--focus); stroke-width: 3; }
.topo-detail article + article { margin-top: var(--space-6); }
.topo.is-live .topo-detail article + article { margin-top: 0; }
.topo-detail h3 { font-size: var(--step-lead); letter-spacing: -0.02em; }
.topo-detail article > * + * { margin-top: var(--space-3); }
.topo-detail .frame { aspect-ratio: auto; background: var(--surface); padding: var(--space-3); }
.topo-detail figure + figure { margin-top: var(--space-4); }
.topo-detail article:focus-visible, .topo-detail h3:focus-visible { outline-offset: 6px; }
/* The focused panel heading must clear the fixed header (a11y round 2). */
.topo-detail article, .topo-detail h3 { scroll-margin-top: calc(var(--header-h, 60px) + 16px); }

/* ---------- Storage tiers ---------- */
.tiers .tab-panel { display: grid; gap: var(--space-4) var(--gutter); align-items: start; }
@media (min-width: 1024px) {
  .tiers .tab-panel { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .tiers .tab-panel > h3, .tiers .tab-panel > p { grid-column: 1 / 8; }
  .tiers .tab-panel > dl { grid-column: 8 / -1; grid-row: 1 / span 2; margin-top: 0; background: var(--surface); padding: var(--space-5); }
}
.tier-facts { display: grid; grid-template-columns: max-content 1fr; gap: var(--space-2) var(--space-5); margin-top: var(--space-4); }
.tier-facts dt { font-weight: 600; }
.tier-facts dd { margin: 0; }
.tier-name { font-size: var(--step-head); }

/* ---------- Smart home diagram: filled chips, no outlines ---------- */
.sh { background: var(--surface); padding: var(--space-5); }
.sh-grid { display: grid; gap: var(--space-3); align-items: stretch; }
.sh-col { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.sh-chip { background: var(--surface-2); padding: var(--space-3) var(--space-4); font-weight: 800; line-height: 1.25; font-size: var(--step-small); }
.sh-chip small { display: block; margin-top: 2px; font-weight: 400; color: var(--muted); font-size: 0.8125rem; }
.sh-chip--main { background: var(--accent); color: var(--accent-ink); padding: var(--space-5); font-size: var(--step-lead); letter-spacing: -0.02em; }
.sh-chip--main small { color: var(--accent-ink); font-size: var(--step-small); }
.sh-link { text-align: center; color: var(--muted); font-weight: 800; line-height: 1; }
.sh-link::before { content: "\2193"; }
.sh-link--both::before { content: "\2195"; }
@media (min-width: 900px) {
  .sh-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr) minmax(0, 1fr); align-items: center; }
  .sh-col { grid-template-columns: 1fr; }
  .sh-link::before { content: "\2192"; }
  .sh-link--both::before { content: "\2194"; }
}

/* ---------- Challenges: rows ---------- */
.rows { list-style: none; padding: 0; margin: 0; }
.rows li { display: grid; gap: var(--space-1) var(--gutter); padding-block: var(--space-3); }
.rows li { padding-inline: var(--space-4); }
.rows li:nth-child(odd) { background: var(--surface); }
.rows li span:first-child { font-weight: 600; }

/* ---------- Next project: a full-screen door in the next project's palette ---------- */
.p-door { background-color: var(--bg); color: var(--ink); }
html.palette-scroll .p-door { background-color: transparent; }
.p-door-body > * + * { margin-top: var(--space-4); }
.next-link {
  display: inline-block; font-size: clamp(1.75rem, 1.1rem + 3vw, 4rem); font-weight: 800; letter-spacing: -0.04em; line-height: 1.05;
  max-width: 20ch; color: var(--ink); text-decoration: none; text-wrap: balance;
}
.next-kicker { display: block; font-size: var(--step-lead); font-weight: 600; letter-spacing: -0.01em; color: var(--muted); margin-bottom: var(--space-2); }
/* Only the project name is underlined, as one even line that never skips ink. */
.next-name { text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 0.05em; text-underline-offset: 0.14em; text-decoration-skip-ink: none; }
.p-door-body > .next-link:only-child { text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 0.05em; text-underline-offset: 0.14em; }
.p-door-blurb { font-size: var(--step-lead); line-height: 1.3; max-width: 40ch; color: var(--muted); }
.p-door-nav { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-6); }
/* Smart Home: one full-screen "Details coming soon" page until the write-up exists. Same scale as the door. */
.p-soon-title { font-size: clamp(2.5rem, 1.4rem + 5vw, 6rem); font-weight: 800; letter-spacing: -0.04em; line-height: 1; max-width: 14ch; text-wrap: balance; }
.prev-link { font-size: var(--step-small); font-weight: 600; color: var(--ink); text-decoration-color: var(--accent); text-decoration-thickness: 2px; padding-block: var(--space-2); }

/* ---------- Lightbox (widgets/lightbox.js) ---------- */
.lightbox {
  border: 0; padding: 0; margin: auto; max-width: min(96vw, 1600px); max-height: 96vh;
  background: var(--bg); color: var(--ink); box-shadow: 0 24px 64px color-mix(in srgb, var(--scrim) 45%, transparent); /* taste-skill-ignore: dialog floats */
}
.lightbox::backdrop { background: color-mix(in srgb, var(--scrim) 84%, transparent); }
.lightbox-inner { display: grid; grid-template-rows: minmax(0, 1fr) auto; max-height: 96vh; }
.lightbox img { width: auto; max-width: 100%; max-height: calc(96vh - 96px); margin-inline: auto; object-fit: contain; background: var(--surface); }
.lightbox-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); padding: var(--space-3) var(--space-4); }
.lightbox-bar p { flex: 1 1 16rem; font-size: var(--step-small); font-weight: 600; line-height: 1.35; }
.lightbox-bar .button { min-width: 44px; }

@media (prefers-reduced-motion: reduce) {
  .led, .tab, .t-node .t-box { transition: none; }
}

/* Grid and flex children may shrink below their content (long code lines scroll inside their <pre>) */
.p-pair > *, .p-two > *, .stage > *, .xw > *, .topo > *, .plot > *, .query-io > *, .p-ground > *, .topo-detail, .topo-detail * { min-width: 0; }
.xw-controls [hidden], .lightbox-bar [hidden] { display: none; }
.tab-panel[hidden], [data-topo-panel][hidden] { display: none !important; }

/* ---------- Palette-aware details ----------
   Everything follows the active palette (tokens.css). The only literal colours here are the lit LED
   fills: a real LED is the same colour on any ground. */
.p-chapter {
  --led-fill-red: #ff3b30;     /* true LED fill */
  --led-fill-yellow: #ffc61a;  /* true LED fill */
  --led-fill-green: #22d164;   /* true LED fill */
  --led-fill-blue: #3f7dff;    /* true LED fill */
  /* Scrim and terminal: dark in either theme, built from tokens */
  --scrim: var(--ink);
  --term-bg: var(--ink);
  --term-ink: var(--bg);
}
@supports (color: light-dark(red, red)) {
  .p-chapter {
    --scrim: light-dark(var(--ink), var(--bg));
    --term-bg: light-dark(var(--ink), var(--surface-2));
    --term-ink: light-dark(var(--bg), var(--ink));
  }
}
.lightbox { --scrim: var(--ink); }
@supports (color: light-dark(red, red)) { .lightbox { --scrim: light-dark(var(--ink), var(--bg)); } }
.serial, .query-io pre.out { background: var(--term-bg); color: var(--term-ink); }

/* Screenshots sit on a --surface mat, so white captures read as framed panels, never as glare */
.pair-fig .frame--shot { background: var(--surface); padding: var(--space-3); }
/* In the dark theme, white captures are toned down a little */
:root[data-theme="dark"] .frame--shot img { filter: brightness(0.86) contrast(1.04); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .frame--shot img { filter: brightness(0.86) contrast(1.04); }
}

/* The first chapter of the NETW211 page fits one 900px screen: the wide map is capped in height. */
@media (min-width: 1200px) { .topo-map--wide svg { max-height: 400px; margin-inline: auto; } }

/* ---------- Depth (tokens.css) ----------
   The interactive panels and shot frames sit slightly above the page. Disabled buttons stay flat. */
.xw-board, .serial, .query-io pre.out, .topo-map, .sh, .plot .frame, .stage-media .frame,
.pair-fig .frame--shot, .tiers .tab-panel > dl { box-shadow: var(--shadow-panel); }
.button[aria-disabled="true"] { box-shadow: none; }
