/* ============================================================================
   jeremyvun.com — one stylesheet.
   The whole site is a terminal. Flat, calm, retro: zenwritten-dark tones on a
   near-black warm ground, a warm-paper light theme, no glow, no scanlines.
   The terminal is a single floating pane — a hairline rounded frame inset from
   the viewport, holding top-anchored monospace output, a crisp block cursor and
   dashed rules — with a full-bleed vim/tmux status line pinned below it.
   OS preference decides the theme until the visitor chooses (cookie-driven,
   server-side; see the dual light-theme mechanism below).
   ============================================================================ */

/* ---- fonts ---- */
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/jetbrains-mono-400.woff2) format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../fonts/jetbrains-mono-500.woff2) format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/jetbrains-mono-700.woff2) format("woff2");
}

/* ---- design tokens (zenwritten dark) ---- */
:root {
  --bg: #191919;
  --bg-sunken: #141414;
  --bg-raised: #232323;
  --border: #333333;
  --border-soft: #262626;
  --fg: #bbbbbb;
  --fg-dim: #9a9a9a;
  --muted: #6f6f6f;
  --faint: #454545;
  --accent: #819b69;      /* leaf green — prompt user, primary */
  --link: #64a0c8;        /* steel blue — host, links, directories */
  --link-hover: #82b8dc;
  --danger: #de6e7c;
  --selection: #2b3440;

  --t-comment: #6b6b6b;
  --t-key: #bb7777;
  --t-type: #64a0c8;
  --t-fn: #c0b078;
  --t-str: #819b69;
  --t-num: #b279a7;
  --t-op: #8f8f8f;
  --t-builtin: #c99a6a;
  --t-name: #a6a6a6;
  --t-attr: #c0b078;

  --font: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --measure: 70ch;

  /* Floating pane: centered, capped width, inset from the viewport edges.
     --pane-gap is the breathing room between the pane and the status line. */
  --pane-max: 72rem;
  --pane-inset-x: clamp(1rem, 5vw, 4rem);
  --pane-inset-y: clamp(1rem, 4vh, 2.75rem);
  --pane-gap: clamp(0.75rem, 2.4vh, 1.6rem);
}

/* Light (warm paper). Two mechanisms, both required:
   1) OS preference wins only while no cookie has set data-theme;
   2) an explicit data-theme="light" wins over everything. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --bg: #f4efe1;
    --bg-sunken: #ebe4d1;
    --bg-raised: #eae2cd;
    --border: #d8cfb4;
    --border-soft: #e2d9bf;
    --fg: #3a3a42;
    --fg-dim: #54545e;
    --muted: #77746a;
    --faint: #b3ab8f;
    --accent: #5c7340;
    --link: #3f6ea3;
    --link-hover: #2c5688;
    --danger: #b5424f;
    --selection: #ddd4b8;

    --t-comment: #8a8980;
    --t-key: #a0505a;
    --t-type: #3f6ea3;
    --t-fn: #8a7333;
    --t-str: #5c7340;
    --t-num: #97527f;
    --t-op: #5c6068;
    --t-builtin: #a06a2e;
    --t-name: #43434c;
    --t-attr: #7a6a2f;
  }
}
:root[data-theme="light"] {
  --bg: #f4efe1;
  --bg-sunken: #ebe4d1;
  --bg-raised: #eae2cd;
  --border: #d8cfb4;
  --border-soft: #e2d9bf;
  --fg: #3a3a42;
  --fg-dim: #54545e;
  --muted: #77746a;
  --faint: #b3ab8f;
  --accent: #5c7340;
  --link: #3f6ea3;
  --link-hover: #2c5688;
  --danger: #b5424f;
  --selection: #ddd4b8;

  --t-comment: #8a8980;
  --t-key: #a0505a;
  --t-type: #3f6ea3;
  --t-fn: #8a7333;
  --t-str: #5c7340;
  --t-num: #97527f;
  --t-op: #5c6068;
  --t-builtin: #a06a2e;
  --t-name: #43434c;
  --t-attr: #7a6a2f;
}

/* ---- reset / base ---- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scrollbar-color: var(--border) transparent; }
body {
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.55;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100dvh;
}
@media (max-width: 480px) {
  body { font-size: 14px; }
}
::selection { background: var(--selection); color: var(--fg); }
a { color: var(--link); text-decoration: none; }
a:hover { color: var(--link-hover); text-decoration: underline; text-underline-offset: 3px; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
img { max-width: 100%; height: auto; }

/* ---- utilities ---- */
.muted { color: var(--muted); }
.k { color: var(--muted); }
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 10;
  background: var(--accent); color: var(--bg); padding: 0.5rem 0.9rem;
}
.skip-link:focus { left: 0; }

