/* DWS Research, on Skiff and Amidol's frame. Two halves: words on white in one mono, and
   figure plates on the grey. Same rows as the app sites, minus the collage: plates sit
   straight, stacked, like figures in a paper.

   ┌──────────── row ────────────┬──────────────────────────────┐
   │ .txt   mono, lists, tags    │ .pics  .plate                 │
   │                             │        .plate  (straight)     │
   └─────────────────────────────┴──────────────────────────────┘ */

@font-face {
  font-family: "DWS Mono";
  src: url("/fonts/dwsmono-regular.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "DWS Mono";
  src: url("/fonts/dwsmono-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

:root {
  --paper: #ffffff;
  --side: #f2f1ee;
  --ink: #161616;
  --mute: #8f8c86;
  --rule: #c9c6bf;
  --hair: #e8e6e1;
  --edge: rgb(20 20 20 / 0.1);
  --shadow: 0 1px 2px rgb(20 20 20 / 0.05), 0 18px 36px -24px rgb(20 20 20 / 0.3);

  /* One accent, the loss curve in the icon. */
  --accent: #2f4fc0;
  --accent-soft: #dfe6fb;

  /* Token tints: four, so neighbours never match. */
  --t0: #dfe6fb;
  --t1: #fdebd6;
  --t2: #dcefe0;
  --t3: #f3e1ef;

  --mono: "DWS Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --pad: clamp(20px, 2.6vw, 36px);
  --gap: clamp(40px, min(8vw, 11vh), 112px);

  color-scheme: light;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  overflow-x: clip;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  overflow-x: clip;
  margin: 0;
  background: linear-gradient(90deg, var(--paper) 50%, var(--side) 50%);
  color: var(--ink);
  /* Type grows with the window, same curve as Skiff and Amidol. */
  font: 400 clamp(15px, 0.9vw + 6.5px, 26px)/1.7 var(--mono);
  -webkit-font-smoothing: antialiased;
}

img,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  text-decoration-color: var(--rule);
}

a:hover {
  text-decoration-color: currentColor;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

h1,
h2,
h3,
p,
ul,
ol,
dl,
pre {
  margin: 0 0 1.4em;
}

h1,
h2,
h3 {
  font: inherit;
}

.skip {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 50;
  padding: 8px 12px;
  background: var(--ink);
  color: var(--paper);
}

.skip:focus {
  top: 12px;
}

/* ── Rows: words left, plates right ──────────────────────── */

.row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.txt {
  padding: var(--gap) var(--pad) 0;
}

.txt > * {
  max-width: 54ch;
}

.txt > .table,
.txt > .tbl,
.txt > .topbar {
  max-width: 66ch;
}

.pics {
  display: flex;
  flex-direction: column;
  gap: var(--pad);
  padding: var(--gap) var(--pad) 0;
}

.foot .txt {
  padding-bottom: var(--gap);
}

/* ── Top: name and nav ───────────────────────────────────── */

.topbar {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  max-width: none !important;
  margin: calc(var(--pad) - var(--gap)) 0 clamp(40px, min(9vw, 10vh), 120px);
}

.topbar .name {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  white-space: nowrap;
}

.topbar .name img {
  width: 1.45em;
  height: 1.45em;
}

.topbar nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 4px 22px;
  color: var(--mute);
}

.topbar nav a {
  text-decoration: none;
}

.topbar nav a:hover,
.topbar nav a[aria-current] {
  color: var(--ink);
}

/* Projects dropdown: a <details> panel with the project tree inside.

   Projects ▾
   ┌──────────────┐
   │ DWSLM        │
   │ └ Tokenizer  │
   └──────────────┘ */
.menu {
  position: relative;
}

.menu summary {
  display: block;
  list-style: none;
  cursor: pointer;
}

.menu summary::-webkit-details-marker {
  display: none;
}

.menu summary::after {
  content: " ▾";
  font-size: 0.8em;
}

.menu summary:hover,
.menu[open] summary {
  color: var(--ink);
}

.topbar .menu ul {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 40;
  min-width: 18ch;
  margin: 0;
  padding: 0.6em 0;
  list-style: none;
  border: 1px solid var(--edge);
  border-radius: 6px;
  background: var(--paper);
  box-shadow: var(--shadow);
}

.topbar .menu li {
  margin: 0;
  padding: 0;
}

.topbar .menu li::before {
  content: none;
}

.topbar .menu a {
  display: block;
  padding: 0.15em 1.2em;
  white-space: nowrap;
}

/* The nested level sits in the same panel, drawn as a tree branch. */
.topbar .menu ul ul {
  position: static;
  min-width: 0;
  padding: 0;
  border: 0;
  box-shadow: none;
}

.topbar .menu ul ul a::before {
  content: "└ ";
  color: var(--rule);
}

/* Focus areas: area on the left, where to look on the right. */
.areas {
  display: grid;
  gap: 0.35em;
  margin: 0 0 1.4em;
}

.txt > .areas {
  max-width: 72ch;
}

.areas div {
  display: grid;
  grid-template-columns: 27ch minmax(0, 1fr);
  gap: 2ch;
}

.areas dd {
  margin: 0;
}

/* ── Text pieces ─────────────────────────────────────────── */

.lede {
  font-size: 1.12em;
  line-height: 1.6;
}

h2 .n,
.mute {
  color: var(--mute);
}

h2 .n {
  margin-right: 1ch;
}

.txt h3 {
  margin: 1.6em 0 0.4em;
  color: var(--mute);
}

.txt ul {
  padding-left: 0;
  list-style: none;
}

.txt ul li {
  position: relative;
  padding-left: 2.6ch;
}

.txt ul li::before {
  content: "•";
  position: absolute;
  left: 1ch;
}

.txt ol {
  padding-left: 3ch;
}

.txt li {
  margin-bottom: 0.2em;
}

code,
kbd {
  font: inherit;
}

code {
  padding: 0 0.3em;
  background: var(--side);
  border-radius: 3px;
}

.fine {
  color: var(--mute);
  font-size: 0.86em;
}

/* Status tags: done, now, next, later. */
.tag {
  display: inline-block;
  padding: 0 0.5em;
  border-radius: 4px;
  font-size: 0.86em;
  line-height: 1.7;
  white-space: nowrap;
}

.tag.done { background: #dcefe0; color: #2d6a3e; }
.tag.now { background: var(--accent-soft); color: var(--accent); }
.tag.next { background: var(--side); color: var(--ink); }
.tag.later { background: var(--side); color: var(--mute); }

/* Index table: name, what, and a tag or a number. */
.table {
  margin: 0 0 1.6em;
}

.table > a,
.table > div {
  display: grid;
  grid-template-columns: 15ch minmax(0, 1fr) auto;
  gap: 2ch;
  padding: 0.28em 0;
  text-decoration: none;
}

.table a:hover .what {
  text-decoration: underline;
  text-decoration-color: var(--rule);
}

.table .end {
  color: var(--mute);
  text-align: right;
}

/* Spec list: label left, value right. */
.spec {
  display: grid;
  grid-template-columns: 13ch minmax(0, 1fr);
  gap: 0.25em 2ch;
}

.spec dt {
  color: var(--mute);
}

.spec dd {
  margin: 0;
}

/* Plain tables. */
.tbl {
  overflow-x: auto;
  margin: 0 0 1.4em;
}

.tbl table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92em;
}

.tbl th,
.tbl td {
  padding: 0.45em 1.5ch 0.45em 0;
  border-bottom: 1px solid var(--hair);
  text-align: left;
  vertical-align: top;
}

.tbl th {
  color: var(--mute);
  font-weight: 400;
}

.tbl .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ── Plates: figures on the grey, straight ───────────────── */

.plate {
  width: min(100%, 860px);
  margin: 0;
  padding: clamp(16px, 1.6vw, 28px);
  border: 1px solid var(--edge);
  border-radius: 8px;
  background: var(--paper);
  box-shadow: var(--shadow);
}

.plate figcaption {
  margin-top: 1em;
  color: var(--mute);
  font-size: 0.78em;
  line-height: 1.55;
}

.plate figcaption b {
  font-weight: 400;
  color: var(--ink);
}

.plate .spec {
  margin: 0;
  font-size: 0.86em;
}

/* A spec list under a chart in the same plate needs air. */
.plate .chart + .spec {
  margin-top: 1.4em;
}

.plate .tbl {
  margin: 0;
}

/* Big numbers, two across. */
.figs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.2em 2ch;
  margin: 0;
}

.figs div {
  display: grid;
  gap: 0.1em;
}

.figs dt {
  order: 2;
  color: var(--mute);
  font-size: 0.8em;
}

.figs dd {
  margin: 0;
  font-size: 1.9em;
  line-height: 1.15;
}

/* Phase progress: one cell per phase. */
.progress {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
  margin: 1.4em 0 0.5em;
  padding: 0;
  list-style: none;
}

.progress li {
  height: 10px;
  border-radius: 2px;
  background: var(--hair);
}

.progress .done { background: var(--ink); }
.progress .now { background: var(--accent); }

.progress-label {
  display: flex;
  justify-content: space-between;
  margin: 0;
  color: var(--mute);
  font-size: 0.8em;
}

/* Charts are inline SVG so they get the page's font. Sizes are SVG user units. */
.chart {
  width: 100%;
  font-family: var(--mono);
}

.chart text { fill: var(--ink); font-size: 13px; }
.chart .m { fill: var(--mute); }
.chart .s { font-size: 11px; }
.chart .w { fill: var(--paper); }
.chart .ac { fill: var(--accent); }
.chart .ink { fill: var(--ink); }
.chart .soft { fill: var(--accent-soft); }
.chart .hair { fill: var(--hair); }
.chart .grey { fill: var(--rule); }
.chart .ln { stroke: var(--rule); stroke-width: 1; fill: none; }
.chart .ln-ink { stroke: var(--ink); stroke-width: 1.5; fill: none; }
.chart .dash { stroke: var(--mute); stroke-width: 1; stroke-dasharray: 3 3; fill: none; }
.chart .ring { fill: var(--paper); stroke: var(--rule); stroke-width: 1.5; }
.chart .ring-ac { fill: var(--paper); stroke: var(--accent); stroke-width: 2; }

/* ── Tokens: one tinted chip per token ───────────────────── */

.toks {
  margin: 0;
  font-size: 0.92em;
  line-height: 2.1;
  overflow-wrap: anywhere;
}

.toks span {
  padding: 0.12em 0.08em;
  border-radius: 3px;
  white-space: pre;
}

.toks span:nth-child(4n + 1) { background: var(--t0); }
.toks span:nth-child(4n + 2) { background: var(--t1); }
.toks span:nth-child(4n + 3) { background: var(--t2); }
.toks span:nth-child(4n + 4) { background: var(--t3); }

/* A character that took several byte-fragment tokens: count in the corner. */
.toks [data-n]::after {
  content: attr(data-n);
  margin-left: 1px;
  color: var(--accent);
  font-size: 0.62em;
  vertical-align: super;
}

.toks + .toks {
  margin-top: 0.8em;
}

.tok-label {
  margin: 0 0 0.2em;
  color: var(--mute);
  font-size: 0.78em;
}

.tok-label + .toks {
  margin-top: 0;
}

.toks + .tok-label {
  margin-top: 1em;
}

/* ── Live demo ───────────────────────────────────────────── */

.demo textarea {
  display: block;
  width: 100%;
  min-height: 8.5em;
  margin: 0 0 0.8em;
  padding: 12px 14px;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-size: 0.92em;
  line-height: 1.6;
  resize: vertical;
}

.demo textarea:focus {
  border-color: var(--accent);
  outline: none;
}

.presets {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 1.4em;
}

.presets button,
.pick button {
  padding: 2px 10px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-size: 0.82em;
  cursor: pointer;
}

.presets button:hover,
.pick button:hover {
  border-color: var(--ink);
}

.pick {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 1em;
}

.pick button[aria-pressed="true"] {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--paper);
}

.stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4em 3ch;
  margin: 0 0 1em;
  font-size: 0.86em;
}

.stats b {
  font-weight: 400;
  font-size: 1.4em;
}

.stats span {
  color: var(--mute);
}

.chips {
  max-height: 60vh;
  overflow-y: auto;
  white-space: pre-wrap;
}

.cmp tr.ours td {
  color: var(--accent);
}

.cmp td.best::after {
  content: " ←";
  color: var(--mute);
}

/* ── Footer ──────────────────────────────────────────────── */

.foot .txt {
  color: var(--mute);
  font-size: 0.86em;
}

.foot nav {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 20px;
  margin: 0 0 1em;
  color: var(--ink);
}

.foot nav a {
  text-decoration: none;
}

.foot nav a:hover {
  text-decoration: underline;
}

/* ── Live dashboard (/llm/dashboard): drawn by dashboard.js ─ */

/* Run states. Failed and stale wear status colors and always say so in words. */
.tag.running { background: var(--accent-soft); color: var(--accent); }
.tag.stale { background: #fdebd6; color: #8a5a12; }
.tag.failed { background: #f8dcdc; color: #a12d2d; }
.tag.stopped { background: var(--side); color: var(--mute); }
.tag.paused { background: var(--side); color: var(--ink); } /* on purpose, resumes by itself */

.chart .ln-ac { stroke: var(--accent); stroke-width: 2; fill: none; }
.chart .ln-2 { stroke: var(--ink); stroke-width: 2; fill: none; }
.chart .ln-dash { stroke: var(--ink); stroke-width: 2; stroke-dasharray: 5 4; fill: none; }
.chart .dashed { stroke-dasharray: 5 4; }
.chart .dotted { stroke-dasharray: 1 4; stroke-linecap: round; }
.chart .ln-mute { stroke: var(--rule); stroke-width: 1.5; fill: none; }
.chart .ln-ref { stroke: var(--mute); stroke-width: 2; fill: none; } /* another type's run, shown for reference */
.chart .longdash { stroke-dasharray: 10 3; } /* a second baseline in the same row */
.chart .ln-seed { stroke: #b3afa7; stroke-width: 1.5; fill: none; } /* seed reruns: the noise band around a baseline */
.chart .pick { stroke-width: 3.5; } /* the run picked in Fig. 2, in every side-by-side chart */
.chart .cross { stroke: var(--mute); stroke-width: 1; }
.chart .hit { fill: transparent; cursor: crosshair; }
.chart .tip { fill: var(--paper); stroke: var(--rule); stroke-width: 1; }
.chart .dot { fill: var(--accent); stroke: var(--paper); stroke-width: 2; }

/* LR sweep: one hue, light to dark with the peak LR (sequential, not categorical). */
.chart .q0 { stroke: #7189db; }
.chart .q1 { stroke: #4d69cf; }
.chart .q2 { stroke: #2f4fc0; }
.chart .q3 { stroke: #1f3591; }
.chart .q4 { stroke: #121f55; }

.tbl .dash-runs { font-size: 0.8em; } /* seven columns fit a laptop's half without sideways scrolling */
.tbl .dash-cloze { font-size: 0.78em; } /* up to ten columns of three digits */
.dash-cloze th,
.dash-cloze td { padding-right: 1.1ch; }
.dash-cloze th:first-child,
.dash-cloze td:first-child { position: sticky; left: 0; background: var(--paper); } /* task names stay put while the columns scroll */
.dash-runs a { color: var(--ink); }
.dash-runs th,
.dash-runs td { white-space: nowrap; }
.dash-runs td:first-child { white-space: normal; } /* long run names wrap at their hyphens, the numbers never do */
.dash-runs tr.sel td { background: var(--accent-soft); }
.dash-none { color: var(--mute); }

/* Plates fill their half here: the site's 860px cap suits one chart, not a table or a grid of run cards.
   Run-type charts flow two across once the half fits two 18em charts; min-width 0 lets a plate scroll on phones. */
.dash .plate { width: auto; }

.dash .pics.charts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 18em), 1fr));
  align-content: start;
}

.dash .pics.charts > .plate { min-width: 0; }

/* Fig. 1: one card per live run, as many across as fit 14em cards (em, since type grows with the window). */
#dash-now {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 14em), 1fr));
  gap: 2.4em 4ch;
}

#dash-now > .dash-none { grid-column: 1 / -1; }
.now-run > p { margin: 0 0 0.6em; }
.now-run .figs { margin-top: 0.8em; }
.now-run .figs dd { font-size: 1.5em; } /* seven-character values ("pending") fit a 14em card */
/* The per-slice table (80-odd rows) folds behind one line until asked for. */
.fold summary { list-style: none; cursor: pointer; }
.fold summary::-webkit-details-marker { display: none; }
.fold summary::after { content: " ▾"; font-size: 0.8em; }
.fold[open] summary { margin-bottom: 1em; }
.fold[open] summary::after { content: " ▴"; }
.nobr { white-space: nowrap; }
.dash .plate[hidden] { display: none; } /* plates without data (cloze, long context) stay out of the way */
#run-scores table + table { margin-top: 1.4em; } /* "1e-02" never splits at its hyphen */

/* ── Phones and narrow windows: one column, plates under their words ── */

@media (max-width: 900px) {
  body {
    background: var(--paper);
  }

  .row {
    grid-template-columns: minmax(0, 1fr);
  }

  .txt {
    padding-top: 56px;
  }

  .topbar {
    margin-top: calc(var(--pad) - 56px);
    margin-bottom: 56px;
  }

  .pics {
    margin-top: 28px;
    padding: 32px var(--pad) 40px;
    background: var(--side);
  }

  .pics:empty {
    display: none;
  }
}

@media (max-width: 560px) {
  body {
    font-size: 14.5px;
  }

  .topbar nav .wide {
    display: none;
  }

  .table a,
  .table > div {
    grid-template-columns: 12ch minmax(0, 1fr);
  }

  .table .end {
    display: none;
  }

  .areas div {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }

  .areas dd {
    margin-bottom: 0.5em;
    color: var(--mute);
  }

  /* Status tables keep their tags: the tag is the point. */
  .table.status > a,
  .table.status > div {
    grid-template-columns: 12ch minmax(0, 1fr) auto;
  }

  .table.status .end {
    display: block;
  }

  .spec {
    grid-template-columns: 11ch minmax(0, 1fr);
  }

  .figs dd {
    font-size: 1.6em;
  }

  /* Charts keep a readable size and scroll inside their plate instead of shrinking to 9px text. */
  .plate:has(.chart) {
    overflow-x: auto;
  }

  .chart {
    min-width: 420px;
  }

  /* progress bars are just bars: they shrink with the card */
  .chart.bar {
    min-width: 0;
  }

  /* The demo table drops vocab size so token counts fit. */
  .cmp th:nth-child(2),
  .cmp td:nth-child(2) {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}

/* ── Try page: the chat ──────────────────────────────────── */

.chat-log {
  min-height: 14em;
  max-height: 32em;
  margin: 0 0 1em;
  overflow-y: auto;
  font-size: 0.92em;
  line-height: 1.6;
}

.msg { margin: 0 0 1em; white-space: pre-wrap; overflow-wrap: anywhere; }
.msg .who { display: block; color: var(--mute); font-size: 0.82em; }
.msg.err { color: var(--mute); }
.chat-log .dash-none { margin: 0; }

.chat-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4em 3ch;
  margin: 0 0 1em;
  color: var(--mute);
  font-size: 0.82em;
}

.chat-form textarea { min-height: 4.5em; }

.chat-opts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11em, 1fr));
  gap: 0.8em 2ch;
  margin: 0 0 1.4em;
  font-size: 0.82em;
}

