/* Every page's sheet, the front page's included (it adds home.css after this
   one for its own sections, so a rule here that the front page must not take
   is overridden there rather than scoped here).

   The tokens are the site's, in two themes, and this is the one place they
   are defined (docs/site-pages-design.md). Three states, as on the front
   page: no data-theme on <html> follows the system, data-theme="light" or
   "dark" overrides it (theme.js sets it from the toggle and from what the
   toggle saved). The older names (--border, --border-soft, --output-bg,
   --code-bg-soft) stay as aliases because the Playground's editor bundle
   (site/play-ui/src/playground.css) reads them. */

/* The monospace face, served from /assets/ like everything else: the site
   makes no request to anybody but itself. The names are rewritten to the
   hashed ones when the generator writes this file (gen/pages.repoint_url),
   and resolve next to it. */
@font-face {
  font-family: "JetBrains Mono";
  src: url("JetBrainsMono-Regular.a9cb1cd8.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("JetBrainsMono-Medium.086c48df.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  /* the sky: day is a pale dawn, night is the indigo of before it */
  --day-top: #faf9ff;
  --day-mid: #f3f0ff;
  --day-low: #fbe9f3;
  --night: #0d1020;
  --dusk: #1d2040;
  --dawn-1: #4f46e5;
  --dawn-2: #7c3aed;
  --dawn-3: #db2777;
  --dawn-grad: linear-gradient(90deg, var(--dawn-1) 0%, var(--dawn-2) 50%, var(--dawn-3) 100%);
  --night-op: 0; --star-op: 0;

  --bg: #ffffff;
  --surface: #ffffff;
  --text: #1f2328;
  --muted: #57606a;
  /* 5.0:1 on --code-bg and 5.3:1 on white, so WCAG AA's 4.5:1 for the small
     text it is used on (the eyebrow, the Output badge, the Playground links) */
  --faint: #656d76;
  --line: #d0d7de;
  --line-soft: #e9ecf1;
  --accent: #7c3aed;
  --accent-hover: #6d28d9;
  --code-bg: #f6f8fa;
  --out-bg: #fbfcfd;
  --soft-bg: #fafbfc;
  --danger: #b42318;
  --shadow: 0 1px 2px rgba(31, 35, 40, 0.04), 0 10px 28px -20px rgba(31, 35, 40, 0.3);

  /* GitHub-light code colours */
  --k: #cf222e; --t: #9333ea; --f: #7c3aed; --s: #0a3069; --i: #0e7490; --n: #0550ae; --c: #6e7781;
  --hue-1: #4f46e5; --hue-2: #7c3aed; --hue-3: #db2777;

  /* text on the sky band */
  --sky-text: #1f2328; --sky-muted: #57606a; --sky-faint: #656d76; --sky-strong: #1f2328;
  --sky-line: rgba(31, 35, 40, 0.12); --sky-hover: rgba(31, 35, 40, 0.05);
  /* the band's own: the horizon glow, the chips' ground, the current section
     (a deeper ink and a heavier line by day), the title's ink */
  --glow-1: rgba(124, 58, 237, 0.15); --glow-2: rgba(219, 39, 119, 0.075);
  --chip-bg: rgba(255, 255, 255, 0.55);
  --nav-on: #3b1d8f; --nav-on-shadow: 0.012em 0 0 currentColor; --ink-h: 3px;
  --title-ink: linear-gradient(100deg, #1b1745 0%, #2e1a6b 55%, #4a1747 100%);

  /* the older names, for the rules (and the editor bundle) that read them */
  --border: var(--line);
  --border-soft: var(--line-soft);
  --output-bg: var(--out-bg);
  --code-bg-soft: var(--soft-bg);

  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB",
    "Microsoft YaHei", sans-serif;

  --max: 66rem;      /* the page */
  --col: 46rem;      /* a single reading column */
  --measure: 66ch;   /* prose inside it */
  --rail: 12.5rem;   /* the contents rail */
  --gap: 3rem;
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0f1117; --surface: #0f1117; --text: #e6edf3; --muted: #9198a1; --faint: #8b949e;
    --line: #30363d; --line-soft: #21262d; --accent: #a78bfa; --accent-hover: #c4b5fd;
    --code-bg: #161b22; --out-bg: #12161d; --soft-bg: #12161d; --danger: #ff7b72;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 10px 28px -20px rgba(0, 0, 0, 0.7);
    --k: #ff7b72; --t: #d2a8ff; --f: #c4b5fd; --s: #a5d6ff; --i: #67e8f9; --n: #79c0ff; --c: #8b949e;
    --hue-1: #818cf8; --hue-2: #a78bfa; --hue-3: #f472b6;
    --night-op: 1; --star-op: 1;
    --sky-text: #e6e8f0; --sky-muted: #9ea3b8; --sky-faint: #8b90a8; --sky-strong: #ffffff;
    --sky-line: rgba(230, 232, 240, 0.12); --sky-hover: rgba(255, 255, 255, 0.06);
    --glow-1: rgba(167, 139, 250, 0.20); --glow-2: rgba(244, 114, 182, 0.10);
    --chip-bg: rgba(255, 255, 255, 0.03);
    --nav-on: #e6e8f0; --nav-on-shadow: none; --ink-h: 2px;
    --title-ink: linear-gradient(100deg, #ffffff 0%, #f1ecff 55%, #fde7f3 100%);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: #0f1117; --surface: #0f1117; --text: #e6edf3; --muted: #9198a1; --faint: #8b949e;
  --line: #30363d; --line-soft: #21262d; --accent: #a78bfa; --accent-hover: #c4b5fd;
  --code-bg: #161b22; --out-bg: #12161d; --soft-bg: #12161d; --danger: #ff7b72;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 10px 28px -20px rgba(0, 0, 0, 0.7);
  --k: #ff7b72; --t: #d2a8ff; --f: #c4b5fd; --s: #a5d6ff; --i: #67e8f9; --n: #79c0ff; --c: #8b949e;
  --hue-1: #818cf8; --hue-2: #a78bfa; --hue-3: #f472b6;
  --night-op: 1; --star-op: 1;
  --sky-text: #e6e8f0; --sky-muted: #9ea3b8; --sky-faint: #8b90a8; --sky-strong: #ffffff;
  --sky-line: rgba(230, 232, 240, 0.12); --sky-hover: rgba(255, 255, 255, 0.06);
  --glow-1: rgba(167, 139, 250, 0.20); --glow-2: rgba(244, 114, 182, 0.10);
  --chip-bg: rgba(255, 255, 255, 0.03);
  --nav-on: #e6e8f0; --nav-on-shadow: none; --ink-h: 2px;
  --title-ink: linear-gradient(100deg, #ffffff 0%, #f1ecff 55%, #fde7f3 100%);
  color-scheme: dark;
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* 预留滚动条槽位：短页（如 Playground）与长页切换时不再左右漂移 */
  scrollbar-gutter: stable;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.75 var(--sans);
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); text-decoration: underline; text-underline-offset: 0.18em; }
code, pre, kbd { font-family: var(--mono); font-variant-ligatures: none; font-feature-settings: "liga" 0, "calt" 0; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }

h1 { font-size: 1.75rem; line-height: 1.35; margin: 0 0 1.25rem; }
h2 { font-size: 1.32rem; line-height: 1.4; margin: 2.5rem 0 0.75rem; }
h3 { font-size: 1.08rem; line-height: 1.4; margin: 1.75rem 0 0.5rem; }
h1, h2, h3 { font-weight: 680; letter-spacing: -0.015em; }
p { margin: 0.85rem 0; }
ul, ol { padding-left: 1.5rem; margin: 0.85rem 0; }
li { margin: 0.3rem 0; }

code {
  font-size: 0.875em;
  background: var(--code-bg);
  border-radius: 5px;
  padding: 0.15em 0.4em;
}

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 16px; }
@media (min-width: 720px) { .wrap { padding: 0 2rem; } }

/* ---- the reading-progress line ----
   The site's 3px gradient across the top. Where the browser can drive an
   animation from scroll it grows with the page; elsewhere it is the full
   line the site always had. */
.progress { position: fixed; z-index: 20; top: 0; left: 0; right: 0; height: 3px; background: var(--dawn-grad); transform-origin: 0 50%; pointer-events: none; }
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: scroll()) {
    .progress { animation: progress-grow linear both; animation-timeline: scroll(root); }
    @keyframes progress-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  }
}

/* ---- the sky ----
   The front page's sky, cut down on every other page to a short band that
   holds the nav and the page's title (html/page.shell_ext). The night is a
   layer over the day, so it is one opacity away in either theme. */
.sky {
  position: relative;
  color: var(--sky-text);
  background: linear-gradient(180deg, var(--day-top) 0%, var(--day-mid) 70%, var(--day-low) 100%);
  overflow: hidden;
}
.sky::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, var(--night) 0%, var(--dusk) 100%);
  opacity: var(--night-op);
}
.sky > .wrap { position: relative; }
.stars { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; opacity: var(--star-op); }
/* the band's own horizon: a low glow where the sun would come up, and the
   line itself (the front page draws its own, with the sun and moon on it) */
header.sky > .glow {
  position: absolute; left: 50%; bottom: 0; width: max(100%, 1100px); height: 150px; transform: translateX(-50%);
  background: radial-gradient(50% 100% at 50% 100%, var(--glow-1), var(--glow-2) 45%, transparent 75%);
  pointer-events: none;
}
header.sky::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: var(--dawn-grad); }
/* The cat looking over the band's lower edge (html/page.band_cat): a
   zero-height bar on the band's bottom, as wide as the page, holds it at the
   right, ears and eyes above the line, the rest below it where the band
   clips it, and the line (::after, painted after it) runs across its chest.
   It stands in the band's bottom padding, clear of the chips at every width,
   and takes no room: the band's height does not change. Awake by day, asleep
   by night: the theme's --night-op picks the drawing, so the eyes change with
   the theme inside the switch's circle, with no tween of their own. */
header.sky > .peek { position: absolute; left: 0; right: 0; bottom: 0; height: 0; max-width: var(--max); margin: 0 auto; pointer-events: none; }
header.sky > .peek > span { position: absolute; right: 3rem; bottom: -16px; width: 62px; height: 50px; }
header.sky > .peek svg { position: absolute; inset: 0; width: 100%; height: 100%; }
header.sky > .peek .awake { opacity: calc(1 - var(--night-op)); }
header.sky > .peek .asleep { opacity: var(--night-op); }
@media (max-width: 719px) { header.sky > .peek > span { right: 16px; bottom: -12px; width: 48px; height: 39px; } }

/* ---- the nav (html/page.nav_bar: the same markup on every page) ----
   One row: the mark and its release, the sections, the tools, the toggle.
   Nothing in it moves on hover but colour; the one thing that travels is
   the line under the current section (theme.js slides it). Not sticky: the
   page already holds the reading-progress line and the contents rail at the
   top of the screen, and a third fixed layer would take the room they use. */
.site-nav {
  position: relative;
  display: flex; align-items: center;
  gap: 0.5rem 1.2rem;
  padding: 0.85rem 0;
  font-size: 0.92rem;
  border-bottom: 1px solid var(--sky-line);
}
.site-nav > * { flex: none; }
.site-nav .id { display: flex; align-items: center; gap: 0.6rem; margin-right: auto; }
.site-nav .brand {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-weight: 780; font-size: 1.14rem; letter-spacing: -0.03em; line-height: 1;
  color: var(--sky-strong);
}
.site-nav .brand:hover { text-decoration: none; color: var(--sky-strong); }
.brand-logo { width: 1.6em; height: 1.6em; display: block; }
.site-nav .brand .word { padding-right: 0.04em; }
/* the release this site was built from, with the dawn as its dot */
.site-nav .release {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font: 500 0.68rem/1 var(--mono); letter-spacing: 0.01em; color: var(--sky-faint);
  padding: 0.28rem 0.5rem 0.28rem 0.45rem; border: 1px solid var(--sky-line); border-radius: 999px;
}
.site-nav .release::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--dawn-grad); }
.site-nav .release:hover { color: var(--sky-text); text-decoration: none; border-color: color-mix(in srgb, var(--sky-text) 25%, transparent); }

/* The sections reach down to the nav's rule (the negative margin gives the
   padding back, so the row's height is not touched), so that the line under
   the current one can sit on the rule itself. */
.site-nav .links {
  position: relative; display: flex; gap: 1.05rem;
  align-self: stretch; margin-block: -0.85rem; padding-block: 0.85rem;
}
.site-nav .links a { position: relative; display: flex; align-items: center; color: var(--sky-muted); white-space: nowrap; }
.site-nav .links a:hover { color: var(--sky-text); text-decoration: none; }
/* The page you are on: the deepest ink of the dawn and a heavier line by
   day, where the plain ink read as barely different from its neighbours on
   the pale sky; by night the ink and the 2px line as they were. No weight
   change: a bolder item is a wider one, and the row would shift on
   navigation; the hair of a shadow thickens the strokes without moving
   anything. */