/* ============================================================================
   TERMINAL SHELL — a floating pane. The terminal is a centered, max-width card
   (hairline border, small radius) inset from the viewport; a full-bleed status
   line is pinned below it. A flex column keeps the pane filling the space above
   the status line, with output top-anchored inside it (the prompt follows the
   last output like a real shell — see .term-scroll flex below).
   ============================================================================ */
.terminal {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100dvh;
  background: var(--bg);
}

.term-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  width: min(calc(100% - 2 * var(--pane-inset-x)), var(--pane-max));
  margin: var(--pane-inset-y) auto var(--pane-gap);
  padding: clamp(1rem, 1.6vw, 1.5rem) clamp(1.1rem, 1.8vw, 1.65rem) clamp(0.85rem, 1.4vw, 1.2rem);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.term-scroll {
  position: relative;
  /* Top-anchored: size to content up to the available height, then scroll —
     so the prompt sits right under the output instead of pinned to the bottom. */
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Clip the x-axis: the scrollback never scrolls sideways. Text wraps, and the
     one intentionally-wide thing (code blocks) scrolls inside its own
     overflow-x:auto box. Without this, the row hover's decorative -0.6rem bleed
     (see .term-row) pokes ~2px past the right padding and raises a horizontal
     scrollbar on narrow screens. */
  overflow-x: hidden;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
  padding-right: 0.5rem;
  scrollbar-width: thin;
}
.term-scroll::-webkit-scrollbar { width: 8px; }
.term-scroll::-webkit-scrollbar-thumb { background: var(--border); }
.term-scroll::-webkit-scrollbar-track { background: transparent; }

/* On small screens the pane hugs the edges — margins would waste scarce width. */
@media (max-width: 560px) {
  :root {
    --pane-inset-x: 0.55rem;
    --pane-inset-y: 0.55rem;
    --pane-gap: 0.55rem;
  }
  .term-body { border-radius: 5px; }
}

/* ---- output rhythm: a command line, then its output block ---- */
.term-block { margin: 0 0 1rem; }
.term-block:last-child { margin-bottom: 0.25rem; }
.term-line--cmd { margin: 1rem 0 0.4rem; word-break: break-word; }
/* .term-scroll is a BFC (overflow-y: auto), so the first child's top margin
   doesn't collapse — it renders as a gap. After `clear`/Ctrl+L empties the
   scrollback, the next command's echo line becomes that first child and its
   1rem top margin would shove everything down. Keep the top flush so the
   echoed line lands exactly where the (flush) prompt was — pairs with the
   #scrollback:empty rule on .term-input below. */
.term-scroll > :first-child { margin-top: 0; }
.term-echo-prompt { user-select: none; }
.term-echo { color: var(--fg); font-weight: 500; }
.term-text { white-space: pre-wrap; word-break: break-word; max-width: var(--measure); }
.term-text--muted, .term-muted { color: var(--muted); }
.term-text--error, .term-error { color: var(--danger); }
.term-error__cmd { color: var(--fg-dim); }
.term-muted a { color: var(--link); }
.term-muted code, .term-text code { color: var(--accent); }

/* ---- prompt — oh-my-zsh-ish: visitor@jeremyvun.com:~/blog$
   The classes are shared by the live prompt and the echoed history lines
   (terminal.js clones the prompt markup), so color by span, not container. */
.term-prompt { flex: none; user-select: none; white-space: nowrap; }
.term-prompt__user { color: var(--accent); font-weight: 500; }
.term-prompt__at { color: var(--muted); }
.term-prompt__host { color: var(--link); }
.term-prompt__sep { color: var(--muted); }
.term-prompt__cwd { color: var(--fg); font-weight: 500; }
.term-prompt__sign { color: var(--muted); }