.chat-opts label { display: grid; gap: 0.2em; color: var(--mute); }

.chat-opts input {
  padding: 2px 8px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
}

.presets button:disabled { opacity: 0.45; cursor: default; }
.presets button:disabled:hover { border-color: var(--rule); }
.try .plate[hidden], .try [hidden] { display: none; }

/* ── Model card ──────────────────────────────────────────── */

.txt blockquote {
  margin: 0 0 1.4em;
  padding-left: 2ch;
  border-left: 1px solid var(--rule);
}

.toc { margin: 0; font-size: 0.9em; }
.toc a { color: var(--ink); }

.plate pre {
  margin: 0;
  overflow-x: auto;
  font-size: 0.7em;
  line-height: 1.4;
}

.tbl .card { font-size: 0.86em; }
.tbl .card-wide { font-size: 0.74em; }
.card tr.tot td { border-top: 1px solid var(--rule); color: var(--ink); }
.card th.num, .card td.num { white-space: nowrap; }

/* ── Report diagrams and figures ─────────────────────────── */

.chart .box { fill: var(--paper); stroke: var(--rule); stroke-width: 1; }
.chart .box-ac { fill: var(--accent-soft); stroke: var(--accent); stroke-width: 1; }
.chart .frame { fill: none; stroke: var(--rule); stroke-width: 1; stroke-dasharray: 3 3; }
.chart .arw { fill: var(--mute); }
.chart .ln-m { stroke: var(--mute); stroke-width: 1; fill: none; }
.chart .g1 { fill: #b3afa7; }
.chart .g2 { fill: #8f8c86; }
.chart .g3 { fill: #5b5852; }
.chart .g4 { fill: #2b2a27; }

/* Links inside a row's description. */
.table .what a {
  text-decoration: underline;
  text-decoration-color: var(--rule);
}