.site-nav .links a.active { color: var(--nav-on); text-shadow: var(--nav-on-shadow); }
.site-nav .links a.active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: calc(-0.85rem - 1px); height: var(--ink-h);
  border-radius: 2px; background: var(--dawn-grad);
}
/* with theme.js, one line that slides between the sections instead */
.site-nav.has-ink .links a.active::after { display: none; }
.site-nav .ink {
  position: absolute; left: 0; bottom: -1px; width: 0; height: var(--ink-h); border-radius: 2px;
  background: var(--dawn-grad); opacity: 0; pointer-events: none;
}

.site-nav .tools { display: flex; align-items: center; gap: 0.75rem; }
.site-nav .tools > * { flex: none; white-space: nowrap; }
/* The other language, set apart with a hairline so it does not read as one
   more section of the site. */
.site-nav .tools a.lang { color: var(--sky-muted); border: 1px solid var(--sky-line); border-radius: 999px; padding: 0.1rem 0.6rem; font-size: 0.82rem; }
.site-nav .tools a.lang:hover { color: var(--sky-text); background: var(--sky-hover); text-decoration: none; }
.site-nav .gh { display: inline-grid; place-items: center; color: var(--sky-muted); }
.site-nav .gh:hover { color: var(--sky-text); }
.site-nav .gh svg { width: 18px; height: 18px; fill: currentColor; }
/* search and the theme: two round buttons of one size */
.site-nav button {
  display: inline-grid; place-items: center; width: 2rem; height: 2rem; padding: 0; cursor: pointer;
  color: var(--sky-muted); background: transparent; border: 1px solid var(--sky-line); border-radius: 999px;
}
.site-nav button:hover { color: var(--sky-text); background: var(--sky-hover); }
.site-nav button[hidden] { display: none; }
.site-nav .search-open svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
/* the theme toggle: sun and moon cross-fade with a quarter turn */
.theme-toggle svg { width: 15px; height: 15px; overflow: visible; }
.theme-toggle .ico-sun, .theme-toggle .ico-moon { transform-box: fill-box; transform-origin: center; }
.theme-toggle .ico-moon { opacity: 0; transform: rotate(-90deg) scale(0.6); }
:root[data-theme="dark"] .theme-toggle .ico-sun { opacity: 0; transform: rotate(90deg) scale(0.6); }
:root[data-theme="dark"] .theme-toggle .ico-moon { opacity: 1; transform: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .ico-sun { opacity: 0; transform: rotate(90deg) scale(0.6); }
  :root:not([data-theme="light"]) .theme-toggle .ico-moon { opacity: 1; transform: none; }
}
/* Two rows below 900px, where one does not fit: the mark, the tools and the
   toggle on the first, the sections on the second, scrolling sideways under
   faded edges with no scrollbar drawn (theme.js brings the current one into
   view). GitHub goes (the footer has it); on the narrowest phones the release
   pill too. */
@media (max-width: 899px) {
  .site-nav { flex-wrap: wrap; gap: 0.55rem; padding: 0.65rem 0 0; }
  .site-nav .id { order: 1; }
  .site-nav .tools { order: 2; gap: 0.5rem; }
  .site-nav .theme-toggle { order: 3; }
  .site-nav .gh { display: none; }
  .site-nav .links {
    order: 4; width: calc(100% + 4rem); margin: 0 -2rem; padding: 0.3rem 2rem 0.65rem; gap: 1.05rem;
    align-self: auto; font-size: 0.88rem; overflow-x: auto; scrollbar-width: none;
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 16px, #000 calc(100% - 28px), transparent);
    mask-image: linear-gradient(90deg, transparent 0, #000 16px, #000 calc(100% - 28px), transparent);
  }
  .site-nav .links::-webkit-scrollbar { display: none; }
  .site-nav .links a.active::after { bottom: -0.65rem; }
  .site-nav .ink { bottom: 0; }
}
@media (max-width: 719px) {
  .site-nav .links { width: calc(100% + 32px); margin: 0 -16px; padding-inline: 16px; }
}
@media (max-width: 380px) { .site-nav .release { display: none; } }

/* ---- the page's head, in the band ----
   The trail (where the page sits), the title, the lede, then the row of
   facts. The title is set in a dawn-tinted ink, night indigo to plum by day
   and moonlight by night: one quiet gradient, well below the front page's
   wordmark, where pure black read stiff on the pale sky. */
.page-head { position: relative; padding: 2.4rem 0 2.6rem; }
@media (min-width: 720px) { .page-head { padding: 3.1rem 0 3.3rem; } }
.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 0.1rem 0.55rem; margin: 0 0 0.9rem; font: 0.75rem/1.5 var(--mono); letter-spacing: 0.02em; color: var(--sky-faint); }
.crumbs a { color: var(--sky-muted); }
.crumbs a:hover { color: var(--sky-text); }
.crumbs .sep { opacity: 0.45; }
.crumbs [aria-current] { color: var(--sky-text); }
.crumbs code { font: inherit; background: none; padding: 0; color: inherit; }
.page-head h1 {
  margin: 0; color: var(--sky-strong); font-weight: 720;
  font-size: clamp(2.15rem, 1.35rem + 3vw, 3.35rem); line-height: 1.06; letter-spacing: -0.04em;
  text-wrap: balance;
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  /* The ink is painted only inside the h1's own box, and at this line-height
     a face whose ascent is tall beside its descent (SF, Helvetica) puts the
     tails of g, y, p and j below the box, where they were cut off. The box
     reaches 0.25em further down and 0.15em further up than the line, and the
     margins give the same back, so nothing around it moves. */
  .page-head h1 {
    color: transparent; background: var(--title-ink); -webkit-background-clip: text; background-clip: text;
    padding: 0.15em 0 0.25em; margin: -0.15em 0 -0.19em;
  }
}
/* tracking that tight blurs Chinese glyphs together */
.page-head:lang(zh-CN) h1 { letter-spacing: -0.012em; line-height: 1.14; }
.page-head h1 code { font-family: var(--mono); font-weight: 500; letter-spacing: -0.02em; font-size: 0.9em; background: none; border: 0; padding: 0; color: inherit; }
/* a chapter's number, in the label face and the accent, as in the body */
.page-head h1 .n { font: 500 0.62em var(--mono); letter-spacing: 0; color: var(--accent); -webkit-text-fill-color: var(--accent); vertical-align: 0.18em; }
.page-head .lede { margin: 1rem 0 0; max-width: 40rem; font-size: 1.08rem; line-height: 1.65; color: var(--sky-muted); text-wrap: pretty; }
.page-head .lede a { color: var(--sky-text); text-decoration: underline; text-decoration-color: var(--sky-line); text-underline-offset: 0.2em; }
.page-head .lede code { font-size: 0.86em; background: var(--sky-hover); padding: 0.08em 0.35em; border-radius: 4px; color: var(--sky-text); }
/* the facts: small outlined chips, the ones that lead somewhere linked */
.page-head .meta { list-style: none; display: flex; flex-wrap: wrap; align-items: center; gap: 0.45rem; margin: 1.4rem 0 0; padding: 0; }
.page-head .chip {
  display: inline-flex; align-items: center; gap: 0.4rem; height: 1.7rem; margin: 0; padding: 0 0.62rem;
  font: 0.72rem/1 var(--mono); letter-spacing: 0.01em; color: var(--sky-muted); white-space: nowrap;
  border: 1px solid var(--sky-line); border-radius: 999px; background: var(--chip-bg);
}
.page-head .chip a { color: inherit; display: inline-flex; align-items: center; gap: 0.4rem; }
.page-head .chip a:hover { color: var(--sky-text); text-decoration: none; }
.page-head .chip code { font: inherit; background: none; padding: 0; color: inherit; }
.page-head .chip .ci { width: 12px; height: 12px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; opacity: 0.8; }
.page-head .chip.rel::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--dawn-grad); }
.page-head .chip.step { padding: 0 0.2rem; gap: 0.15rem; }
.page-head .chip.step span { padding: 0 0.35rem; }
.page-head .chip.step a { width: 1.3rem; height: 1.3rem; justify-content: center; border-radius: 999px; color: var(--sky-faint); }
.page-head .chip.step a:hover { color: var(--sky-text); background: var(--sky-hover); }
.page-head .chip.step svg { width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
/* over a single column, the head lines up with the column */
.page-head.col { max-width: var(--col); margin-left: auto; margin-right: auto; }

/* ---- layouts below the line ---- */
.col { max-width: var(--col); margin-left: auto; margin-right: auto; }
main.page { padding-top: 2.75rem; padding-bottom: 1rem; }
.with-toc { display: block; }
@media (min-width: 960px) {
  .with-toc { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); column-gap: var(--gap); }
  .with-toc > article { min-width: 0; }
  .with-toc > article pre { font-size: 0.8rem; }
  /* the title lines up with the article, not with the rail */
  .page-head.toc-aligned { padding-left: calc(var(--rail) + var(--gap)); }
}

/* ---- prose ----
   Paragraphs, lists and quotes keep a measure of about 66 characters (33
   Chinese ones); code and tables may use the whole column. */
.prose { font-size: 1.02rem; line-height: 1.78; min-width: 0; }
.prose > p, .prose > ul, .prose > ol, .prose li > p, .prose blockquote > p, .prose blockquote > ul { max-width: var(--measure); }
.prose p { margin: 0.95rem 0; text-wrap: pretty; }
.prose > :first-child { margin-top: 0; }
.prose ul, .prose ol { padding-left: 1.35rem; margin: 0.95rem 0; }
.prose li { margin: 0.35rem 0; }
.prose li::marker { color: var(--faint); }
.prose strong { font-weight: 650; }
.prose h2, .prose h3, .prose h4 { position: relative; scroll-margin-top: 1.5rem; text-wrap: balance; }
.prose h2 { font-weight: 720; font-size: 1.5rem; line-height: 1.3; letter-spacing: -0.022em; margin: 3.4rem 0 0.9rem; padding-top: 1.6rem; border-top: 1px solid var(--line-soft); }
.prose h3 { font-weight: 680; font-size: 1.14rem; line-height: 1.4; letter-spacing: -0.014em; margin: 2.3rem 0 0.6rem; }
.prose h4 { font-weight: 650; font-size: 1rem; line-height: 1.45; margin: 1.8rem 0 0.5rem; }
.prose > h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
/* section numbers in the label face, so the eye can run down them */
.hn { font: 500 0.78em var(--mono); letter-spacing: 0; color: var(--accent); margin-right: 0.55em; }
.prose h2 code, .prose h3 code, .prose h4 code { font-size: 0.86em; }
.anchor { margin-left: 0.4em; font: 400 0.8em var(--mono); color: var(--faint); opacity: 0; }
:is(h2, h3, h4):hover > .anchor, .anchor:focus-visible { opacity: 1; }
.anchor:hover { color: var(--accent); text-decoration: none; }
.prose hr { border: 0; height: 1px; background: var(--line-soft); margin: 2.6rem 0; }
.prose del { color: var(--faint); text-decoration-color: color-mix(in srgb, var(--faint) 70%, transparent); }
.prose :not(pre) > code { font-size: 0.86em; color: var(--text); background: var(--code-bg); border: 1px solid var(--line-soft); padding: 0.05em 0.32em; border-radius: 5px; overflow-wrap: anywhere; }
.prose a > code { color: inherit; }

.prose blockquote {
  margin: 1.4rem 0; padding: 0.35rem 1.15rem;
  max-width: calc(var(--measure) + 3rem);
  border-left: 3px solid var(--accent);
  border-image: linear-gradient(180deg, var(--dawn-1), var(--dawn-2), var(--dawn-3)) 1;
  background: var(--soft-bg); color: var(--muted);
}
.prose blockquote p, .prose blockquote li { font-size: 0.97rem; }
.prose blockquote strong { color: var(--text); }
/* the document's status note: its first block (html/render.render_doc_play) */
.prose blockquote.status { border-radius: 0 10px 10px 0; padding: 0.6rem 1.3rem 0.6rem 1.2rem; }

