/* Fonts: the template's own OTFs (SIL OFL), copied to fonts/ by site/assemble.sh, and Caveat
   for the pen (SIL OFL; site/fonts/caveat/OFL.txt): the latin woff2 files of
   @fontsource/caveat@5.3.0 from jsDelivr, committed, never fetched at runtime. The Chinese pen
   writes in LXGW WenKai (SIL OFL; site/fonts/wenkai/OFL.txt): a subset of its Medium weight with
   only the characters the Chinese strings use (site/fonts/wenkai/subset.sh), fetched only when a
   Chinese note is drawn. Chinese body text uses the system's CJK fonts after the Latin ones. */
@font-face {
  font-family: "LXGW WenKai";
  src: url("fonts/wenkai/lxgw-wenkai-medium-subset.woff2") format("woff2");
  font-weight: 400 700; /* one weight for the pen's 400 and 600: never a synthesised bold */
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Caveat";
  src: url("fonts/caveat/caveat-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Caveat";
  src: url("fonts/caveat/caveat-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Serif 4 SmText";
  src: url("fonts/SourceSerif4/SourceSerif4SmText-Regular.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Serif 4 SmText";
  src: url("fonts/SourceSerif4/SourceSerif4SmText-It.otf") format("opentype");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Source Serif 4 SmText";
  src: url("fonts/SourceSerif4/SourceSerif4SmText-Semibold.otf") format("opentype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Serif 4 SmText";
  src: url("fonts/SourceSerif4/SourceSerif4SmText-SemiboldIt.otf") format("opentype");
  font-weight: 600;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Source Sans 3";
  src: url("fonts/SourceSans3/SourceSans3-Regular.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Sans 3";
  src: url("fonts/SourceSans3/SourceSans3-It.otf") format("opentype");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Source Sans 3";
  src: url("fonts/SourceSans3/SourceSans3-Semibold.otf") format("opentype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Sans 3";
  src: url("fonts/SourceSans3/SourceSans3-SemiboldIt.otf") format("opentype");
  font-weight: 600;
  font-style: italic;
  font-display: swap;
}

/* ------------------------------------------------------------------------------------------
   Resume replica (site/resume.js). Geometry follows common/resume.cls at 96 px/in:
   1pt = 1.3333px; US Letter 816 × 1056; margins 0.6in = 57.6px; body 10.5pt/13.9pt.
   Everything is scoped under .resume so page layout CSS can't collide with it.
   ------------------------------------------------------------------------------------------ */
.resume {
  --r-accent: #374151;
  --r-pill: #e9eaec; /* accent 11% */
  --r-spine: #c3c6cb; /* accent 30% */
  --r-pill-text: #222222;
  --r-secondary: #404040;
  --r-headline: #333333;
  --r-foot: #666666;
  --r-serif: "Source Serif 4 SmText", Georgia, serif;
  --r-sans: "Source Sans 3", "Helvetica Neue", Arial, sans-serif;

  position: relative;
  width: 816px;
  height: 1056px;
  color: #000;
  font-family: var(--r-serif);
  font-size: 14px; /* 10.5pt */
  line-height: 18.533px; /* 13.9pt */
  font-kerning: normal;
  text-align: left;
  hyphens: manual;
  overflow-wrap: normal;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
.resume *,
.resume *::before {
  box-sizing: border-box;
}
.resume b {
  font-weight: 600;
}

/* Page sheets behind the columns. */
.resume .r-sheets,
.resume .r-ghosts {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.resume .r-sheet {
  position: absolute;
  top: 0;
  width: 816px;
  height: 1056px;
  background: var(--paper, #fff); /* the page's paper token: a touch off-white in dark */
  box-shadow:
    0 1px 2px rgb(0 0 0 / 0.06),
    0 6px 24px rgb(0 0 0 / 0.08);
}
.resume .r-foot {
  position: absolute;
  left: 0;
  right: 0;
  top: 1018.2px; /* baseline 0.32in below the text area */
  font: 12px/14.667px var(--r-sans); /* 9pt */
  color: var(--r-foot);
  text-align: center;
}

/* One column per page: column width = content width, height = content height. */
.resume .r-flow {
  position: absolute;
  left: 57.6px;
  top: 57.6px;
  width: 700.8px;
  height: 940.8px;
  column-width: 700.8px;
  column-gap: 163.2px; /* page gap (48px) + both margins */
  column-fill: auto;
}

/* Header: name and headline left, contact block right, bottoms aligned; then the accent bar. */
.resume .r-header {
  margin-top: -5.9px; /* TeX starts the name at its glyph top, CSS at the font's ascent */
  display: flex;
  justify-content: space-between;
  align-items: last baseline;
}
.resume .r-header-main {
  width: 62%;
}
.resume .r-name {
  font: 600 37.333px/40px var(--r-sans); /* 28pt/30pt */
}
.resume .r-headline {
  margin-top: 2.5px; /* 4.5pt, less CSS half-leading */
  font: 15.333px/18.667px var(--r-sans); /* 11.5pt/14pt */
  color: var(--r-headline);
}
.resume .r-contact {
  width: 36%;
  font: 13px/16.667px var(--r-sans); /* 9.75pt/12.5pt */
  text-align: right;
}
.resume .r-bar {
  height: 4px; /* 3pt */
  margin-top: 22.2px; /* 9pt + interline glue above the rule */
  background: var(--r-accent);
}
.resume .r-bar + .r-sec {
  margin-top: 18px;
}

/* Sections: keep blocks never split; needspace (resume.js) may force a page break. */
.resume .r-sec {
  margin-top: 13px; /* \addvspace{10.5pt}, as measured against the PDF */
}
.resume .r-sec[data-sec="summary"] + .r-sec {
  margin-top: 13.9px; /* the skills rows end a little lower */
}
.resume .r-sec-spine + .r-sec {
  margin-top: 16.3px; /* the spine's framed box ends a little lower */
}
.resume .r-sec.r-break {
  break-before: column;
  margin-top: 0;
}
.resume .r-keep,
.resume .r-bullet,
.resume .r-pub,
.resume .r-lineitem,
.resume .r-skill,
.resume .r-degree {
  break-inside: avoid;
}

/* Heading: solid accent tab, then a 1.1pt rule to the right margin, 2.5pt above the baseline. */
.resume .r-head {
  display: flex;
  align-items: baseline;
  margin: 0 0 4.167px; /* \vspace{5pt}, as measured against the PDF */
  font: 600 16px/18.667px var(--r-sans); /* 12pt/14pt */
  break-after: avoid;
}
.resume .r-sec-spine .r-head {
  margin-bottom: 6.667px; /* \vspace{5pt} before the spine's framed box */
}
.resume .r-tab {
  padding: 0.4px 10px 2.667px; /* inner ysep 2pt, xsep 7.5pt; less on top for the line box */
  border-radius: 2px;
  background: var(--r-accent);
  color: #fff;
}
.resume .r-rule {
  position: relative;
  top: -3.333px; /* bottom edge 2.5pt above the baseline */
  flex: 1;
  height: 1.467px;
  background: var(--r-accent);
}

/* Summary */
.resume .r-summary {
  margin: 0;
}
.resume .r-skill {
  display: flex;
  align-items: baseline;
  margin-top: 4px; /* 3pt */
}
.resume .r-keep + .r-skill {
  margin-top: 3px; /* as measured against the PDF */
}
.resume .r-skill-label {
  flex: none;
  width: 117.333px; /* 88pt */
  font: 600 13.333px/13.333px var(--r-sans); /* 10pt; short line box keeps the row 13.9pt */
}

/* Spine: a 1.5pt line 3.75pt from the margin; entry text starts 18.75pt in. */
.resume .r-spine {
  display: flow-root;
  margin-left: 5px;
  padding-left: 18px;
  border-left: 2px solid var(--r-spine);
}
.resume .r-entry {
  position: relative;
}
.resume .r-gap.r-entry {
  margin-top: 7.7px; /* 6pt between entries, as measured against the PDF */
}
.resume .r-node {
  position: absolute;
  left: -25px;
  top: 4.3px;
  width: 12px;
  height: 12px;
  border: 2.533px solid var(--r-accent); /* ring: radius 3.55pt, line 1.9pt */
  border-radius: 50%;
  background: #fff;
}
.resume .r-line {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.resume .r-title {
  flex: 1;
  font: 14.667px/18.533px var(--r-sans); /* 11pt */
  font-variant-numeric: tabular-nums;
}
.resume .r-pill {
  flex: none;
  padding: 1.6px 6.667px; /* inner ysep 1.2pt, xsep 5pt */
  border-radius: 8px; /* 6pt */
  background: var(--r-pill);
  color: var(--r-pill-text);
  font: 13.333px/13.333px var(--r-sans); /* 10pt */
  font-variant-numeric: tabular-nums;
}
.resume .r-sub {
  font-style: italic;
}
.resume .r-bullet {
  position: relative;
  padding-left: 15.4px; /* 1.1em */
}
.resume .r-bullet::before {
  content: "•";
  position: absolute;
  left: 3.5px; /* labelindent 0.25em */
}

/* Education */
.resume .r-gap.r-degree {
  margin-top: 5.333px; /* 4pt */
}
.resume .r-date {
  flex: none;
  font: 13.333px/13.333px var(--r-sans); /* 10pt; short line box keeps the row 13.9pt */
  color: var(--r-secondary);
  font-variant-numeric: tabular-nums;
}

/* Publications: hanging 2em, number in the hang. */
.resume .r-pub {
  position: relative;
  padding-left: 28px; /* 2em */
}
.resume .r-gap.r-pub {
  margin-top: 4px; /* 3pt */
}
.resume .r-num {
  position: absolute;
  left: 0;
  font: 13.333px/18.533px var(--r-sans); /* 10pt */
  color: var(--r-secondary);
}
.resume .r-award {
  color: var(--r-accent);
  font-style: italic;
  font-weight: 600;
}

/* Service and honors: text with right-aligned years. */
.resume .r-lineitem {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.resume .r-gap.r-lineitem {
  margin-top: 2px; /* 1.5pt */
}

/* highlight(ids) */
.resume [data-id] {
  transition:
    background-color 240ms ease-out,
    box-shadow 240ms ease-out;
}
.resume .is-hl {
  border-radius: 2px;
  background-color: rgb(55 65 81 / 0.1);
  box-shadow: 0 0 0 3px rgb(55 65 81 / 0.1);
}
.resume .r-ghost {
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .resume [data-id] {
    transition: none;
  }
}

/* ------------------------------------------------------------------------------------------
   Page layout, the film, and the sections below it (site/index.html, main.js, film.js).
   Nothing here styles the replica's internals (.resume …).
   ------------------------------------------------------------------------------------------ */
:root {
  color-scheme: light;
  /* Theme tokens (light; dark below). The desk is under everything; paper stays light in both
     themes and keeps the resume's own colours; the terminal is dark in both (.term). */
  --desk: #eef0f3;
  --ink: #1d232b;
  --muted: #5d6570;
  --paper: #ffffff;
  --pen: #c2410c; /* on paper */
  --pen-desk: #c2410c; /* on the desk */
  --pen-term: #fb923c; /* on the terminal card (dark in both themes) */
  --line: rgb(29 35 43 / 0.18);
  --cat-edge: transparent; /* the cats' outline, for the dark desk */
  --term-edge: transparent; /* the terminal card's edge, for the dark desk */
  --cat-shadow: rgb(29 35 43 / 0.13);
  --dot: rgb(29 35 43 / 0.09); /* the film's desk grid */
  --hl: rgb(251 191 36 / 0.5); /* the caption's highlighter */
  --sheet-shadow: 0 2px 4px rgb(0 0 0 / 0.05), 0 26px 50px -18px rgb(29 35 43 / 0.32);
  --paper-lift: 0 1px 2px rgb(0 0 0 / 0.06), 0 12px 26px -14px rgb(29 35 43 / 0.4);
  --accent: #374151;
  --on-accent: #ffffff;
  --tint: #e2e5e9;
  --spine: #c3c6cb; /* accent 30% */
  --code-bg: #f7f8f9;
  --title-h: 48px;
  --cjk-sans: "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei";
  --cjk-serif: "Songti SC", "Noto Serif CJK SC", "Noto Serif SC";
  --ui: "Source Sans 3", "Helvetica Neue", Arial, var(--cjk-sans), sans-serif;
  --serif: "Source Serif 4 SmText", Georgia, var(--cjk-serif), serif;
  --mono:
    ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", var(--cjk-sans),
    monospace;
  --pen-font: "Caveat", "Bradley Hand", "Segoe Print", cursive;
}
/* Chinese handwriting: WenKai for every character (its own Latin too, so a note reads as one
   hand), Caveat behind it. */
:root:lang(zh) {
  --pen-font: "LXGW WenKai", "Caveat", "Kaiti SC", "STKaiti", cursive;
}
/* Dark: the system's choice unless the user picked light, or the user's pick (theme.js). Keep
   the two blocks the same. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --desk: #1b1f25;
    --ink: #eef1f5;
    --muted: #a3acb8;
    --paper: #f7f7f5;
    --pen-desk: #fb923c;
    --pen-term: #fb923c;
    --line: rgb(238 241 245 / 0.22);
    --cat-edge: rgb(255 255 255 / 0.2);
    --term-edge: rgb(255 255 255 / 0.14);
    --cat-shadow: rgb(0 0 0 / 0.35);
    --dot: rgb(238 241 245 / 0.07);
    --hl: rgb(234 88 12 / 0.55);
    --sheet-shadow: 0 2px 4px rgb(0 0 0 / 0.3), 0 30px 60px -18px rgb(0 0 0 / 0.7);
    --paper-lift: 0 1px 2px rgb(0 0 0 / 0.3), 0 14px 30px -14px rgb(0 0 0 / 0.75);
    --accent: #d5dbe3;
    --on-accent: #1b1f25;
    --tint: #2c323b;
    --spine: #4b535e;
    --code-bg: #252a32;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --desk: #1b1f25;
  --ink: #eef1f5;
  --muted: #a3acb8;
  --paper: #f7f7f5;
  --pen-desk: #fb923c;
  --pen-term: #fb923c;
  --line: rgb(238 241 245 / 0.22);
  --cat-edge: rgb(255 255 255 / 0.2);
  --term-edge: rgb(255 255 255 / 0.14);
  --cat-shadow: rgb(0 0 0 / 0.35);
  --dot: rgb(238 241 245 / 0.07);
  --hl: rgb(234 88 12 / 0.55);
  --sheet-shadow: 0 2px 4px rgb(0 0 0 / 0.3), 0 30px 60px -18px rgb(0 0 0 / 0.7);
  --paper-lift: 0 1px 2px rgb(0 0 0 / 0.3), 0 14px 30px -14px rgb(0 0 0 / 0.75);
  --accent: #d5dbe3;
  --on-accent: #1b1f25;
  --tint: #2c323b;
  --spine: #4b535e;
  --code-bg: #252a32;
}
html {
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  background: var(--desk);
  color: var(--ink);
  font: 16px/1.5 var(--ui);
}
a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}
a:hover {
  text-decoration-thickness: 2px;
}
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

.site-title {
  display: flex;
  align-items: baseline;
  gap: 12px;
  box-sizing: border-box;
  height: var(--title-h);
  max-width: 2200px;
  margin: 0 auto;
  padding: 10px 16px 0;
  white-space: nowrap;
}
.site-title h1 {
  margin: 0;
  font-size: clamp(18px, 0.25vw + 14px, 21px);
  font-weight: 600;
}
.site-title p {
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--muted);
}
.site-title code {
  font: 0.9em var(--mono);
}
.site-title a {
  margin-left: auto;
}
.theme-toggle,
.lang-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: center;
  height: 32px;
  margin-top: -6px; /* centred in the line below the header's top padding */
  padding: 0 12px 0 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  font: 600 14px/1 var(--ui);
  cursor: pointer;
}
.theme-toggle svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linejoin: round;
}
.theme-toggle:hover,
.lang-toggle:hover {
  background: var(--tint);
}
/* Names the language it switches to: "中文" or "EN". */
.lang-toggle {
  padding: 0 12px;
}
.theme-toggle[aria-pressed="true"] {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--desk);
}
.theme-toggle[aria-pressed="true"] svg {
  fill: currentColor;
}
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.theme-toggle::after,
.lang-toggle::after {
  content: "";
  position: absolute;
  inset: -7px -4px; /* a 44px target */
}
/* While a Chinese page waits for i18n.js (the head script set data-lang), the English it
   replaces stays hidden; should i18n.js never run, the English shows after 2.5 s after all. */
:root[data-lang="zh"]:not(.i18n-ready) [data-i18n] {
  animation: i18n-wait 0s 2.5s both;
}
@keyframes i18n-wait {
  from {
    visibility: hidden;
  }
  to {
    visibility: visible;
  }
}

/* The film (film.js, camera.js, scenes.js) fills the window under the title line: a viewport onto
   the desk (the world, which the camera moves), the caption and the controls over its bottom. */
.film {
  --gutter: clamp(16px, 2.4vw, 56px);
  --fc-h: 64px; /* the controls */
  position: relative;
  box-sizing: border-box;
  height: calc(100dvh - var(--title-h));
  min-height: 300px;
  overflow: hidden;
  background: var(--desk);
  touch-action: pan-y; /* horizontal swipes step the film */
  -webkit-user-select: none;
  user-select: none;
}
.film-viewport {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.film-world {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  transform-origin: 0 0;
  will-change: transform;
}
/* The desk: a faint dot grid that moves with the camera. */
.film-desk {
  position: absolute;
  left: -8000px;
  top: -6000px;
  width: 20000px;
  height: 14000px;
  background: radial-gradient(circle, var(--dot) 2.2px, transparent 2.8px) 0 0 / 64px 64px;
}
/* The desk fades into the caption and the controls, below what the camera frames. */
.film::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--cap-top, 75%) - 56px);
  bottom: 0;
  z-index: 1;
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--desk) 0%, transparent) 0,
    color-mix(in srgb, var(--desk) 90%, transparent) 56px,
    var(--desk) 100%
  );
  pointer-events: none;
}
/* Screen-space content that assistive tech must reach (the world is aria-hidden): links and
   buttons a scene puts over the film. Under the caption and the controls. */
.film-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}
.film-overlay > * {
  pointer-events: auto;
}

.film-caption {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  bottom: calc(var(--fc-h) + env(safe-area-inset-bottom) + 4px);
  z-index: 2;
  pointer-events: none;
}
.film-kicker {
  display: flex;
  align-items: baseline;
  gap: 0.7em;
  margin: 0 0 0.4em;
  color: var(--muted);
  font: 600 clamp(12px, 0.3vw + 10px, 17px) / 1.2 var(--ui);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.film-num {
  color: var(--pen-desk);
  font-variant-numeric: tabular-nums;
}
.film-line {
  max-width: 32ch;
  margin: 0;
  color: var(--ink);
  font: 600 clamp(26px, 2.2vw + 12px, 68px) / 1.08 var(--serif);
  letter-spacing: -0.015em;
  text-wrap: balance;
}
/* Chinese wraps at its punctuation and spaces, not between any two characters ("一份" stays
   whole); a phrase too long for the line still breaks. */
.film-line:lang(zh) {
  letter-spacing: 0;
  word-break: keep-all;
  overflow-wrap: anywhere;
}
/* The emphasised word, as if run over with a highlighter. */
.film-line em {
  margin: 0 -0.08em;
  padding: 0 0.08em;
  background: linear-gradient(transparent 56%, var(--hl) 56%, var(--hl) 92%, transparent 92%);
  font-style: normal;
  white-space: nowrap;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Controls: play/pause, prev/next, a segment per scene, the "replay" label. They fade while
   the film plays undisturbed (film.js sets data-controls). */
.film-controls {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 4px 14px;
  box-sizing: border-box;
  height: calc(var(--fc-h) + env(safe-area-inset-bottom));
  padding: 0 var(--gutter) env(safe-area-inset-bottom);
  transition: opacity 500ms ease;
}
.film[data-controls="hidden"] .film-controls {
  opacity: 0;
  pointer-events: none;
}
.film[data-controls="hidden"] {
  cursor: none;
}
.fc-buttons {
  display: flex;
  gap: 2px;
  margin-left: -6px;
}
.fc-btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}
.fc-btn svg {
  fill: currentColor;
}
.fc-btn:hover {
  background: var(--tint);
}
.fc-play,
.fc-play:hover {
  background: var(--ink);
  color: var(--desk);
}
.fc-chapters {
  display: flex;
  flex: 1;
  gap: 6px;
  min-width: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}
.fc-chapters li {
  flex: 1;
  min-width: 0;
}
.fc-seg {
  position: relative;
  display: block;
  width: 100%;
  min-width: 24px; /* WCAG 2.5.8: nine segments share a phone's row; 44 px tall */
  height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}
.fc-bar {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 4px;
  margin-top: -2px;
  overflow: hidden;
  border-radius: 2px;
  background: var(--line);
  transition:
    height 160ms ease,
    margin 160ms ease;
}
.fc-fill {
  display: block;
  width: calc(var(--fill, 0) * 100%);
  height: 100%;
  background: var(--ink);
  transition: width 600ms ease;
}
.fc-seg[aria-current] .fc-fill {
  background: var(--pen-desk);
}
/* Hover only where a pointer can hover: on touch, :hover sticks after a tap. */
@media (hover: hover) {
  .fc-seg:hover .fc-bar {
    height: 8px;
    margin-top: -4px;
  }
  .fc-seg:hover .fc-tip {
    opacity: 1;
  }
}
.fc-seg:focus-visible .fc-bar {
  height: 8px;
  margin-top: -4px;
}
.fc-tip {
  position: absolute;
  bottom: calc(100% - 2px);
  left: 50%;
  translate: -50% 0;
  padding: 5px 10px;
  border-radius: 6px;
  background: var(--ink);
  color: var(--desk);
  font: 600 13px/1.2 var(--ui);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 150ms ease;
}
.fc-chapters li:first-child .fc-tip {
  left: 0;
  translate: none;
}
.fc-chapters li:last-child:not(:first-child) .fc-tip {
  left: auto;
  right: 0;
  translate: none;
}
.fc-seg:focus-visible .fc-tip {
  opacity: 1;
}
.fc-label {
  color: var(--muted);
  font: 13px/1 var(--mono);
}
.film-controls :focus-visible {
  outline-offset: 2px;
}

/* A phone held upright: the chapters on a row of their own, above the buttons. */
@media (max-width: 599px) {
  .film {
    --fc-h: 100px;
  }
  .film-controls {
    flex-wrap: wrap;
    align-content: center;
    gap: 0 8px;
    padding-left: max(8px, env(safe-area-inset-left));
    padding-right: max(12px, env(safe-area-inset-right));
  }
  .fc-chapters {
    order: -1;
    flex: 1 0 100%;
    gap: 4px;
  }
  .fc-buttons {
    margin-left: 0;
  }
  .fc-label {
    margin-left: auto;
  }
}
/* A short window (a phone on its side): a smaller caption and controls. */
@media (max-height: 500px) {
  .film {
    --fc-h: 52px;
  }
  .film-caption {
    padding-left: env(safe-area-inset-left);
  }
  .film-kicker {
    margin-bottom: 0.2em;
    font-size: 11px;
  }
  .film-line {
    max-width: 34ch;
    font-size: clamp(20px, 3.4vh + 6px, 30px);
  }
}

/* --- Actors on the desk (scenes.js), in world units. -------------------------------------- */
.film-world > .actor {
  position: absolute;
  box-sizing: border-box;
}
.film-world > .pen-mark,
.film-world > .pen-note {
  z-index: 20;
}
.film-world .cat {
  aspect-ratio: auto;
}

/* A stray copy of the resume. */
.copy {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.copy-sheet {
  box-sizing: border-box;
  width: 100%;
  aspect-ratio: 8.5 / 11;
  padding: 36px 38px;
  background: var(--paper);
  color: #1d232b;
  box-shadow: var(--sheet-shadow);
}
.copy-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
}
.copy-name {
  font: 600 32px/1.1 var(--serif);
}
.copy-headline {
  margin-top: 6px;
  color: #4b5563;
  font: 400 16px/1.2 var(--serif);
}
.copy-contact {
  flex: 0 0 24%;
}
.copy-contact .copy-l {
  height: 6px;
  margin: 6px 0 0 auto;
}
.copy-bar {
  height: 4px;
  margin: 14px 0 6px;
  background: #374151;
}
.copy-sec {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 18px 0 10px;
}
.copy-tab {
  padding: 2px 9px;
  background: #374151;
  color: #fff;
  font: 600 12px/1.35 var(--ui);
}
.copy-rule {
  flex: 1;
  height: 1.5px;
  background: #374151;
}
.copy-l {
  display: block;
  height: 8px;
  margin: 9px 0;
  border-radius: 4px;
  background: #dcdfe4;
}
.copy-role {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
}
.copy-role .copy-l {
  height: 10px;
  background: #a2a8b1;
}
.copy-pill {
  flex: 0 0 22%;
  height: 14px;
  border-radius: 7px;
  background: #e9eaec;
}
.copy-file {
  min-height: 1.25em;
  margin: 20px 0 0;
  padding: 4px 16px;
  border-radius: 999px;
  background: var(--paper);
  color: #1d232b;
  box-shadow: 0 0 0 1.5px var(--line);
  font: 500 30px/1.25 var(--mono);
  white-space: pre;
}
.copy-file:has(.copy-file-name:empty):not(:has(.is-typing)) {
  visibility: hidden;
}
.is-typing::after {
  content: "";
  display: inline-block;
  width: 0.55em;
  height: 1.05em;
  margin-left: 2px;
  vertical-align: -0.18em;
  background: currentColor;
  opacity: 0.75;
}

/* The resume replica (resume.js) at full size; the real PDF page over page 1 (proof cue). */
.sheet-proof {
  position: absolute;
  left: 0;
  top: 0;
  width: 816px;
  height: 1056px;
  opacity: 0;
  box-shadow: var(--sheet-shadow);
  transition: opacity 600ms ease;
}
.sheet-stack[data-proof] .sheet-proof {
  opacity: 1;
}

/* The job posting. */
.posting {
  padding: 56px 62px;
  background: var(--paper);
  color: #1d232b;
  box-shadow: var(--sheet-shadow);
  font: 400 23px/1.45 var(--serif);
}
.posting-org {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 24px;
  color: #5d6570;
  font: 600 16px/1.2 var(--ui);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.posting-logo {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: #b45309;
}
.posting-logo svg {
  width: 26px;
  height: 26px;
  fill: #fde68a;
}
.posting-title {
  margin: 0;
  font: 600 46px/1.1 var(--serif);
  letter-spacing: -0.01em;
}
.posting-meta {
  margin: 14px 0 0;
  color: #5d6570;
  font: 400 19px/1.4 var(--ui);
}
.posting h4 {
  margin: 32px 0 8px;
  color: #374151;
  font: 600 16px/1.2 var(--ui);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.posting ul {
  margin: 0;
  padding-left: 1.1em;
}
.posting li {
  margin: 6px 0;
}
.posting li::marker {
  color: #9aa1ab;
}
.posting [data-ask] {
  white-space: nowrap;
}

/* Paw prints. */
.paws {
  width: 0;
  height: 0;
}
.paw {
  position: absolute;
  width: 34px;
  height: 34px;
  color: var(--ink);
  opacity: 0.22;
}
.paw svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: currentColor;
}

/* A terminal card on the desk (terminal.js), only while Duna types (scenes 4, 5, 8). Wide while
   the camera's free area is landscape, narrow and tall while it is portrait (film.js sets
   data-shape): the camera frames its lines at a size
   that reads (scenes.js names its parts, not its size). The log keeps to its bottom, as a
   terminal does; older lines fade out under the title bar. */
.term-card {
  display: flex;
  flex-direction: column;
  width: 1440px;
  height: 760px;
  overflow: hidden;
  border-radius: 22px;
  background: #1c1f24;
  box-shadow:
    0 0 0 1.5px var(--term-edge),
    var(--sheet-shadow);
  font-size: 24px;
}
.film[data-shape="portrait"] .term-card {
  width: 640px;
  height: 1240px;
}
.term-bar {
  display: flex;
  flex: none;
  align-items: center;
  gap: 12px;
  height: 52px;
  padding: 0 22px;
  background: #262a31;
  color: #8f96a1;
  font: 500 19px/1 var(--mono);
}
.term-bar i {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: #4b525c;
}
.term-bar i:first-child {
  background: #e0685d;
}
.term-title {
  margin-left: 10px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.term-card > .term {
  flex: 1;
  min-height: 0;
  height: auto;
  padding: 18px 28px 24px;
  border-radius: 0;
  font-size: 1em;
}
.term-card .t-log {
  position: relative; /* the camera measures lines through it (camera.js offsetRect) */
  display: flex;
  flex-direction: column;
  overflow: hidden;
  mask-image: linear-gradient(to bottom, transparent 0, #000 72px);
}
/* Short logs sit on the input too (the newest line is always just above it). */
.term-card .t-log > :first-child {
  margin-top: auto;
}

/* A rubber stamp on paper, in the pen's ink. */
.stamp {
  display: flex;
  align-items: center;
  gap: 18px;
  box-sizing: border-box;
  padding: 10px 22px 10px 16px;
  border: 5px solid currentColor;
  border-radius: 16px;
  color: var(--pen);
  font: 700 27px/1.2 var(--mono);
  white-space: nowrap;
  opacity: 0.9;
  mix-blend-mode: multiply;
}
.stamp-paw svg {
  display: block;
  width: 54px;
  height: 54px;
  fill: currentColor;
}
.stamp-text {
  display: flex;
  flex-direction: column;
}

/* Confetti (the confetti cue): pieces fall in the world and are gone when they land. */
.film-world > .confetti {
  position: absolute;
  pointer-events: none;
}
.confetti i {
  position: absolute;
  border-radius: 3px;
}

/* The closing call to action (the cta cue, in the overlay): real links in a band of their own
   under the caption, which moves up to make room (film.js sets data-scene). */
.film {
  --cta-band: 76px;
}
.film[data-scene="cta"] .film-caption {
  bottom: calc(var(--fc-h) + env(safe-area-inset-bottom) + 4px + var(--cta-band));
}
.film-cta {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  bottom: calc(var(--fc-h) + env(safe-area-inset-bottom) + 14px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}
.film-cta a {
  display: inline-flex;
  align-items: center;
  box-sizing: border-box;
  min-height: 52px;
  padding: 0 26px;
  border-radius: 999px;
  font: 600 18px/1 var(--ui);
  text-decoration: none;
}
.cta-primary {
  background: var(--ink);
  color: var(--desk);
}
.cta-secondary {
  color: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--line);
}
.cta-primary:hover {
  background: var(--pen-desk);
}
.cta-secondary:hover {
  box-shadow: inset 0 0 0 2px var(--ink);
}
@media (max-height: 500px) {
  .film {
    --cta-band: 56px;
  }
  .film-cta {
    bottom: calc(var(--fc-h) + env(safe-area-inset-bottom) + 6px);
  }
  .film-cta a {
    min-height: 44px;
    padding: 0 20px;
    font-size: 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .film-controls,
  .fc-fill,
  .sheet-proof {
    transition: none;
  }
}

/* The phone header keeps only the name and the links. */
@media (max-width: 799px) and (orientation: portrait), (max-width: 799px) and (min-height: 501px) {
  .site-title p {
    display: none;
  }
}

/* The product page below the film (page.js): one reading column on the desk, the real pages as
   papers, pen notes in Caveat. The only motion is the pen drawing each group once, and the cats'
   idle life; neither with reduced motion. */
.sections {
  box-sizing: border-box;
  max-width: 1160px;
  margin: 0 auto;
  padding: 0 16px;
}
.section {
  padding-top: clamp(72px, 8vw, 136px);
}
.section h2,
.site-foot h2 {
  margin: 0 0 16px;
  font: 600 clamp(28px, 1.2vw + 20px, 40px) / 1.15 var(--ui);
  letter-spacing: -0.01em;
}
.lead,
.prose,
.tour-text p,
.beat > p,
.cast-list p {
  max-width: 64ch;
  font-family: var(--serif);
}
.lead {
  margin: 0 0 40px;
  font-size: clamp(18px, 0.3vw + 15px, 21px);
  line-height: 1.55;
}
.prose {
  margin: 0 0 8px;
  font-size: 18px;
  line-height: 1.6;
}
code {
  font-family: var(--mono);
  font-size: 0.86em;
}
p code {
  padding: 0.05em 0.3em;
  border-radius: 3px;
  background: var(--code-bg);
  white-space: nowrap;
}
.pill {
  padding: 0.05em 0.5em;
  border-radius: 0.6em;
  background: var(--tint);
  font: 0.88em var(--ui);
  white-space: nowrap;
}
pre {
  margin: 16px 0 0;
  padding: 14px 16px;
  border-radius: 8px;
  background: var(--code-bg);
  font: 14px/1.6 var(--mono);
  overflow-x: auto;
}
pre code {
  font-size: inherit;
}
pre .c {
  color: var(--muted);
}
.nowrap {
  white-space: nowrap;
}
/* Handwriting that is page text, not a pen note. */
.hand {
  color: var(--pen-desk);
  font: 600 26px/1.15 var(--pen-font);
}

/* The real pages: papers side by side on the desk; a swipeable row on phones. */
.sheets {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 48px);
  margin: 0 0 72px;
}
.sheets figure {
  margin: 0;
}
.sheets a {
  display: block;
  border-radius: 2px;
  box-shadow: var(--paper-lift);
}
.sheets img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 2px;
}
.sheets figcaption {
  margin-top: 12px;
  color: var(--pen-desk);
  font: 600 24px/1.1 var(--pen-font);
  rotate: -1.5deg;
  transform-origin: left;
}

/* What to notice: numbered in pen; each with a close-up of the real page, marked up. */
.tour {
  margin: 32px 0 0;
  padding: 0;
  list-style: none;
  counter-reset: tour;
}
.tour > li {
  position: relative;
  padding: 0 0 64px 48px;
  counter-increment: tour;
}
.tour > li:last-child {
  padding-bottom: 0;
}
.tour > li::before {
  content: counter(tour) / "";
  position: absolute;
  left: 2px;
  top: -9px;
  color: var(--pen-desk);
  font:
    600 40px/1 "Caveat",
    "Bradley Hand",
    "Segoe Print",
    cursive;
  rotate: -4deg;
}
.tour h3 {
  margin: 2px 0 6px;
  font: 600 20px/1.3 var(--ui);
}
.tour-text p {
  margin: 0;
  font-size: 17px;
  line-height: 1.6;
}
.closeup,
.tour-art {
  margin: 24px 0 0;
}
.tour-art > .closeup {
  margin-top: 28px;
}
/* A crop of the real page 1 (data-crop, in PDF points: --x, --y, --w, --h on a 612 × 792 pt
   page) at the PNG's own scale (110 dpi: 110 / 72 px per point), narrower if need be. */
.closeup {
  width: calc(var(--w) * 1.5278px);
  max-width: 100%;
}
.closeup-paper {
  position: relative;
  border-radius: 3px;
  background: var(--paper);
  box-shadow: var(--paper-lift);
}
/* A one-line crop sits on a slip of paper, with room for the pen around the line. */
.closeup.is-line .closeup-paper {
  padding: 12px 0;
}
.closeup-crop {
  position: relative;
  overflow: hidden;
  aspect-ratio: var(--w) / var(--h);
  border-radius: inherit;
}
.closeup-crop img {
  position: absolute;
  left: calc(var(--x) / var(--w) * -100%);
  top: calc(var(--y) / var(--h) * -100%);
  width: calc(612 / var(--w) * 100%);
  max-width: none;
  height: auto;
}
.code-pair {
  position: relative;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), max-content));
  gap: 0 16px;
}
.code-pair pre {
  overflow: visible;
}
.error-wrap {
  position: relative;
  padding-bottom: 40px; /* room for the pen's note under the error */
}
pre.error {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
pre.error,
.commands {
  box-sizing: border-box;
  width: fit-content;
  max-width: 100%;
}
@media (min-width: 1000px) {
  .tour > li {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 500px);
    column-gap: 56px;
    align-items: start;
  }
  .tour > li > .closeup,
  .tour > li > .tour-art {
    margin-top: 6px;
  }
  .code-pair {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* How it works: three beats, each over a small scene on the desk (decorative). */
.beats {
  display: grid;
  gap: 64px 48px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 960px) {
  .beats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
/* Between a phone and three across: the scene beside its text. */
@media (min-width: 640px) and (max-width: 959px) {
  .beat {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    column-gap: 40px;
  }
  .beat-art {
    grid-row: span 2;
  }
  .beat .beat-art + h3 {
    margin-top: 8px;
  }
}
.beat h3 {
  margin: 24px 0 8px;
  font: 600 20px/1.3 var(--ui);
}
.beat h3 code {
  font-size: 0.92em;
}
.beat > p {
  margin: 0;
  font-size: 17px;
  line-height: 1.6;
}
.beat-art {
  position: relative;
  width: 300px;
  max-width: 100%;
  height: 184px;
}
.beat-art .cast-slot {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 84px;
}
.beat-art .cat {
  width: 100%;
}
.mini-paper {
  position: absolute;
  left: 0;
  top: 8px;
  box-sizing: border-box;
  padding: 12px 14px;
  border-radius: 3px;
  background: var(--paper);
  color: #1d232b;
  box-shadow: var(--paper-lift);
  font: 11px/1.65 var(--mono);
}
.mini-paper > span {
  display: block;
  white-space: nowrap;
}
.mini-c {
  color: #6b7280;
}
/* A small terminal card: dark in both themes, as in the film. */
.mini-term {
  position: absolute;
  left: 0;
  top: 40px;
  box-sizing: border-box;
  width: 200px;
  padding: 12px 0 12px 12px;
  border-radius: 8px;
  background: #1c1f24;
  color: #e6e6e6;
  box-shadow:
    0 0 0 1.5px var(--term-edge),
    var(--paper-lift);
  font: 11px/1.7 var(--mono);
}
.mini-term > span {
  display: block;
  overflow: hidden;
  white-space: nowrap;
}
.mini-dim {
  color: #8f96a1;
}
.mini-sel {
  color: #9ec5fe;
}
/* A one-page resume, sketched, with the paw-print stamp. */
.mini-sheet {
  display: flex;
  flex-direction: column;
  gap: 7px;
  width: 150px;
  height: 176px;
  top: 4px;
  padding: 16px;
}
.mini-sheet i {
  display: block;
  flex: none;
  height: 4px;
  border-radius: 2px;
  background: #d5d9de;
}
.mini-sheet i.short {
  width: 62%;
}
.mini-sheet i.mini-name {
  width: 55%;
  height: 8px;
  background: #374151;
}
.mini-sheet i.mini-bar {
  height: 2px;
  margin-bottom: 4px;
  background: #374151;
}
.mini-stamp {
  position: absolute;
  left: 14px;
  bottom: 22px;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px 3px 6px;
  border: 2.5px solid currentColor;
  border-radius: 8px;
  color: var(--pen);
  font: 700 13px/1.2 var(--mono);
  opacity: 0.9;
  rotate: -8deg;
  mix-blend-mode: multiply;
}

.commands {
  margin-bottom: 28px;
}
.links {
  display: grid;
  gap: 18px;
  max-width: 64ch;
  margin: 32px 0 0;
  padding: 0;
  list-style: none;
}
.links a {
  font: 600 18px/1.4 var(--ui);
}
.links span {
  display: block;
  color: var(--muted);
}

/* Credits: the cast, the name, the license, the fonts. */
.site-foot {
  box-sizing: border-box;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(72px, 8vw, 136px) 16px max(40px, env(safe-area-inset-bottom));
}
.cast-list {
  position: relative;
  display: grid;
  gap: 36px 40px;
  margin: 32px 0 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 1100px) {
  .cast-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
.cast-list > li {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}
.cast-list .cat {
  width: 84px;
}
.cast-list h3 {
  margin: 4px 0 4px;
  font: 600 19px/1.3 var(--ui);
}
.cast-list p {
  margin: 0;
  font-size: 16px;
  line-height: 1.55;
}
.cast-list .hand {
  margin-top: 10px;
  font-family: var(--pen-font);
  font-size: min(24px, 6vw);
  line-height: 1.15;
  white-space: nowrap;
}
/* The Chinese name sum is two underlined halves: on a phone the second goes on a line of its own. */
.cast-list .hand:lang(zh) {
  white-space: normal;
}
.cast-list .hand:lang(zh) > span {
  white-space: nowrap;
}
.site-foot .fine {
  max-width: 72ch;
  margin: 64px 0 0;
  padding-top: 24px;
  border-top: 1px solid var(--tint);
  color: var(--muted);
  font: 14px/1.6 var(--ui);
}
.site-foot .fine a {
  color: inherit;
}

@media (max-width: 599px) {
  .cast-list > li {
    grid-template-columns: 64px minmax(0, 1fr);
    gap: 16px;
  }
  .cast-list .cat {
    width: 64px;
  }
}
@media (max-width: 799px) {
  .sheets {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 78%;
    margin: 0 -16px 56px;
    padding: 8px 16px 24px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding: 0 16px;
    scrollbar-width: none;
  }
  .sheets figure {
    scroll-snap-align: start;
  }
  .tour > li {
    padding-left: 40px;
  }
  .tour > li::before {
    left: 0;
    font-size: 36px;
  }
  pre {
    font-size: 13px;
  }
  /* Short snippets wrap on a phone rather than hide their ends; the commands scroll. */
  .tour pre {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
  }
}

/* ------------------------------------------------------------------------------------------
   Terminal (site/terminal.js): the only dark surface.
   ------------------------------------------------------------------------------------------ */
.term {
  --t-bg: #1c1f24;
  --t-fg: #e6e6e6;
  --t-dim: #8f96a1;
  --t-line: #4b525c;
  --t-ok: #7cc68e;
  --t-star: #d7896b;
  --t-bash: #e49ac3;
  --t-sel: #9ec5fe;

  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  height: 100%;
  padding: 14px 16px 12px;
  border-radius: 10px;
  background: var(--t-bg);
  color: var(--t-fg);
  font-family: var(--mono);
  font-size: clamp(12px, 0.45vw + 7px, 16px);
  line-height: 1.5;
  overflow: hidden;
}
.t-log {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  touch-action: pan-y; /* a scroll container: without this it takes horizontal swipes */
  overflow-anchor: none; /* terminal.js keeps it at the bottom; anchoring would fight that */
  scrollbar-width: thin;
  scrollbar-color: var(--t-line) transparent;
}
.t-line {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.t-line + .t-line {
  margin-top: 0.15em;
}
.t-prompt,
.t-bash,
.t-tool,
.t-say,
.t-spin {
  display: grid;
  grid-template-columns: 2ch minmax(0, 1fr);
}
/* Space before each new turn, tool call, or box. */
.t-line.t-prompt,
.t-line.t-bash,
.t-line.t-tool,
.t-line.t-say,
.t-line.t-code,
.t-line.t-table,
.t-line.t-ask {
  margin-top: 0.6em;
}
.t-prompt,
.t-bash {
  color: #c9ced6;
}
.t-sigil {
  color: var(--t-dim);
}
.t-bash .t-sigil,
.t-input.is-bash .t-sigil {
  color: var(--t-bash);
}
.t-result,
.t-hang {
  display: grid;
  grid-template-columns: 5ch minmax(0, 1fr);
}
.t-elbow {
  white-space: pre;
  color: var(--t-dim);
}
.t-dim {
  color: var(--t-dim);
}
.t-ok {
  color: var(--t-ok);
}
.t-star {
  color: var(--t-star);
}
.t-tool b {
  font-weight: 700;
}

.t-box {
  display: inline-block;
  max-width: 100%;
  box-sizing: border-box;
  padding: 0.4em 1.2em 0.4em 0.9em;
  border: 1px solid var(--t-star);
  border-radius: 6px;
}
.t-box-title {
  margin-bottom: 0.4em;
}

.t-code-box {
  margin-left: 2ch;
  padding: 0.3em 0;
  border: 1px solid var(--t-line);
  border-radius: 6px;
  white-space: normal;
}
.t-code-file {
  padding: 0 0.9em 0.2em;
  color: var(--t-dim);
  overflow-wrap: anywhere;
}
.t-cl {
  display: flex;
  padding: 0 0.9em 0 0.4em;
}
.t-mark {
  flex: none;
  width: 2ch;
  color: var(--t-dim);
}
.t-src {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: pre;
}
.t-add {
  background: rgb(46 160 67 / 0.22);
}
.t-add .t-mark {
  color: var(--t-ok);
}
.t-del {
  background: rgb(248 81 73 / 0.2);
}
.t-del .t-mark {
  color: #f0938c;
}

.t-grid {
  margin-left: 2ch;
  border-collapse: collapse;
  white-space: normal;
  font-size: 0.92em;
}
.t-grid th,
.t-grid td {
  padding: 0.15em 0.6em;
  border: 1px solid var(--t-line);
  text-align: left;
  vertical-align: top;
}
.t-grid th {
  font-weight: 700;
}

.t-ask-box {
  padding: 0.4em 0.9em;
  border: 1px solid var(--t-line);
  border-radius: 6px;
}
.t-q {
  margin-bottom: 0.2em;
  font-weight: 700;
}
.t-opt.is-sel {
  color: var(--t-sel);
}
.t-opt.is-picked {
  font-weight: 700;
}

.t-input {
  display: grid;
  grid-template-columns: 2ch minmax(0, 1fr);
  flex: none;
  margin-top: 0.7em;
  padding: 0.3em 0.8em;
  border: 1px solid var(--t-line);
  border-radius: 6px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.t-input.is-bash {
  border-color: var(--t-bash);
}
.t-caret {
  display: inline-block;
  width: 0.6em;
  height: 1.15em;
  margin-left: 1px;
  vertical-align: text-bottom;
  background: var(--t-fg);
  opacity: 0.75;
  animation: t-blink 1.1s steps(1) infinite;
}
.term.is-typing .t-caret {
  animation: none;
}
@keyframes t-blink {
  50% {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .t-caret {
    animation: none;
  }
}

/* ------------------------------------------------------------------------------------------
   The cast (cast.js): one cat symbol coloured per cat; idle life and poses.
   ------------------------------------------------------------------------------------------ */
.cat {
  --cat-wag: none;
  --cat-breathe: none;
  --cat-blink: none;
  position: relative;
  width: 140px;
  aspect-ratio: 140 / 190;
}
.cat[data-cat="duna"] {
  --coat: #9aa3ad;
  --stripe: #59626d;
  --light: #eceff2;
  --iris: #e3a72f;
  --nose: #e48b8b;
}
.cat[data-cat="dudu"] {
  --coat: #8c939c;
  --stripe: #8c939c;
  --light: #b9bfc6;
  --iris: #8fc27a;
  --nose: #c98a8f;
}
.cat[data-cat="nangnang"] {
  --coat: #b48c5f;
  --stripe: #5a4230;
  --light: #f2e7d7;
  --iris: #b9c25a;
  --nose: #d98579;
}
.cat-svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.cast-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}
/* Inside the symbol (styled through <use>; the variables reach it by inheritance). */
.cat-o {
  stroke: var(--cat-edge);
  stroke-width: 1.5;
  stroke-linejoin: round;
}
.cat-tail {
  transform-origin: 92px 150px;
  animation: var(--cat-wag);
}
.cat-breath {
  transform-origin: 70px 182px;
  animation: var(--cat-breathe);
}
.cat-eye {
  transform-box: fill-box;
  transform-origin: center;
  animation: var(--cat-blink);
}
.cat-paw-l {
  opacity: var(--cat-paw-l, 1);
}
.cat-paw-r {
  opacity: var(--cat-paw-r, 1);
}
.cat.is-idle {
  --cat-wag: cat-wag 1.8s ease-in-out var(--cat-delay, 0s) infinite;
  --cat-breathe: cat-breathe 3s ease-in-out var(--cat-delay, 0s) infinite;
  --cat-blink: cat-blink 4.5s var(--cat-delay, 0s) infinite;
}
@keyframes cat-wag {
  50% {
    transform: rotate(10deg);
  }
}
@keyframes cat-breathe {
  50% {
    transform: scale(1.015, 0.99);
  }
}
@keyframes cat-blink {
  0%,
  93%,
  100% {
    transform: scaleY(1);
  }
  96% {
    transform: scaleY(0.1);
  }
}

/* Poses: overlays over the symbol, hidden until their pose. */
.cat-ground {
  fill: var(--cat-shadow);
  transform-origin: 70px 186px;
}
.cat-figure {
  transform-origin: 70px 186px;
}
.cat-wave,
.cat-tuck,
.cat-tap,
.cat-lids {
  display: none;
}
.cat-wave-edge {
  fill: none;
  stroke: var(--cat-edge);
  stroke-width: 17;
  stroke-linecap: round;
}
.cat[data-pose="wave"] {
  --cat-paw-r: 0;
}
.cat[data-pose="wave"] .cat-wave {
  display: inline;
  transform-origin: 88px 134px;
  animation: cat-pose-wave 1.2s ease-in-out infinite;
}
@keyframes cat-pose-wave {
  0%,
  100% {
    transform: rotate(-4deg);
  }
  50% {
    transform: rotate(14deg);
  }
}
.cat[data-pose="jump"],
.cat[data-pose="tap"] {
  --cat-paw-l: 0;
  --cat-paw-r: 0;
}
.cat[data-pose="jump"] .cat-tuck {
  display: inline;
}
.cat[data-pose="jump"] .cat-figure {
  animation: cat-pose-jump 1s cubic-bezier(0.3, 0, 0.3, 1) infinite;
}
.cat[data-pose="jump"] .cat-ground {
  animation: cat-pose-ground 1s cubic-bezier(0.3, 0, 0.3, 1) infinite;
}
@keyframes cat-pose-jump {
  0%,
  100% {
    transform: none;
  }
  14% {
    transform: scale(1.05, 0.93);
  }
  46% {
    transform: translateY(-34px) rotate(-5deg);
  }
  80% {
    transform: translateY(-4px);
  }
  90% {
    transform: scale(1.03, 0.96);
  }
}
@keyframes cat-pose-ground {
  46% {
    transform: scale(0.6);
    opacity: 0.6;
  }
}
.cat[data-pose="tap"] .cat-tap {
  display: inline;
}
.cat[data-pose="tap"] .cat-tap-l {
  animation: cat-pose-tap 0.7s ease-in-out infinite;
}
.cat[data-pose="tap"] .cat-tap-r {
  animation: cat-pose-tap 0.7s ease-in-out -0.35s infinite;
}
@keyframes cat-pose-tap {
  0%,
  50%,
  100% {
    transform: none;
  }
  25% {
    transform: translateY(-7px);
  }
}
.cat[data-pose="blink"] .cat-lids {
  display: inline;
}
.cat-lid {
  transform-box: fill-box;
  transform-origin: 50% 0;
  transform: scaleY(0);
}
.cat-lash {
  opacity: 0;
}
.cat[data-pose="blink"] .cat-lid {
  animation: cat-pose-lid 3s ease-in-out infinite;
}
.cat[data-pose="blink"] .cat-lash {
  animation: cat-pose-lash 3s ease-in-out infinite;
}
@keyframes cat-pose-lid {
  0%,
  12%,
  88%,
  100% {
    transform: scaleY(0);
  }
  38%,
  62% {
    transform: scaleY(1);
  }
}
@keyframes cat-pose-lash {
  0%,
  30%,
  70%,
  100% {
    opacity: 0;
  }
  38%,
  62% {
    opacity: 1;
  }
}
/* Reduced motion: no idle life; each pose holds its key frame. */
@media (prefers-reduced-motion: reduce) {
  .cat.is-idle {
    --cat-wag: none;
    --cat-breathe: none;
    --cat-blink: none;
  }
  .cat .cat-svg * {
    animation: none !important;
  }
  .cat[data-pose="wave"] .cat-wave {
    transform: rotate(8deg);
  }
  .cat[data-pose="jump"] .cat-figure {
    transform: translateY(-28px) rotate(-4deg);
  }
  .cat[data-pose="jump"] .cat-ground {
    transform: scale(0.65);
    opacity: 0.6;
  }
  .cat[data-pose="tap"] .cat-tap-l {
    transform: translateY(-7px);
  }
  .cat[data-pose="blink"] .cat-lid {
    transform: scaleY(1);
  }
  .cat[data-pose="blink"] .cat-lash {
    opacity: 1;
  }
}

/* ------------------------------------------------------------------------------------------
   The pen (pen.js): marks and notes, placed in a positioned layer in its own units.
   ------------------------------------------------------------------------------------------ */
.pen-mark {
  position: absolute;
  overflow: visible;
  pointer-events: none;
  color: var(--pen-desk);
}
.pen-mark path {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1 2;
  stroke-dashoffset: 1.05; /* hidden until drawn */
}
.pen-note {
  position: absolute;
  margin: 0;
  color: var(--pen-desk);
  font-family: var(--pen-font);
  line-height: 1.05;
  white-space: pre;
  pointer-events: none;
}
.pen-mark[data-ink="paper"],
.pen-note[data-ink="paper"] {
  color: var(--pen);
}
/* On a terminal card (dark in both themes). */
.pen-mark[data-ink="term"] {
  color: var(--pen-term);
}

/* ------------------------------------------------------------------------------------------
   The kit page (index.html?kit, kit.js).
   ------------------------------------------------------------------------------------------ */
.is-kit > :not(.site-title, .kit, .cast-defs) {
  display: none;
}
.kit {
  box-sizing: border-box;
  max-width: 1120px;
  margin: 0 auto;
  padding: 8px 16px 48px;
}
.kit h2 {
  margin: 24px 0 8px;
  font: 600 20px/1.3 var(--ui);
}
.kit-row {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 8px 24px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}
.kit-row h3 {
  width: 96px;
  margin: 0;
  font: 600 16px/1.3 var(--ui);
}
.kit-cell {
  margin: 0;
  text-align: center;
}
.kit-cell .cat {
  width: 130px;
  margin-top: 40px; /* room for the jump */
}
.kit-cell figcaption {
  color: var(--muted);
  font-size: 14px;
}
.kit-desk {
  position: relative;
  min-height: 420px;
}
.kit-paper {
  position: relative;
  box-sizing: border-box;
  width: min(100%, 600px);
  margin: 56px 0 0;
  padding: 24px 28px;
  background: var(--paper);
  color: #1d232b;
  font: 17px/1.5 var(--serif);
  box-shadow:
    0 1px 2px rgb(0 0 0 / 0.06),
    0 6px 24px rgb(0 0 0 / 0.1);
}
.kit-paper p {
  margin: 14px 0 0;
}
.kit-replay {
  min-height: 44px;
  padding: 0 18px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  font: 600 15px var(--ui);
  cursor: pointer;
}