/* ---- input row ---- */
.term-input {
  display: none;
  align-items: center;
  gap: 1ch;
  padding-top: 0.6rem;
  flex: none;
}
.terminal--ready .term-input { display: flex; }
/* padding-top above separates the prompt from output. After `clear`/Ctrl+L the
   scrollback is empty, so there's nothing to separate from — drop it, and the
   prompt sits flush at the pane top, exactly where the first echoed command
   line lands (see .term-scroll > :first-child). Otherwise the typed text jumps
   the moment you hit Enter. */
#scrollback:empty + .term-input { padding-top: 0; }
.term-input__field { position: relative; display: flex; align-items: center; flex: 1; min-width: 0; }
.term-cmd {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  outline: none;
  color: var(--fg);
  font: inherit;
  caret-color: var(--accent);
  padding: 0;
}
.term-input__field.is-busy { opacity: 0.55; }

/* Idle block cursor: sits at the start of the input (right after the prompt)
   when the line is empty and focused; the native caret takes over on typing. */
.term-cursor {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  display: none;
  width: 0.6ch;
  height: 1.2em;
  background: var(--accent);
  opacity: 0.9;
  pointer-events: none;
}
.term-input__field.is-empty.is-focus:not(.is-busy) .term-cursor {
  display: block;
  animation: blink 1.06s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* ---- quick-command chips: quiet key-hint tiles, not GUI buttons ---- */
.term-hints { display: none; flex-wrap: wrap; gap: 0.45rem; padding-top: 0.7rem; flex: none; }
.terminal--ready .term-hints { display: flex; }

.cmd-chip {
  font-size: 0.85rem;
  color: var(--fg-dim);
  background: var(--bg-raised);
  padding: 0.08rem 0.55rem;
  border-radius: 2px;
  transition: color 0.12s, background-color 0.12s;
}
.cmd-chip:hover {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, var(--bg-raised));
}
.cmd-chip--bare { background: none; padding: 0; border-radius: 0; color: var(--accent); }
.cmd-chip--bare:hover { background: none; text-decoration: underline; text-underline-offset: 3px; }

.term-intro .term-welcome { color: var(--muted); margin-top: 1rem; max-width: 62ch; }
.term-welcome a { color: var(--link); }

/* ============================================================================
   NEOFETCH — the hero on load: accent logo, aligned info list.
   ============================================================================ */
.neofetch { display: flex; gap: 2.2rem; flex-wrap: wrap; align-items: flex-start; padding-top: 0.35rem; }
.neofetch__logo { color: var(--accent); font-size: 0.95rem; line-height: 1.3; white-space: pre; }
.neofetch__info { display: flex; flex-direction: column; gap: 0.05rem; font-size: 0.95rem; }
.neofetch__info > div { display: flex; gap: 1.25ch; }
.neofetch__info dt { color: var(--muted); min-width: 8ch; }
.neofetch__info dd { color: var(--fg); }

/* ============================================================================
   LISTINGS — <button class="term-row"> rendered as plain terminal text rows:
   full-width, left-aligned, flat hover lift. Directories are blue like
   `ls --color`; documents are accent (the runnable things).
   Doc rows: date · name · title. Section rows: name · description.
   ============================================================================ */
.term-list { display: flex; flex-direction: column; }
.term-list__title { color: var(--muted); margin-bottom: 0.45rem; }

.term-row {
  display: flex;
  align-items: baseline;
  gap: 2ch;
  text-align: left;
  padding: 0.22rem 0.6rem;
  margin: 0 -0.6rem;
  color: var(--fg);
}
.term-row:hover { background: var(--bg-raised); }
.term-row:focus-visible { outline-offset: -2px; }

.term-row__date { flex: none; width: 10ch; color: var(--muted); }
.term-row__name { flex: none; min-width: 14ch; color: var(--accent); }
.term-row__title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--fg-dim);
}
.term-row:hover .term-row__title { color: var(--fg); }
.term-row--dir .term-row__name { color: var(--link); font-weight: 500; }
/* Executables (foo.sh*) get a warm hue — distinct from blue dirs and green docs,
   the way `ls --color` marks runnable files apart. */
.term-row--exec .term-row__name { color: var(--t-builtin); }