/* ---- code ---- */
pre { margin: 1.35rem 0; background: var(--code-bg); border: 1px solid var(--line); border-radius: 10px; padding: 1rem 1.15rem; overflow-x: auto; font-size: 0.84rem; line-height: 1.65; color: var(--text); scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
pre code { font-size: inherit; background: none; border: 0; padding: 0; }
@media (max-width: 719px) { pre { font-size: 0.78rem; padding: 0.85rem 0.95rem; } }
/* the highlighter's classes (site/src/hl): k keyword, t type, f definition,
   s string, i interpolation, n number, c comment */
.k { color: var(--k); } .t { color: var(--t); } .f { color: var(--f); } .s { color: var(--s); } .i { color: var(--i); } .n { color: var(--n); } .c { color: var(--c); }

/* 输出块：右上角角标。这张样式表两棵语言树共用，所以角标的文字得跟着页面语言走：
   默认写英文（站点默认语言，<html lang="en">），中文树由下面那条 lang 限定的规则覆盖。
   site/src/gen/assets.dawn 会盯着这里——CSS 注入的文字绕过了 #172 的双语外壳。 */
pre.output { position: relative; background: var(--out-bg); border-style: dashed; }
pre.output::before { content: "Output"; position: absolute; top: 0.45rem; right: 0.8rem; font: 0.68rem var(--mono); color: var(--faint); }
html[lang="zh-CN"] pre.output::before { content: "输出"; }

/* A program in a window (html/play.dawn): a bar with dots, a label and, for
   one the page offers to the Playground, the link; then the code; then the
   output it prints, in the same frame behind a dashed line. The link's words
   are in the markup (html/page.playground_label), not in a content: rule. */
.win { margin: 1.5rem 0; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; background: var(--code-bg); box-shadow: var(--shadow); }
.win-bar { display: flex; align-items: center; gap: 0.4rem; padding: 0.42rem 0.9rem; border-bottom: 1px solid var(--line); background: var(--surface); font: 0.72rem var(--mono); color: var(--faint); min-height: 2.1rem; }
.win-bar i { width: 8px; height: 8px; border-radius: 50%; background: var(--line); flex: none; }
.win-bar i:first-child { background: var(--hue, var(--accent)); opacity: 0.85; }
.win-bar .lbl { margin-left: 0.35rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.win-bar a.play-open { margin-left: auto; display: inline-flex; align-items: center; gap: 0.35rem; color: var(--faint); white-space: nowrap; }
.win-bar a.play-open::after { content: "↗"; font-size: 0.9em; }
.win-bar a.play-open:hover { color: var(--accent); text-decoration: none; }
.win pre { margin: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; }
.win pre.output { border-top: 1px dashed var(--line); background: var(--out-bg); }
.win.hue-1 { --hue: var(--hue-1); }
.win.hue-3 { --hue: var(--hue-3); }
/* an example's run: a terminal, the command after a $ (gen/examples.case_html) */
.win.run { --hue: var(--hue-3); background: var(--out-bg); }
.win .runline { margin: 0; padding: 0.7rem 1.15rem 0; background: var(--out-bg); font: 0.84rem/1.6 var(--mono); color: var(--muted); max-width: none; }
.win .runline code { background: none; border: 0; padding: 0; font-size: inherit; color: var(--text); }
.win .runline::before { content: "$ "; color: var(--faint); }
.win .runline + pre.output { border-top: 0; padding-top: 0.3rem; }
.win.run pre.output::before { display: none; }
.win.run > p:not(.runline) { margin: 0; padding: 0.6rem 1.15rem 0; font-size: 0.85rem; color: var(--faint); max-width: none; }
.win.run > p:not(.runline) + pre { padding-top: 0.3rem; }
@media (max-width: 719px) { .win .runline { font-size: 0.78rem; padding: 0.6rem 0.95rem 0; } }

/* ---- tables, in a scrolling frame (html/render.table_html) ---- */
.table-wrap { margin: 1.5rem 0; overflow-x: auto; border: 1px solid var(--line); border-radius: 10px; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
.table-wrap table { width: 100%; border-collapse: collapse; font-size: 0.9rem; line-height: 1.6; }
.table-wrap th, .table-wrap td { text-align: left; vertical-align: top; padding: 0.6rem 0.9rem; border-bottom: 1px solid var(--line-soft); }
.table-wrap tr:last-child td { border-bottom: 0; }
.table-wrap th { font: 500 0.7rem/1.4 var(--mono); letter-spacing: 0.05em; text-transform: uppercase; color: var(--faint); background: var(--code-bg); border-bottom: 1px solid var(--line); white-space: nowrap; }
.table-wrap td + td, .table-wrap th + th { border-left: 1px solid var(--line-soft); }
.table-wrap td.key, .table-wrap .date { white-space: nowrap; }
/* A phone shares 340px between the columns until a sentence runs two words
   to a line; past 20ch the frame scrolls sideways instead. */
@media (max-width: 719px) { .table-wrap td { min-width: 20ch; } }
.table-wrap tbody tr:hover td { background: color-mix(in srgb, var(--code-bg) 60%, transparent); }

/* ---- the contents rail (html/page.rail_html) ----
   A sticky column on a wide screen; below 960px a card at the top of the
   page, folded shut by theme.js. On a wide screen the summary is only the
   heading: no marker and no click, so the rail cannot be folded away by
   accident. */
.toc { font-size: 0.86rem; line-height: 1.45; min-width: 0; }
.toc > nav { position: sticky; top: 1.25rem; max-height: calc(100vh - 2.5rem); overflow-y: auto; padding: 0 0.4rem 1.5rem 0; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
.toc-title { display: block; list-style: none; font: 500 0.7rem/1.4 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--faint); margin: 0 0 0.7rem 0.5rem; }
.toc-title::-webkit-details-marker { display: none; }
.toc-fold > summary { pointer-events: none; }
.toc ul { list-style: none; margin: 0; padding: 0; }
.toc li { margin: 0; }
.toc a { display: block; padding: 0.26rem 0.5rem; border-radius: 6px; color: var(--muted); }
.toc a.has-n { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 0.5rem; }
.toc .tn { font: 0.72rem/1.75 var(--mono); color: var(--faint); min-width: 1.4rem; }
.toc a:hover { color: var(--text); background: var(--code-bg); text-decoration: none; }
.toc a:hover .tn { color: var(--accent); }
.toc a.cur { color: var(--text); background: var(--code-bg); box-shadow: inset 2px 0 0 var(--accent); border-radius: 0 6px 6px 0; }
.toc a.cur .tn { color: var(--accent); }
.toc ul ul { margin: 0.1rem 0 0.45rem 0.85rem; padding-left: 0.3rem; border-left: 1px solid var(--line-soft); font-size: 0.82rem; }
.toc ul ul a { padding-top: 0.2rem; padding-bottom: 0.2rem; }
@media (max-width: 959px) {
  .toc { margin: 0 0 2.25rem; }
  .toc > nav { position: static; max-height: none; overflow: visible; padding: 0; }
  .toc-fold { border: 1px solid var(--line); border-radius: 10px; background: var(--surface); padding: 0.6rem 0.75rem; box-shadow: var(--shadow); }
  .toc .toc-fold > summary { pointer-events: auto; cursor: pointer; display: flex; align-items: center; gap: 0.5rem; margin: 0; }
  .toc .toc-fold > summary::after { content: ""; width: 0.45rem; height: 0.45rem; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg); margin: -0.2rem 0 0 auto; }
  .toc .toc-fold[open] > summary { margin-bottom: 0.6rem; }
  .toc .toc-fold[open] > summary::after { transform: rotate(-135deg); margin-top: 0.2rem; }
  /* until theme.js has fitted the fold, it is held shut, so a narrow screen
     never shows it open for a frame; without the script it stays open */
  :root.js .toc-fold:not(.is-fit) > :not(summary) { display: none; }
}

/* ---- the tutorial ---- */
/* The chapters as a road (gen/tutorial.chapter_road): one line from indigo
   to magenta runs through the numbers, night to morning, first program to
   effects of your own. Each disc's colour is mixed along it by --p. */
.prose .chapters { list-style: none; margin: 0; padding: 0; position: relative; max-width: none; }
.chapters::before { content: ""; position: absolute; left: 1.15rem; top: 1.4rem; bottom: 1.4rem; width: 2px; border-radius: 2px; background: linear-gradient(180deg, var(--hue-1), var(--hue-2) 50%, var(--hue-3)); opacity: 0.35; }
.chapters li { margin: 0; position: relative; }
.chapters a {
  display: grid; grid-template-columns: 2.3rem minmax(0, 1fr) auto; align-items: center; column-gap: 1rem;
  padding: 0.62rem 0.85rem 0.62rem 0; border-radius: 10px; color: var(--text); font-size: 1.02rem; line-height: 1.45;
}
.chapters a:hover { text-decoration: none; background: var(--code-bg); color: var(--text); }
.chapters .cn {
  --c: color-mix(in oklab, var(--hue-1), var(--hue-3) calc(var(--p) * 100%));
  width: 2.3rem; height: 2.3rem; display: grid; place-items: center; border-radius: 50%;
  font: 500 0.78rem var(--mono); color: var(--c); background: var(--bg);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 40%, var(--line));
}
.chapters a:hover .cn { background: color-mix(in srgb, var(--c) 10%, var(--bg)); }
.chapters .ca { color: var(--faint); font-family: var(--mono); font-size: 0.85rem; opacity: 0; }
.chapters a:hover .ca { opacity: 1; color: var(--accent); }
@media (prefers-reduced-motion: no-preference) {
  .chapters a, .chapters .ca { transition: background-color 0.15s ease, opacity 0.15s ease, transform 0.15s ease; }
  .chapters .ca { transform: translateX(-4px); }
  .chapters a:hover .ca { transform: none; }
}
/* the previous and next chapters, as two cards */
.chapter-nav { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.9rem; margin-top: 3.5rem; padding-top: 1.75rem; border-top: 1px solid var(--line-soft); }
.chapter-nav a { display: flex; flex-direction: column; gap: 0.2rem; padding: 0.85rem 1rem 0.95rem; border: 1px solid var(--line); border-radius: 10px; color: var(--text); background: var(--surface); line-height: 1.45; }
.chapter-nav a:hover { text-decoration: none; border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.chapter-nav .dir { font: 0.72rem var(--mono); color: var(--faint); letter-spacing: 0.02em; }
.chapter-nav a:hover .dir { color: var(--accent); }
.chapter-nav .ttl { font-weight: 600; font-size: 0.98rem; }
.chapter-nav .next { text-align: right; grid-column: 2; }
@media (max-width: 559px) { .chapter-nav { grid-template-columns: 1fr; } .chapter-nav .next { grid-column: auto; } }

/* ---- history: a timeline (html/render.is_timeline) ----
   The early decisions' milestones and each period of the history page: the
   dawn gradient runs down the left edge, one dot per entry. */
.prose ul.timeline { list-style: none; padding: 0 0 0 1.6rem; margin: 1.4rem 0; position: relative; }
ul.timeline::before { content: ""; position: absolute; left: 0.3rem; top: 0.6rem; bottom: 0.6rem; width: 2px; border-radius: 2px; background: linear-gradient(180deg, var(--hue-1), var(--hue-2) 50%, var(--hue-3)); opacity: 0.45; }
ul.timeline > li { position: relative; margin: 0 0 1.4rem; max-width: var(--measure); }
ul.timeline > li::before { content: ""; position: absolute; left: -1.6rem; top: 0.55em; width: 0.75rem; height: 0.75rem; margin-left: -0.05rem; border-radius: 50%; background: var(--bg); box-shadow: inset 0 0 0 2px var(--accent); }
ul.timeline > li > strong:first-child, ul.timeline > li > p:first-child > strong:first-child { color: var(--text); font-weight: 700; }
ul.timeline ul { padding-left: 1.2rem; }

/* ---- the example gallery ---- */
.ex-group { --hue: var(--hue-1); }
.ex-group.hue-2 { --hue: var(--hue-2); }
.ex-group.hue-3 { --hue: var(--hue-3); }
.ex-group + .ex-group { margin-top: 2.6rem; }
.prose .ex-group h2 { display: flex; align-items: center; gap: 0.6rem; margin: 0 0 0.4rem; padding: 0; border: 0; font-size: 1.2rem; }
.prose .ex-group h2::before { content: ""; width: 0.55rem; height: 0.55rem; border-radius: 50%; background: var(--hue); flex: none; }
.ex-count { font: 500 0.7rem/1 var(--mono); color: var(--faint); border: 1px solid var(--line); border-radius: 999px; padding: 0.22rem 0.5rem; }
.prose .ex-list { list-style: none; padding: 0; margin: 0; border-top: 1px solid var(--line-soft); max-width: none; }
.prose .ex-list li { margin: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.15rem; padding: 0.8rem 0.25rem; border-bottom: 1px solid var(--line-soft); }
@media (min-width: 720px) { .prose .ex-list li { grid-template-columns: 13.5rem minmax(0, 1fr); column-gap: 1.25rem; } }
.ex-name { align-self: start; }
.prose .ex-name code { font-size: 0.88rem; background: none; border: 0; padding: 0; color: var(--text); overflow-wrap: anywhere; }
.ex-name:hover { text-decoration: none; }
.prose .ex-name:hover code { color: var(--accent); }
.ex-name code::before { content: ""; display: inline-block; width: 0.35rem; height: 0.35rem; border-radius: 50%; background: var(--hue); margin: 0 0.55rem 0.12rem 0; vertical-align: middle; opacity: 0.8; }
.prose .ex-desc { margin: 0; color: var(--muted); font-size: 0.95rem; line-height: 1.65; max-width: var(--measure); }
/* one example's page: its files are h2s over windows */
.prose h2 > code:only-child { background: none; border: 0; padding: 0; font-size: 0.8em; font-weight: 500; color: var(--muted); }

/* ---- the standard library ----
   A reference, so the spacing is set by how much a screen can scan. The
   group name sticks under the scroll line while its entries go by. */
.prose h3.api-group {
  position: sticky; top: 3px; z-index: 3;
  margin: 2.6rem 0 0; padding: 0.7rem 0 0.55rem;
  font: 500 0.95rem/1.4 var(--mono); letter-spacing: 0;
  background: var(--bg); border-bottom: 1px solid var(--line);
  display: flex; align-items: baseline; gap: 0.6rem;
}
.prose h3.api-group::before { content: ""; width: 0.5rem; height: 0.5rem; border-radius: 2px; background: var(--dawn-grad); align-self: center; flex: none; }
.prose h3.api-group + p { margin-top: 0.9rem; }
.api-item { padding: 1.05rem 0 1.15rem; border-bottom: 1px solid var(--line-soft); scroll-margin-top: 3.4rem; }
.api-item:target { background: linear-gradient(90deg, color-mix(in srgb, var(--accent) 7%, transparent), transparent 70%); box-shadow: inset 2px 0 0 var(--accent); padding-left: 0.9rem; }
.prose h3.api-name { margin: 0 0 0.5rem; font: 500 0.94rem/1.4 var(--mono); letter-spacing: 0; }
.api-name a { color: var(--text); }
.api-name a::after { content: "#"; margin-left: 0.4em; color: var(--faint); opacity: 0; }
.api-name a:hover { color: var(--accent); text-decoration: none; }
.api-name a:hover::after { opacity: 1; }
/* a signature is one line: it wraps with a hanging indent rather than scrolling */
.api-item pre.api-sig { white-space: pre-wrap; overflow-wrap: anywhere; text-indent: -1.6em; padding: 0.5rem 0.8rem 0.5rem calc(0.8rem + 1.6em); margin: 0 0 0.6rem; border-color: var(--line-soft); border-radius: 8px; font-size: 0.8rem; line-height: 1.55; }
/* break-word: a doc comment's slash-joined list (OPTIONS/PROPFIND/MKCOL/...)
   is one word, and on a phone it pushed the whole page sideways */
.api-doc { color: var(--muted); font-size: 0.96rem; line-height: 1.7; overflow-wrap: break-word; }
.api-doc p { margin: 0.45rem 0; max-width: var(--measure); }
.api-doc > :first-child { margin-top: 0; }
.api-doc > :last-child { margin-bottom: 0; }
.prose .api-doc code { color: var(--text); }
/* a doc's [`name`] link (spec 1.2): the code keeps its chip, in the link colour, so a linked name reads apart from a plain one */
.prose .api-doc a code, .api-members dd a code { color: var(--accent); }
.prose .api-doc a:hover code, .api-members dd a:hover code { color: var(--accent-hover); }
.api-members { margin: 0.75rem 0 0; padding: 0 0 0 0.9rem; border-left: 2px solid var(--line-soft); }
.api-members dt { margin: 0.6rem 0 0.15rem; font: 0.8rem/1.5 var(--mono); overflow-wrap: anywhere; }
.api-members dt:first-child { margin-top: 0; }
.api-members dd { margin: 0; color: var(--muted); font-size: 0.93rem; line-height: 1.65; }
.api-members dd p { margin: 0.3rem 0; max-width: var(--measure); }
.prose .api-members code { color: var(--text); }
/* a declaration's examples (spec 3.4): the bodies of the tests named by it, under a small label */
.api-examples { margin: 0.7rem 0 0; }
.prose .api-examples p.api-examples-title { margin: 0 0 0.3rem; font: 0.7rem/1.4 var(--mono); color: var(--faint); letter-spacing: 0.05em; text-transform: uppercase; }
.api-item pre.api-example { margin: 0 0 0.5rem; padding: 0.6rem 0.85rem; border-color: var(--line-soft); border-radius: 8px; font-size: 0.8rem; line-height: 1.55; }
.prose .api-impls { font-size: 0.88rem; color: var(--muted); padding: 0.55rem 0.8rem; border: 1px dashed var(--line); border-radius: 8px; max-width: none; }
/* std/gpu's reference kernels, folded into one closed card under the
   functions a caller uses (gen/stdlib.is_reference_kernel) */
.api-refs { margin: 1.6rem 0; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); }
.api-refs > summary { cursor: pointer; padding: 0.7rem 1rem; color: var(--muted); font-size: 0.92rem; list-style: none; display: flex; gap: 0.6rem; align-items: center; }
.api-refs > summary::-webkit-details-marker { display: none; }
.api-refs > summary::before { content: ""; width: 0.42rem; height: 0.42rem; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(-45deg); flex: none; }
.api-refs[open] > summary::before { transform: rotate(45deg); }
.api-refs > summary:hover { color: var(--accent); }
.api-refs[open] > summary { border-bottom: 1px solid var(--line-soft); }
.api-refs > .api-item { padding-left: 1rem; padding-right: 1rem; }
.api-refs > .api-item:last-child { border-bottom: 0; }

/* ---- the demo page (/tea.html): two wasm reactors, each mounted in a frame
   inside a window. .counter/.todo/.row and the rest are not named here: the
   guests' views draw them, so the selectors follow the two applications under
   examples/projects/. Every colour is a token, so what the guests draw follows
   the theme. ---- */
.tea-win { margin: 1.25rem 0 0.9rem; }
.tea-frame { padding: 1.4rem 1.4rem 1.2rem; background: var(--surface); }
.prose .tea-note { color: var(--muted); font-size: 0.93rem; line-height: 1.7; }
/* The placeholder under a frame until its demo mounts (gen/pages.tea_frame);
   empty afterwards, so it collapses rather than leaving a gap. */
.tea-status { margin: 0.5rem 0 0; font-size: 0.9rem; color: var(--muted); }
.tea-status:empty { display: none; }
.tea-error { margin: 0.75rem 0 0; font-size: 0.9rem; color: var(--danger); }
.tea-error:empty { display: none; }
/* the source under each demo, folded: read from examples/projects by gen/pages */
.tea-src { margin: 0.4rem 0 2.4rem; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; background: var(--code-bg); }
.tea-src > summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: 0.6rem; padding: 0.6rem 0.95rem; background: var(--surface); color: var(--muted); font-size: 0.9rem; }
.tea-src > summary::-webkit-details-marker { display: none; }
.tea-src > summary::before { content: ""; width: 0.42rem; height: 0.42rem; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(-45deg); flex: none; }
.tea-src[open] > summary::before { transform: rotate(45deg); }
.tea-src[open] > summary { border-bottom: 1px solid var(--line); }
.tea-src > summary:hover { color: var(--accent); }
.tea-src pre.dawn { margin: 0; border: 0; border-radius: 0; font-size: 0.78rem; }
.tea-frame h1 { font-size: 1rem; font-weight: 650; margin: 0 0 0.75rem; letter-spacing: -0.01em; }
.tea-frame button { font: inherit; font-size: 0.88rem; padding: 0.2rem 0.75rem; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); color: var(--text); cursor: pointer; }
.tea-frame button:hover { border-color: var(--accent); color: var(--accent); }
/* the counter */
.tea-frame .counter.below-zero .count { color: var(--danger); }
.tea-frame .count { font: 500 2.4rem/1.2 var(--mono); margin: 0 0 0.75rem; font-variant-numeric: tabular-nums; color: var(--hue); }
.tea-frame .bar { display: flex; gap: 3px; min-height: 12px; margin-bottom: 1rem; flex-wrap: wrap; }
.tea-frame .tick { width: 10px; height: 12px; background: var(--accent); opacity: 0.55; border-radius: 2px; }
.tea-frame .counter .row { display: flex; gap: 0.5rem; flex-wrap: wrap; }
/* the todo list */
.tea-frame .compose { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem; flex-wrap: wrap; }
.tea-frame .field { flex: 1; min-width: 8rem; padding: 0.25rem 0.55rem; border: 1px solid var(--line); border-radius: 6px; font: 0.9rem var(--mono); background: var(--bg); color: var(--text); }
.tea-frame .field:focus { outline: none; border-color: var(--accent); }
.tea-frame .filters { display: flex; gap: 0.4rem; margin-bottom: 0.75rem; flex-wrap: wrap; }
.tea-frame .filter.on { font-weight: 600; border-color: var(--accent); color: var(--accent); }
.tea-frame .list { list-style: none; margin: 0 0 0.75rem; padding: 0; max-width: none; }
.tea-frame .todo .row { display: flex; gap: 0.5rem; align-items: center; padding: 0.15rem 0; }
.tea-frame .todo .row.done .title { opacity: 0.5; text-decoration: line-through; }
.tea-frame .todo .row .title { flex: 1; cursor: pointer; }
.tea-frame .todo .row.editing .draft { flex: 1; font: 0.9rem var(--mono); background: transparent; color: inherit; border: none; border-bottom: 1px solid var(--accent); }
.tea-frame .todo .row.editing .draft:focus { outline: none; }
.tea-frame .status { margin: 0; font-size: 0.9rem; color: var(--muted); }

