/* ============================================================
   TERMINAL THEME PROTOTYPE
   - Inconsolata (readable coding monospace) for chrome, headings, and code;
     Inter (proportional) for the running prose of the reading column
   - phosphor palette (amber default; green / mono via toggle)
   - faint scanline + vignette CRT overlay
   - decode "rain" reveal scoped to the first screen
   This is a static mock of how the Hugo theme would look.
   ============================================================ */

:root{
  --bg:        #0d0e0c;
  --bg-soft:   #15171400;
  --panel:     #131512;
  --fg:        #eed2a7;   /* phosphor body text (amber) */
  --fg-dim:    #6f776b;
  --fg-bright: #d6ddd0;
  --accent:    #dfa22c;   /* amber (matches existing site accent) */
  --accent-2:  #5fd75f;   /* command/run green */
  --rule:      #2a2d27;
  --selection: #3a3410;
  --code-bg:   #0c0e0c;   /* run box command panel */
  --sel-bg:    #fff;      /* copy select-all reverse video (bg) */
  --sel-fg:    #000;      /* ...and text */
  --col: 74ch;            /* reading column width */
  --font-mono: "Inconsolata", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --font-read: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;  /* proportional reading face for prose */
  color-scheme:dark;      /* native UI (scrollbars, etc.) match the dark themes */
}
/* palette variants -------------------------------------------------*/
:root[data-theme="green"]{ --accent:#5fd75f; --accent-2:#5fd75f; --fg:#b4deac; --fg-bright:#c8f5c8; --selection:#16320f; }
:root[data-theme="mono"]{  --accent:#cdd3c8; --accent-2:#9aa394; --fg:#d2d5cd; --fg-bright:#e6ebe2; --selection:#2c2f29; }
/* lite: mono, but reverse video (light bg / dark text). reverse-video bits flip back. */
:root[data-theme="lite"]{
  --bg:#d3d6cd; --panel:#c7cabf; --fg:#2b2e28; --fg-dim:#5f645a; --fg-bright:#111310;
  --accent:#2f332b; --accent-2:#4a4f44; --rule:#a6aa9f; --selection:#b3b7a8;
  --code-bg:#c4c7bd; --sel-bg:#16180f; --sel-fg:#e8eadf;
  color-scheme:light;     /* lite is a light theme */
}

*{ box-sizing:border-box; }
html,body{ margin:0; }
/* fluid base size: ~21px on desktop, easing down to ~16px on a phone.
   rem-based headings scale with this automatically. */
html{ font-size:clamp(16px, 0.7vw + 13px, 21px);
      scrollbar-gutter:stable;       /* reserve scrollbar space so it never reflows the header */
      background:var(--bg); }        /* bg on the root -> always covers the full page (viewport resize safe) */
.wait-fonts body{ visibility:hidden; }   /* removed once the web font has loaded */
body{
  min-height:100vh;
  background:var(--bg);
  color:var(--fg);
  font-family:var(--font-mono);
  font-size:1rem;
  line-height:1.7;
  letter-spacing:.1px;
  -webkit-font-smoothing:antialiased;
}
::selection{ background:var(--selection); color:var(--fg-bright); }

/* layout: TUI sidebar + reading column ---------------------------- */
.wrap{ display:grid; grid-template-columns:30ch minmax(0,1fr); min-height:100vh; }

/* sidebar: book-of-books, terminal styled ------------------------- */
.sidebar{
  border-right:1px solid var(--rule);
  padding:.85rem 1.1rem 1.4rem; position:sticky; top:0; align-self:start; height:100vh; overflow:hidden;   /* top padding aligns the brand with the centered topbar prompt */
  display:flex; flex-direction:column;   /* pinned brand (top) + scrolling tree + pinned controls (bottom) */
  background:var(--panel);
  font-size:.82rem;            /* keep nav compact at the larger base size */
}
.sidebar .brand{ color:var(--accent); font-weight:600; margin-bottom:.2rem;
  display:flex; align-items:center; gap:.4ch; min-width:0; flex:none;   /* pinned top; tighter gaps so the title + deco fit the 30ch sidebar */
  user-select:none; -webkit-user-select:none; }
.brand .bname{ color:inherit; text-decoration:none; border-bottom:none; }
.brand .bname:hover{ color:var(--fg-bright); }
/* CSS checkered "block-art" flanking the title, fading toward the name, mirrored */
.brand .deco{ display:inline-flex; gap:1px; flex:none; }
.brand .blk{ display:block; width:.7em; height:.7em;
  background:repeating-conic-gradient(var(--accent) 0 25%, color-mix(in srgb, var(--accent), #000 62%) 0 50%);
  background-size:.35em .35em; }
.brand .deco .blk:nth-child(1){ opacity:1; }
.brand .deco .blk:nth-child(2){ opacity:.6; }
.brand .deco .blk:nth-child(3){ opacity:.32; }
.brand .deco.right .blk:nth-child(1){ opacity:.32; }
.brand .deco.right .blk:nth-child(3){ opacity:1; }
/* on load: the three shades rotate through the block positions once (slow),
   each keyframe ending on the block's resting opacity. Timed to the other fx. */
@keyframes shade1{ 0%,33%{opacity:.32;} 34%,66%{opacity:.6;}  67%,100%{opacity:1;}   }
@keyframes shade2{ 0%,33%{opacity:1;}   34%,66%{opacity:.32;} 67%,100%{opacity:.6;}  }
@keyframes shade3{ 0%,33%{opacity:.6;}  34%,66%{opacity:1;}   67%,100%{opacity:.32;} }
@media (prefers-reduced-motion: no-preference){
  .go .brand .deco .blk:nth-child(1){ animation:shade1 1.5s linear; }
  .go .brand .deco .blk:nth-child(2){ animation:shade2 1.5s linear; }
  .go .brand .deco .blk:nth-child(3){ animation:shade3 1.5s linear; }
  .go .brand .deco.right .blk:nth-child(1){ animation:shade3 1.5s linear; }
  .go .brand .deco.right .blk:nth-child(2){ animation:shade2 1.5s linear; }
  .go .brand .deco.right .blk:nth-child(3){ animation:shade1 1.5s linear; }
}
.sidebar .brand .blink{ color:var(--accent); }
.sidebar .tag{ color:var(--fg-dim); font-size:.85em; margin-bottom:1.3rem; flex:none; }
.tree{ list-style:none; margin:0; padding:0;
  flex:1 1 auto; min-height:0; overflow:auto; overscroll-behavior:contain; }   /* the only scrolling region */
.tree li{ overflow-wrap:anywhere; }   /* long slugs wrap instead of overflowing */
.tree a{ color:var(--fg); text-decoration:none; display:block; padding:1px 0; }
.tree a:hover{ color:var(--accent); }
.tree .book::before{ content:"▸ "; color:var(--fg-dim); }
.tree .book.open::before{ content:"▾ "; color:var(--accent); }
.tree .book.open > a{ color:var(--fg-bright); }
.tree .chapters{ list-style:none; margin:.1rem 0 .7rem; padding:0 0 0 1.6ch; border-left:1px solid var(--rule); }
.tree .chapters li::before{ content:none; }   /* drop the global "–" li bullet; the · / › anchor markers are the tree's own */
.tree .chapters a::before{ content:"· "; color:var(--fg-dim); }
.tree .chapters a.active{ color:var(--accent); }
.tree .chapters a.active::before{ content:"› "; color:var(--accent); }

/* top bar: a terminal title / prompt line ------------------------- */
.topbar{
  border-bottom:1px solid var(--rule); padding:.7rem 8.25rem .7rem 2rem;   /* right padding clears the fixed .topnav cluster */
  color:var(--fg-dim); display:flex; gap:1.5ch; align-items:center; flex-wrap:wrap;
  background:var(--panel); position:sticky; top:0; z-index:10;
}
/* prompt stays on ONE non-wrapping line so it never grows the header height.
   JS (fitPrompt) drops the visitor@host: prefix when the line won't fit, then
   left-truncates the path; the CSS here is the static / no-JS fallback. */
.topbar .cmd{ display:flex; flex-wrap:nowrap; flex:1 1 auto; min-width:0; max-width:100%; overflow:hidden; }   /* grow to fill the bar so clientWidth = available width, not content width */
.topbar .cmd .seg{ white-space:nowrap; }
.topbar .cmd .prefix{ flex:0 0 auto; }                  /* shown only when the whole line fits */
.topbar .cmd.hide-prefix .prefix{ display:none; }
.topbar .cmd .pathseg{ flex:0 1 auto; min-width:0; overflow:hidden; }
.topbar .prompt{ color:var(--accent); }
.topbar .prompt .at{ color:var(--fg-dim); }
.topbar .username{ font-weight:700; color:color-mix(in srgb, var(--accent), #fff 18%); }
.topbar a.cmd{ text-decoration:none; border-bottom:none; color:inherit; cursor:pointer; }
.topbar .path{ color:var(--fg); }
.topbar a.cmd:hover .path{ color:var(--accent); }
.btn{
  font:inherit; font-size:.82em; background:transparent; color:var(--fg-dim);
  border:1px solid var(--rule); padding:.15rem .6rem; cursor:pointer; border-radius:2px;
}
.btn:hover{ color:var(--accent); border-color:var(--accent); }

/* top-right control cluster: previous-chapter / page-outline(#) / next-chapter,
   fixed in the corner, mirroring the sidebar's menu toggle on the left.
     sidebar (left)  = site / book / chapter navigation
     #  (here)       = this page's sub-headings — a second, separate index
     arrows (here)   = previous / next chapter */
.topnav{ position:fixed; top:.5rem; right:.55rem; z-index:70; display:flex; gap:.4rem; }
.navbtn{
  width:2.1rem; height:2.1rem; flex:none; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  font:inherit; font-weight:700; font-size:1.2rem; line-height:1;
  color:var(--fg-dim); background:var(--panel); text-decoration:none;
  border:1px solid var(--rule); border-radius:3px; cursor:pointer;
}
.navbtn:hover{ color:var(--accent); border-color:var(--accent); }
.navbtn[aria-disabled="true"]{ opacity:.32; pointer-events:none; }   /* at the first / last chapter */
.navprev::before{ content:"\2039"; }   /* ‹ previous chapter */
.navnext::before{ content:"\203A"; }   /* › next chapter */
.toc-toggle::before{ content:"#"; font-size:.95em; }
.toc-toggle.is-home::before{ content:"\03BB"; }   /* root page: the index is the book list -> lambda, not # */
/* the checkbox holds open/closed state; clip it offscreen but keep it focusable */
.toc-checkbox{ position:absolute; width:1px; height:1px; margin:-1px; padding:0;
  border:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
#toctoggle:checked ~ .toc-toggle{ color:var(--bg); background:var(--accent); border-color:var(--accent); }
.toc-checkbox:focus-visible ~ .toc-toggle{ outline:2px solid var(--accent); outline-offset:2px; }

.toc{
  display:none;   /* shown when #toctoggle is checked (label click); works without JS */
  position:absolute; top:100%; right:0; margin-top:.4rem; z-index:30;
  width:min(92vw, 40ch); max-height:75vh; overflow:auto;
  background:var(--panel); border:1px solid var(--accent); border-radius:3px;
  padding:.85rem 1rem 1rem; box-shadow:0 12px 30px rgba(0,0,0,.45);
}
#toctoggle:checked ~ .toc{ display:block; }
/* book title: the container context, in case the breadcrumb truncated it away */
.toc .toc-book{ display:block; color:var(--fg-bright); font-weight:700; font-size:.78rem; text-decoration:none;
  border-bottom:1px solid var(--rule); padding-bottom:.5rem; margin-bottom:.5rem; overflow-wrap:anywhere; }
/* the header link always goes up one level (book index, or site root from a book
   index) -> a turn-up arrow instead of the #-heading marker, to advertise it */
.toc .toc-book::before{ content:"\2191\00a0"; color:var(--fg-dim); font-weight:400; }   /* ↑ (basic arrow: renders where the turn-arrows don't) */
.toc .toc-book:hover::before{ color:var(--accent); }
.toc .toc-book.is-root::before{ content:none; }   /* root page: nowhere up to go */
.toc .toc-book:hover{ color:var(--accent); }
.toc ul{ list-style:none; margin:0; padding:0; font-size:.92rem; }
.toc li{ overflow-wrap:anywhere; padding-left:0; }
.toc li::before{ content:none; }   /* suppress the global "ul li" en-dash bullet; the ## prefix is on the link */
.toc a{ color:var(--fg); text-decoration:none; display:block; padding:2px 0; border-bottom:none; }
.toc a::before{ content:"## "; color:var(--fg-dim); }    /* mirror the heading's own # markers */
.toc li.lvl1 a::before{ content:"# "; }                  /* the page title (h1), first in the list */
.toc li.lvl3 a::before{ content:"### "; }                /* h3 -> ###, flush left (the # count shows depth) */
/* child-page links (book/chapter index) navigate elsewhere -> a "go to" arrow
   instead of a #-heading marker, with nesting shown by indent rather than depth */
.toc li.page a::before{ content:"\2192\00a0"; color:var(--fg-dim); }   /* → */
.toc li.page.lvl3{ padding-left:1.6ch; }
.toc a:hover, .toc a:hover::before, .toc a.active, .toc a.active::before{ color:var(--accent); }

/* sidebar theme control */
/* action row: external-link + settings icon buttons, pinned near the bottom */
.sidebar-actions{
  flex:none; margin-top:1rem; padding-top:1rem; border-top:1px solid var(--rule);
  display:flex; flex-wrap:wrap; gap:.55rem;
}
.iconbtn{ display:inline-flex; align-items:center; justify-content:center;
  width:2.1rem; height:2.1rem; padding:0; min-width:0; }
.iconbtn svg{ display:block; }
/* JS-only chrome (the settings gear): shown only once scripting is confirmed */
.js-only{ display:none; }
html.js .iconbtn.js-only{ display:inline-flex; }
/* site build date, pinned beneath the actions (templated by Hugo in the real theme) */
.build-date{ flex:none; margin-top:.6rem; color:var(--fg-dim); font-size:.62rem;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.build-date .lbl{ color:var(--accent); }

/* settings modal (theme + fx controls), opened from the gear in the action row */
.settings-modal{
  margin:auto; padding:0; max-width:min(92vw, 30ch); width:max-content;
  color:var(--fg); background:var(--panel); border:1px solid var(--accent); border-radius:3px;
  box-shadow:0 12px 30px rgba(0,0,0,.45);
}
.settings-modal::backdrop{ background:rgba(4,5,4,.74); }
.settings-head{ display:flex; align-items:center; justify-content:space-between; gap:1ch;
  padding:.55rem .7rem; border-bottom:1px solid var(--rule); }
.settings-title{ color:var(--fg-bright); font-weight:700; font-size:.82rem; }
.settings-close{ width:2.1rem; height:2.1rem; padding:0; min-width:0; line-height:1;
  display:inline-flex; align-items:center; justify-content:center; }
.settings-body{ display:grid; grid-template-columns:max-content max-content; gap:.7rem .8ch;
  align-items:center; padding:.85rem .9rem 1rem; }
.settings-row{ display:contents; }   /* label + button land in the grid columns */
.settings-body .ctl-label{ color:var(--accent); font-size:.82rem; }
.settings-body .btn{ justify-self:start; min-width:7ch; text-align:center; }

/* menu toggle: a circle glyph, hidden on wide screens, shown when the sidebar
   collapses. ○ (hollow) = closed, ● (filled) = open. Both circles exist in
   virtually every monospace font, so it degrades cleanly to the system fallback. */
/* the checkbox itself is the open/closed state; keep it off-screen but still
   focusable (clip, not display:none) so the menu is keyboard-reachable. */
.nav-checkbox{ position:absolute; width:1px; height:1px; margin:-1px; padding:0;
  border:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
.menutoggle{ display:none; }
.menutoggle::before{ content:"\25CB"; }                  /* ○ menu closed */
#navtoggle:checked ~ .menutoggle::before{ content:"\25CF"; }    /* ● menu open */
#navtoggle:checked ~ .menutoggle{ color:var(--bg); background:var(--accent); border-color:var(--accent); } /* reverse-video when open, matching the # toggle */
.nav-checkbox:focus-visible ~ .menutoggle{ outline:2px solid var(--accent); outline-offset:2px; }

/* inline UI widget demos: rendered on the intro page in place of screenshots, so
   the docs always show the live chrome (and follow the active theme). They reuse
   the real .navbtn / .btn classes; the wrapper just strips the fixed positioning
   those carry inside .topnav and lays them out in a captioned row. */
.uidemo{ display:flex; flex-wrap:wrap; align-items:flex-end; gap:1.2rem; margin:.3rem 0 .1rem; }
.uidemo .navbtn, .uidemo .btn{ position:static; }
.uidemo figure{ margin:0; display:flex; flex-direction:column; align-items:center; gap:.45rem; }
.uidemo figcaption{ color:var(--fg-dim); font-size:.72rem; text-align:center; max-width:16ch; }
.uidemo .row{ display:inline-flex; align-items:center; gap:.4rem; }
.uidemo .ctl-label{ color:var(--accent); font-size:.82rem; }
/* the standalone hamburger demo: same ○ glyph + box as the real .menutoggle */
.uidemo .menudemo::before{ content:"\25CB"; }
/* keycaps for the arrow-key demo */
.uidemo .kbd{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:2.1rem; height:2.1rem; padding:0 .55rem;
  font:inherit; font-weight:700; font-size:1.15rem; line-height:1;
  color:var(--fg-dim); background:var(--panel);
  border:1px solid var(--rule); border-bottom-width:3px; border-radius:4px;
}

/* off-canvas backdrop: only exists on narrow screens (see media query) */
.nav-backdrop{ display:none; }
.toggles button.on{ color:var(--bg); background:var(--accent); border-color:var(--accent); }

/* reading column -------------------------------------------------- */
main{ padding:0.5rem 1rem 6rem; }
.content{ max-width:var(--col); margin:0 auto;
  overflow-wrap:anywhere; }   /* break-less scramble tokens still wrap -> page width never grows */

/* Running prose reads in a proportional face; the terminal chrome, headings, and
   ALL code stay monospace (Inconsolata). Code inside a paragraph must re-assert
   the mono var so it doesn't inherit the reading font from its <p>. */
.content p, .content li, .content blockquote, .content dd, .content dt{
  font-family:var(--font-read); letter-spacing:0;
}
.content code, .content pre, .content kbd, .content samp{ font-family:var(--font-mono); }

h1,h2,h3{ color:var(--fg-bright); font-weight:600; line-height:1.3; letter-spacing:.3px; }
h1{ font-size:1.55rem; margin:.2rem 0 1.4rem; }
h1::before{ content:"# "; color:var(--accent); }
h2{ font-size:1.15rem; margin:2.6rem 0 .9rem; padding-top:.8rem; border-top:1px dashed var(--rule); }
h2::before{ content:"## "; color:var(--accent); }
h3{ font-size:1rem; margin:1.8rem 0 .6rem; }
h3::before{ content:"### "; color:var(--accent); }
h1,h2,h3{ scroll-margin-top:4.5rem; }   /* anchor jumps clear the sticky header */
h3{ scroll-margin-top:5.3rem; }         /* h3 lacks h2's border-top + .8rem padding, so add that clearance or its text tucks under the header */

p{ margin:.9rem 0; }
a{ color:var(--accent); text-decoration:none; border-bottom:1px solid color-mix(in srgb, var(--accent) 35%, transparent); }
a:hover{ border-bottom-color:var(--accent); }

ul{ margin:.9rem 0; padding-left:0; list-style:none; }
ul li{ padding-left:2.2ch; position:relative; }
ul li::before{ content:"–"; position:absolute; left:0; color:var(--fg-dim); }

code{ color:var(--accent); background:color-mix(in srgb, var(--fg) 14%, var(--bg)); padding:.05em .45em; border-radius:2px; }

/* ox-hugo shortcode boxes as TUI framed dialogs -------------------- */
.box{
  --bw:3px; --bs:double;               /* border width/style (overridden per box) */
  border:var(--bw) var(--bs) transparent;   /* invisible at first; the beam draws it in */
  --line:var(--rule);                  /* the eventual line color (per box below) */
  margin:1.7rem 0; background:transparent; position:relative;
}
.box .label{                           /* title straddles the top line, ncurses/DOS legend style */
  position:absolute; top:0; left:1.4ch; transform:translateY(-55%);
  user-select:none; -webkit-user-select:none;   /* chrome, not content -> excluded from selection/copy */
  z-index:1;                           /* above the beam so it isn't drawn through the title */
  padding:.14em .6ch; font-size:.83em; font-weight:700;
  background:var(--bg);                /* page-colored -> "cuts" a gap in the border (and the beam) */
  color:var(--fg-bright);
  /* subdued chip border around the title */
  border:1px solid color-mix(in srgb, var(--accent), #fff 28%);
  max-width:calc(100% - 3ch);          /* keep clear of the right corner */
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.box .body{ padding:1.2rem 1.1rem .95rem; }
.box .body pre{ margin:0; white-space:pre; overflow:hidden; text-overflow:ellipsis; }

.run{ --line:color-mix(in srgb, var(--accent) 65%, var(--rule));
  background:color-mix(in srgb, var(--accent), transparent 92%); }   /* same faint wash as notes */
.run .label{ color:var(--accent); max-width:calc(100% - 8ch); }   /* leave room for copy button + a gap */
.run .label .lt::before{ content:"$ "; }
.run code, .run .body pre{ color:var(--fg-bright); background:none; padding:0; }
.run .body{ background:none; }   /* let the box's accent wash show through */

/* copy button: a second cutout in the top-right border of run boxes */
.run .copy{
  position:absolute; top:0; right:1.4ch; transform:translateY(-55%); z-index:1;
  background:var(--bg); border:none; cursor:pointer; padding:0 .55ch;
  color:#a5a5a5; line-height:1; display:inline-flex; align-items:center;
}
.run .copy:hover{ color:var(--accent); }
.run .copy .ico{ display:inline-block; position:relative; }
/* two overlapping sheets = the universal "copy" symbol */
.run .copy .clip{ width:1.5em; height:1.6em; }
.run .copy .clip::before{ content:""; position:absolute; left:0; top:0;          /* back sheet (peeks out top-left) */
  width:1em; height:1.2em; border:2px solid currentColor; border-radius:2px; }
.run .copy .clip::after{ content:""; position:absolute; left:.45em; top:.4em;     /* front sheet, shifted down-right */
  width:1em; height:1.2em; border:2px solid currentColor; border-radius:2px; background:var(--bg); }
.run .copy .check{ display:none; width:.82em; height:1.5em;
  border-right:2.5px solid currentColor; border-bottom:2.5px solid currentColor; transform:rotate(45deg); }
.run .copy.copied{ color:var(--accent); }
.run .copy.copied .clip{ display:none; }
.run .copy.copied .check{ display:inline-block; }
/* terminal reverse-video selection sweep during copy (run pre + inline code) */
.ch.sel{ background:var(--sel-bg); color:var(--sel-fg); }
.content code{ cursor:pointer; }
.content code:hover{ background:color-mix(in srgb, var(--fg) 26%, var(--bg)); }

/* notes: palette-derived (not blue) and a distinct call-out box —
   single solid border + a faint accent wash, vs run's double-line frame */
.notice{
  --line:color-mix(in srgb, var(--accent) 60%, var(--rule));
  --bw:2px; --bs:dashed;
  background:color-mix(in srgb, var(--accent), transparent 92%);
}
.notice .label{ color:var(--accent); }
.notice .label::before{          /* CSS-drawn chevron (no font glyph -> renders identically everywhere) */
  content:""; display:inline-block;
  width:.38em; height:.38em; margin-right:.55em; vertical-align:.08em;
  border-top:2px solid currentColor; border-right:2px solid currentColor;
  transform:rotate(45deg);
}
.notice .body{ color:var(--fg); }

/* draw-on border-beam: a glowing head circles the frame and PAINTS the line
   behind it (the box draws itself), in sync with the text rain. Then the real
   double-border settles in and the beam overlay fades. */
@property --draw{ syntax:"<angle>"; inherits:false; initial-value:0deg; }
.box::before{   /* the REAL border style (dashed/double), revealed clockwise by a conic mask */
  content:""; position:absolute; inset:calc(-1 * var(--bw)); border-radius:inherit;
  border:var(--bw) var(--bs) var(--line); pointer-events:none; opacity:0;
  -webkit-mask:conic-gradient(from var(--beam-start,45deg), #000 0 var(--draw), transparent var(--draw) 360deg);
          mask:conic-gradient(from var(--beam-start,45deg), #000 0 var(--draw), transparent var(--draw) 360deg);
}
.box::after{    /* bright leading-edge glow, riding the front of the drawn line */
  content:""; position:absolute; inset:calc(-1 * var(--bw)); border-radius:inherit;
  padding:var(--bw); pointer-events:none; opacity:0;
  background:conic-gradient(from var(--beam-start,45deg),
    transparent 0 calc(var(--draw) - 9deg),
    color-mix(in srgb, var(--accent), #fff 60%) var(--draw),
    transparent var(--draw) 360deg);
  -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
          mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite:exclude;
}
/* the real border fades in once the beam has drawn it */
.go .box{ border-color:var(--line); }
/* fx off: show the border statically, no beam */
body.no-fx .box{ border-color:var(--line); transition:none; }
body.no-fx .box::before, body.no-fx .box::after{ display:none; }
body.no-fx .brand .deco .blk{ animation:none !important; }   /* checker rotation off when fx is off (!important beats the higher-specificity .go :nth-child rules) */
@media (prefers-reduced-motion: no-preference){
  .box{ transition:border-color .5s ease; }
  .go .box{ transition-delay:1.05s; }
  .go .box::before, .go .box::after{ animation:draw 1.5s ease-out forwards; }
}
@keyframes draw{
  0%  { --draw:0deg;   opacity:1; }
  78% { --draw:360deg; opacity:1; }   /* one lap paints the whole frame */
  100%{ --draw:360deg; opacity:0; }   /* hold, then hand off to the real border */
}

/* blinking block cursor ------------------------------------------- */
.cursor{ display:inline-block; width:1ch; background:var(--accent); color:var(--accent); }
@keyframes blink{ 50%{ opacity:0; } }

.hint{ color:var(--fg-dim); font-size:.85em; margin-top:.4rem; }
.firstscreen-marker{ border-top:1px dashed var(--rule); color:var(--fg-dim);
  font-size:.78em; text-align:center; margin:2.2rem 0; padding-top:.4rem; }

/* glyph lab (prototype probe) — see which decorative glyphs the webfont
   actually provides vs. which fall back to a system monospace (watch the
   advance width: fallback glyphs won't line up with the grid). */
.glyphs{ margin:1rem 0; display:grid; gap:.35rem; }
.glyphs .row{ display:flex; gap:1.4ch; align-items:baseline; }
.glyphs .lbl{ color:var(--fg-dim); font-size:.78em; min-width:12ch; flex:none; text-align:right; }
.glyphs .g{ color:var(--fg-bright); font-size:1.25rem; letter-spacing:0; overflow-wrap:anywhere; }
pre.tui{ color:var(--accent); background:var(--code-bg); padding:1rem 1.1rem; margin:1.4rem 0;
  border:1px solid var(--rule); border-radius:3px; overflow:auto; line-height:1.15; font-size:1.05rem; }
.glyphs .g .miss{ color:var(--fg-dim); }   /* glyphs Inconsolata lacks even at source */

/* half-block pixel art: each cell is U+2580 (▀, upper half). The glyph colour
   paints the TOP pixel, the cell background paints the BOTTOM pixel -> two
   vertical pixels per character, so an N-tall image needs only N/2 rows. */
.pixart{ line-height:1; font-size:1.3rem; margin:1.4rem 0; }
.pixart .prow{ display:block; white-space:pre; }
.pixart .prow span{ background-clip:padding-box; }   /* crisp bottom-pixel edges */

/* ============ narrow screens: off-canvas sidebar + menu toggle =========
   MUST come after the base .sidebar/.nav-backdrop rules so its position
   overrides win (equal specificity -> later source wins).

   Breakpoint = the exact width where the reading column can no longer hold
   its full --col, so the sidebar collapses at the same moment the text would
   start to rewrap (rather than at an arbitrary device width):
     sidebar(30ch) + content(74ch) + main padding(1rem x 2)  =  104ch + 2rem
   At these widths the font-size clamp is pinned to its 21px max, so
   1ch = 0.6em ~ 12.6px and 1rem = 21px:  104*12.6 + 2*21  ~  1352px.
   (Tunable: nudge if the column visibly squeezes before the sidebar drops.) */
@media (max-width:1352px){
  .wrap{ grid-template-columns:minmax(0,1fr); }
  .menutoggle{
    display:inline-flex; align-items:center; justify-content:center;
    position:fixed; top:.5rem; left:.55rem; z-index:70;   /* above the sidebar */
    width:2.1rem; height:2.1rem; padding:0; box-sizing:border-box;   /* rem (not em) so the box doesn't scale with the glyph, and fits inside the header */
    font:inherit; font-weight:700; font-size:1.4rem; line-height:1; color:var(--accent);
    background:var(--panel); border:1px solid var(--rule); border-radius:3px; cursor:pointer;
  }
  .menutoggle:hover{ color:var(--fg-bright); border-color:var(--accent); }
  #navtoggle:checked ~ .topnav{ opacity:.32; pointer-events:none; }   /* sidebar overlay covers the page -> dim/disable the right-hand page-nav cluster */
  .topbar{ padding-left:4rem; }     /* clear the fixed toggle */
  .sidebar{ padding-top:.55rem; }   /* align header with the toggle's top, not below it */
  .sidebar .brand, .sidebar .tag{ padding-left:2rem; }   /* sit to the right of the toggle */
  .sidebar{                                   /* terminal panel: snaps open + decodes in, no web slide */
    position:fixed; z-index:60; top:0; left:0;
    width:min(86vw, 34ch); height:100vh; height:100dvh;   /* dvh: match the visible area so the bottom controls stay reachable under the mobile toolbar */
    display:none; border-right:1px solid var(--accent);
    overscroll-behavior:contain;                          /* keep scroll momentum inside the panel */
  }
  #navtoggle:checked ~ .wrap .sidebar{ display:flex; }   /* flex (not block) so the pinned-header/scroll-tree/pinned-footer layout holds on mobile */
  .nav-backdrop{                              /* solid console dim, snaps in */
    display:none; position:fixed; inset:0; z-index:55; background:rgba(4,5,4,.74);
  }
  #navtoggle:checked ~ .wrap .nav-backdrop{ display:block; }
}
/* ============================================================
   THEME ADDITIONS (beyond the static prototype's <style>)
   Kept separate so re-extracting the prototype never clobbers it.
   - third level in the nav tree (book -> chapter -> section)
   - notice style variants, badge, button, math block, children index
   ============================================================ */

/* --- nav tree: expandable middle (chapter) node + third (section) level --- */
.tree .chapters li.node > a::before{ content:"\25B8 "; color:var(--fg-dim); }   /* ▸ */
.tree .chapters li.node.open > a::before{ content:"\25BE "; color:var(--accent); }   /* ▾ */
.tree .chapters li.node.open > a{ color:var(--fg-bright); }
.tree .sections{ list-style:none; margin:.1rem 0 .55rem; padding:0 0 0 1.6ch; border-left:1px solid var(--rule); }
.tree .sections a{ color:var(--fg); text-decoration:none; display:block; padding:1px 0; }
.tree .sections a:hover{ color:var(--accent); }
.tree .sections a.active{ color:var(--accent); }
.tree .sections a.active::before{ content:"\203A "; color:var(--accent); }   /* › */

/* --- notice style variants (accent stays palette-driven; hue shifts wash/line) --- */
.notice-warning, .notice-orange{
  --line:color-mix(in srgb, #e0a33a 60%, var(--rule));
  background:color-mix(in srgb, #e0a33a, transparent 92%);
}
.notice-warning .label, .notice-orange .label{ color:#e8b552; }
.notice-grey, .notice-credits{
  --line:var(--rule);
  background:color-mix(in srgb, var(--fg) 6%, transparent);
}
.notice-grey .label, .notice-credits .label{ color:var(--fg-dim); }
/* primary / info / blue fall through to the prototype's default accent .notice */

/* --- inline badge --- */
.badge{
  display:inline-block; font-size:.8em; font-weight:700; line-height:1.3;
  padding:.02em .6ch; border-radius:2px; vertical-align:.05em;
  border:1px solid var(--accent); color:var(--accent);
  background:color-mix(in srgb, var(--accent), transparent 88%);
}
.badge-green{ border-color:var(--accent-2); color:var(--accent-2); }

/* --- link button --- */
.button-link{
  display:inline-block; font-weight:700; padding:.3em 1ch; margin:.3rem .5ch .3rem 0;
  border:1px solid var(--accent); border-radius:3px;
  color:var(--accent); text-decoration:none;
}
.button-link:hover{ background:var(--accent); color:var(--bg); border-bottom-color:var(--accent); }
.button-green{ border-color:var(--accent-2); color:var(--accent-2); }
.button-green:hover{ background:var(--accent-2); }

/* --- math block --- */
.math-block{ margin:1.4rem 0; overflow-x:auto; }

/* --- fenced code blocks (Chroma .highlight): scroll long lines instead of
       overflowing, and strip the inline-code pill styling that leaks onto the
       block <code> (its background/padding drew stray edge lines) --- */
.content .highlight{ margin:1.4rem 0; }
/* smaller font so the reading column fits ~80+ monospace columns without scrolling */
.content .highlight pre{ overflow-x:auto; max-width:100%; border-radius:3px; padding:.9rem .25rem; font-size:.7em; line-height:1.5; }
.content pre code{ background:none; padding:0; color:inherit; border-radius:0; cursor:auto; }
.content pre code:hover{ background:none; }
/* match the fenced-code size (.7em above) for run-box text */
.run .body pre, .run .body code{ font-size:.7em; line-height:1.5; }

/* --- images / figures: fit the reading column, centered --- */
.content img{ max-width:100%; height:auto; display:block; margin:0 auto; border-radius:2px; }
.content figure{ margin:1.7rem auto; max-width:100%; text-align:center; }
.content figure figcaption{ color:var(--fg-dim); font-size:.85em; margin-top:.5rem; }

/* --- mermaid diagrams: light panel so the lines have contrast (mermaid's
       default theme assumes a light background), centered and width-capped --- */
.content .mermaid{
  background:#f4f4ee;
  border:1px solid var(--rule);
  border-radius:3px;
  padding:1.2rem;
  margin:1.7rem 0;
  text-align:center;
  overflow-x:auto;
}
.content .mermaid svg{ max-width:100%; height:auto; }

/* --- children index list (book/chapter listing) --- */
ul.children{ margin:.6rem 0; }
ul.children .children-desc{ color:var(--fg-dim); }

/* --- intro λ logo (home page only): an oversized lambda centered like an
       image, with a matrix-style glyph-rain canvas fading in behind it.
       The canvas is wired up + animated in terminal.js (lambdaRain). --- */
.lambda-logo{
  position:relative;
  display:flex;
  align-items:center;
  justify-content:center;
  height:clamp(360px, 64vh, 680px);
  margin:1.4rem auto 2.6rem;
  overflow:hidden;
}
.lambda-logo .lambda-rain{
  position:absolute; inset:0;
  width:100%; height:100%;
  pointer-events:none;
  opacity:0;
  transition:opacity 1.4s ease;
}
.lambda-logo.rain-on .lambda-rain{ opacity:.5; }
.lambda-logo .lambda-glyph{
  position:relative; z-index:1;
  font-family:var(--font-mono);
  font-size:clamp(7rem, 22vh, 15rem);
  line-height:1;
  color:var(--accent);
  text-shadow:0 0 24px color-mix(in srgb, var(--accent), transparent 55%);
  user-select:none;
}
/* fx off: no animated field, just the static glyph */
.no-fx .lambda-logo .lambda-rain{ display:none; }

/* lite (light) palette: the page is pale, so back the scene with a translucent
   gray panel — the dark phosphor trails read much better against it than on white */
:root[data-theme="lite"] .lambda-logo{ background:rgba(20,24,18,0.12); border-radius:4px; }

/* when a maxed mother core detonates, its glyph ascends to replace the λ here —
   flash + scale-pop so the swap reads as a climactic event */
@keyframes lambda-swap{ 0%{ transform:scale(1.7); filter:brightness(2.4); } 100%{ transform:scale(1); filter:none; } }
.lambda-logo .lambda-glyph.swap{ animation:lambda-swap .7s ease-out; }