@media (max-width: 620px) {
  /* collapse doc rows to date + name; keep section descriptions */
  .term-row__date ~ .term-row__title { display: none; }
  .term-row__name { min-width: 0; }
  /* The date column is fixed-width, so a long slug (e.g. backpressure-is-a-
     feature) can only be absorbed by the name — let it shrink and wrap instead
     of pushing the scrollback into a horizontal scroll on narrow screens. */
  .term-row__date ~ .term-row__name { flex: 1; overflow-wrap: anywhere; }
}

/* ---- help ---- */
.help-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.15rem 2.5ch;
  margin-bottom: 0.7rem;
}
.help-row { display: contents; }
.help-cmd { color: var(--accent); white-space: nowrap; }
.help-args { color: var(--muted); }
.help-desc { color: var(--fg-dim); }
@media (max-width: 520px) {
  .help-grid { display: block; }
  .help-row { display: block; margin-bottom: 0.4rem; }
  .help-desc { display: block; padding-left: 2ch; }
}

/* ---- history / completion / tags ---- */
.hist__row { display: flex; gap: 1.5ch; }
.hist__n { color: var(--muted); min-width: 3ch; text-align: right; }
.hist__cmd { color: var(--fg-dim); }

.complete { display: flex; flex-wrap: wrap; gap: 0.3rem 2.5ch; }
.complete__opt { color: var(--accent); }

.tag-cloud { display: flex; flex-wrap: wrap; gap: 0.25rem 1.2ch; margin-bottom: 0.7rem; }
.tag--btn { color: var(--fg-dim); padding: 0.05rem 0.35rem; margin: 0 -0.35rem; border-radius: 2px; }
.tag--btn:hover { color: var(--accent); background: var(--bg-raised); }
.tag__n { color: var(--muted); margin-left: 0.75ch; font-size: 0.85em; }

.noscript-note {
  margin: 1.25rem clamp(0.9rem, 2.5vw, 2rem);
  max-width: 60ch;
  padding: 0.8rem 1rem;
  border: 1px dashed var(--border);
  color: var(--fg-dim);
}

/* ============================================================================
   TREE — `tree` prints the whole virtual filesystem. Box-drawing connectors in
   a faint hue, names colored by kind (blue dir / green doc / warm exec), every
   row a real button that runs the thing it points at.
   ============================================================================ */
.tree { line-height: 1.55; }
.tree__root { color: var(--link); font-weight: 500; padding: 0 0.6rem; }
.tree__row {
  display: flex;
  align-items: baseline;
  text-align: left;
  width: calc(100% + 1.2rem);
  margin: 0 -0.6rem;
  padding: 0 0.6rem;
}
.tree__row:hover { background: var(--bg-raised); }
.tree__row:focus-visible { outline-offset: -2px; }
.tree__branch { flex: none; color: var(--faint); white-space: pre; }
.tree__name { color: var(--fg-dim); }
.tree__row:hover .tree__name { color: var(--fg); }
.tree__row--dir .tree__name { color: var(--link); font-weight: 500; }
.tree__row--doc .tree__name { color: var(--accent); }
.tree__row--exec .tree__name { color: var(--t-builtin); }
/* No .tree__row--file: the home-level "files" are all executables now. */

/* ============================================================================
   SCRIPT SOURCE — what `cat foo.sh` prints: a titled, accent-ruled code block
   (the playful "source"), then a chip to actually run it.
   ============================================================================ */
.script { max-width: var(--measure); }
.script__name { color: var(--muted); margin-bottom: 0.4rem; }
.script__code {
  background: var(--bg-sunken);
  border: 1px solid var(--border-soft);
  border-left: 2px solid var(--accent);
  padding: 0.7rem 1.1rem;
  overflow-x: auto;
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--fg-dim);
  white-space: pre;
  tab-size: 2;
}
.script > .term-muted { margin-top: 0.55rem; }

/* ============================================================================
   GUESS — guess_number.sh. The machine's line, a muted range/sub-line, and the
   answer buttons. State lives entirely in each button's data-cmd, so a run is a
   trail of these blocks marching the search down to the number.
   ============================================================================ */