/* ---- the Playground: the band holds the nav and nothing else; the editor
   bundle's own sheet (site/play-ui/src/playground.css) lays out the rest ---- */

/* ---- the cuTile page: prose in the reading column, the evidence at the
   page's full width (gen/gpu.dawn) ---- */
.gpu-page > .prose { margin-top: 3.6rem; }
.gpu-page > .prose:first-child { margin-top: 0; }
.gpu-page > .prose h2 { margin-bottom: 0.6rem; }
.gpu-layers { display: grid; gap: 1rem; margin: 1.6rem 0 0; }
.gpu-layer { border: 1px solid var(--line); border-radius: 12px; background: var(--surface); padding: 1rem 1.15rem 0.2rem; box-shadow: var(--shadow); border-left: 3px solid var(--hue); }
.gpu-layer.host { --hue: var(--hue-3); }
.gpu-layer.device { --hue: var(--hue-1); }
.gpu-layer header { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem 0.8rem; }
.gpu-layer-name { font: 500 0.7rem/1.4 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--hue); }
.gpu-layer header a code, .gpu-eff { font: 500 0.86rem var(--mono); color: var(--text); }
.gpu-eff { color: var(--hue); margin-left: auto; }
.gpu-steps { list-style: none; display: flex; flex-wrap: wrap; align-items: center; gap: 0.45rem; margin: 0.85rem 0 0; padding: 0; }
.gpu-steps li { margin: 0; }
.gpu-steps code { display: inline-block; font: 0.8rem/1.5 var(--mono); padding: 0.2rem 0.6rem; border: 1px solid var(--line); border-radius: 999px; background: var(--code-bg); color: var(--text); white-space: nowrap; }
.gpu-steps li:first-child code { border-color: color-mix(in srgb, var(--hue) 55%, var(--line)); color: var(--hue); }
.gpu-arrow { color: var(--faint); font-size: 0.9rem; }
.gpu-fork { display: inline-flex; flex-direction: column; gap: 0.3rem; }
.gpu-layer p { margin: 0.75rem 0 0.85rem; max-width: var(--measure); color: var(--muted); font-size: 0.95rem; line-height: 1.7; }
.gpu-layer p code { font-size: 0.86em; background: var(--code-bg); border: 1px solid var(--line-soft); padding: 0.05em 0.32em; border-radius: 5px; color: var(--text); }
/* The head's background: real Tile IR from a few goldens, very faint,
   drifting upward (two copies, so the loop has no seam); still under
   reduced motion. */
