:root {
  --sans: 'DM Sans', sans-serif;
  font-family: var(--sans);
  font-synthesis: none;
  color-scheme: light;
  --page: #f3f5f9;
  --surface: #ffffff;
  --inset: #edf0f6;
  --text: #202634;
  --muted: #566174;
  --border: #ccd2df;
  --purple: #5838b5;
  --purple-bg: #eee8fa;
  --green: #0d7160;
  --green-bg: #e0f3ed;
  --amber: #8c4d05;
  --amber-bg: #fcf0db;
  --error: #9b3025;
  --error-bg: #fff0eb;
  --focus: #8865df;
  /* The command editor takes the page's own colours; the terminal theme makes it a black terminal. */
  --term-bg: var(--surface);
  --term-border: var(--border);
  --term-text: var(--text);
  --term-muted: var(--muted);
  --term-prompt: var(--purple);
  --term-caret: var(--text);
  --term-mark: var(--purple-bg);
  --term-hover: var(--purple-bg);
  color: var(--text);
  background: var(--page);
  --content: 75rem;
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --page: #11151d;
  --surface: #1b2230;
  --inset: #242d3e;
  --text: #edf1f8;
  --muted: #b7c1d3;
  --border: #445169;
  --purple: #b9a7ff;
  --purple-bg: #342c52;
  --green: #62d8ba;
  --green-bg: #163b35;
  --amber: #ffc579;
  --amber-bg: #443421;
  --error: #ffb3a6;
  --error-bg: #432925;
  --focus: #b9a7ff;
}
/* Phosphor green on black, all monospace. The three streams keep separate hues, as in ANSI colours. */
:root[data-theme="terminal"] {
  color-scheme: dark;
  --sans: 'IBM Plex Mono', monospace;
  --page: #020604;
  --surface: #050d08;
  --inset: #0a1a10;
  --text: #b6f2c4;
  --muted: #74c48a;
  --border: #1f5532;
  --purple: #d3a2ff;
  --purple-bg: #2c1a40;
  --green: #4dff88;
  --green-bg: #0c3519;
  --amber: #ffc247;
  --amber-bg: #392a09;
  --error: #ff8a80;
  --error-bg: #3a100c;
  --focus: #4dff88;
  --term-bg: #000;
  --term-border: #2b7a46;
  --term-text: #c4ffd2;
  --term-muted: #5fae75;
  --term-prompt: #4dff88;
  --term-caret: #4dff88;
  --term-mark: #1f5532;
  --term-hover: #0a1a10;
}
[data-theme="terminal"] body { text-shadow: 0 0 .35em rgb(77 255 136 / .22); }
[data-theme="terminal"] *, [data-theme="terminal"] *::before, [data-theme="terminal"] *::after { border-radius: 0 !important; }
[data-theme="terminal"] #diagram rect { rx: 1px; }
/* Faint scanlines over the whole page, above everything but dialogs. */
[data-theme="terminal"] body::after { content: ''; position: fixed; inset: 0; z-index: 2; pointer-events: none; background: repeating-linear-gradient(to bottom, rgb(0 0 0 / .16) 0 1px, transparent 1px 3px); }
* { box-sizing: border-box; }
body { margin: 0; }
button, textarea { font: inherit; }
button, a { -webkit-tap-highlight-color: transparent; }
button { cursor: pointer; transition: background .16s, color .16s; }
button:focus-visible, a:focus-visible, [tabindex]:focus-visible { outline: 3px solid var(--focus); outline-offset: 4px; }
a { color: inherit; }
.site-header { height: 5rem; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; padding: 0 max(6.5%, calc((100vw - var(--content))/2)); background: var(--surface); }
.brand-heading { margin: 0; font: inherit; }
.brand { text-decoration: none; display: flex; align-items: center; font-size: 1.4375rem; font-weight: 700; letter-spacing: -.04em; }
.brand-icon { width: 2rem; height: 2rem; margin-right: .625rem; }
.brand-dot { color: var(--purple); }
.header-actions { display: flex; align-items: center; gap: 1.25rem; }
.text-button { background: none; border: 0; color: var(--muted); font-size: .8125rem; font-weight: 500; padding: .625rem 0; }
.text-button:hover { color: var(--purple); }
.talk-button { display: flex; align-items: center; gap: .4375rem; min-height: 2.5rem; padding: .5rem .875rem .5rem .6875rem; border: 1px solid var(--purple-bg); border-radius: .4375rem; background: var(--purple-bg); color: var(--purple); font-size: .75rem; font-weight: 600; }
.talk-button:hover { border-color: var(--purple); }
.talk-button svg { width: 1rem; height: 1rem; fill: currentColor; }
/* The shell switch sits in the header, a two-way toggle of the same height as its neighbours. Its two
   halves are equal, and a raised thumb slides under the chosen one, overshooting a touch as it lands. */