.guess { max-width: 48ch; }
.guess__line { color: var(--fg); font-weight: 500; display: flex; gap: 1ch; align-items: baseline; }
.guess__icon { flex: none; color: var(--accent); }
.guess--done .guess__icon { color: var(--link); }
.guess__sub { color: var(--muted); font-size: 0.9rem; margin-top: 0.15rem; }
.guess__choices { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }
.guess__btn {
  color: var(--fg-dim);
  background: var(--bg-raised);
  border: 1px solid var(--border-soft);
  padding: 0.14rem 0.85rem;
  border-radius: 3px;
  transition: color 0.12s, background-color 0.12s, border-color 0.12s;
}
.guess__btn:hover {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-raised));
}
.guess__btn--no:hover {
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 45%, var(--border));
  background: color-mix(in srgb, var(--danger) 12%, var(--bg-raised));
}

/* ============================================================================
   STATUS LINE — vim/tmux-inspired: thin, flat, one accent segment. Anchors
   the bottom of the terminal; the cwd on the right is updated live by JS.
   ============================================================================ */
.term-statusline {
  flex: none;
  display: flex;
  align-items: stretch;
  min-height: 1.75rem;
  background: var(--bg-sunken);
  border-top: 1px solid var(--border-soft);
  font-size: 0.8rem;
  color: var(--fg-dim);
  user-select: none;
}
.term-statusline__seg { display: inline-flex; align-items: center; padding: 0 1ch; }
.term-statusline__seg--mode {
  padding: 0 1.5ch;
  background: var(--accent);
  color: var(--bg-sunken);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
}
.term-statusline__seg--host { padding: 0 1.5ch; color: var(--muted); }
.term-statusline__spacer { flex: 1; }
.term-statusline__seg--branch { padding: 0 1.5ch; color: var(--muted); border-left: 1px solid var(--border-soft); }
.term-statusline__branch { color: var(--accent); }
.term-statusline__cwd { color: var(--fg-dim); padding: 0 1.5ch; border-left: 1px solid var(--border-soft); }
.term-statusline__seg--toggle { padding: 0 0.75ch 0 0; }
@media (max-width: 480px) {
  .term-statusline__seg--host { display: none; }
  .term-statusline__seg--branch { display: none; }
}

.theme-toggle {
  display: inline-flex;
  align-items: center;
  color: var(--muted);
  padding: 0.25rem 0.5rem;
}
.theme-toggle:hover { color: var(--fg); }
.theme-toggle__moon { display: none; }
:root[data-theme="light"] .theme-toggle__sun { display: none; }
:root[data-theme="light"] .theme-toggle__moon { display: inline; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) .theme-toggle__sun { display: none; }
  :root:not([data-theme]) .theme-toggle__moon { display: inline; }
}

/* ============================================================================
   INLINE DOCUMENTS — what `cat` prints into the scrollback. A dashed rule
   separates the article from the session; the measure keeps long-form
   readable inside the full-bleed terminal (man-page style).
   ============================================================================ */
.term-doc { border-top: 1px dashed var(--border); padding-top: 1.1rem; }
.term-doc > .term-muted { margin-top: 1.6rem; }

.doc { max-width: var(--measure); }
.doc__head { margin-bottom: 1.8rem; }
.doc__title { font-size: 1.4rem; font-weight: 700; line-height: 1.25; letter-spacing: -0.01em; color: var(--fg); }
.doc__meta {
  display: flex; flex-wrap: wrap; gap: 1ch; align-items: center;
  color: var(--muted); font-size: 0.88rem; margin-top: 0.5rem;
}
.doc__meta .dot { color: var(--faint); }
.dot { color: var(--faint); }

.tags { list-style: none; display: flex; flex-wrap: wrap; gap: 1.5ch; margin-top: 0.55rem; padding: 0; }
.tag { color: var(--muted); font-size: 0.85rem; }
li.tag::marker { content: ""; }

.project-meta {
  margin-top: 1.2rem;
  display: flex; flex-direction: column; gap: 0.25rem;
  padding: 0.15rem 0 0.15rem 1.25ch;
  border-left: 2px solid var(--border);
  font-size: 0.92rem;
}
.project-meta__row { display: flex; gap: 2ch; }
.project-meta dt { color: var(--muted); min-width: 6ch; }
.project-meta dd { color: var(--fg-dim); word-break: break-word; }

/* ============================================================================
   PROSE — long-form body, set for comfortable reading in mono.
   ============================================================================ */