.page-head:has(> .gpu-hero-ir) { isolation: isolate; }
.gpu-hero-ir { position: absolute; z-index: -1; top: 0; bottom: 0; right: 0; width: min(46%, 34rem); overflow: hidden; pointer-events: none; user-select: none; -webkit-user-select: none; opacity: 0.13; -webkit-mask-image: linear-gradient(180deg, transparent, #000 22%, #000 70%, transparent), linear-gradient(90deg, transparent, #000 30%); -webkit-mask-composite: source-in; mask-image: linear-gradient(180deg, transparent, #000 22%, #000 70%, transparent), linear-gradient(90deg, transparent, #000 30%); mask-composite: intersect; }
.gpu-hero-ir pre { margin: 0; padding: 0; border: 0; background: none; overflow: visible; font: 0.7rem/1.75 var(--mono); color: var(--sky-text); white-space: pre; }
@media (max-width: 719px) { .gpu-hero-ir { width: 100%; opacity: 0.08; } }
@media (prefers-reduced-motion: no-preference) {
  .gpu-hero-ir pre { animation: gpu-drift 140s linear infinite; }
  @keyframes gpu-drift { to { transform: translateY(-50%); } }
}
/* The call map: one row per line of flash_attn, the Tile IR its calls wrote
   beside it, each run under its call's name. No fill of its own: the page
   shows through, hairlines and six row colours carry the pairing. The six
   tell neighbouring rows apart and mean nothing else; each has a day ink and
   a night ink, like the hues above. Laid out by the figure's own width
   (container query), so one markup reads in the page column and on a phone. */
.gpu-page {
  --gm-0: #4f46e5; --gm-1: #db2777; --gm-2: #0e7490; --gm-3: #b45309; --gm-4: #15803d; --gm-5: #7c3aed;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gpu-page {
    --gm-0: #818cf8; --gm-1: #f472b6; --gm-2: #67e8f9; --gm-3: #fbbf24; --gm-4: #4ade80; --gm-5: #c4b5fd;
  }
}
:root[data-theme="dark"] .gpu-page {
  --gm-0: #818cf8; --gm-1: #f472b6; --gm-2: #67e8f9; --gm-3: #fbbf24; --gm-4: #4ade80; --gm-5: #c4b5fd;
}
.km { margin: 1.6rem 0 0; container-type: inline-size; }
.km-cap { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem 0.9rem; padding: 0 0 0.55rem; border-bottom: 1px solid var(--line); }
.km-name code { font: 600 1.02rem var(--mono); color: var(--text); }
.km-kind { font-size: 0.84rem; color: var(--faint); }
.km-facts { margin: 0 0 0 auto; font-size: 0.82rem; color: var(--muted); }
.km-facts b { font: 600 0.9rem var(--mono); color: var(--text); font-variant-numeric: tabular-nums; }
.km-facts span { color: var(--faint); }
.km-heads { display: none; }
.km-rows { list-style: none; margin: 0; padding: 0; }
.km-row { margin: 0; padding: 0; --g: var(--gm-0); }
.km-row + .km-row { border-top: 1px solid var(--line-soft); }
.km-row.g1 { --g: var(--gm-1); } .km-row.g2 { --g: var(--gm-2); } .km-row.g3 { --g: var(--gm-3); }
.km-row.g4 { --g: var(--gm-4); } .km-row.g5 { --g: var(--gm-5); }
.km-row.ge { --g: var(--line); }
/* A row is one block, `.km-s`: a plain div, or the summary of the row's
   details when it has Tile IR to fold. The right edge keeps room for the
   marker on every row, so folding rows and plain ones line up. */
.km-s { display: block; position: relative; padding: 0.4rem 1.7rem 0.4rem 0; font-size: 0.76rem; }
summary.km-s { list-style: none; cursor: pointer; }
summary.km-s::-webkit-details-marker { display: none; }
summary.km-s:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 4px; }
summary.km-s:hover { background: color-mix(in srgb, var(--g) 5%, transparent); }
.km pre { margin: 0; padding: 0; border: 0; border-radius: 0; background: none; overflow: visible; white-space: pre-wrap; overflow-wrap: anywhere; font: 0.76rem/1.6 var(--mono); font-variant-ligatures: none; }
.km pre code { font: inherit; background: none; border: 0; padding: 0; }
/* every line wraps under itself, past its number: a hanging indent */
.km-l { display: block; padding-left: calc(3em + 2ch); text-indent: calc(-3em - 2ch); }
.km-l i { display: inline-block; width: 2.4em; margin-right: 0.6em; text-indent: 0; text-align: right; font-style: normal; color: var(--faint); opacity: 0.75; user-select: none; -webkit-user-select: none; }
.km pre.km-d { border-left: 3px solid var(--g); padding-left: 0.45rem; color: var(--text); }
.km-row.ge .km-d { color: var(--muted); }
/* the source's indentation, a faint dot a space on an open row: drawn by
   the stylesheet over a real space, so a copy is the source byte for byte */
.km-sp { position: relative; }
.km-f[open] .km-sp::before { content: "·"; position: absolute; left: 0; right: 0; text-indent: 0; text-align: center; color: var(--faint); opacity: 0.6; pointer-events: none; user-select: none; -webkit-user-select: none; }
.km-t { display: grid; grid-template-columns: minmax(0, 1fr); margin: 0.35rem 0 0 1.1rem; }
.km-t:empty { display: none; }
.km-tag { display: block; min-height: 0; line-height: calc(0.76rem * 1.6); }
.km-tag code { font: 600 0.7rem/calc(0.76rem * 1.6) var(--mono); color: var(--g); vertical-align: top; }
.km-tag:empty { display: none; }
.km pre.km-ir { border-left: 2px solid color-mix(in srgb, var(--g) 60%, transparent); padding-left: 0.45rem; color: var(--muted); }
.km-ir + .km-tag { margin-top: 0.25rem; }
.km-row.ge pre.km-ir { border-left-color: var(--line); }
.km-ir .ty { color: var(--faint); opacity: 0.85; }
/* the operation a call is for: its line in full ink, its name in the row's hue */
.km-ir .km-res { color: var(--text); }
.km-ir .km-res b { font-weight: 650; color: var(--g); }
.km-row.ge .km-ir .km-res { color: inherit; }
.km-row.ge .km-ir .km-res b { font-weight: inherit; color: inherit; }
/* folded: the key line under its call's name and nothing else, one line
   high, its type tail cut off at the edge */
.km-f:not([open]) .km-t > :not(.km-kt):not(.km-kp) { display: none; }
.km-f:not([open]) .km-ir .km-l:not(.km-k) { display: none; }
.km-f:not([open]) .km-ir .km-k { white-space: pre; overflow: hidden; text-overflow: ellipsis; }
/* the marker: how many lines are folded away, and a chevron that turns */
.km-x { position: absolute; top: 0.4rem; right: 0.15rem; font: 600 0.62rem/1.95 var(--mono); color: var(--faint); white-space: nowrap; user-select: none; -webkit-user-select: none; }
.km-x::after { content: ""; display: inline-block; width: 0.3rem; height: 0.3rem; margin: 0 0.1rem 0.15rem 0.25rem; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg); }
summary.km-s:hover .km-x { color: var(--g); }
.km-f[open] .km-x { color: var(--g); font-size: 0; }
.km-f[open] .km-x::after { margin-bottom: -0.1rem; transform: rotate(-135deg); }
.km-row.ge summary.km-s:hover .km-x, .km-row.ge .km-f[open] .km-x { color: var(--muted); }
@container (min-width: 44rem) {
  /* The source column is as wide as the longest line (`--kmn`, in code
     points, from the generator) up to a bound. A folded row is one line on
     both sides: a source line too long for the column is cut at its edge
     until its row is opened. An open row wraps and its source column runs
     the full height of its Tile IR. */
  .km-s, .km-heads { display: grid; grid-template-columns: min(calc(var(--kmn, 60) * 1ch + 3em + 2ch + 0.8rem), 52%) minmax(0, 1fr); font-family: var(--mono); }
  .km-heads { padding: 0.5rem 1.7rem 0.15rem 0; font-size: 0.76rem; }
  .km-heads span { font: 500 0.66rem/1.4 var(--mono); letter-spacing: 0.07em; text-transform: uppercase; color: var(--faint); }
  .km-heads code { text-transform: none; letter-spacing: 0; }
  .km-heads span:nth-child(2) { display: none; }
  .km-heads span:last-child { padding-left: calc(1.2rem + 6.6rem); }
  .km-f:not([open]) pre.km-d { white-space: pre; overflow: hidden; text-overflow: ellipsis; }
  .km-f:not([open]) pre.km-d .km-l { padding-left: 0; text-indent: 0; }
  .km-t { grid-template-columns: 6.6rem minmax(0, 1fr); margin: 0 0 0 1.2rem; row-gap: 0.25rem; align-content: start; }
  .km-t:empty { display: grid; }
  .km-tag code { white-space: nowrap; }
  .km-ir + .km-tag { margin-top: 0; }
  .km-tag { text-align: right; padding-right: 0.5rem; }
  /* a short lead-in from the call's name to its lines */
  .km-tag code::after { content: ""; display: inline-block; width: 0.55rem; margin-left: 0.35rem; vertical-align: middle; border-top: 1px solid color-mix(in srgb, var(--g) 70%, transparent); }
  .km-tag:empty { display: block; }
}
/* narrow: a Tile IR line stays one line and its run scrolls sideways (the
   type tails are what goes off the edge); the Dawn lines still wrap */
@container (max-width: 43.99rem) {
  .km pre.km-ir { white-space: pre; overflow-x: auto; overflow-wrap: normal; scrollbar-width: thin; }
  .km-ir .km-l { padding-left: 0; text-indent: 0; }
  .km-f:not([open]) pre.km-ir { overflow: hidden; }
}
.km-note { margin: 0.6rem 0 0; max-width: var(--measure); font-size: 0.84rem; color: var(--faint); }
/* a call picked (gpu.js): its span underlined, its own Tile IR lines given an
   accent edge and number, the lines its body's calls wrote a fainter edge.
   No fill anywhere: the page stays the colour it is. */
.km-c { border-bottom: 1px dashed color-mix(in srgb, var(--accent) 55%, transparent); }
.km-live .km-c { cursor: pointer; }
.km-live .km-c:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 2px; }
.km-live .km-ir .km-l[data-o] { cursor: pointer; }
.km [data-k].km-on { text-decoration: underline 2px var(--accent); text-underline-offset: 3px; }
.km-c[aria-pressed="true"] { color: var(--accent); border-bottom-style: solid; }
.km-ir .km-l.km-hit { box-shadow: inset 3px 0 0 var(--accent); }
.km-ir .km-l.km-hit i { color: var(--accent); opacity: 1; }
.km-ir .km-l.km-in { box-shadow: inset 3px 0 0 color-mix(in srgb, var(--accent) 30%, transparent); }
/* ---- the explorer page (gen/explorer.dawn, site/assets/explorer.js): a Dawn
   function beside what it compiled to. No fill of its own, like the call map
   above: hairlines, an underline for a picked span, an edge for a picked
   line. Laid out by the figure's own width (container query), so one markup
   reads in the page column and on a phone: two columns wide, stacked narrow,
   and each listing scrolls inside its box so the page never scrolls sideways. ---- */
.xp-page > .prose { margin-top: 3.6rem; }
.xp-page > .prose:first-child { margin-top: 0; }
.xp-page h2 { margin-bottom: 0.6rem; }
.xp-prog { margin-top: 3.6rem; }
.xp-prog > .prose + .xp { margin-top: 1.6rem; }
.xp { margin: 1.6rem 0 0; container-type: inline-size; min-width: 0; }
.xp-cap { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem 0.9rem; padding: 0 0 0.55rem; border-bottom: 1px solid var(--line); }
.xp-name code { font: 600 1.02rem var(--mono); color: var(--text); }
.xp-facts { margin-left: auto; font-size: 0.82rem; color: var(--muted); }
.xp-facts b { font: 600 0.9rem var(--mono); color: var(--text); font-variant-numeric: tabular-nums; }
.xp-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.4rem 1.6rem; }
@container (min-width: 44rem) {
  .xp-grid { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); align-items: start; }
}
.xp-src, .xp-out { min-width: 0; }
.xp-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 0 0.8rem; margin: 0; padding: 0.55rem 0 0.35rem; font: 500 0.66rem/1.5 var(--mono); letter-spacing: 0.07em; text-transform: uppercase; color: var(--faint); }
.xp-head code, .xp-head a { text-transform: none; letter-spacing: 0; }
.xp-shown { font-variant-numeric: tabular-nums; }
.xp-tabs { display: flex; gap: 0.2rem; margin: 0.35rem 0 0; border-bottom: 1px solid var(--line); }
.xp-tab { min-height: 2.5rem; padding: 0.4rem 0.95rem; font: 500 0.82rem var(--mono); color: var(--muted); background: none; border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: pointer; }
.xp-tab:hover { color: var(--text); }
.xp-tab[aria-selected="true"] { color: var(--text); border-bottom-color: var(--accent); }
.xp-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 4px; }
.xp pre.xp-code { position: relative; margin: 0; padding: 0; border: 0; border-radius: 0; background: none; overflow: auto; white-space: pre; font: 0.76rem/1.6 var(--mono); font-variant-ligatures: none; tab-size: 4; scrollbar-width: thin; border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft); }
.xp-pane .xp-code { max-height: 34rem; }
.xp-src .xp-code { max-height: 34rem; }
.xp pre.xp-code code { font: inherit; background: none; border: 0; padding: 0; display: block; width: max-content; min-width: 100%; }
.xl { display: block; padding: 0 0.6rem 0 calc(3em + 1ch); text-indent: calc(-3em - 1ch); box-shadow: inset 3px 0 0 transparent; }
.xl i { display: inline-block; width: 2.4em; margin-right: 0.6em; text-indent: 0; text-align: right; font-style: normal; color: var(--faint); opacity: 0.75; user-select: none; -webkit-user-select: none; }
.xl .ty { color: var(--faint); opacity: 0.85; }
/* a call's name: the thing a reader can pick */
.xc { border-bottom: 1px dashed color-mix(in srgb, var(--accent) 55%, transparent); }
.xp-live .xc { cursor: pointer; }
.xp-live .xc:focus-visible, .xp-live .xl[data-o]:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 2px; }
.xp-live .xl[data-o] { cursor: pointer; }
.xp-live .xl[data-o]:hover { box-shadow: inset 3px 0 0 var(--line); }
/* a call picked: its span underlined in the source and in C's columns, its own
   lines given an accent edge and number, the lines of the calls inside it a
   fainter edge, and the instruction that implements it in bold. No fill. */