.shell-switch { position: relative; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: .125rem; min-height: 2.5rem; padding: .1875rem; border: 1px solid var(--border); border-radius: .4375rem; background: var(--inset); }
.shell-switch::before { content: ''; position: absolute; top: .1875rem; bottom: .1875rem; left: .1875rem; width: calc((100% - .5rem) / 2); border-radius: .3125rem; background: var(--surface); box-shadow: 0 0 0 1px var(--border), 0 1px 3px rgb(0 0 0 / .12); }
:root[data-platform="macos"] .shell-switch::before { transform: translateX(calc(100% + .125rem)); }
/* The thumb starts moving only once the page has placed it, so it never slides in on load. */
.shell-switch.ready::before { transition: transform .24s cubic-bezier(.34, 1.45, .55, 1); }
.shell-switch button { position: relative; display: inline-flex; align-items: center; justify-content: center; gap: .375rem; padding: 0 .625rem; border: 0; border-radius: .3125rem; background: transparent; color: var(--muted); font-size: .75rem; transition: color .2s; }
.shell-switch button:hover { color: var(--text); }
.shell-switch button.active { color: var(--purple); }
.shell-switch .os-icon { transition: transform .24s cubic-bezier(.34, 1.45, .55, 1); }
.shell-switch button.active .os-icon { transform: scale(1.12); }
.theme-toggle { display: flex; align-items: center; justify-content: center; gap: .5rem; padding: .5625rem .75rem; min-height: 2.5rem; border: 1px solid var(--border); border-radius: .4375rem; background: var(--surface); color: var(--text); font-size: .75rem; }
.theme-toggle:hover { background: var(--inset); }
.theme-toggle svg { width: 1.0625rem; height: 1.0625rem; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
/* The button names, and shows, the current theme. */
.theme-toggle svg { display: none; }
.theme-toggle[data-current="light"] .sun-icon, .theme-toggle[data-current="dark"] .moon-icon, .theme-toggle[data-current="terminal"] .terminal-icon { display: block; }
main { max-width: var(--content); margin: auto; padding: 2rem 2.5rem 2.5rem; }
.editor-panel { border: 1px solid var(--term-border); border-radius: .75rem; overflow: hidden; background: var(--term-bg); }
.code-editor { position: relative; display: flex; gap: .9375rem; padding: .875rem 2.875rem .875rem 1.5rem; }
.prompt { font: 1rem/1.7 'IBM Plex Mono', monospace; color: var(--term-prompt); }
/* Names the shell the SHELL switch picks, like a terminal tab's title. */
.shell-name { position: absolute; top: .4375rem; right: .875rem; font: .625rem 'IBM Plex Mono', monospace; letter-spacing: .06em; color: var(--term-muted); pointer-events: none; }
/* The mirror sits under the textarea with identical text metrics, so a <mark> in it lines up with the typed text. */
.editor-field { position: relative; flex: 1; min-width: 0; }
textarea, .editor-mirror { padding: 0; font: .875rem/1.9 'IBM Plex Mono', monospace; tab-size: 2; white-space: pre-wrap; overflow-wrap: break-word; }
textarea { position: relative; display: block; resize: none; background: transparent; border: 0; width: 100%; min-height: 1.6625rem; max-height: 70vh; outline: none; color: var(--term-text); caret-color: var(--term-caret); }
textarea::placeholder { color: var(--term-muted); opacity: .55; }
.editor-mirror { position: absolute; top: 0; left: 0; overflow: hidden; color: transparent; pointer-events: none; }
.editor-mirror mark { color: transparent; background: var(--term-mark); border-radius: .1875rem; box-shadow: 0 0 0 .125rem var(--term-mark); }
/* A large resize handle; the native grabber is small and cannot be restyled everywhere. */
.resize-handle { position: absolute; right: .5rem; bottom: .5rem; width: 2.125rem; height: 2.125rem; display: grid; place-items: center; border-radius: .4375rem; color: var(--term-muted); cursor: ns-resize; touch-action: none; }
.resize-handle:hover, .resize-handle.dragging { color: var(--term-prompt); background: var(--term-hover); }
.resize-handle svg { width: 1.375rem; height: 1.375rem; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; }
.editor-panel:focus-within { border-color: var(--focus); box-shadow: 0 0 0 2px var(--purple-bg); }
/* One grid for every example row, so each row's first button starts in the same column. */
.example-rows { display: grid; grid-template-columns: max-content minmax(0, 1fr); align-items: baseline; gap: 1.125rem 1.125rem; padding: 0 0 1.25rem; }
.example-row { display: contents; }
.example-row[hidden] { display: none; }
.row-label { font-size: .625rem; letter-spacing: .12em; color: var(--muted); font-weight: 600; }
/* The SHELL buttons show each system's mascot or fruit before the shell's name. Tux is the
   Simple Icons glyph (CC0), after Larry Ewing's original drawn with The GIMP. */
.os-icon { width: 1rem; height: 1rem; fill: currentColor; flex-shrink: 0; }
/* A faint watermark of the system being mapped sits behind the page, in its lower right. */
body::before { content: ''; position: fixed; z-index: -1; right: max(2rem, 4vw); bottom: -1.5rem; width: min(26rem, 60vw); aspect-ratio: 1; background: var(--text); opacity: .035; pointer-events: none;
  mask: var(--watermark) no-repeat center / contain; -webkit-mask: var(--watermark) no-repeat center / contain; }
:root { --watermark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12.504 0c-.155 0-.315.008-.48.021-4.226.333-3.105 4.807-3.17 6.298-.076 1.092-.3 1.953-1.05 3.02-.885 1.051-2.127 2.75-2.716 4.521-.278.832-.41 1.684-.287 2.489a.424.424 0 00-.11.135c-.26.268-.45.6-.663.839-.199.199-.485.267-.797.4-.313.136-.658.269-.864.68-.09.189-.136.394-.132.602 0 .199.027.4.055.536.058.399.116.728.04.97-.249.68-.28 1.145-.106 1.484.174.334.535.47.94.601.81.2 1.91.135 2.774.6.926.466 1.866.67 2.616.47.526-.116.97-.464 1.208-.946.587-.003 1.23-.269 2.26-.334.699-.058 1.574.267 2.577.2.025.134.063.198.114.333l.003.003c.391.778 1.113 1.132 1.884 1.071.771-.06 1.592-.536 2.257-1.306.631-.765 1.683-1.084 2.378-1.503.348-.199.629-.469.649-.853.023-.4-.2-.811-.714-1.376v-.097l-.003-.003c-.17-.2-.25-.535-.338-.926-.085-.401-.182-.786-.492-1.046h-.003c-.059-.054-.123-.067-.188-.135a.357.357 0 00-.19-.064c.431-1.278.264-2.55-.173-3.694-.533-1.41-1.465-2.638-2.175-3.483-.796-1.005-1.576-1.957-1.56-3.368.026-2.152.236-6.133-3.544-6.139zm.529 3.405h.013c.213 0 .396.062.584.198.19.135.33.332.438.533.105.259.158.459.166.724 0-.02.006-.04.006-.06v.105a.086.086 0 01-.004-.021l-.004-.024a1.807 1.807 0 01-.15.706.953.953 0 01-.213.335.71.71 0 00-.088-.042c-.104-.045-.198-.064-.284-.133a1.312 1.312 0 00-.22-.066c.05-.06.146-.133.183-.198.053-.128.082-.264.088-.402v-.02a1.21 1.21 0 00-.061-.4c-.045-.134-.101-.2-.183-.333-.084-.066-.167-.132-.267-.132h-.016c-.093 0-.176.03-.262.132a.8.8 0 00-.205.334 1.18 1.18 0 00-.09.4v.019c.002.089.008.179.02.267-.193-.067-.438-.135-.607-.202a1.635 1.635 0 01-.018-.2v-.02a1.772 1.772 0 01.15-.768c.082-.22.232-.406.43-.533a.985.985 0 01.594-.2zm-2.962.059h.036c.142 0 .27.048.399.135.146.129.264.288.344.465.09.199.14.4.153.667v.004c.007.134.006.2-.002.266v.08c-.03.007-.056.018-.083.024-.152.055-.274.135-.393.2.012-.09.013-.18.003-.267v-.015c-.012-.133-.04-.2-.082-.333a.613.613 0 00-.166-.267.248.248 0 00-.183-.064h-.021c-.071.006-.13.04-.186.132a.552.552 0 00-.12.27.944.944 0 00-.023.33v.015c.012.135.037.2.08.334.046.134.098.2.166.268.01.009.02.018.034.024-.07.057-.117.07-.176.136a.304.304 0 01-.131.068 2.62 2.62 0 01-.275-.402 1.772 1.772 0 01-.155-.667 1.759 1.759 0 01.08-.668 1.43 1.43 0 01.283-.535c.128-.133.26-.2.418-.2zm1.37 1.706c.332 0 .733.065 1.216.399.293.2.523.269 1.052.468h.003c.255.136.405.266.478.399v-.131a.571.571 0 01.016.47c-.123.31-.516.643-1.063.842v.002c-.268.135-.501.333-.775.465-.276.135-.588.292-1.012.267a1.139 1.139 0 01-.448-.067 3.566 3.566 0 01-.322-.198c-.195-.135-.363-.332-.612-.465v-.005h-.005c-.4-.246-.616-.512-.686-.71-.07-.268-.005-.47.193-.6.224-.135.38-.271.483-.336.104-.074.143-.102.176-.131h.002v-.003c.169-.202.436-.47.839-.601.139-.036.294-.065.466-.065zm2.8 2.142c.358 1.417 1.196 3.475 1.735 4.473.286.534.855 1.659 1.102 3.024.156-.005.33.018.513.064.646-1.671-.546-3.467-1.089-3.966-.22-.2-.232-.335-.123-.335.59.534 1.365 1.572 1.646 2.757.13.535.16 1.104.021 1.67.067.028.135.06.205.067 1.032.534 1.413.938 1.23 1.537v-.043c-.06-.003-.12 0-.18 0h-.016c.151-.467-.182-.825-1.065-1.224-.915-.4-1.646-.336-1.77.465-.008.043-.013.066-.018.135-.068.023-.139.053-.209.064-.43.268-.662.669-.793 1.187-.13.533-.17 1.156-.205 1.869v.003c-.02.334-.17.838-.319 1.35-1.5 1.072-3.58 1.538-5.348.334a2.645 2.645 0 00-.402-.533 1.45 1.45 0 00-.275-.333c.182 0 .338-.03.465-.067a.615.615 0 00.314-.334c.108-.267 0-.697-.345-1.163-.345-.467-.931-.995-1.788-1.521-.63-.4-.986-.87-1.15-1.396-.165-.534-.143-1.085-.015-1.645.245-1.07.873-2.11 1.274-2.763.107-.065.037.135-.408.974-.396.751-1.14 2.497-.122 3.854a8.123 8.123 0 01.647-2.876c.564-1.278 1.743-3.504 1.836-5.268.048.036.217.135.289.202.218.133.38.333.59.465.21.201.477.335.876.335.039.003.075.006.11.006.412 0 .73-.134.997-.268.29-.134.52-.334.74-.4h.005c.467-.135.835-.402 1.044-.7zm2.185 8.958c.037.6.343 1.245.882 1.377.588.134 1.434-.333 1.791-.765l.211-.01c.315-.007.577.01.847.268l.003.003c.208.199.305.53.391.876.085.4.154.78.409 1.066.486.527.645.906.636 1.14l.003-.007v.018l-.003-.012c-.015.262-.185.396-.498.595-.63.401-1.746.712-2.457 1.57-.618.737-1.37 1.14-2.036 1.191-.664.053-1.237-.2-1.574-.898l-.005-.003c-.21-.4-.12-1.025.056-1.69.176-.668.428-1.344.463-1.897.037-.714.076-1.335.195-1.814.12-.465.308-.797.641-.984l.045-.022zm-10.814.049h.01c.053 0 .105.005.157.014.376.055.706.333 1.023.752l.91 1.664.003.003c.243.533.754 1.064 1.189 1.637.434.598.77 1.131.729 1.57v.006c-.057.744-.48 1.148-1.125 1.294-.645.135-1.52.002-2.395-.464-.968-.536-2.118-.469-2.857-.602-.369-.066-.61-.2-.723-.4-.11-.2-.113-.602.123-1.23v-.004l.002-.003c.117-.334.03-.752-.027-1.118-.055-.401-.083-.71.043-.94.16-.334.396-.4.69-.533.294-.135.64-.202.915-.47h.002v-.002c.256-.268.445-.601.668-.838.19-.201.38-.336.663-.336zm7.159-9.074c-.435.201-.945.535-1.488.535-.542 0-.97-.267-1.28-.466-.154-.134-.28-.268-.373-.335-.164-.134-.144-.333-.074-.333.109.016.129.134.199.2.096.066.215.2.36.333.292.2.68.467 1.167.467.485 0 1.053-.267 1.398-.466.195-.135.445-.334.648-.467.156-.136.149-.267.279-.267.128.016.034.134-.147.332a8.097 8.097 0 01-.69.468zm-1.082-1.583V5.64c-.006-.02.013-.042.029-.05.074-.043.18-.027.26.004.063 0 .16.067.15.135-.006.049-.085.066-.135.066-.055 0-.092-.043-.141-.068-.052-.018-.146-.008-.163-.065zm-.551 0c-.02.058-.113.049-.166.066-.047.025-.086.068-.14.068-.05 0-.13-.02-.136-.068-.01-.066.088-.133.15-.133.08-.031.184-.047.259-.005.019.009.036.03.03.05v.02h.003z'/></svg>"); }
:root[data-platform="macos"] { --watermark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 7.6c-1.2-.9-2.4-1.2-3.6-1.1-2.6.2-4.2 2.5-4 5.7.2 3.6 2.4 7.7 4.6 8.6 1 .4 2 .2 3-.3 1 .5 2 .7 3 .3 2.2-.9 4.4-5 4.6-8.6.2-3.2-1.4-5.5-4-5.7-1.2-.1-2.4.2-3.6 1.1zM12.3 6.2c0-1.9 1.3-3.6 3.4-4 0 2-1.3 3.6-3.4 4z'/></svg>"); }
:root:is([data-theme="dark"], [data-theme="terminal"]) body::before { opacity: .03; }
/* The examples share the switches' track; only the buttons inside it scroll sideways, and an edge
   fades only while there is more that way, so the track's own border stays whole. */
.example-track { max-width: 100%; }
.example-strip { position: relative; display: flex; gap: .125rem; min-width: 0; overflow-x: auto; scrollbar-width: none; overscroll-behavior-x: contain; --fade-left: 0rem; --fade-right: 0rem;
  mask-image: linear-gradient(to right, transparent, #000 var(--fade-left), #000 calc(100% - var(--fade-right)), transparent); }
.example-strip::-webkit-scrollbar { display: none; }
.example-strip.more-left { --fade-left: 2.5rem; }
.example-strip.more-right { --fade-right: 2.5rem; }
.example-strip button { flex-shrink: 0; white-space: nowrap; }
/* A segmented switch on a recessed track, so variations read as modes of one example rather than more examples. */
.variation-buttons { display: flex; flex-wrap: wrap; gap: .125rem; width: fit-content; padding: .1875rem; background: var(--inset); border: 1px solid var(--border); border-radius: .5rem; }
.variation-buttons button { background: transparent; border: 0; border-radius: .3125rem; padding: .3125rem .6875rem; color: var(--muted); font-size: .75rem; }
.variation-buttons button:hover { color: var(--text); }
.variation-buttons button.active { background: var(--surface); color: var(--purple); font-weight: 550; box-shadow: 0 0 0 1px var(--border), 0 1px 2px rgb(0 0 0 / .1); }
/* Rows with a sliding thumb draw the chosen button's raised look on the thumb instead. */
#variation-buttons, #redirect-style, #levels { position: relative; }
:is(#variation-buttons, #redirect-style, #example-strip, #levels) > button { position: relative; transition: color .2s; }
:is(#variation-buttons, #redirect-style, #example-strip, #levels) > button.active { background: transparent; box-shadow: none; }
.thumb { position: absolute; top: 0; left: 0; border-radius: .3125rem; background: var(--surface); box-shadow: 0 0 0 1px var(--border), 0 1px 2px rgb(0 0 0 / .1); opacity: 0; pointer-events: none;
  transition: transform .24s cubic-bezier(.34, 1.45, .55, 1), width .24s cubic-bezier(.34, 1.45, .55, 1), height .24s cubic-bezier(.34, 1.45, .55, 1), opacity .15s; }
.thumb.instant { transition: opacity .15s; }
.thumb.shown { opacity: 1; }
h2 { font-size: 1rem; letter-spacing: -.02em; margin: 0; font-weight: 650; }
.count { font-size: .6875rem; letter-spacing: 0; font-weight: 450; padding: .25rem .4375rem; background: var(--inset); color: var(--muted); border-radius: .25rem; white-space: nowrap; }
.dot { display: inline-block; width: .4375rem; height: .4375rem; border-radius: 50%; flex-shrink: 0; }
.stdin { background: var(--green); }
.stdout { background: var(--purple); }
.stderr { background: var(--amber); }
#results { margin-top: .625rem; }
.diagram-panel { position: relative; border: 1px solid var(--border); border-radius: .6875rem; background: var(--surface); overflow: hidden; }
.diagram-toolbar { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: .5rem 1rem; padding: .75rem 1.1875rem 0; font: .6875rem 'IBM Plex Mono', monospace; color: var(--muted); }
.diagram-summary { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .625rem; }
.diagram-summary > * { white-space: nowrap; }
.diagram-summary .count { font-family: var(--sans); }
.count:empty { display: none; }
.diagram-summary h2 { font-family: var(--sans); font-size: .875rem; color: var(--text); }
.diagram-toolbar button { border: 0; background: transparent; font: .75rem var(--sans); color: var(--muted); display: flex; gap: .4375rem; align-items: center; }
.diagram-toolbar button:hover { color: var(--purple); }
.diagram-toolbar button:disabled { opacity: .4; cursor: default; color: var(--muted); }
.diagram-actions { display: flex; align-items: center; gap: 1.125rem; }
.zoom-controls { display: flex; align-items: center; border: 1px solid var(--border); border-radius: .375rem; overflow: hidden; }
.zoom-controls button { min-width: 2rem; height: 1.75rem; justify-content: center; padding: 0 .375rem; font-variant-numeric: tabular-nums; }
.zoom-controls button:hover:not(:disabled) { background: var(--inset); }
.zoom-controls #zoom-out, .zoom-controls #zoom-in { font-size: 1rem; }
.zoom-controls #zoom-reset { min-width: 3.125rem; border-left: 1px solid var(--border); border-right: 1px solid var(--border); border-radius: 0; font-size: .6875rem; }
#diagram-scroll { overflow-x: auto; transition: opacity .16s; }
/* While the pipeline does not parse, the last good diagram stays put, faded, under the message. */
#results.stale #diagram-scroll, #results.stale #insights, #results.stale #notes, #results.stale .details { opacity: .35; }
#results.empty #diagram-scroll { min-height: 8rem; }
#results.empty .usage-key, #results.empty .details-section { display: none; }
#diagram-scroll.panning { cursor: grabbing; user-select: none; }
#diagram { min-width: 45rem; line-height: 0; }
#diagram svg { width: 100%; height: auto; min-height: 17.8125rem; max-height: 30rem; display: block; }
/* Hover a stream to trace it: it thickens and the others fade. */
#diagram .stream-link path { transition: stroke-width .12s, opacity .12s; }
#diagram .stream-link:hover path:not(.link-hit, .glyph *) { stroke-width: 3.5; }
#diagram svg:has(.stream-link:hover) .stream-link:not(:hover) { opacity: .2; }
/* The caret inspector: whatever the editor's caret is in stays lit and everything else fades. */
#diagram :is([data-card], [data-dest]) { transition: opacity .12s; }
#diagram svg.inspecting :is([data-card], [data-dest]):not(.lit) { opacity: .18; }
#diagram .lit-card > .card-body { stroke: var(--focus); stroke-width: 2.5; filter: drop-shadow(0 0 .5rem color-mix(in srgb, var(--focus) 40%, transparent)); }
#diagram svg.inspecting .stream-link.lit path:not(.link-hit, .glyph *) { stroke-width: 3.5; }
#diagram svg.inspecting .file-tag.lit .tag-body { stroke: var(--focus); stroke-width: 1.5; }
#diagram .lit-node > .node-body { stroke: var(--focus); stroke-width: 2; }
#diagram .lit-port .port-dot { r: 6px; stroke-width: 2.5; }
#diagram .lit-port .port-badge { stroke: var(--focus); stroke-width: 1.5; }
#diagram .lit-port .extra-fd { fill: var(--focus); }
#diagram :is([data-card], [data-command], [data-dest]) { cursor: pointer; }
.no-highlight #diagram :is([data-card], [data-command], [data-dest]) { cursor: inherit; }
/* Toolbar switches: the knob slides right and the track fills purple when on. */
.toolbar-switch .switch-track { position: relative; width: 1.875rem; height: 1.0625rem; border-radius: 1rem; background: var(--inset); box-shadow: inset 0 0 0 1px var(--border); transition: background .2s, box-shadow .2s; }
.toolbar-switch .switch-knob { position: absolute; top: .1875rem; left: .1875rem; width: .6875rem; height: .6875rem; border-radius: 50%; background: var(--muted); transition: transform .2s cubic-bezier(.3, 1.4, .5, 1), background .2s; }
.toolbar-switch[aria-checked="true"] { color: var(--purple); }
.toolbar-switch[aria-checked="true"] .switch-track { background: var(--purple); box-shadow: none; }
.toolbar-switch[aria-checked="true"] .switch-knob { transform: translateX(.8125rem); background: var(--surface); }
.toolbar-switch .switch-track::after { content: ''; position: absolute; inset: -.25rem; border-radius: 1rem; box-shadow: 0 0 0 0 var(--focus); opacity: 0; }
.toolbar-switch.just-toggled .switch-track::after { animation: switch-pulse .6s ease-out; }
/* A redrawn diagram fades in, so a switch that changes the drawing visibly takes effect. */
#diagram.redrawn svg { animation: redrawn .35s ease-out; }
@keyframes redrawn { from { opacity: .25; } to { opacity: 1; } }
/* With no variations, or no redirects to restyle, the row keeps its label and its height, but the
   empty track is hidden. The invisible character gives the track a button's line box and baseline,
   so the label lines up as it does beside buttons. */
#redirect-style.idle button { display: none; }
#variation-buttons:not(:has(button)), #redirect-style.idle { visibility: hidden; }
#variation-buttons:not(:has(button))::before, #redirect-style.idle::before { content: '\200b'; padding: .3125rem 0; font-size: .75rem; }
@keyframes switch-pulse { from { opacity: .8; box-shadow: 0 0 0 0 var(--focus); } to { opacity: 0; box-shadow: 0 0 0 .5rem var(--focus); } }
/* Feedback on the whole diagram: a purple glow when the linking comes on, a brief grey dim when it goes off. */
.diagram-panel.linking-on { animation: linking-on .7s ease-out; }
.diagram-panel.linking-off { animation: linking-off .7s ease-out; }
@keyframes linking-on { 0% { box-shadow: 0 0 0 0 var(--purple-bg); border-color: var(--purple); } 40% { box-shadow: 0 0 0 .3125rem var(--purple-bg); border-color: var(--purple); } 100% { box-shadow: 0 0 0 0 transparent; } }
@keyframes linking-off { 0% { filter: none; } 35% { filter: grayscale(1) opacity(.75); } 100% { filter: none; } }
.details-section { margin-top: 1.8125rem; }
.details-heading { display: flex; align-items: center; gap: .5625rem; width: fit-content; margin-bottom: .875rem; cursor: pointer; list-style: none; }
.details-heading::-webkit-details-marker { display: none; }
.details-heading h2 { font-size: .875rem; margin: 0; }
.details-heading:hover h2 { color: var(--purple); }
.details-heading:focus-visible { outline: 3px solid var(--focus); outline-offset: 4px; border-radius: .25rem; }
.disclosure { width: .4375rem; height: .4375rem; border-right: 1.7px solid var(--muted); border-bottom: 1.7px solid var(--muted); transform: rotate(-45deg); transition: transform .16s; }
.details-section[open] .disclosure { transform: rotate(45deg) translate(-.125rem, -.0625rem); }
.details { display: grid; grid-template-columns: repeat(auto-fit, minmax(15.625rem, 1fr)); gap: .8125rem; }
.detail-card { background: var(--surface); border: 1px solid var(--border); border-radius: .5625rem; padding: 1rem 1.0625rem; min-width: 0; }
.detail-title { display: grid; gap: .3125rem; margin-bottom: 1rem; min-width: 0; }
/* Matches the diagram's card labels; purple is reserved for stdout. */
.detail-label { font-size: .625rem; letter-spacing: .13em; color: var(--muted); }
.detail-title code { font: .8125rem 'IBM Plex Mono', monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.substitution-card { border-style: dashed; }
.detail-context { margin: -.5rem 0 .875rem; font-size: .75rem; color: var(--muted); line-height: 1.5; overflow-wrap: anywhere; }
.detail-context code { font-family: 'IBM Plex Mono', monospace; font-size: .6875rem; }
.fd-row { display: grid; grid-template-columns: 1.25rem 2.8125rem 1.0625rem minmax(0, 1fr); align-items: baseline; gap: .3125rem; margin: .75rem 0; font-size: .75rem; color: var(--muted); }
.fd-row .fd-badge { font: .6875rem 'IBM Plex Mono', monospace; padding: .125rem .25rem; border-radius: .1875rem; background: var(--inset); color: var(--muted); text-align: center; }
/* Stream colours belong to 0–2 only; other descriptors stay neutral. */
.fd-row.fd-0 .fd-badge { background: var(--green-bg); color: var(--green); }
.fd-row.fd-1 .fd-badge { background: var(--purple-bg); color: var(--purple); }
.fd-row.fd-2 .fd-badge { background: var(--amber-bg); color: var(--amber); }
.fd-row .destination { color: var(--text); overflow-wrap: anywhere; font-size: .75rem; }
.destination code { font-family: 'IBM Plex Mono', monospace; font-size: inherit; color: var(--text); background: var(--inset); padding: .125rem .25rem; border-radius: .1875rem; line-height: 1.8; box-decoration-break: clone; -webkit-box-decoration-break: clone; }
.usage-note { display: flex; align-items: center; gap: .375rem; margin-top: .25rem; color: var(--muted); font-size: .6875rem; line-height: 1.5; }
.usage-note i { width: .4375rem; height: .4375rem; flex-shrink: 0; border: 1px solid currentColor; border-radius: 50%; }
.usage-possible i { background: currentColor; }
.usage-unknown i { border-style: dashed; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.usage-key { display: flex; flex-wrap: wrap; gap: .625rem 1.25rem; margin: .75rem 0; color: var(--muted); font-size: .6875rem; }
.usage-key>span { display: flex; align-items: center; gap: .4375rem; }
.usage-key>span[hidden] { display: none; }
.usage-assumption { margin-left: auto; }
.connection-sample { width: 1.5rem; border-top: 2px solid var(--purple); }
.connection-sample.unused { border-top: 2px dashed var(--muted); }
/* Matches the diagram's tag for stderr left on the terminal. */
.ground-sample { display: inline-flex; align-items: center; font-style: normal; }
.ground-sample::before { content: ''; width: .75rem; border-top: 2px solid var(--tag); }
.ground-sample.from { flex-direction: row-reverse; --tag: var(--green); --tag-bg: var(--green-bg); }
.ground-sample { --tag: var(--amber); --tag-bg: var(--amber-bg); }
.ground-sample.out { --tag: var(--purple); --tag-bg: var(--purple-bg); }
.ground-sample.closed { --tag: var(--muted); --tag-bg: var(--inset); }
.ground-sample.closed::before { border-top-style: dashed; }
.ground-sample b { padding: .0625rem .375rem; border: 1px solid var(--tag); border-radius: 1rem; background: var(--tag-bg); color: var(--tag); font-size: .5625rem; font-weight: 500; }
/* Matches the diagram's file tag: a short arrow into a small box. */
.file-sample { display: inline-flex; align-items: center; font-style: normal; }
.file-sample::before { content: ''; width: .75rem; border-top: 2px solid var(--purple); }
.file-sample b { padding: .0625rem .375rem; border: 1px solid var(--border); border-radius: .1875rem; background: var(--inset); color: var(--text); font: 500 .5625rem 'IBM Plex Mono', monospace; }
.usage-insight { margin: .875rem 0 0; padding: .875rem max(1rem, calc(100% - 62.5rem)) .875rem 1rem; border-left: 3px solid var(--purple); background: var(--surface); color: var(--text); font-size: .8125rem; line-height: 1.7; }
.usage-insight code { font-family: 'IBM Plex Mono', monospace; font-size: .75rem; color: var(--purple); }
.reference-usage-heading { margin: 1.5rem 0 0; font-size: .875rem; }
.steps { border-top: 1px solid var(--border); margin-top: .8125rem; padding-top: .625rem; font-size: .75rem; color: var(--muted); line-height: 1.7; }
.steps summary { cursor: pointer; color: var(--purple); }
.steps ol { margin: .4375rem 0 0; padding-left: 1.125rem; }
.steps code { font-family: 'IBM Plex Mono', monospace; font-size: .6875rem; color: var(--text); }
.error { position: absolute; z-index: 1; top: 3.25rem; left: 50%; transform: translateX(-50%); width: max-content; max-width: calc(100% - 2rem); padding: .625rem .875rem; border: 1px solid var(--error); background: var(--error-bg); color: var(--error); border-radius: .5rem; font-size: .8125rem; }
.note { font-size: .75rem; color: var(--amber); background: var(--amber-bg); padding: .75rem max(1rem, calc(100% - 62.5rem)) .75rem 1rem; border-radius: .375rem; margin-top: .75rem; }
dialog { border: 1px solid var(--border); border-radius: 1rem; width: min(35rem, calc(100% - 2rem)); padding: 1.75rem; box-shadow: 0 20px 100px #00000040; color: var(--text); background: var(--surface); }
dialog::backdrop { background: #11151d99; backdrop-filter: blur(4px); }
.modal-heading { display: flex; align-items: center; justify-content: space-between; }
.modal-heading h2 { font-size: 1.375rem; }
.modal-heading button { border: 0; background: none; font-size: 1.75rem; color: var(--muted); }
dialog p { font-size: .8125rem; line-height: 1.7; color: var(--muted); }
.reference-streams { display: flex; flex-direction: column; gap: .75rem; font-size: .8125rem; margin: 1.5625rem 0; }
.reference-streams span { display: flex; gap: .625rem; align-items: center; }
.reference-streams strong { min-width: 4.6875rem; font-size: .8125rem; font-weight: 500; }
/* Each entry is a row that opens, one at a time, to explain more. The chevron and the row's hover
   show that it opens; the play button on a command draws it in the viewer. */
.ref-entries { border-top: 1px solid var(--border); padding-top: .75rem; }
.ref-entry summary { display: grid; grid-template-columns: 9.375rem minmax(0, 1fr) .5rem; gap: .875rem; align-items: baseline; margin: 0 -.5rem; padding: .5rem; border-radius: .375rem; font-size: .8125rem; line-height: 1.5; cursor: pointer; list-style: none; }
.ref-entry summary::-webkit-details-marker { display: none; }
.ref-entry summary:hover { background: var(--inset); }
.ref-entry summary::after { content: ''; width: .375rem; height: .375rem; border-right: 1.5px solid var(--muted); border-bottom: 1.5px solid var(--muted); transform: translateY(-.2em) rotate(45deg); opacity: .5; transition: transform .16s, opacity .16s; }
.ref-entry summary:hover::after, .ref-entry[open] summary::after { opacity: 1; }
.ref-entry[open] summary::after { transform: translateY(.05em) rotate(-135deg); }
.ref-syntax { font: .75rem 'IBM Plex Mono', monospace; color: var(--purple); }
.ref-entry summary code:not(.ref-syntax), .ref-more code { font: .75rem 'IBM Plex Mono', monospace; color: var(--text); }
.ref-more { margin: .25rem 0 .75rem; padding: .875rem 1rem .25rem; border-left: 3px solid var(--purple); border-radius: 0 .375rem .375rem 0; background: var(--inset); font-size: .8125rem; line-height: 1.6; color: var(--muted); animation: tour-text .25s ease-out; }
.ref-more p { margin: 0 0 .75rem; font-size: inherit; line-height: inherit; }
.ref-more h3 { margin: 1rem 0 .375rem; font-size: .875rem; color: var(--text); }
.ref-code { position: relative; margin: 0 0 .75rem; border: 1px solid var(--border); border-radius: .375rem; background: var(--surface); cursor: pointer; transition: border-color .16s; }
.ref-code pre { margin: 0; padding: .5rem 2.5rem .5rem .75rem; overflow-x: auto; font: .75rem/1.6 'IBM Plex Mono', monospace; color: var(--text); }
.ref-try { position: absolute; top: .3125rem; right: .3125rem; display: grid; place-items: center; width: 1.5rem; height: 1.5rem; padding: 0; border: 0; border-radius: .25rem; background: none; color: var(--muted); opacity: .45; transition: opacity .16s, background .16s, color .16s; }
.ref-try svg { width: .875rem; height: .875rem; fill: currentColor; }
.ref-code:hover { border-color: var(--purple); }
.ref-code:hover .ref-try, .ref-try:focus-visible { opacity: 1; color: var(--purple); background: var(--purple-bg); }
/* In training the editor belongs to the level, so commands are for reading. */
.training .ref-code { cursor: auto; }
.training .ref-code:hover { border-color: var(--border); }
.training .ref-try { display: none; }
.reference-limit { border-top: 1px solid var(--border); padding-top: 1rem; }
dialog a { font-size: .75rem; color: var(--purple); }
dialog p code { font-family: 'IBM Plex Mono', monospace; font-size: .75rem; }
/* Reads as a link inside the sentence; the chevron shows whether the list is open. */
.link-button { display: inline; padding: 0; border: 0; background: none; color: var(--purple); font: inherit; text-decoration: underline; text-underline-offset: .15em; }
.link-button::after { content: ''; display: inline-block; margin: 0 .125rem 0 .3125rem; width: .375rem; height: .375rem; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: translateY(-.15em) rotate(45deg); transition: transform .16s; }
.link-button[aria-expanded="true"]::after { transform: translateY(.05em) rotate(-135deg); }
.known-commands { columns: 6rem; column-gap: 1rem; margin: -.25rem 0 1rem; padding: .875rem 1rem; list-style: none; background: var(--inset); border-radius: .5rem; font: .75rem/1.75 'IBM Plex Mono', monospace; color: var(--text); }
.known-commands li { break-inside: avoid; }
.known-commands code { font: inherit; }
/* Narrow enough on short windows that the whole 16:9 frame, plus the chapter column, fits without scrolling. */
.talk-dialog { --chapters: 14rem; width: min(78rem, calc(100% - 2rem), calc((100vh - 11rem) * 16 / 9 + var(--chapters) + 4.25rem)); padding: 1.25rem 1.5rem 1.5rem; }
.talk-dialog h2 { margin: 0; }
.talk-info { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 1rem; margin-top: 1rem; }
.talk-dialog .talk-file { display: flex; flex-wrap: wrap; gap: .25rem .5rem; margin: 0; font: .6875rem/1.5 'IBM Plex Mono', monospace; }
.talk-speed button { font-variant-numeric: tabular-nums; }
.talk-file code { font: inherit; overflow-wrap: anywhere; }
.talk-body { display: grid; grid-template-columns: minmax(0, 1fr) var(--chapters); gap: 1.25rem; margin-top: .5rem; }
.talk-frame { aspect-ratio: 16 / 9; border-radius: .625rem; overflow: hidden; background: #000; }
.talk-frame video { display: block; width: 100%; height: 100%; }
/* The list scrolls inside the video's height rather than stretching the row. */
.talk-chapters { position: relative; min-height: 12rem; }
.talk-chapters ol { position: absolute; inset: 1.375rem 0 0; overflow-y: auto; margin: 0; padding: 0 .25rem 0 0; list-style: none; }
.talk-chapters .row-label { display: block; }
.talk-chapters button { display: flex; gap: .75rem; width: 100%; padding: .4375rem .5625rem; border: 0; border-radius: .375rem; background: none; color: var(--muted); font-size: .8125rem; text-align: left; }
.talk-chapters button:hover { background: var(--inset); color: var(--text); }
.talk-chapters button.active { background: var(--purple-bg); color: var(--purple); font-weight: 550; }
.chapter-time { min-width: 2.5rem; font: .75rem/1.6 'IBM Plex Mono', monospace; }
.talk-frame p { margin: 0; padding: 1.5rem; color: #fff; }
/* Training. The header button is green, stdin's colour, as the place to start. */
.training-button { display: flex; align-items: center; gap: .4375rem; min-height: 2.5rem; padding: .5rem .875rem .5rem .6875rem; border: 1px solid var(--green-bg); border-radius: .4375rem; background: var(--green-bg); color: var(--green); font-size: .75rem; font-weight: 600; }
.training-button:hover, .training-button[aria-pressed="true"] { border-color: var(--green); }
.training-button svg { width: 1rem; height: 1rem; fill: none; stroke: currentColor; stroke-width: 1.8; }
.training-only { display: none; }
.training .training-only { display: inline-flex; }
.training #redirect-count, .training #command-count { display: none; }
/* Training crops its drawings to fit, so zoom and export stand down and the two toolbars stay one line high. */
.training .zoom-controls, .training #download, .training .toolbar-switch { display: none; }
/* Training keeps to the two pictures: the key, insights and details belong to the viewer. */
.training :is(.usage-key, #insights, #notes, #details-section) { display: none; }
.training #diagram :is([data-card], [data-command], [data-dest]) { cursor: inherit; }
.training-bar { margin-bottom: 1rem; }
.training-top { display: flex; flex-wrap: wrap; align-items: center; gap: .625rem 1.125rem; }
.level-buttons button { display: inline-flex; flex-direction: column; align-items: center; gap: .125rem; padding: .25rem .5rem; font-variant-numeric: tabular-nums; line-height: 1; }
.level-number { font-weight: 600; }
/* DM Sans draws 0 like O, so a word with zeros in it, as n00b has, is set in Plex Mono. */
.level-label { font: 600 .75rem 'IBM Plex Mono', monospace; }
/* Until it's solved, level 0 takes stdin's green, as the Training button does: the place to start. When the
   student looks stuck it pulses a few times, then keeps a green outline. */
.level-buttons button.fresh:not(.active) { background: var(--green-bg); color: var(--green); }
.level-buttons button.nudge { box-shadow: 0 0 0 1px var(--green); }
.level-buttons button.nudge.pulse { animation: n00b-nudge 1.6s ease-out .15s 3; }
@keyframes n00b-nudge { 0% { box-shadow: 0 0 0 1px var(--green), 0 0 0 0 color-mix(in srgb, var(--green) 60%, transparent); } 100% { box-shadow: 0 0 0 1px var(--green), 0 0 0 .625rem transparent; } }
.lesson-label { font-family: 'IBM Plex Mono', monospace; letter-spacing: -.02em; }
.level-stars { display: inline-flex; gap: .0625rem; }
.level-stars .star { width: .5rem; height: .5rem; }
.level-stars.unearned { opacity: .55; }
.star { width: 1rem; height: 1rem; fill: none; stroke: var(--muted); stroke-width: 1.6; stroke-linejoin: round; flex-shrink: 0; }
.star.filled { fill: var(--amber); stroke: var(--amber); }
.star-total { display: inline-flex; align-items: center; gap: .3125rem; font: 600 .8125rem 'IBM Plex Mono', monospace; font-variant-numeric: tabular-nums; }
.star-of { color: var(--muted); font-weight: 400; }
#tour-button { margin-left: auto; padding: .25rem 0; }
#exit-training { padding: .25rem 0; }
.lesson { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: .75rem 2rem; margin-top: 1.125rem; }
.lesson-text { flex: 1 1 26rem; min-width: 0; }
.lesson h2 { font-size: 1.375rem; letter-spacing: -.03em; display: flex; align-items: baseline; gap: .625rem; }
.lesson-number { font: 600 .6875rem 'IBM Plex Mono', monospace; letter-spacing: .06em; text-transform: uppercase; color: var(--green); background: var(--green-bg); padding: .1875rem .4375rem; border-radius: .25rem; transform: translateY(-.15em); }
.lesson p { margin: .4375rem 0 0; font-size: .875rem; line-height: 1.6; color: var(--muted); max-width: 44rem; }
.lesson code, .coach code { font: .8125em 'IBM Plex Mono', monospace; color: var(--text); background: var(--inset); padding: .0625rem .3125rem; border-radius: .1875rem; }
.hint-buttons { display: flex; flex-wrap: wrap; align-items: center; gap: .375rem; }
.worth { display: inline-flex; align-items: center; gap: .0625rem; margin-right: .375rem; }
.worth-label { font-size: .6875rem; color: var(--muted); margin-right: .3125rem; }
.worth .star { width: .9375rem; height: .9375rem; transition: fill .3s, stroke .3s; }
.hint-buttons button { border: 1px solid var(--border); background: var(--surface); color: var(--muted); border-radius: .375rem; padding: .375rem .6875rem; font-size: .75rem; }
.hint-buttons button:hover:not(:disabled) { color: var(--text); border-color: var(--muted); }
.hint-buttons button.active { color: var(--purple); border-color: var(--purple); background: var(--purple-bg); }
.hint-buttons button:disabled { opacity: .45; cursor: default; }
.hint-buttons .restart { display: grid; place-items: center; width: 2rem; height: 2rem; padding: 0; }
.restart svg { width: 1rem; height: 1rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.coach:empty { display: none; }
.coach { margin-top: .875rem; }
.hints { display: grid; gap: .5rem; }
.hint { padding: .75rem 1rem; border-left: 3px solid var(--purple); background: var(--surface); font-size: .8125rem; line-height: 1.6; }
.hint p { margin: .25rem 0 0; }
.hint .row-label { display: block; }
.answer { font-size: .875rem !important; color: var(--purple) !important; }
.answer-note { color: var(--muted); font-size: .75rem; margin-left: .375rem; }
.diff-list { list-style: none; margin: .375rem 0 0; padding: 0; display: grid; gap: .375rem; }
.diff-list { grid-template-columns: auto auto auto auto; justify-content: start; column-gap: 1.25rem; }
.diff-list li { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; align-items: baseline; }
.diff-list li.diff-shape { display: block; }
.diff-list .fd-badge { font: .6875rem 'IBM Plex Mono', monospace; padding: .0625rem .3125rem; border-radius: .1875rem; background: var(--inset); color: var(--muted); text-align: center; min-width: 1.25rem; }
.diff-list .fd-0 .fd-badge { background: var(--green-bg); color: var(--green); }
.diff-list .fd-1 .fd-badge { background: var(--purple-bg); color: var(--purple); }
.diff-list .fd-2 .fd-badge { background: var(--amber-bg); color: var(--amber); }
.diff-list strong { font-weight: 550; overflow-wrap: anywhere; }
/* The result of a solved level: the stars, what it showed, and the way on. */
.solved { display: flex; gap: 1.5rem; align-items: flex-start; padding: 1rem 1.25rem; border: 1px solid var(--green); border-radius: .6875rem; background: var(--green-bg); animation: solved-in .35s cubic-bezier(.3, 1.3, .5, 1); }
.solved-stars { position: relative; display: flex; gap: .25rem; padding-top: .25rem; }
.solved-stars .star { width: 1.75rem; height: 1.75rem; animation: star-pop .5s cubic-bezier(.3, 1.6, .5, 1) both; }
.solved-stars .star:nth-child(2) { animation-delay: .12s; }
.solved-stars .star:nth-child(3) { animation-delay: .24s; }
.solved-stars .star:not(.filled) { stroke: color-mix(in srgb, var(--green) 45%, transparent); }
.spark { position: absolute; left: 50%; top: 50%; font: 600 .75rem 'IBM Plex Mono', monospace; opacity: 0; pointer-events: none; animation: spark .9s ease-out var(--delay) both; }
.spark.fd-0 { color: var(--green); }
.spark.fd-1 { color: var(--purple); }
.spark.fd-2 { color: var(--amber); }
.solved-body { flex: 1; min-width: 0; font-size: .8125rem; line-height: 1.6; }
.solved-body p { margin: 0 0 .375rem; }
.solved-title { font-size: 1rem; }
.solved-title strong { color: var(--green); }
.solved-spelling { color: var(--muted); }
.solved-spelling:empty { display: none; }
.solved-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; margin-top: .75rem; }
.next-button { border: 0; border-radius: .4375rem; padding: .5625rem 1rem; background: var(--green); color: var(--surface); font-size: .8125rem; font-weight: 600; }
.next-button:hover { filter: brightness(1.1); }
.key-hint { color: var(--muted); font-size: .75rem; }
kbd { font: .6875rem 'IBM Plex Mono', monospace; padding: .0625rem .3125rem; border: 1px solid var(--border); border-bottom-width: 2px; border-radius: .25rem; background: var(--surface); }
.solved-finale { font-size: .875rem; }
@keyframes solved-in { from { opacity: 0; transform: translateY(-.375rem); } }
@keyframes star-pop { 0% { transform: scale(0) rotate(-40deg); } 100% { transform: none; } }
@keyframes spark { 0% { opacity: 1; transform: translate(-50%, -50%) scale(.6); } 70% { opacity: 1; } 100% { opacity: 0; transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(1); } }
/* The n00b explainer stands in for the exercise, one idea at a time, until the student moves on. */
.explaining :is(#lesson-brief, #hint-buttons, #coach, #tour-button, .editor-panel, #results, #target-panel) { display: none !important; }
.intro { margin-top: 1rem; padding: 1.25rem 1.5rem 1rem; border: 1px solid var(--border); border-radius: .75rem; background: var(--surface); }
.intro-slide { display: grid; grid-template-columns: minmax(0, 23rem) minmax(0, 1fr); gap: 1.25rem 2rem; align-items: center; animation: tour-text .35s ease-out; }
.intro-text h3 { margin: 0 0 .5rem; font-size: 1.125rem; letter-spacing: -.02em; }
.intro-text p { margin: 0; font-size: .875rem; line-height: 1.6; color: var(--muted); }
.intro code { font: .8125em 'IBM Plex Mono', monospace; color: var(--text); background: var(--inset); padding: .0625rem .3125rem; border-radius: .1875rem; }
.stream-word { font-weight: 600; }
.stream-word.fd-0 { color: var(--green); }
.stream-word.fd-1 { color: var(--purple); }
.stream-word.fd-2 { color: var(--amber); }
.intro blockquote { margin: .875rem 0 0; padding: .5rem .875rem; border-left: 3px solid var(--purple); background: var(--inset); border-radius: 0 .375rem .375rem 0; }
.intro blockquote p { color: var(--text); font-style: italic; }
.intro blockquote footer { margin-top: .25rem; font-size: .75rem; color: var(--muted); }
.intro blockquote footer::before { content: '— '; }
.intro-example { margin-top: .875rem; }
.intro-example > code { font-size: .875rem; color: var(--purple); padding: .1875rem .5rem; }
.intro-example p { margin-top: .4375rem; font-size: .8125rem; }
.intro-figure { min-width: 0; }
.intro-picture { display: block; width: 100%; height: auto; max-height: 15rem; font-family: 'IBM Plex Mono', monospace; }
.intro-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-top: 1rem; }
.intro-dots { display: flex; gap: .3125rem; }
.intro-dots i { width: .4375rem; height: .4375rem; border-radius: .25rem; background: var(--border); transition: width .25s, background .25s; }
.intro-dots i.on { width: 1.125rem; background: var(--green); }
.intro-count { margin-right: auto; font: 600 .625rem 'IBM Plex Mono', monospace; letter-spacing: .08em; color: var(--muted); }
#intro-skip { padding: .25rem 0; margin-right: .5rem; }
.intro-picture .fd0 { --c: var(--green); }
.intro-picture .fd1 { --c: var(--purple); }
.intro-picture .fd2 { --c: var(--amber); }
.pic-card rect { fill: var(--surface); stroke: var(--border); stroke-width: 1.2; }
.pic-card line { stroke: var(--border); }
.pic-name { font-size: 13px; font-weight: 500; fill: var(--text); }
.pic-port { fill: var(--c); }
.pic-fd { font-size: 11px; font-weight: 600; fill: var(--c); }
.pic-wire { stroke: var(--c); stroke-width: 2; }
.pic-wire.idle { stroke-dasharray: 4 4; opacity: .6; }
.pic-token { opacity: 0; }
.pic-token rect { fill: var(--c); }
.pic-token text { font-size: 11px; font-weight: 600; fill: var(--surface); }
.pic-device rect, .pic-device > line { fill: var(--inset); stroke: var(--border); stroke-width: 1.2; }
.pic-device .pic-key { fill: var(--border); stroke: none; }
.pic-label { font: 500 10px var(--sans); fill: var(--muted); }
.pic-out { font-size: 11px; fill: var(--c); }
.pic-tag rect { fill: var(--surface); stroke: var(--c); stroke-width: 1.2; }
.pic-tag text { font: 500 9.5px var(--sans); fill: var(--c); }
.pic-number circle { fill: var(--surface); stroke: var(--c); stroke-width: 2; }
.pic-number text { font-size: 13px; font-weight: 600; fill: var(--c); }
/* The film waits as a tape, black in every theme, in place of the picture. */
.intro-video { display: grid; place-items: center; }
.tape { width: min(17rem, 100%); padding: 0; border: 0; background: none; border-radius: .5rem; transition: transform .2s; }
.tape svg { display: block; width: 100%; height: auto; }
.tape:hover { transform: rotate(-2deg) scale(1.04); }
.tape-body { fill: #1c1d21; }
.tape-label { fill: #efe6cf; }
.tape-title { font: 700 17px 'IBM Plex Mono', monospace; fill: #2b2a28; letter-spacing: .04em; }
.tape-by { font: 500 12px 'IBM Plex Mono', monospace; fill: #6b5f4a; letter-spacing: .08em; }
.tape-window { fill: #33353b; }
.tape-reel { fill: #0f1012; transform-box: fill-box; transform-origin: center; }
.tape-reel rect { fill: #4a4d55; }
.tape-hub { fill: #8a8d96; }
.tape-play circle { fill: var(--green); opacity: .9; transition: transform .2s; transform-box: fill-box; transform-origin: center; }
.tape-play path { fill: #fff; }
.tape:hover .tape-reel { animation: reel 1.6s linear infinite; }
.tape:hover .tape-play circle { transform: scale(1.12); }
@keyframes reel { to { transform: rotate(360deg); } }
/* Played, the film takes the whole slide, under the text. */
.intro-slide:has(.tape-player) { grid-template-columns: minmax(0, 1fr); }
/* The film is as wide as the slide, but never so tall that the slide's buttons leave the window. */
.intro-video:has(.tape-player) { display: block; width: min(100%, calc(52vh * 16 / 9)); justify-self: center; }
.tape-player { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: .5rem; background: #000; }
/* Its chapters, to scale: the one worth waiting for in stdout's purple, and a playhead moving along. */
.chapters { position: relative; display: flex; gap: 2px; width: 100%; margin-top: .5rem; }
.chapter { flex-basis: 0; min-width: 0; padding-top: .5rem; border-top: 4px solid var(--border); font: 500 .6875rem 'IBM Plex Mono', monospace; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chapter.goal { border-top-color: var(--purple); color: var(--purple); font-weight: 600; }
.chapter.goal.now { animation: chapter-now 1.6s ease-in-out infinite alternate; }
@keyframes chapter-now { to { border-top-color: var(--green); color: var(--green); } }
.playhead { position: absolute; top: -3px; left: 0; width: 10px; height: 10px; margin-left: -5px; border-radius: 50%; background: var(--text); box-shadow: 0 0 0 2px var(--surface); opacity: 0; transition: left .25s linear, opacity .3s; }
.playhead.live { opacity: 1; }
/* The text stays at the top, so it doesn't move when the tape opens into the player. */
.intro-slide:has(.intro-video) { align-items: start; }
@media (prefers-reduced-motion: reduce) { .intro-picture * { animation: none !important; } }
@media (max-width: 47.5em) {
  .intro { padding: 1rem; }
  .intro-slide { grid-template-columns: minmax(0, 1fr); }
  .intro-figure { margin: 0 -.75rem; }
  .intro-count { display: none; }
  .intro-dots { margin-right: auto; }
  #intro-skip { order: 1; width: 100%; margin: 0; }
}
/* The two drawings: the target above the editor, or beside the student's on wide screens. */
.target-panel { position: relative; border: 1px dashed var(--border); border-radius: .6875rem; background: var(--surface); overflow: hidden; margin-bottom: .875rem; }
.target-scroll { overflow-x: auto; }
#target-diagram { min-width: 45rem; line-height: 0; }
#target-diagram svg { width: 100%; height: auto; display: block; }
#target-diagram.redrawn svg { animation: redrawn .35s ease-out; }
.panel-name { font: 600 .625rem var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.diagram-summary h2.panel-name { font-size: .625rem; color: var(--muted); }
.panel-hint { font-family: var(--sans); }
.panel-hint code { font: 500 .75rem 'IBM Plex Mono', monospace; color: var(--green); background: var(--green-bg); padding: .125rem .4375rem; border-radius: .25rem; white-space: pre-wrap; }
.match-status { align-items: center; font: 500 .75rem var(--sans); padding: .1875rem .5rem; border-radius: 1rem; background: var(--inset); color: var(--muted); }
.match-status.differs { background: var(--error-bg); color: var(--error); }
.match-status.matched { background: var(--green-bg); color: var(--green); font-weight: 600; }
.diagram-panel.matched-glow { animation: matched-glow 1.2s ease-out; }
@keyframes matched-glow { 0%, 40% { border-color: var(--green); box-shadow: 0 0 0 .3125rem var(--green-bg); } 100% { box-shadow: 0 0 0 0 transparent; } }
/* Each difference is ringed at its port, in both drawings, and a card whose words differ is outlined. */
.diff-ring { stroke: var(--error); stroke-width: 1.6; stroke-dasharray: 3 2.5; pointer-events: none; transform-box: fill-box; transform-origin: center; animation: diff-ring 1.6s ease-in-out infinite; }
.diff-card > .card-body { stroke: var(--error); stroke-width: 1.6; stroke-dasharray: 6 4; }
@keyframes diff-ring { 50% { transform: scale(1.25); opacity: .55; } }
/* Matching drawings run their streams, as data would flow through the finished plumbing. */
svg.flowing .stream-link:not(.unused-link) path:not(.link-hit, .glyph *) { stroke-dasharray: 7 5; animation: flow .8s linear infinite; }
@keyframes flow { to { stroke-dashoffset: -12; } }
@media (min-width: 64em) {
  .training main { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 1.25rem; }
  .training main > *, .training #results > * { grid-column: 1 / -1; order: 5; }
  .training #results { display: contents; }
  .training #training { order: 1; }
  .training .editor-panel { order: 2; margin-bottom: .875rem; }
  /* The student's picture sits on the left, right under the command they are typing. */
  .training #results > .diagram-panel { grid-column: auto; order: 3; }
  .training #target-panel { grid-column: auto; order: 4; margin-bottom: 0; }
}
@media (max-width: 47.5em) {
  /* On a phone both drawings shrink to the screen's width, so they can be compared without scrolling. */
  .training #diagram, .training #target-diagram { min-width: 0 !important; }
  .training #diagram-scroll::after { content: none; }
  .lesson h2 { font-size: 1.125rem; }
  .diff-list { grid-template-columns: auto minmax(0, 1fr); }
  .diff-list li > :nth-child(n+3) { grid-column: 2; }
  .solved { flex-direction: column; gap: .5rem; }
  .panel-hint { display: none; }
}
/* The tour dims the page but for a spotlight on one part, with a card beside it. The spotlight's
   shadow does the dimming, so the spot glides from part to part. The layer takes clicks so the
   dimmed page cannot be used until the tour ends. */
.tour { position: fixed; inset: 0; z-index: 10; opacity: 0; transition: opacity .3s; }
.tour.open { opacity: 1; }
.tour-spot { position: fixed; border-radius: .875rem; pointer-events: none; box-shadow: 0 0 0 2px var(--green), 0 0 0 200vmax rgb(6 9 14 / .66);
  transition: left .45s cubic-bezier(.3, 1, .4, 1), top .45s cubic-bezier(.3, 1, .4, 1), width .45s cubic-bezier(.3, 1, .4, 1), height .45s cubic-bezier(.3, 1, .4, 1); }
.tour-spot::after { content: ''; position: absolute; inset: -2px; border-radius: inherit; animation: tour-pulse 1.8s ease-out infinite; }
@keyframes tour-pulse { from { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 60%, transparent); } to { box-shadow: 0 0 0 .75rem transparent; } }
.tour-card { position: fixed; width: min(23rem, calc(100vw - 1rem)); padding: 1.125rem 1.25rem 1rem; border: 1px solid var(--border); border-radius: .75rem; background: var(--surface); color: var(--text); box-shadow: 0 1rem 3rem rgb(0 0 0 / .35);
  transition: left .45s cubic-bezier(.3, 1, .4, 1), top .45s cubic-bezier(.3, 1, .4, 1); }
.tour-card.arrived > :not(.tour-actions) { animation: tour-text .35s ease-out; }
@keyframes tour-text { from { opacity: 0; transform: translateY(.25rem); } }
.tour-count { font: 600 .625rem 'IBM Plex Mono', monospace; letter-spacing: .08em; color: var(--green); }
.tour-card h2 { margin: .25rem 0 .375rem; font-size: 1.125rem; }
.tour-card p { margin: 0; font-size: .875rem; line-height: 1.6; color: var(--muted); }
.tour-link { padding: 0; border: 0; background: none; color: var(--green); font-weight: 600; text-decoration: underline; text-underline-offset: .15em; }
.tour-link:hover { text-decoration-thickness: 2px; }
.tour-card code { font: .8125em 'IBM Plex Mono', monospace; color: var(--text); background: var(--inset); padding: .0625rem .3125rem; border-radius: .1875rem; }
.tour-actions { display: flex; align-items: center; gap: .5rem; margin-top: 1rem; }
.tour-actions .text-button { margin-right: auto; padding: .25rem 0; }
.tour-back { border: 1px solid var(--border); border-radius: .4375rem; padding: .5rem .875rem; background: var(--surface); color: var(--text); font-size: .8125rem; }
.tour-back:hover { background: var(--inset); }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .35s; }
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; } }
[hidden] { display: none !important; }
/* Pipelines read left to right, so wide windows give the page their width instead of margins. */
@media (min-width: 90.625em) { :root { --content: calc(100vw - 12rem); } main { padding: 2rem 0 2.5rem; } }
/* Mid-width windows keep every header control on one line by showing icons for all but Training. */
@media (max-width: 64em) {
  .header-actions { gap: .875rem; }
  #theme-label, .shell-label, .talk-label { display: none; }
  .theme-toggle { width: 2.5rem; padding: .5rem; }
  .talk-button { width: 2.5rem; justify-content: center; padding: 0; }
  .shell-switch button { padding: 0 .5rem; }
}
.text-button { white-space: nowrap; }
@media (max-width: 60em) {
  .talk-dialog { width: min(48rem, calc(100% - 2rem)); }
  .talk-body { grid-template-columns: minmax(0, 1fr); }
  .talk-chapters { min-height: 0; }
  .talk-chapters ol { position: relative; inset: auto; max-height: 13rem; margin-top: .5rem; display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 0 .5rem; }
}
@media (max-width: 47.5em) {
  .site-header { height: 4.375rem; padding: 0 1.25rem; }
  .brand { font-size: 1.3125rem; }
  .header-actions { gap: .875rem; }
  .theme-toggle { width: 2.5rem; padding: .5rem; }
  main { padding: 1.5rem 1.375rem 2rem; }
  .code-editor { padding: .75rem 2.75rem .75rem 1.0625rem; gap: .625rem; }
  textarea, .editor-mirror { font-size: .8125rem; }
  /* Stack each label above its buttons. */
  .example-rows { grid-template-columns: minmax(0, 1fr); gap: .5rem; }
  .example-row + .example-row .row-label { margin-top: .875rem; }
  .text-button { font-size: .75rem; }
  .talk-dialog { padding: 1rem 1rem 1.125rem; }
  .talk-dialog .talk-file { flex-direction: column; }
  .talk-separator { display: none; }
  .ref-entry summary { grid-template-columns: 7.5rem minmax(0, 1fr) .5rem; gap: .625rem; }
  #diagram svg { min-height: 17.5rem; }
  .diagram-toolbar { gap: .625rem; }
  /* The actions wrap rather than run past the panel's edge. */
  .diagram-actions { flex-wrap: wrap; gap: .5rem; }
  #download .download-label { display: none; }
  .details { grid-template-columns: 1fr; }
  .usage-assumption { margin-left: 0; flex-basis: 100%; }
  #diagram-scroll::after { content: 'Scroll horizontally →'; position: sticky; left: 0; display: block; width: 100%; text-align: center; font-size: .6875rem; color: var(--muted); padding: .375rem 0 .75rem; }
}
/* On narrow windows the controls move to a row of their own under the name. */
@media (max-width: 40em) {
  .site-header { height: auto; flex-wrap: wrap; gap: .625rem; padding: .875rem 1.25rem; }
  /* Controls keep their size; on the narrowest screens the last one wraps instead. */
  .header-actions { width: 100%; max-width: 26rem; flex-wrap: wrap; justify-content: space-between; }
  .header-actions > * { flex-shrink: 0; }
}
/* Phones: the header keeps every control on one line by shortening the reference label and showing Training's icon alone. */
@media (max-width: 26.25em) {
  .header-actions { gap: .625rem; }
  .reference-quick { display: none; }
  .training-button { width: 2.5rem; justify-content: center; padding: 0; }
  .training-label { display: none; }
}
@media (max-width: 22.5em) {
  .site-header { padding: .75rem; }
  .brand { font-size: 1.1875rem; }
  .brand-icon { margin-right: .375rem; }
  .header-actions { gap: .25rem; }
  .talk-button { width: 2.25rem; min-height: 2.25rem; }
}
/* Touch screens get controls a fingertip can hit: at least 44px (2.75rem) each way. */
@media (pointer: coarse) {
  .training-button, .talk-button, .theme-toggle, .shell-switch, .text-button, .variation-buttons button, .zoom-controls button, .toolbar-switch, #download, .details-heading { min-height: 2.75rem; }
  .training-button, .talk-button, .theme-toggle, .zoom-controls button, #download { min-width: 2.75rem; }
  .brand { min-height: 2.75rem; }
  .shell-switch button { min-width: 2.25rem; }
  /* The shell switch keeps its inset look; each half's hit area reaches the switch's outer edge. */
  .shell-switch button::after { content: ''; position: absolute; inset: -.25rem -.0625rem; }
  .diagram-toolbar button, .details-heading { justify-content: center; }
}
@media (prefers-reduced-motion: reduce) { *, .shell-switch::before { transition: none !important; animation: none !important; } }