.prose { font-size: 1rem; line-height: 1.75; color: var(--fg-dim); }
.prose > * + * { margin-top: 1.25rem; }
.prose h2, .prose h3, .prose h4 { color: var(--fg); font-weight: 700; line-height: 1.3; letter-spacing: -0.01em; }
.prose h2 { font-size: 1.2rem; margin-top: 2.4rem; }
.prose h3 { font-size: 1.05rem; margin-top: 1.9rem; }
.prose h2::before { content: "## "; color: var(--faint); font-weight: 400; }
.prose h3::before { content: "### "; color: var(--faint); font-weight: 400; }
.prose a {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--link) 40%, transparent);
}
.prose a:hover { color: var(--link-hover); text-decoration-color: var(--link-hover); }
.prose strong { color: var(--fg); font-weight: 700; }
.prose em { font-style: italic; }
.prose ul, .prose ol { padding-left: 3ch; }
.prose li { margin-top: 0.4rem; }
.prose li::marker { color: var(--accent); }
.prose blockquote { border-left: 2px solid var(--accent); padding-left: 2ch; color: var(--muted); font-style: italic; }
.prose hr { border: none; border-top: 1px dashed var(--border); margin: 2.4rem 0; }
.prose img { border: 1px solid var(--border-soft); }
.prose table { width: 100%; border-collapse: collapse; font-size: 0.9rem; display: block; overflow-x: auto; }
.prose th, .prose td { text-align: left; padding: 0.45rem 1.5ch; border-bottom: 1px solid var(--border-soft); }
.prose th { color: var(--fg); }

/* inline + block code */
.prose :not(pre) > code {
  font-size: 0.92em;
  color: var(--accent);
  background: var(--bg-sunken);
  padding: 0.08rem 0.5ch;
  border-radius: 2px;
  word-break: break-word;
}
.prose pre {
  background: var(--bg-sunken);
  border: 1px solid var(--border-soft);
  padding: 0.9rem 1.1rem;
  overflow-x: auto;
  font-size: 0.88rem;
  line-height: 1.6;
  tab-size: 4;
}
.prose pre code { color: var(--fg); background: none; padding: 0; font-size: inherit; }

/* ---- syntax tokens (chroma, ClassPrefix "tok-") ---- */
.prose .tok-c, .prose .tok-c1, .prose .tok-cm, .prose .tok-cs, .prose .tok-cp, .prose .tok-cpf { color: var(--t-comment); font-style: italic; }
.prose .tok-k, .prose .tok-kn, .prose .tok-kp, .prose .tok-kr, .prose .tok-kd { color: var(--t-key); }
.prose .tok-kc { color: var(--t-builtin); }
.prose .tok-kt, .prose .tok-nc, .prose .tok-nn { color: var(--t-type); }
.prose .tok-nf, .prose .tok-nd, .prose .tok-fm { color: var(--t-fn); }
.prose .tok-s, .prose .tok-s1, .prose .tok-s2, .prose .tok-sb, .prose .tok-sc, .prose .tok-sd, .prose .tok-se, .prose .tok-sh, .prose .tok-si, .prose .tok-sx, .prose .tok-sr, .prose .tok-ss, .prose .tok-dl { color: var(--t-str); }
.prose .tok-m, .prose .tok-mi, .prose .tok-mf, .prose .tok-mh, .prose .tok-mo, .prose .tok-mb, .prose .tok-il { color: var(--t-num); }
.prose .tok-o, .prose .tok-ow { color: var(--t-op); }
.prose .tok-nb, .prose .tok-bp { color: var(--t-builtin); }
.prose .tok-nt { color: var(--t-key); }
.prose .tok-na { color: var(--t-attr); }
.prose .tok-nv, .prose .tok-vc, .prose .tok-vg, .prose .tok-vi { color: var(--t-name); }
.prose .tok-p, .prose .tok-nx { color: var(--t-name); }
.prose .tok-err { color: var(--danger); }
.prose .tok-gi { color: var(--t-str); }
.prose .tok-gd { color: var(--danger); }
.prose .tok-gh, .prose .tok-gu { color: var(--t-fn); }

/* ---- motion ---- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
  .term-input__field.is-empty.is-focus:not(.is-busy) .term-cursor { animation: none; opacity: 0.9; }
}

/* ---- print ---- */
@media print {
  .term-input, .term-hints, .term-statusline, .skip-link { display: none !important; }
  body { color: #000; background: #fff; }
  .terminal { height: auto; }
  .term-scroll { overflow: visible; }
}