.xp [data-k].xp-on { text-decoration: underline 2px var(--accent); text-underline-offset: 3px; }
.xc[aria-pressed="true"] { color: var(--accent); border-bottom-style: solid; }
.xl.xp-hit { box-shadow: inset 3px 0 0 var(--accent); }
.xl.xp-hit i { color: var(--accent); opacity: 1; }
.xl.xp-in { box-shadow: inset 3px 0 0 color-mix(in srgb, var(--accent) 30%, transparent); }
.xl.xp-ipc { font-weight: 650; }
.xp-status { min-height: 1.5rem; margin: 0.6rem 0 0; font: 0.8rem/1.5 var(--mono); color: var(--muted); }
.xp-note { margin: 0.2rem 0 0; max-width: var(--measure); font-size: 0.84rem; color: var(--faint); }
.gpu-figs { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: 1rem; margin: 1.6rem 0 0; }
.gpu-fig { position: relative; display: flex; flex-direction: column; gap: 0.3rem; border: 1px solid var(--line); border-radius: 12px; padding: 1rem 1.15rem; background: var(--surface); box-shadow: var(--shadow); outline: none; }
.gpu-fig:focus-visible { border-color: var(--accent); }
.gpu-fig strong { font: 600 2rem/1.1 var(--mono); letter-spacing: -0.03em; color: var(--text); font-variant-numeric: tabular-nums; }
.gpu-fig strong b { font-weight: inherit; }
.gpu-fig strong small { font-size: 0.55em; font-weight: 500; color: var(--faint); letter-spacing: 0; }
.gpu-fig-bar { display: block; height: 4px; margin: 0.2rem 0 0.15rem; border-radius: 2px; background: var(--line-soft); overflow: hidden; }
.gpu-fig-bar i { display: block; height: 100%; width: var(--p); border-radius: inherit; background: var(--dawn-grad); }
.gpu-fig span { font-size: 0.92rem; color: var(--muted); line-height: 1.5; }
.gpu-fig .gpu-fig-rest { font-size: 0.8rem; color: var(--faint); }
.gpu-fig .gpu-fig-rest code { font: 0.95em var(--mono); }
.gpu-fig a { margin-top: auto; padding-top: 0.4rem; font-size: 0.78rem; color: var(--faint); }
.gpu-fig a code { font-family: var(--mono); }
/* the rows that are not implemented, over the card's lower edge when it is
   pointed at or focused */
.gpu-fig-miss { position: absolute; z-index: 3; left: -1px; right: -1px; top: calc(100% - 0.4rem); margin: 0; padding: 0.6rem 0.85rem; list-style: none; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); box-shadow: var(--shadow); font-size: 0.78rem; line-height: 1.5; color: var(--muted); opacity: 0; visibility: hidden; transform: translateY(-4px); transition: opacity 0.16s ease, transform 0.16s ease, visibility 0s linear 0.16s; }
.gpu-fig:hover .gpu-fig-miss, .gpu-fig:focus-within .gpu-fig-miss { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.gpu-fig-miss li { margin: 0.12rem 0; }
.gpu-fig-miss code { font: 0.95em var(--mono); color: var(--text); }
.gpu-fig-miss small { color: var(--faint); font-family: var(--mono); font-size: 0.9em; }
.gpu-fig-miss li span { display: block; font-size: 0.95em; color: var(--faint); }
@media (prefers-reduced-motion: no-preference) {
  .gpu-fig-bar i { transition: width 1.1s cubic-bezier(0.2, 0.7, 0.2, 1); }
  .gpu-fig.gf-wait .gpu-fig-bar i { width: 0; transition: none; }
}
/* Three gates, one row: each card is a gate, its number and name, how many
   mutants it catches and one dot per mutant (`title` names it), then what it
   checks and its harness. Subgrid rows keep the count, the dots and the
   sentence level across the three. Under 720 px the cards stack, in gate
   order, each unchanged. */
.gpu-gates { list-style: none; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: repeat(5, auto); gap: 0 1rem; margin: 1.6rem 0 0; padding: 0; }
.gg { position: relative; display: grid; grid-row: span 5; grid-template-rows: subgrid; row-gap: 0.55rem; margin: 0; padding: 1rem 1.15rem 1.05rem; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); box-shadow: var(--shadow); --g: var(--gm-0); }
.gg.g1 { --g: var(--gm-1); } .gg.g2 { --g: var(--gm-2); }
.gg::before { content: ""; position: absolute; left: -1px; top: 14px; bottom: 14px; width: 3px; border-radius: 2px; background: repeating-linear-gradient(180deg, var(--g) 0 3px, transparent 3px 7px); }
.gg header { display: flex; align-items: center; gap: 0.6rem; }
.gpu-gate-n { display: inline-grid; place-items: center; width: 1.7rem; height: 1.7rem; border-radius: 50%; font: 600 0.8rem var(--mono); color: #fff; background: var(--dawn-grad); }
.gg h3 { margin: 0; font-size: 1.02rem; font-weight: 680; letter-spacing: -0.012em; }
.gg-n { margin: 0; font-size: 0.84rem; color: var(--muted); }
.gg-n b { font: 600 1.5rem/1 var(--mono); color: var(--text); margin-right: 0.15rem; font-variant-numeric: tabular-nums; }
.gg-dots { display: flex; flex-wrap: wrap; align-content: flex-start; gap: 4px; }
.gg-dots i { display: block; width: 9px; height: 9px; border-radius: 50%; background: var(--g); box-shadow: 0 0 0 2px color-mix(in srgb, var(--g) 18%, transparent); }
.gg-body { margin: 0.2rem 0 0; font-size: 0.92rem; line-height: 1.65; color: var(--muted); }
.gg-body code { font-size: 0.86em; background: var(--code-bg); border: 1px solid var(--line-soft); padding: 0.05em 0.32em; border-radius: 5px; color: var(--text); }
.gg > a { align-self: end; font-size: 0.78rem; color: var(--faint); }
@media (max-width: 719px) {
  .gpu-gates { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; gap: 0.9rem; }
  .gg { grid-row: auto; grid-template-rows: none; }
}
/* Writing a kernel: one card a row, each real kernels.dawn code. From
   900 px the words sit in a left column and the code takes the rest, so a
   dispatch arm's long line fits; below that they stack. Code wraps with a
   hanging indent rather than hiding its tail (an arm's `along:` is the
   point of the card). The keepdims card's border is the device layer's hue:
   it leads into the map below. */
.gpu-cards { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; margin: 1.6rem 0 0; }
.gpu-card { display: grid; grid-template-columns: minmax(0, 1fr); align-content: start; min-width: 0; margin: 0; padding: 0.95rem 1.15rem 0.85rem; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); box-shadow: var(--shadow); }
.gpu-card-wide { border-left: 3px solid var(--hue-1); }
.gpu-card header { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.2rem 0.8rem; }
.gpu-card h3 { margin: 0; font-size: 1.02rem; font-weight: 680; letter-spacing: -0.012em; }
.gpu-card h3 code { font-size: 0.9em; }
.gpu-card-k { margin-left: auto; font: 500 0.76rem var(--mono); color: var(--faint); background: none; border: 0; padding: 0; }
.gpu-card > p { margin: 0.5rem 0 0.75rem; font-size: 0.92rem; line-height: 1.65; color: var(--muted); }
.gpu-card > p code { font-size: 0.86em; background: var(--code-bg); border: 1px solid var(--line-soft); padding: 0.05em 0.32em; border-radius: 5px; color: var(--text); }
.gpu-card pre.gpu-card-src { margin: 0; padding: 0.75rem 0.9rem; font-size: 0.76rem; line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; }
.gpu-card-src .gpu-l { display: block; padding-left: 4ch; text-indent: -4ch; }
.gpu-card > p.gpu-card-from { margin: 0.55rem 0 0; font-size: 0.76rem; line-height: 1.7; color: var(--faint); }
.gpu-card .gpu-card-from code { font-size: 1em; background: none; border: 0; padding: 0; color: inherit; }
@media (min-width: 900px) {
  .gpu-card { grid-template-columns: minmax(15rem, 1fr) minmax(0, 2.3fr); grid-template-rows: auto auto 1fr; column-gap: 1.4rem; }
  .gpu-card > header, .gpu-card > p { grid-column: 1; }
  .gpu-card > p.gpu-card-from { margin-top: auto; }
  .gpu-card pre.gpu-card-src { grid-column: 2; grid-row: 1 / span 3; }
  .gpu-card-k { margin-left: 0; flex-basis: 100%; }
}
.gpu-picks a { display: block; color: inherit; text-decoration: none; border-radius: 6px; margin: 0 -0.4rem; padding: 0.15rem 0.4rem 0.15rem calc(0.4rem + 5ch); text-indent: -5ch; }
.gpu-picks a:hover, .gpu-picks a:focus-visible { background: color-mix(in srgb, var(--hue-1) 12%, transparent); }
.gpu-picks i { display: inline-block; width: 4ch; margin-right: 1ch; text-indent: 0; text-align: right; font-style: normal; white-space: nowrap; overflow-wrap: normal; color: var(--faint); user-select: none; -webkit-user-select: none; }
.gpu-pick-go { display: inline-block; margin-left: 1.2ch; text-indent: 0; font: 600 0.72rem var(--mono); white-space: nowrap; color: var(--hue-1); }
.gpu-card-from a { white-space: nowrap; }
.gpu-api-more { margin-top: 0.3rem; }
.gpu-learn { margin: 1rem 0 0; font-weight: 600; }
.gpu-learn a { text-decoration: none; }
.gpu-learn a:hover { text-decoration: underline; }
.km-row:target { background: color-mix(in srgb, var(--hue-1) 8%, transparent); }
.gpu-ledgers { margin-top: 1.6rem; }
.gpu-ledgers td { white-space: nowrap; font-variant-numeric: tabular-nums; }
@media (max-width: 719px) { .gpu-ledgers td { min-width: 0; } }
.gpu-note { max-width: var(--measure); margin: 0.8rem 0 0; font-size: 0.86rem; color: var(--faint); }

/* ---- packages.html: one table, a row per package (gen/packages.dawn) ----
   Six columns share one 66rem page, and the summary is the only one that is
   prose, so it is the one that gets the room. Four things pay for it: the
   headers may wrap ("manifest name" is two words), the cells pad a little
   less, and the dependency lines soft-wrap at their spaces instead of
   setting the width of the column (copying one still yields one line; the
   quoted path is a .pkg-nb, so it never breaks at a hyphen). That took the
   summary from 240px to about 360px at full width and ended the 3px
   sideways scroll the frame had there. Keeping a 46-character
   signature on one line as well would need 30px more than the page has, so
   it breaks once, at a space. The frame still scrolls sideways below
   1024px. */
.pkg-table { margin-top: 0; }
.pkg-table th { white-space: normal; }
.pkg-table th, .pkg-table td { padding-left: 0.7rem; padding-right: 0.7rem; }
.pkg-table tr { scroll-margin-top: 1rem; }
.pkg-table tr:target td { background: color-mix(in srgb, var(--accent) 7%, transparent); }
.pkg-table td.pkg-ver { white-space: nowrap; font-variant-numeric: tabular-nums; }
.pkg-table td.pkg-sum { min-width: 30ch; }
.pkg-table td.pkg-sum p { margin: 0; text-wrap: pretty; }
.pkg-table .pkg-mods { margin-top: 0.45rem; display: flex; flex-wrap: wrap; gap: 0.3rem; }
.pkg-table .pkg-mods code { font-size: 0.76rem; color: var(--muted); }
.pkg-table td.pkg-deps code { white-space: nowrap; }
.pkg-table .pkg-none { color: var(--faint); white-space: nowrap; }
.pkg-table td.pkg-use code { display: block; white-space: pre-wrap; font-size: 0.76rem; }
.pkg-table td.pkg-use .pkg-nb { white-space: nowrap; }
.pkg-table .pkg-use-k { display: block; font: 500 0.66rem/1.4 var(--mono); letter-spacing: 0.05em; text-transform: uppercase; color: var(--faint); margin: 0 0 0.15rem; white-space: nowrap; }
.pkg-table .pkg-use-k + code + .pkg-use-k { margin-top: 0.5rem; }
/* the name, manifest name and version cells are short words, not sentences:
   the 20ch floor a phone gives every cell would only widen the scroll */
@media (max-width: 719px) { .pkg-table td.key, .pkg-table td.pkg-ver, .pkg-table td.pkg-name, .pkg-table td.pkg-deps { min-width: 0; } }
/* The notes hang under a table as wide as the page. One 66ch column of
   small print beside half a page of nothing read as an afterthought, and
   66ch counted in the notes' own smaller ch was narrower than the prose
   measure besides. So: two columns, one per note, once the page is wide
   enough for each to keep about 65 characters; a single column at the
   prose measure (66ch of the body size, converted back from 0.86rem)
   below that. */
.pkg-notes { margin: 0.9rem 0 0; font-size: 0.86rem; color: var(--faint); }
.pkg-notes p { margin: 0 0 0.5rem; max-width: calc(var(--measure) / 0.86); text-wrap: pretty; }
.pkg-notes code { overflow-wrap: anywhere; }
@media (min-width: 960px) {
  .pkg-notes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 2.5rem; }
  .pkg-notes p { margin: 0; max-width: none; }
}

/* ---- 404: the head centred, a sun under the horizon that has not come up ---- */
.page-head.nf { text-align: center; padding-bottom: 0; max-width: var(--col); margin-left: auto; margin-right: auto; }
.page-head.nf .lede { margin-left: auto; margin-right: auto; max-width: 34rem; }
.page-head.nf .lede + .lede { margin-top: 0.6rem; font-size: 0.98rem; }
.page-head.nf .crumbs { justify-content: center; letter-spacing: 0.2em; }
.nf-scene { display: block; width: min(320px, 86%); height: auto; margin: 2.6rem auto 0; }
main.nf-body { min-height: max(6rem, calc(100vh - 34rem)); }

/* ---- the footer ---- */
footer.site-footer { margin-top: 5rem; border-top: 1px solid var(--line-soft); padding: 1.75rem 0 2.75rem; font-size: 0.9rem; color: var(--muted); }
footer.site-footer .row { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; justify-content: space-between; align-items: center; }
footer.site-footer a { color: var(--muted); text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 0.2em; }
footer.site-footer a:hover { color: var(--accent); }
footer.site-footer .ver { font-family: var(--mono); font-size: 0.8rem; }
footer.site-footer .ver b { color: var(--text); font-weight: 500; }
footer.site-footer .mark { display: inline-flex; align-items: center; gap: 0.5rem; }
.mark-logo { width: 1.25rem; height: 1.25rem; flex: none; }

/* ---- switching the theme ----
   No colour tweens of their own: Chrome restarts a child's colour transition
   on every frame its parent's runs, so text would trail its background, and
   two inks crossing over a sky half way to night are grey on grey. The new
   theme is revealed in one piece instead, a circle growing out of the toggle
   (a view transition, driven by theme.js). Where view transitions are
   missing, or under reduced motion, the theme simply switches. The front
   page has its own switch (home.css, home.js). */
::view-transition-old(root), ::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
/* The toggle is lifted out of the circle into a layer of its own, shown live
   and above it, so its quarter turn plays in full, exactly as on the front
   page, which has no circle; inside the circle the new icon would appear
   only once the edge reached it, already turned. */
.theme-toggle { view-transition-name: theme-toggle; }
::view-transition-group(theme-toggle) { animation: none; }
::view-transition-old(theme-toggle) { display: none; }
::view-transition-new(theme-toggle) { animation: none; }
@media (prefers-reduced-motion: no-preference) {
  .theme-toggle .ico-sun, .theme-toggle .ico-moon { transition: opacity 0.3s ease, transform 0.3s ease; }
  /* hover is a change of colour, never of place */
  .site-nav button, .site-nav a, .crumbs a, .page-head .chip a {
    transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
  }
  /* While the circle opens (theme.js sets theme-cut for its length) these
     do not run: the new theme is already drawn whole inside it, and a tween
     there would only be more work in the frames that have the least to
     spare. Listed, not `*`, for the reason home.css gives. */
  :root.theme-cut :is(.site-nav button, .site-nav a, .crumbs a, .page-head .chip a) { transition: none; }
  /* the line under the current section, sliding (theme.js) */
  .site-nav .ink {
    transition: transform 0.34s cubic-bezier(0.3, 0.7, 0.2, 1), width 0.34s cubic-bezier(0.3, 0.7, 0.2, 1), opacity 0.2s ease;
  }
  /* The wordmark on hover: one pass of the dawn's light through the word,
     the front page's wordmark in a glance; the cat stays still. */
  @supports ((-webkit-background-clip: text) or (background-clip: text)) {
    .site-nav .brand:is(:hover, :focus-visible) .word {
      color: transparent;
      background: linear-gradient(100deg, var(--sky-strong) 0 38%, var(--dawn-1) 44%, var(--dawn-2) 50%, var(--dawn-3) 56%, var(--sky-strong) 62% 100%) 100% 0 / 300% 100%;
      -webkit-background-clip: text; background-clip: text;
      padding-bottom: 0.2em; margin-bottom: -0.2em;
      animation: wordmark-sweep 0.95s cubic-bezier(0.4, 0, 0.2, 1);
    }
    @keyframes wordmark-sweep { from { background-position: 100% 0; } to { background-position: 0 0; } }
  }
  /* The head arrives once: the title and the lede rise together, the trail
     fades in, the facts follow one by one, 60ms apart. `backwards`, not
     `both`: a finished animation that fills forwards stays in
     getAnimations() for the life of the page. */
  @keyframes head-rise { from { opacity: 0; transform: translateY(12px); } }
  @keyframes head-fade { from { opacity: 0; } }
  .page-head .crumbs { animation: head-fade 0.35s ease backwards; }
  .page-head h1, .page-head .lede { animation: head-rise 0.48s cubic-bezier(0.2, 0.7, 0.2, 1) backwards; }
  .page-head .lede { animation-delay: 40ms; }
  .page-head .chip { animation: head-rise 0.42s cubic-bezier(0.2, 0.7, 0.2, 1) backwards; }
  .page-head .chip:nth-child(1) { animation-delay: 120ms; }
  .page-head .chip:nth-child(2) { animation-delay: 180ms; }
  .page-head .chip:nth-child(3) { animation-delay: 240ms; }
  .page-head .chip:nth-child(4) { animation-delay: 300ms; }
  .page-head .chip:nth-child(5) { animation-delay: 360ms; }
  .page-head .chip:nth-child(6) { animation-delay: 420ms; }
  /* the cat comes up over the edge once, after the facts */
  @keyframes peek-rise { from { transform: translateY(14px); } }
  header.sky > .peek > span { animation: peek-rise 0.6s 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) backwards; }
}

/* ---- 搜索面板 ---- */
/* 页头按钮 + 一个懒挂载的 wasm reactor（examples/projects/tea_dom_search）。
   面板内部的一切由 guest 画，这里只负责壳与状态类；content: 只放空串（图标与色点
   靠背景和 mask 画），面板里的每个字都跟着页面语言从 guest 出来（gen/assets.dawn 的三条规矩）。
   页头按钮本身的样式在上面的 nav 一节。 */

/* The panel, in the site's tokens. Every colour below is a token or a mix of
   one, so the panel follows the theme on every page without a rule of its
   own for either. The few literal colours are shadow inks, and those go
   through light-dark(), which reads the page's color-scheme: the dark
   token blocks at the top of this sheet set it.

   `hidden` on the host is the page script's switch and the empty tree is the
   guest's; when both hold, the panel takes no room. The host is also the
   scrim, so a click that lands on the host and not inside the panel is a
   click outside it (search.js closes on that). */
.search-host {
  position: fixed;
  inset: 0;
  z-index: 30;
  padding: 8vh 1rem 1rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .search-host { background: color-mix(in srgb, var(--bg) 78%, transparent); }
}

.search-host[hidden] { display: none; }

/* The arrows scroll the list under a pointer that has not moved, and a row
   arriving under it would otherwise take the selection back (mouseenter).
   search.js sets this on an arrow key and clears it on the next mousemove. */
.search-host.is-keying .search-row { pointer-events: none; }

/* Reopening starts the guest again on its worker, and until that answers the
   document is still the panel the reader closed, old query and all.
   search.js sets this for that turn and takes it off with the new panel. */
.search-host.is-starting .search-panel { visibility: hidden; }

.search-panel {
  display: flex;
  flex-direction: column;
  max-width: 42rem;
  max-height: min(37rem, 84vh);
  margin: 0 auto;
  overflow: hidden;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(13, 16, 32, 0.05), 0 28px 70px -24px rgba(13, 16, 32, 0.38);
  /* dark: a hairline and a faint glow of the accent, where a drop shadow
     would not show against the night */
  box-shadow:
    0 0 0 1px light-dark(transparent, color-mix(in srgb, var(--accent) 6%, transparent)),
    0 0 48px -12px light-dark(transparent, color-mix(in srgb, var(--accent) 18%, transparent)),
    0 1px 2px light-dark(rgba(13, 16, 32, 0.05), transparent),
    0 28px 70px -24px light-dark(rgba(13, 16, 32, 0.38), rgba(0, 0, 0, 0.7));
}

/* The empty tree the guest answers once it is left. It has no children, so
   with no padding it leaves no trace. */
.search-panel.is-closed { display: none; }

.search-panel kbd {
  display: inline-grid;
  place-items: center;
  min-width: 1.45rem;
  height: 1.35rem;
  padding: 0 0.35rem;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 6px;
  background: var(--code-bg);
  color: var(--muted);
  font: 0.68rem/1 var(--mono);
}

.search-bar {
  flex: none;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.7rem;
  padding: 0.9rem 1.1rem;
}

/* The magnifier, as a mask so it takes the accent in either theme. */
.search-bar::before {
  content: "";
  width: 1.2rem;
  height: 1.2rem;
  background: var(--accent);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='m16 16 4.5 4.5'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='m16 16 4.5 4.5'/%3E%3C/svg%3E") center / contain no-repeat;
}

.search-input {
  width: 100%;
  min-width: 0;
  padding: 0;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 1.05rem;
  -webkit-appearance: none;
  appearance: none;
}
.search-input::placeholder { color: var(--faint); }
/* The field is where focus lives the whole time the panel is open, and the
   caret already says so; home.css's ring for every :focus-visible would
   frame it for good. */
.search-bar .search-input:focus-visible { outline: none; }

/* Shown in place of the esc key where there is no keyboard; see the phone
   rules below. */
.search-cancel {
  display: none;
  padding: 0.2rem 0;
  border: 0;
  background: none;
  color: var(--accent);
  font: 500 1rem var(--sans);
  cursor: pointer;
}

/* The one brand mark inside the panel: the dawn hairline under the field. */
.search-line {
  flex: none;
  height: 1px;
  background: var(--dawn-grad);
  opacity: 0.9;
}

/* The scope pills: All and one per group, with counts. One line that scrolls
   sideways when it does not fit (a phone), with no scrollbar drawn; empty,
   it takes no room. */
.search-pills {
  flex: none;
  display: flex;
  gap: 0.35rem;
  padding: 0.65rem 1.1rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  border-bottom: 1px solid var(--line-soft);
}
.search-pills::-webkit-scrollbar { display: none; }
.search-pills:empty { display: none; }
.search-pill {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.18rem 0.65rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font: 0.72rem/1.5 var(--mono);
  cursor: pointer;
}
.search-pill-count { color: var(--faint); }
.search-pill:hover:not(:disabled) { color: var(--text); }
.search-pill.is-on {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: color-mix(in srgb, var(--accent) 9%, transparent);
  color: var(--accent);
}
.search-pill.is-on .search-pill-count { color: inherit; opacity: 0.75; }
.search-pill.is-zero { opacity: 0.5; cursor: default; }

.search-results {
  flex: 1 1 auto;
  min-height: 0;
  margin: 0;
  padding: 0.35rem 0 0.6rem;
  list-style: none;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.search-results:empty { display: none; }
/* the last settled answer, kept while the next query's words are on their way */
.search-results.is-stale { opacity: 0.55; transition: opacity 0.15s; }

.search-group + .search-group { margin-top: 0.35rem; }
.search-group.hue-1 { --g: var(--hue-1); }
.search-group.hue-2 { --g: var(--hue-2); }
.search-group.hue-3 { --g: var(--hue-3); }

.search-group-name {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1.1rem 0.3rem;
  color: var(--faint);
  font: 500 0.66rem/1.4 var(--mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.search-group-name::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--g);
}
.search-group-count { display: inline-flex; align-items: center; gap: 0.5rem; opacity: 0.8; }
/* the dot between the name and the count, drawn: a glyph here would be text
   in a stylesheet, which gen/assets keeps to the guest */
.search-group-count::before {
  content: "";
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: currentColor;
}

.search-group-rows { margin: 0; padding: 0; list-style: none; }

.search-row a, .search-recall {
  position: relative;
  display: block;
  margin: 0 0.45rem;
  padding: 0.5rem 2.2rem 0.55rem 0.75rem;
  border-radius: 8px;
  color: inherit;
  text-decoration: none;
}

/* The selection: a 2px accent bar and a tint of the ink, which is a shade
   darker on white and a shade lighter on the night, so it shows in both. */
.search-row.is-selected a, .search-row.is-selected .search-recall {
  background: color-mix(in srgb, var(--text) 6%, transparent);
  box-shadow: inset 2px 0 0 var(--accent);
}
/* the return key on the selected row, as an icon for the same reason */
.search-row.is-selected a::after {
  content: "";
  position: absolute;
  top: 0.7rem;
  right: 0.85rem;
  width: 0.8rem;
  height: 0.8rem;
  background: var(--accent);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13 3v5.5a2 2 0 0 1-2 2H3.5'/%3E%3Cpath d='m6 7.5-3 3 3 3'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13 3v5.5a2 2 0 0 1-2 2H3.5'/%3E%3Cpath d='m6 7.5-3 3 3 3'/%3E%3C/svg%3E") center / contain no-repeat;
}

.search-head {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  min-width: 0;
}

.search-title {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  font: 500 0.85rem/1.45 var(--mono);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.search-detail {
  flex: 0 1 auto;
  min-width: 0;
  margin-left: auto;
  overflow: hidden;
  color: var(--faint);
  font: 0.7rem/1.45 var(--mono);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.search-title, .search-detail, .search-group-name, .search-panel kbd {
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
}

.search-note {
  display: -webkit-box;
  margin-top: 0.15rem;
  overflow: hidden;
  color: var(--muted);
  font-size: 0.84rem;
  line-height: 1.55;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.search-note code {
  padding: 0;
  background: none;
  color: var(--text);
  font-size: 0.86em;
}

.search-panel mark {
  padding: 0 0.08em;
  border-radius: 3px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--text);
}
.search-title mark { box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--accent) 55%, transparent); }

/* ---- before anything is typed: Recent, then Start here ----
   The rows are result rows with an icon in front: a clock on a recent query,
   an arrow in its group's hue on a suggestion. The icons are masks, like the
   magnifier, so they take a colour from the theme and carry no text. */
.search-group-recent { --g: var(--faint); }
.search-group-start { --g: var(--accent); }
.search-start.hue-1 { --g: var(--hue-1); }
.search-start.hue-2 { --g: var(--hue-2); }
.search-start.hue-3 { --g: var(--hue-3); }

.search-recent { position: relative; }
.search-recall, .search-start a {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding-top: 0.45rem;
  padding-bottom: 0.45rem;
  cursor: pointer;
}
.search-recall .search-title, .search-start .search-head { flex: 1 1 auto; }

.search-icon {
  position: relative;
  flex: none;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 7px;
  color: var(--faint);
  background: var(--code-bg);
}
.search-icon::before {
  content: "";
  position: absolute;
  inset: 0.32rem;
  background: currentColor;
}
.search-icon-clock::before {
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Cpath d='M12 7.5V12l3 2'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Cpath d='M12 7.5V12l3 2'/%3E%3C/svg%3E") center / contain no-repeat;
}
.search-icon-go { color: var(--g); background: color-mix(in srgb, var(--g) 10%, transparent); }
.search-icon-go::before {
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13M13 6l6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13M13 6l6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
}
/* Delete one recent query: a cross at the row's right end, faint until the
   row is under the pointer or the button has focus. */
.search-forget {
  position: absolute;
  top: 50%;
  right: 1rem;
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--faint);
  cursor: pointer;
  opacity: 0.6;
  transform: translateY(-50%);
}
.search-forget::before {
  content: "";
  width: 0.85rem;
  height: 0.85rem;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M7 7l10 10M17 7 7 17'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M7 7l10 10M17 7 7 17'/%3E%3C/svg%3E") center / contain no-repeat;
}
.search-row:hover .search-forget, .search-forget:focus-visible { opacity: 1; }
.search-forget:hover { background: var(--line-soft); color: var(--text); }

/* Clear, at the right end of the Recent heading. */
.search-clear {
  margin-left: auto;
  padding: 0;
  border: 0;
  background: none;
  color: var(--faint);
  font: 0.68rem var(--mono);
  letter-spacing: 0;
  text-transform: none;
  cursor: pointer;
}
.search-clear:hover { color: var(--accent); }

/* ---- a query nothing answers ----
   A small sunrise over the horizon line, the query, and three tips. The
   picture is the stylesheet's: the guest's element for it is empty, because
   tea_dom builds every element in the HTML namespace and an <svg> from the
   guest would not draw. It is the same in both themes, as the brand's
   gradient is. */
.search-nothing { padding: 1.4rem 1.4rem 1.6rem; text-align: center; }
.search-none-art {
  width: 7.5rem;
  height: 4rem;
  margin: 0 auto;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 64'%3E%3Cdefs%3E%3ClinearGradient id='s' x1='0' y1='1' x2='0' y2='0'%3E%3Cstop offset='0' stop-color='%23db2777'/%3E%3Cstop offset='1' stop-color='%237c3aed'/%3E%3C/linearGradient%3E%3ClinearGradient id='l' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='%234f46e5' stop-opacity='0'/%3E%3Cstop offset='.3' stop-color='%234f46e5'/%3E%3Cstop offset='.5' stop-color='%237c3aed'/%3E%3Cstop offset='.7' stop-color='%23db2777'/%3E%3Cstop offset='1' stop-color='%23db2777' stop-opacity='0'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath d='M42 58a18 18 0 0 1 36 0z' fill='url(%23s)' opacity='.85'/%3E%3Crect x='0' y='57' width='120' height='2' fill='url(%23l)'/%3E%3C/svg%3E") center / contain no-repeat;
}
.search-none-title { margin: 0.4rem 0 1.1rem; color: var(--text); font-weight: 650; overflow-wrap: anywhere; }
/* "Did you mean handle? 9 results", when the panel has a query like this
   one that answers. The term is a button that reads as a link: it asks the
   suggested query in place rather than going anywhere. It closes the gap the
   title leaves for the tips, so the two lines read as one answer. */
.search-fix { margin: -0.9rem 0 1.1rem; color: var(--muted); font-size: 0.95rem; overflow-wrap: anywhere; }
.search-fix-term {
  padding: 0;
  border: 0;
  border-bottom: 1px dashed color-mix(in srgb, var(--accent) 55%, transparent);
  background: none;
  color: var(--accent);
  font: 500 0.95rem var(--mono);
  cursor: pointer;
}
.search-fix-term:hover { border-bottom-style: solid; }
.search-fix-term:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
.search-fix-count { margin-left: 0.35rem; color: var(--faint); font: 0.72rem var(--mono); }
.search-tips {
  max-width: 28rem;
  margin: 0 auto;
  padding: 0.9rem 0 0;
  border-top: 1px solid var(--line-soft);
  list-style: none;
  color: var(--muted);
  font-size: 0.86rem;
  text-align: left;
}
.search-tips li { position: relative; margin: 0.35rem 0; padding-left: 1rem; }
.search-tips li::before {
  content: "";
  position: absolute;
  top: 0.62em;
  left: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--line);
}
.search-tips code {
  padding: 0.02em 0.3em;
  border-radius: 4px;
  background: var(--code-bg);
  color: var(--text);
  font-size: 0.86em;
}

/* The live region is always there and is empty while there are rows. */
.search-none:empty { display: none; }
.search-status {
  margin: 0;
  padding: 1.4rem 1.1rem 1.5rem;
  color: var(--muted);
  font-size: 0.9rem;
  text-align: center;
}

.search-foot {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 1rem;
  padding: 0.6rem 1.1rem;
  border-top: 1px solid var(--line-soft);
  background: var(--code-bg);
  color: var(--faint);
  font-size: 0.74rem;
}
.search-keys { display: flex; flex-wrap: wrap; gap: 0.4rem 1rem; }
.search-hint { display: inline-flex; align-items: center; gap: 0.25rem; }
.search-foot kbd { min-width: 1.3rem; height: 1.2rem; font-size: 0.64rem; background: var(--surface); }
.search-scope { margin: 0 0 0 auto; font-size: 0.72rem; }

/* Copy link, at the end of the foot while there is a query. It is a button
   drawn as a pill, so it reads as something to press and not as one more
   key hint. Both of its labels are the guest's; `is-copied` on the host is
   search.js's word that the clipboard took the link, and swaps them for a
   moment. The status line repeats it for a screen reader and is otherwise
   off screen. */
.search-copy {
  flex: none;
  padding: 0.12rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font: inherit;
  cursor: pointer;
}
.search-copy:hover { color: var(--text); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.search-copy-done, .search-copy-said-text { display: none; }
.search-host.is-copied .search-copy-do { display: none; }
.search-host.is-copied .search-copy-done { display: inline; color: var(--accent); }
.search-host.is-copied .search-copy-said-text { display: inline; }
.search-copy-said {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* A clipboard that refused: the address in a field under the panel,
   selected, for the reader to copy. */
.search-copy-manual {
  display: block;
  width: 100%;
  max-width: 42rem;
  margin: 0.5rem auto 0;
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font: 0.8rem var(--mono);
}

/* What Enter left behind. The page script reads it and leaves, so no reader
   ever sees it. */
.search-goto { display: none; }

/* A phone: the panel is the whole screen. No scrim, no corners, the field
   at 16px so that focusing it does not zoom the page, a Cancel button where
   there is no Escape key, and no key hints where there are no keys (the line
   saying what is searched stays). */
@media (max-width: 40rem) {
  .search-host {
    padding: 0;
    background: var(--surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .search-panel {
    position: fixed;
    inset: 0;
    max-width: none;
    max-height: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }
  .search-bar { padding: 0.75rem 16px; }
  .search-input { font-size: 16px; }
  .search-panel .search-esc, .search-keys { display: none; }
  .search-cancel { display: inline-block; }
  .search-group-name, .search-pills { padding-left: 16px; padding-right: 16px; }
  .search-row a, .search-recall { margin: 0 8px; }
  .search-forget { right: calc(8px + 0.55rem); }
  .search-head { flex-wrap: wrap; row-gap: 0; }
  .search-title, .search-detail { flex: 1 1 100%; }
  .search-detail { margin-left: 0; }
  .search-foot { margin-top: auto; padding: 0.5rem 16px; }
  .search-scope { margin-left: 0; }
  /* the panel is the screen here, so the fallback field floats over its foot,
     at 16px for the reason the search field is */
  .search-copy-manual { position: fixed; left: 16px; right: 16px; bottom: 3.25rem; z-index: 1; width: auto; margin: 0; font-size: 16px; }
}

/* The panel drops in and the scrim fades; on a phone the sheet rises. None
   of it under reduced motion, and none of it holds a fill, so a panel at
   rest has no animation attached. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes search-fade { from { opacity: 0; } }
  @keyframes search-drop { from { opacity: 0; transform: translateY(-10px) scale(0.985); } }
  @keyframes search-rise { from { opacity: 0; transform: translateY(24px); } }
  .search-host { animation: search-fade 0.25s ease; }
  .search-panel { animation: search-drop 0.28s cubic-bezier(0.2, 0.7, 0.2, 1); }
  .search-row a, .search-recall { transition: background-color 0.12s ease, box-shadow 0.12s ease; }
  @media (max-width: 40rem) {
    .search-host { animation: none; }
    .search-panel { animation-name: search-rise; animation-duration: 0.3s; }
  }
}

/* ---- print ---- */
/* A printed page is the document: the band, the search panel, the footer,
   the contents rail, the anchors and the windows' bars are all for a reader
   with a pointer, and the first three printed on every page. */
@media print {
  .sky, .progress, .site-footer, .search-host, .toc, .anchor, .win-bar { display: none; }
  .with-toc { display: block; }
  main.page { padding-top: 0; }
  pre { white-space: pre-wrap; break-inside: avoid; }
}

/* An interactive example's screens (site/src/gen/screens.dawn): one frame per
   line fed to the program, each under the line that produced it. The ANSI
   bold/dim/underline the program wrote are the sg-* classes; dim reuses the
   theme's faint colour so both themes are covered by the existing tokens. */
.win.run .screens { display: grid; gap: 0; }
.win.run .screen { margin: 0; border-top: 1px dashed var(--line); }
.win.run .screen-cap { margin: 0; padding: 0.5rem 1.15rem 0; font: 0.76rem var(--mono); color: var(--faint); }
.win.run .screen-cap code { background: none; border: 0; padding: 0; font-size: inherit; color: var(--muted); }
.win.run .screen-cap code::before { content: "> "; color: var(--faint); }
.win.run .screen pre.output { border-top: 0; padding-top: 0.25rem; padding-bottom: 0.6rem; }
.sg-b { font-weight: 700; }
.sg-d { color: var(--faint); }
.sg-u { text-decoration: underline; }
