@layer reset, base, components, content, utilities;
@view-transition { navigation: auto; }
:root {
  --series-0: #0072b2;
  --series-1: #e69f00;
  --series-2: #009e73;
  --series-3: #cc79a7;
  --series-4: #56b4e9;
  --series-5: #d55e00;
  --series-6: #c9b800;
  --series-7: #8a8a8a;
  --qr-ground: #ffffff;
}
:root {
  --bg: #fafafa;
  --fg: #18181b;
  --card: #ffffff;
  --muted: #f4f4f5;
  --muted-fg: #6b7280;
  --faint: #a1a1aa;
  --border: #e4e4e7;
  --border-strong: #d4d4d8;
  --primary: #18181b;
  --primary-fg: #fafafa;
  --accent: #2563eb;
  --accent-fg: #ffffff;
  --danger: #dc2626;
  --success: #16a34a;
  --attn: #d97706;
  --merged: #7c3aed;
  --add-bg: #e6ffec;
  --add-fg: #1a7f37;
  --add-edge: #2da44e;
  --del-bg: #ffebe9;
  --del-fg: #cf222e;
  --del-edge: #cf222e;
  --wd-add: #abf2bc;
  --wd-del: #ffc9c2;
  --shadow-1: 0 1px 2px rgb(24 24 27 / 0.05);
  --shadow-2: 0 8px 24px rgb(24 24 27 / 0.10);
  --tok-keyword: #cf222e;
  --tok-string: #0a3069;
  --tok-comment: #6e7781;
  --tok-number: #0550ae;
  --tok-function: #8250df;
  --tok-type: #953800;
  --tok-constant: #0550ae;
  --tok-meta: #116329;
  --tok-property: #0550ae;
  --tok-operator: #57606a;
  --tok-punctuation: #8c959f;
  --tok-tag: #116329;
  --tok-attribute: #953800;
  --tok-regex: #1a7f37;
  --tok-variable: #953800;
  --tok-decorator: #8250df;
  --tok-heading: #0550ae;
  --tok-emphasis: #24292f;
  --tok-link: #0969da;
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) {
  --bg: #09090b;
  --fg: #f4f4f5;
  --card: #111113;
  --muted: #1b1b1f;
  --muted-fg: #a1a1aa;
  --faint: #70707b;
  --border: #27272a;
  --border-strong: #3f3f46;
  --primary: #fafafa;
  --primary-fg: #18181b;
  --accent: #58a6ff;
  --accent-fg: #0b0b0d;
  --danger: #f85149;
  --success: #3fb950;
  --attn: #d29922;
  --merged: #a371f7;
  --add-bg: #12261e;
  --add-fg: #3fb950;
  --add-edge: #2ea043;
  --del-bg: #25171c;
  --del-fg: #f85149;
  --del-edge: #f85149;
  --wd-add: #1b4721;
  --wd-del: #5a1e21;
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.5);
  --shadow-2: 0 12px 32px rgb(0 0 0 / 0.55);
  --tok-keyword: #ff7b72;
  --tok-string: #a5d6ff;
  --tok-comment: #8b949e;
  --tok-number: #79c0ff;
  --tok-function: #d2a8ff;
  --tok-type: #ffa657;
  --tok-constant: #79c0ff;
  --tok-meta: #7ee787;
  --tok-property: #79c0ff;
  --tok-operator: #9198a1;
  --tok-punctuation: #6e7681;
  --tok-tag: #7ee787;
  --tok-attribute: #ffa657;
  --tok-regex: #56d364;
  --tok-variable: #ffa657;
  --tok-decorator: #d2a8ff;
  --tok-heading: #79c0ff;
  --tok-emphasis: #f0f6fc;
  --tok-link: #58a6ff;
  color-scheme: dark;
}
}
:root[data-theme="light"] {
  --bg: #fafafa;
  --fg: #18181b;
  --card: #ffffff;
  --muted: #f4f4f5;
  --muted-fg: #6b7280;
  --faint: #a1a1aa;
  --border: #e4e4e7;
  --border-strong: #d4d4d8;
  --primary: #18181b;
  --primary-fg: #fafafa;
  --accent: #2563eb;
  --accent-fg: #ffffff;
  --danger: #dc2626;
  --success: #16a34a;
  --attn: #d97706;
  --merged: #7c3aed;
  --add-bg: #e6ffec;
  --add-fg: #1a7f37;
  --add-edge: #2da44e;
  --del-bg: #ffebe9;
  --del-fg: #cf222e;
  --del-edge: #cf222e;
  --wd-add: #abf2bc;
  --wd-del: #ffc9c2;
  --shadow-1: 0 1px 2px rgb(24 24 27 / 0.05);
  --shadow-2: 0 8px 24px rgb(24 24 27 / 0.10);
  --tok-keyword: #cf222e;
  --tok-string: #0a3069;
  --tok-comment: #6e7781;
  --tok-number: #0550ae;
  --tok-function: #8250df;
  --tok-type: #953800;
  --tok-constant: #0550ae;
  --tok-meta: #116329;
  --tok-property: #0550ae;
  --tok-operator: #57606a;
  --tok-punctuation: #8c959f;
  --tok-tag: #116329;
  --tok-attribute: #953800;
  --tok-regex: #1a7f37;
  --tok-variable: #953800;
  --tok-decorator: #8250df;
  --tok-heading: #0550ae;
  --tok-emphasis: #24292f;
  --tok-link: #0969da;
  color-scheme: light;
}
:root[data-theme="paper"] {
  --bg: #f2f0e5;
  --fg: #100f0f;
  --card: #fffcf0;
  --muted: #e6e4d9;
  --muted-fg: #6f6e69;
  --faint: #b7b5ac;
  --border: #dad8ce;
  --border-strong: #cecdc3;
  --primary: #100f0f;
  --primary-fg: #fffcf0;
  --accent: #205ea6;
  --accent-fg: #fffcf0;
  --danger: #af3029;
  --success: #66800b;
  --attn: #ad8301;
  --merged: #5e409d;
  --add-bg: #e4e7c5;
  --add-fg: #66800b;
  --add-edge: #879a39;
  --del-bg: #ffe1d5;
  --del-fg: #af3029;
  --del-edge: #d14d41;
  --wd-add: #c9d18c;
  --wd-del: #ffc5b2;
  --shadow-1: 0 1px 2px rgb(16 15 15 / 0.06);
  --shadow-2: 0 8px 24px rgb(16 15 15 / 0.12);
  --tok-keyword: #af3029;
  --tok-string: #24837b;
  --tok-comment: #878580;
  --tok-number: #205ea6;
  --tok-function: #5e409d;
  --tok-type: #bc5215;
  --tok-constant: #205ea6;
  --tok-meta: #66800b;
  --tok-property: #205ea6;
  --tok-operator: #6f6e69;
  --tok-punctuation: #b7b5ac;
  --tok-tag: #66800b;
  --tok-attribute: #bc5215;
  --tok-regex: #24837b;
  --tok-variable: #bc5215;
  --tok-decorator: #5e409d;
  --tok-heading: #205ea6;
  --tok-emphasis: #100f0f;
  --tok-link: #205ea6;
  color-scheme: light;
}
:root[data-theme="dawn"] {
  --bg: #faf4ed;
  --fg: #575279;
  --card: #fffaf3;
  --muted: #f2e9e1;
  --muted-fg: #797593;
  --faint: #9893a5;
  --border: #dfdad9;
  --border-strong: #cecacd;
  --primary: #575279;
  --primary-fg: #faf4ed;
  --accent: #286983;
  --accent-fg: #faf4ed;
  --danger: #b4637a;
  --success: #56949f;
  --attn: #ea9d34;
  --merged: #907aa9;
  --add-bg: #e0ead9;
  --add-fg: #4e7a4e;
  --add-edge: #6f9a6f;
  --del-bg: #f7e2dd;
  --del-fg: #b4637a;
  --del-edge: #d7827e;
  --wd-add: #c3d6bb;
  --wd-del: #f2c5bc;
  --shadow-1: 0 1px 2px rgb(87 82 121 / 0.06);
  --shadow-2: 0 8px 24px rgb(87 82 121 / 0.12);
  --tok-keyword: #286983;
  --tok-string: #ea9d34;
  --tok-comment: #9893a5;
  --tok-number: #b4637a;
  --tok-function: #d7827e;
  --tok-type: #56949f;
  --tok-constant: #907aa9;
  --tok-meta: #56949f;
  --tok-property: #56949f;
  --tok-operator: #797593;
  --tok-punctuation: #9893a5;
  --tok-tag: #286983;
  --tok-attribute: #d7827e;
  --tok-regex: #ea9d34;
  --tok-variable: #575279;
  --tok-decorator: #907aa9;
  --tok-heading: #b4637a;
  --tok-emphasis: #575279;
  --tok-link: #286983;
  color-scheme: light;
}
:root[data-theme="dark"] {
  --bg: #09090b;
  --fg: #f4f4f5;
  --card: #111113;
  --muted: #1b1b1f;
  --muted-fg: #a1a1aa;
  --faint: #70707b;
  --border: #27272a;
  --border-strong: #3f3f46;
  --primary: #fafafa;
  --primary-fg: #18181b;
  --accent: #58a6ff;
  --accent-fg: #0b0b0d;
  --danger: #f85149;
  --success: #3fb950;
  --attn: #d29922;
  --merged: #a371f7;
  --add-bg: #12261e;
  --add-fg: #3fb950;
  --add-edge: #2ea043;
  --del-bg: #25171c;
  --del-fg: #f85149;
  --del-edge: #f85149;
  --wd-add: #1b4721;
  --wd-del: #5a1e21;
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.5);
  --shadow-2: 0 12px 32px rgb(0 0 0 / 0.55);
  --tok-keyword: #ff7b72;
  --tok-string: #a5d6ff;
  --tok-comment: #8b949e;
  --tok-number: #79c0ff;
  --tok-function: #d2a8ff;
  --tok-type: #ffa657;
  --tok-constant: #79c0ff;
  --tok-meta: #7ee787;
  --tok-property: #79c0ff;
  --tok-operator: #9198a1;
  --tok-punctuation: #6e7681;
  --tok-tag: #7ee787;
  --tok-attribute: #ffa657;
  --tok-regex: #56d364;
  --tok-variable: #ffa657;
  --tok-decorator: #d2a8ff;
  --tok-heading: #79c0ff;
  --tok-emphasis: #f0f6fc;
  --tok-link: #58a6ff;
  color-scheme: dark;
}
:root[data-theme="midnight"] {
  --bg: #16161e;
  --fg: #c0caf5;
  --card: #1a1b26;
  --muted: #1f2335;
  --muted-fg: #9aa5ce;
  --faint: #565f89;
  --border: #292e42;
  --border-strong: #3b4261;
  --primary: #c0caf5;
  --primary-fg: #16161e;
  --accent: #7aa2f7;
  --accent-fg: #16161e;
  --danger: #f7768e;
  --success: #9ece6a;
  --attn: #e0af68;
  --merged: #bb9af7;
  --add-bg: #1e2f26;
  --add-fg: #9ece6a;
  --add-edge: #58a460;
  --del-bg: #37222c;
  --del-fg: #f7768e;
  --del-edge: #f7768e;
  --wd-add: #2c4a35;
  --wd-del: #5a2f3f;
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.45);
  --shadow-2: 0 12px 32px rgb(0 0 0 / 0.5);
  --tok-keyword: #bb9af7;
  --tok-string: #9ece6a;
  --tok-comment: #565f89;
  --tok-number: #ff9e64;
  --tok-function: #7aa2f7;
  --tok-type: #2ac3de;
  --tok-constant: #ff9e64;
  --tok-meta: #73daca;
  --tok-property: #7dcfff;
  --tok-operator: #89ddff;
  --tok-punctuation: #7982a9;
  --tok-tag: #f7768e;
  --tok-attribute: #bb9af7;
  --tok-regex: #b4f9f8;
  --tok-variable: #c0caf5;
  --tok-decorator: #e0af68;
  --tok-heading: #7aa2f7;
  --tok-emphasis: #c0caf5;
  --tok-link: #73daca;
  color-scheme: dark;
}
:root[data-theme="aurora"] {
  --bg: #272c36;
  --fg: #e5e9f0;
  --card: #2e3440;
  --muted: #3b4252;
  --muted-fg: #aeb9cf;
  --faint: #616e88;
  --border: #3b4252;
  --border-strong: #4c566a;
  --primary: #eceff4;
  --primary-fg: #2e3440;
  --accent: #88c0d0;
  --accent-fg: #2e3440;
  --danger: #bf616a;
  --success: #a3be8c;
  --attn: #ebcb8b;
  --merged: #b48ead;
  --add-bg: #333f39;
  --add-fg: #a3be8c;
  --add-edge: #a3be8c;
  --del-bg: #3f3239;
  --del-fg: #bf616a;
  --del-edge: #bf616a;
  --wd-add: #4a5f4d;
  --wd-del: #5f3f47;
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.35);
  --shadow-2: 0 12px 32px rgb(0 0 0 / 0.45);
  --tok-keyword: #81a1c1;
  --tok-string: #a3be8c;
  --tok-comment: #616e88;
  --tok-number: #b48ead;
  --tok-function: #88c0d0;
  --tok-type: #8fbcbb;
  --tok-constant: #d08770;
  --tok-meta: #ebcb8b;
  --tok-property: #88c0d0;
  --tok-operator: #81a1c1;
  --tok-punctuation: #7b88a1;
  --tok-tag: #81a1c1;
  --tok-attribute: #8fbcbb;
  --tok-regex: #ebcb8b;
  --tok-variable: #d8dee9;
  --tok-decorator: #ebcb8b;
  --tok-heading: #88c0d0;
  --tok-emphasis: #eceff4;
  --tok-link: #88c0d0;
  color-scheme: dark;
}

@layer reset {
* { box-sizing: border-box; margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }
img, svg, video { max-width: 100%; }
table { border-collapse: collapse; }
ul, ol { list-style: none; padding: 0; }
summary::-webkit-details-marker { display: none; }
}


@layer base {
/* ---- theme-independent constants ---- */
:root {
  --radius-sm: 6px;   /* controls: buttons, inputs, chips, kbd */
  --radius: 8px;      /* surfaces: cards, panels, code blocks */
  --radius-lg: 12px;  /* overlays: dialogs, palette, menus */
  --fs-min: 12px;     /* type floor: no meaningful text is smaller */
  --topbar-h: 56px;
  --page: 1120px;
  --measure: 72ch;
  --ease: cubic-bezier(.2, 0, 0, 1);
  /* One motion vocabulary: the code viewer's timings, named. A hover or a
     focus is --dur-1 to --dur-2, a thing arriving --dur-3, and a pixel
     figure changes frame every --beat (#10570). */
  --dur-1: 100ms;
  --dur-2: 140ms;
  --dur-3: 200ms;
  --beat: 450ms;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, "Cascadia Code", "JetBrains Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Root canvas colour: Chromium view-transition / nav frames use html,
     not body; leaving it transparent flashes the UA default (white). */
  background: var(--bg);
}
body {
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  background: var(--bg);
  color: var(--fg);
  min-height: 100dvh;
  display: flex; flex-direction: column;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: inherit; text-decoration: none; transition: color 120ms var(--ease); }
a:hover { color: var(--accent); }
code, pre, .mono { font-family: var(--mono); font-size: 12.5px; }
.mono { overflow-wrap: anywhere; }

h1 { font-size: 20px; font-weight: 620; letter-spacing: -0.02em; line-height: 1.25; text-wrap: balance; }
h2 { font-size: 16px; font-weight: 600; letter-spacing: -0.01em; line-height: 1.3; text-wrap: balance; }
h3 { font-size: 14px; font-weight: 600; line-height: 1.4; }

::selection { background: color-mix(in srgb, var(--accent) 26%, transparent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

/* Anything anchorable clears the sticky topbar when it is scrolled to. */
[id] { scroll-margin-top: calc(var(--topbar-h) + 12px); }

/* Momentary class the theme switcher adds so a theme change sweeps rather
   than snaps. */
:root.theme-anim, :root.theme-anim *, :root.theme-anim *::before, :root.theme-anim *::after {
  transition: background-color 200ms var(--ease), color 200ms var(--ease),
    border-color 200ms var(--ease) !important;
}

/* ---- shell ---- */
.skip {
  position: absolute; left: 16px; top: -48px; z-index: 40;
  padding: 8px 14px; border-radius: var(--radius);
  background: var(--primary); color: var(--primary-fg);
  font-weight: 500; transition: top 140ms var(--ease);
}
.skip:focus-visible { top: 10px; color: var(--primary-fg); }

.shell { width: 100%; max-width: var(--page); margin: 0 auto; padding: 0 16px 96px; flex: 1; }
/* A bare page owns the whole window: no width, no padding, no chrome. */
.bare { flex: 1; display: flex; flex-direction: column; min-width: 0; }
/* A wide page keeps the chrome but lets the column go: a tree beside a
   file is the one layout that gets better with every pixel of a monitor,
   and holding it to the reading width leaves most of that monitor blank. */
@media (min-width: 1200px) {
  .shell-wide { max-width: none; padding-left: 24px; padding-right: 24px; }
}

.topbar {
  position: sticky; top: 0; z-index: 20;
  view-transition-name: topbar;
  min-height: var(--topbar-h);
  display: flex; align-items: center; gap: 8px;
  padding: 8px 16px;
  background: color-mix(in srgb, var(--bg) 84%, transparent);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border-bottom: 1px solid var(--border);
}
.wordmark {
  display: inline-flex; align-items: center; gap: 8px; flex: none;
  min-height: 44px;
  font-weight: 660; letter-spacing: -0.03em; font-size: 15px;
}
.wordmark .mark {
  width: 10px; height: 10px; border-radius: 3px; flex: none;
  background: linear-gradient(135deg, var(--accent), var(--merged));
  transition: transform 200ms var(--ease);
}
.wordmark:hover { color: var(--fg); }
.wordmark:hover .mark { transform: rotate(135deg); }
.topbar .spacer { flex: 1; }
.topbar-tools { display: flex; align-items: center; gap: 6px; flex: 0 1 auto; min-width: 0; }
.topbar-tools > a.small { display: inline-flex; align-items: center; min-height: 44px; padding: 0 8px; flex: none; }
/* The page never scrolls sideways. A strip that must — the tabs, a code
   table — scrolls inside its own box; nothing else may push the page wide.
   clip, not hidden: hidden would make the body a scroll container and
   unstick the topbar. */
body { overflow-x: clip; }
@media (max-width: 719px) {
  .topbar { gap: 6px; padding-left: 12px; padding-right: 12px; }
  .topbar-tools { gap: 4px; }
}

.foot {
  width: 100%; max-width: var(--page); margin: 0 auto;
  padding: 20px 16px 36px;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  /* Muted, not faint: small text and links must still reach AA (4.5:1) in every theme. */
  color: var(--muted-fg); font-size: 12.5px;
}
.foot .mark {
  width: 7px; height: 7px; border-radius: 2px; opacity: .7;
  background: linear-gradient(135deg, var(--accent), var(--merged));
}
.foot a:hover { color: var(--accent); }
.foot .reduced { color: var(--muted-fg); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

@media (forced-colors: active) {
  :focus-visible { outline-color: Highlight; }
}
}


@layer components {

/* ---- icon slot ---- */
.ico {
  display: inline-flex; flex: none; width: 16px; height: 16px;
  align-items: center; justify-content: center; vertical-align: -0.15em;
}
/* The page's drawings, defined once each at the end of <body> (`iconSprite`,
   src/web/icons.ts). A <symbol> never renders where it is defined, but the
   <svg> holding them would take a line box, so it is taken out of flow. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ---- button ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 36px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card); color: var(--fg);
  font-weight: 500; font-size: 14px; white-space: nowrap; cursor: pointer;
  box-shadow: var(--shadow-1);
  transition: background-color 140ms var(--ease), border-color 140ms var(--ease),
    color 140ms var(--ease), opacity 140ms var(--ease);
}
.btn:hover { background: var(--muted); border-color: var(--border-strong); color: var(--fg); }
.btn:active { opacity: .85; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; pointer-events: none; }
.btn[aria-busy="true"] { opacity: .7; pointer-events: none; }
.btn[data-variant="primary"] {
  background: var(--primary); color: var(--primary-fg); border-color: var(--primary);
}
.btn[data-variant="primary"]:hover { opacity: .88; background: var(--primary); color: var(--primary-fg); }
.btn[data-variant="secondary"] { background: var(--muted); border-color: transparent; box-shadow: none; }
.btn[data-variant="secondary"]:hover { border-color: var(--border); }
.btn[data-variant="outline"] { background: transparent; box-shadow: none; }
.btn[data-variant="ghost"] { background: transparent; border-color: transparent; box-shadow: none; color: var(--muted-fg); }
.btn[data-variant="ghost"]:hover { background: var(--muted); color: var(--fg); border-color: transparent; }
/* A toggle shows its state: the chip, the sort button. */
.btn[aria-pressed="true"] { background: var(--muted); border-color: var(--border-strong); color: var(--fg); font-weight: 550; }
.btn[aria-pressed="false"] { color: var(--muted-fg); }
.btn[data-variant="danger"] { color: var(--danger); }
.btn[data-variant="danger"]:hover {
  border-color: color-mix(in srgb, var(--danger) 45%, var(--border));
  background: color-mix(in srgb, var(--danger) 8%, var(--card));
  color: var(--danger);
}
.btn[data-variant="link"] {
  border-color: transparent; background: none; box-shadow: none;
  color: var(--accent); padding: 0; min-height: 0;
}
.btn[data-variant="link"]:hover { background: none; text-decoration: underline; text-underline-offset: 3px; }
.btn[data-size="sm"] { min-height: 28px; padding: 0 10px; font-size: 13px; gap: 5px; }
.btn[data-size="lg"] { min-height: 44px; padding: 0 18px; font-size: 15px; }
/* An icon button is a square of its size class — 36px matches the button min-height, so a row of mixed buttons has one silhouette. */
.btn-icon { padding: 0; width: 36px; min-width: 36px; }
.btn-icon[data-size="sm"] { width: 28px; min-width: 28px; }
.btn-icon[data-size="lg"] { width: 44px; min-width: 44px; }
.talk-btn { position: relative; }
.talk-count { position: absolute; top: 0; right: 2px; font-size: 12.5px; line-height: 1; font-weight: 600; color: var(--fg); pointer-events: none; }
/* Touch targets stay thumb-sized on a phone; padding does it, so text stays centered. */
@media (pointer: coarse) {
  .btn { min-height: 44px; }
  .btn[data-size="sm"] { min-height: 36px; }
  .btn-icon { width: 44px; min-width: 44px; }
  .btn-icon[data-size="sm"] { width: 36px; min-width: 36px; }
}

/* ---- form controls ---- */
.input {
  width: 100%; min-height: 36px; padding: 7px 10px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card); color: var(--fg);
  transition: border-color 140ms var(--ease), box-shadow 140ms var(--ease);
}
.input.input-num { width: 5rem; }
.input:hover { border-color: var(--border-strong); }
.input:focus-visible {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.input[aria-invalid="true"], .input:user-invalid {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 14%, transparent);
}
.input[readonly] { background: var(--muted); color: var(--muted-fg); }
.input[data-size="sm"] { min-height: 28px; padding: 4px 8px; font-size: 13px; }
textarea.input {
  resize: vertical; min-height: 88px; line-height: 1.55; font-family: inherit;
  field-sizing: content; max-height: 24lh;
}
textarea.input[data-grow] { min-height: 5lh; }
select.input {
  appearance: none; padding-right: 28px; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 13px center, right 8px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
@media (pointer: coarse) { .input { min-height: 44px; } }
.bar .input[type=search] { min-width: 180px; flex: 1; max-width: 320px; }

/* One control for every boolean. A native checkbox tinted with accent-color
   is themed for free, keyboard-correct for free, and honest about what it is —
   a hand-built switch would be none of those. */
.check {
  display: inline-flex; align-items: flex-start; gap: 8px;
  font-weight: 400; font-size: 14px; cursor: pointer; margin: 0;
}
.check input { accent-color: var(--accent); margin-top: 2px; flex: none; }
/* A thumb needs a 44px target and a box it can see; in a table the bare
   check centres in its cell's target, so a miss does not tick the next one. */
@media (pointer: coarse) {
  .check { min-height: 44px; min-width: 44px; align-items: center; }
  .check input { width: 24px; height: 24px; margin: 0; }
  .table .check { justify-content: center; }
}

.field { display: block; margin: 0 0 16px; }
.field > label {
  display: block; font-size: 13px; font-weight: 550; margin: 0 0 6px; color: var(--fg);
}
.field .hint { display: block; font-size: 12.5px; color: var(--muted-fg); margin-top: 6px; overflow-wrap: anywhere; }
/* A setting as one line (#10999): name, control, and the mark that opens its
   reason. The mark is a small bordered button; open, the reason takes a line
   of its own under the row. */
.setting-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.setting-line > label:not(.check) { margin: 0; }
.setting-line > select.input { width: auto; max-width: 100%; flex: 0 1 14rem; }
.setting-line > .check { flex: 0 1 auto; }
.setting-line > details.why { margin: 0; }
.setting-line > details.why[open] { flex-basis: 100%; }
.why > summary {
  list-style: none; cursor: pointer; display: inline-grid; place-items: center;
  width: 28px; height: 28px; border: 1px solid var(--border); border-radius: 999px;
  background: var(--card); color: var(--muted-fg);
}
.why > summary::-webkit-details-marker { display: none; }
.why > summary:hover, .why[open] > summary { border-color: var(--border-strong); color: var(--fg); }
.why > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.why > p { margin: 6px 0 0; font-size: 12.5px; color: var(--muted-fg); overflow-wrap: anywhere; }
@media (pointer: coarse) { .why > summary { width: 44px; height: 44px; } }
.field .error { display: block; font-size: 12.5px; color: var(--danger); margin-top: 6px; font-weight: 500; overflow-wrap: anywhere; }
.field[data-invalid] > label { color: var(--danger); }
/* A group of checks is one field: the legend reads as a label, no frame. */
fieldset.field { border: 0; padding: 0; min-width: 0; }
fieldset.field > legend {
  padding: 0; font-size: 13px; font-weight: 550; margin: 0 0 8px; color: var(--fg);
}
fieldset.field[data-invalid] > legend { color: var(--danger); }
fieldset.field > .check { display: flex; }
fieldset.field > .check + .check { margin-top: 8px; }
.field-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-end; }
.field-row .field { flex: 1; min-width: 160px; margin-bottom: 0; }
.form-actions { margin-top: 16px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* ---- stat tile ---- fixed heights: a changing value shifts nothing */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; }
.stat {
  position: relative; display: block; box-sizing: border-box; height: 104px; padding: 10px 12px;
  overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--card); color: var(--fg); text-decoration: none;
}
@media (max-width: 480px) { .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
a.stat:hover { border-color: var(--border-strong); }
.stat[data-tone="attn"] { border-color: color-mix(in srgb, var(--attn) 40%, var(--border)); }
.stat-label { display: block; height: 18px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: var(--fs-min); line-height: 18px; color: var(--muted-fg); }
.stat-value { display: block; height: 32px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 20px; font-weight: 600; line-height: 32px; }
.stat-note {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  height: 36px; font-size: var(--fs-min); line-height: 18px; color: var(--muted-fg);
}
.stat-spark { position: absolute; top: 10px; right: 12px; width: 56px; height: 24px; color: var(--muted-fg); }
.stat-spark svg { display: block; width: 100%; height: 100%; }

/* ---- badge / label chip / pill / dot ---- */
.badge {
  display: inline-flex; align-items: center; gap: 4px; padding: 1px 8px;
  border: 1px solid var(--border); border-radius: 999px;
  font-size: var(--fs-min); font-weight: 500; line-height: 18px; color: var(--muted-fg);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.badge[data-variant="secondary"] { background: var(--muted); border-color: transparent; }
.badge[data-variant="outline"] { background: none; }
.badge[data-variant="success"], .badge[data-state="open"] {
  color: var(--success);
  border-color: color-mix(in srgb, var(--success) 34%, transparent);
  background: color-mix(in srgb, var(--success) 12%, transparent);
}
.badge[data-variant="danger"], .badge[data-state="closed"] {
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 34%, transparent);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
}
.badge[data-variant="merged"], .badge[data-pr="merged"] {
  color: var(--merged);
  border-color: color-mix(in srgb, var(--merged) 34%, transparent);
  background: color-mix(in srgb, var(--merged) 12%, transparent);
}
.badge[data-variant="attn"] {
  color: var(--attn);
  border-color: color-mix(in srgb, var(--attn) 34%, transparent);
  background: color-mix(in srgb, var(--attn) 12%, transparent);
}
.badge .ico { width: 12px; height: 12px; }
/* A loader that turns: the one icon that means "still going". */
.ico-loader { animation: spin 1.1s linear infinite; }
/* A button never spins at rest: only its own busy state turns the loader. */
.btn .ico-loader { animation-play-state: paused; }
.btn[aria-busy="true"] .ico-loader { animation-play-state: running; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- pixel art (#10570, src/web/pixel.ts) ----
   A crew face works by swapping two frames on the shared --beat; it never
   moves unless a run is going (data-state="working"), lands with one hop,
   and under reduced motion shows its first frame and stays. A hidden tab
   does not paint, so nothing runs there. */
.px { flex: none; shape-rendering: crispEdges; }
.px-scene { color: var(--faint); margin-bottom: 4px; }
.avatar.avatar-px { background: none; border: 0; }
.px[data-state="working"] .px-b { visibility: hidden; }
@media (prefers-reduced-motion: no-preference) {
  .px[data-state="working"] .px-a { animation: px-a calc(var(--beat) * 2) steps(1) infinite; }
  .px[data-state="working"] .px-b { animation: px-b calc(var(--beat) * 2) steps(1) infinite; }
  .px[data-state="landed"] { animation: px-hop calc(var(--dur-3) * 2) steps(4) 1; }
  @keyframes px-a { 50% { visibility: hidden; } }
  @keyframes px-b { 50% { visibility: visible; } }
  @keyframes px-hop { 40% { transform: translateY(-4px); } }
}

/* One stored hex, derived three ways, so a chip reads correctly in all six
   themes. --label is set by a per-page nonce'd rule; the hex is validated
   before it is ever embedded. */
.label {
  --label: var(--muted-fg);
  display: inline-flex; align-items: center; padding: 0 8px;
  border-radius: 999px; font-size: var(--fs-min); font-weight: 500; line-height: 18px;
  color: color-mix(in srgb, var(--label) 78%, var(--fg));
  background: color-mix(in srgb, var(--label) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--label) 32%, transparent);
  white-space: nowrap;
}
a.label:hover { color: color-mix(in srgb, var(--label) 90%, var(--fg)); }

.pill {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; padding: 0 6px; border-radius: 999px;
  background: var(--muted); color: var(--muted-fg);
  font-size: var(--fs-min); font-weight: 550; line-height: 18px;
  font-variant-numeric: tabular-nums;
}
.pill[data-tone="accent"] { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); }
.pill[data-tone="danger"] { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }

progress { display: block; width: 100%; height: 4px; margin: 6px 0; appearance: none; border: 0; border-radius: var(--radius-sm); background: var(--border); overflow: hidden; }
progress::-webkit-progress-bar { background: var(--border); }
progress::-webkit-progress-value { background: var(--success); }
progress::-moz-progress-bar { background: var(--success); }

.dot { display: inline-block; width: 8px; height: 8px; border-radius: 999px; background: var(--faint); flex: none; }
.word-text { font-weight: 600; color: var(--fg); }
.dot[data-tone="success"] { background: var(--success); }
.dot[data-tone="danger"] { background: var(--danger); }
.dot[data-tone="attn"] { background: var(--attn); }
.dot[data-tone="merged"] { background: var(--merged); }
.dot[data-series="0"] { background: var(--series-0); }
.dot[data-series="1"] { background: var(--series-1); }
.dot[data-series="2"] { background: var(--series-2); }
.dot[data-series="3"] { background: var(--series-3); }
.dot[data-series="4"] { background: var(--series-4); }
.dot[data-series="5"] { background: var(--series-5); }
.dot[data-series="6"] { background: var(--series-6); }
.dot[data-series="7"] { background: var(--series-7); }

/* ---- stacked bar chart: series stacked per bucket, drawn as SVG on the server ---- */
.plots { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); gap: 16px; margin: 0 0 16px; }
.plots figcaption { font-size: 13px; font-weight: 600; margin: 0 0 4px; display: flex; gap: 8px; align-items: baseline; }
.plot { display: block; width: 100%; height: auto; }
.plot line { stroke: var(--border); stroke-width: 1; }
.plot text { fill: var(--muted-fg); font-family: var(--mono); }
.plot .plot-name text { fill: var(--faint); font-family: inherit; }
.plot-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 0 0 12px; font-size: 13px; }
.plot-legend li { display: inline-flex; align-items: center; gap: 6px; }

/* ---- meter: a share as a bar — spend against a ceiling, a window used, how sure ---- */
meter {
  display: block; width: 100%; height: 6px; appearance: none;
  background: var(--muted); border: 0; border-radius: 999px; overflow: hidden;
}
meter::-webkit-meter-bar { height: 6px; background: var(--muted); border: 0; border-radius: 999px; }
meter::-webkit-meter-optimum-value, meter::-webkit-meter-suboptimum-value, meter::-webkit-meter-even-less-good-value { background: var(--muted-fg); border-radius: 999px; }
meter::-moz-meter-bar { background: var(--muted-fg); border-radius: 999px; }
meter[data-tone="attn"]::-webkit-meter-optimum-value, meter[data-tone="attn"]::-webkit-meter-suboptimum-value, meter[data-tone="attn"]::-webkit-meter-even-less-good-value { background: var(--attn); }
meter[data-tone="attn"]::-moz-meter-bar { background: var(--attn); }

kbd {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 5px;
  border: 1px solid var(--border); border-bottom-width: 2px;
  border-radius: var(--radius-sm); background: var(--muted);
  font-family: var(--mono); font-size: var(--fs-min); font-weight: 500; color: var(--muted-fg);
}

/* A menu or palette row's key sits in its own column (#8930); anywhere else a
   key is a tooltip or an overlay and takes no room. */
.keyhint { margin-left: 6px; }
@media (pointer: coarse), (max-width: 640px) { .keyhint { display: none; } }

/* ::before, because components already use ::after (the current tab's line,
   a menu's caret). :where() keeps the host rule at zero specificity, so a
   component that positions itself (sticky, absolute) keeps its position. The
   text after "/" is the chip's accessible text: none, so a name is never read
   with its key glued on; the key is `aria-keyshortcuts` instead. */
:where([data-hint]) { position: relative; }
[data-hint]::before {
  content: attr(data-hint); content: attr(data-hint) / ""; position: absolute; z-index: 40;
  top: calc(100% + 4px); left: 50%; transform: translateX(-50%);
  min-width: 20px; padding: 2px 5px; box-sizing: border-box; text-align: center;
  border: 1px solid var(--border); border-bottom-width: 2px;
  border-radius: var(--radius-sm); background: var(--muted); color: var(--muted-fg);
  font-family: var(--mono); font-size: var(--fs-min); font-weight: 500; line-height: 16px; white-space: nowrap;
  opacity: 0; pointer-events: none; transition: opacity 120ms var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  [data-hint]:hover::before, [data-hint]:focus-visible::before, [data-hint]:focus-within::before,
  html[data-hints] [data-hint]::before { opacity: 1; }
}
/* At the window's edges the chip hangs inward, so it never leaves the viewport. */
.wordmark[data-hint]::before { left: 0; transform: none; }
.topbar-tools [data-hint]::before { left: auto; right: 0; transform: none; }
/* A card clips what leaves its box: there the chip sits on the element's top
   right corner, mostly above it, clear of the label's text. */
.card [data-hint]::before { top: 0; left: auto; right: 0; transform: translateY(-60%); }
/* The tab strip scrolls sideways, so it clips above and below too: the chip is
   small and sits in the tab's own top padding, above the label. */
.tabs [data-hint]::before {
  top: 0; min-width: 0; padding: 0 3px; border-bottom-width: 1px; line-height: 12px;
}
@media (pointer: coarse) { [data-hint]::before { display: none; } }

.sha {
  font-family: var(--mono); font-size: 12.5px; padding: 1px 5px;
  border-radius: 4px; background: var(--muted); color: var(--muted-fg);
  font-variant-numeric: tabular-nums;
}
a.sha:hover { color: var(--accent); }

/* ---- avatar ----
   The hue is the person's (data-h, twelve of them), so the twelve are spelled
   here as oklch values (the HSL colours they were, 62% saturation at 52% and
   42% lightness), not palette tokens; the 20px and 16px circles' initials sit
   below the type scale on purpose, in rem so the scale check does not see them.
   The default is the old fallback, hsl(220 62% 52%), which is oklch hue 262. The
   initials are 28% ink and 72% --fg: that keeps 4.5:1 on the tinted circle in
   every theme (the old 88% ink did not, and no single ink can in both a light
   and a dark theme), so the hue is carried by the circle and its ring. */
.avatar {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 20px; height: 20px; border-radius: 999px;
  --av: oklch(54.9% 0.166 262); --av-ink: oklch(47.0% 0.150 262);
  background: color-mix(in srgb, var(--av) 22%, var(--card));
  color: color-mix(in srgb, var(--av-ink) 28%, var(--fg));
  border: 1px solid color-mix(in srgb, var(--av) 30%, transparent);
  font-size: var(--fs-min); font-weight: 650; letter-spacing: 0; text-transform: uppercase;
  user-select: none;
}
.avatar[data-h="0"] { --av: oklch(59.5% 0.170 31); --av-ink: oklch(51.3% 0.154 31); }
.avatar[data-h="1"] { --av: oklch(71.9% 0.128 77); --av-ink: oklch(62.3% 0.114 77); }
.avatar[data-h="2"] { --av: oklch(81.7% 0.170 117); --av-ink: oklch(71.2% 0.151 117); }
.avatar[data-h="3"] { --av: oklch(77.1% 0.205 137); --av-ink: oklch(67.1% 0.183 137); }
.avatar[data-h="4"] { --av: oklch(75.5% 0.214 145); --av-ink: oklch(65.7% 0.191 145); }
.avatar[data-h="5"] { --av: oklch(76.7% 0.149 164); --av-ink: oklch(66.8% 0.133 163); }
.avatar[data-h="6"] { --av: oklch(73.5% 0.113 210); --av-ink: oklch(63.8% 0.100 210); }
.avatar[data-h="7"] { --av: oklch(56.0% 0.160 261); --av-ink: oklch(47.9% 0.145 261); }
.avatar[data-h="8"] { --av: oklch(47.1% 0.220 280); --av-ink: oklch(40.1% 0.197 279); }
.avatar[data-h="9"] { --av: oklch(55.0% 0.224 310); --av-ink: oklch(47.3% 0.200 309); }
.avatar[data-h="10"] { --av: oklch(61.6% 0.231 334); --av-ink: oklch(53.3% 0.206 334); }
.avatar[data-h="11"] { --av: oklch(58.5% 0.192 3); --av-ink: oklch(50.5% 0.171 4); }
.avatar[data-size="md"] { width: 28px; height: 28px; font-size: 12.5px; }
.avatar[data-size="lg"] { width: 56px; height: 56px; font-size: 20px; border-radius: var(--radius-lg); }

.byline { display: inline-flex; align-items: center; gap: 5px; min-width: 0; }
.byline a:hover { color: var(--accent); }
.name-mark {
  display: inline-block; padding: 0 5px; border-radius: 4px;
  font-size: var(--fs-min); font-weight: 600; line-height: 15px; letter-spacing: 0.04em;
  text-transform: uppercase; white-space: nowrap; vertical-align: 1px;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.name-mark[data-mark="crew"] { color: var(--muted-fg); background: var(--muted); }

/* ---- card ---- */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  overflow: clip;
}
/* Cards stacked in normal flow space themselves. Inside a container that
   already manages its own spacing with gap, that margin would double it. */
.card + .card { margin-top: 12px; }
/* The open pulls a held issue waits on: a wrapping line of touch-sized links. */
.held-pulls { display: flex; flex-wrap: wrap; gap: 0 4px; align-items: center; }
.held-pulls a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 8px; }
:is(.stack, .split, .timeline) > .card + .card { margin-top: 0; }
/* A card that is not a box: space, not lines (DESIGN.md §1). Same markup, no frame. */
.card.bare { background: none; border: 0; box-shadow: none; border-radius: 0; overflow: visible; }
.card.bare > .card-head { background: none; border: 0; padding: 0 0 8px; }
.card.bare > .card-foot { background: none; border: 0; padding: 8px 0 0; }
.card.bare > .card-body { padding: 0; }
.card.bare .card-body.stack { padding: 0 0 8px; }
.card.bare .list > li + li { border-top: 0; }
.card.bare .prose { padding: 0; }
.card.bare .row { border-radius: var(--radius); }
.card-head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 14px; border-bottom: 1px solid var(--border); background: var(--muted);
}
.card-head h2, .card-head h3 { margin: 0; }
/* A card head's links: spaced apart, and each a 44px target on a thumb. */
.card-links { display: inline-flex; align-items: center; gap: 10px; }
.card-links > a { color: inherit; }
@media (pointer: coarse) { .card-links { gap: 0; } .card-links > a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 8px; } }
.card-body { padding: 14px; }
.card-foot {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 14px; border-top: 1px solid var(--border); background: var(--muted);
}
.card[data-tone="success"] { border-color: color-mix(in srgb, var(--success) 40%, var(--border)); }
.card[data-tone="danger"] { border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); }
.card[data-tone="merged"] { border-color: color-mix(in srgb, var(--merged) 40%, var(--border)); }
.card[data-tone="attn"] { border-color: color-mix(in srgb, var(--attn) 40%, var(--border)); }

/* ---- look: a picture the forge took, in a hairline frame ----
   A strip sets a phone beside a desktop: the phone keeps a phone's
   narrowness, the desktop takes what is left, never more than its own size;
   under 640px they stack. data-compare sets two sides (before, after) beside
   each other instead. A thumb shows the top of the picture; now is
   production small. */
.look { display: block; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; background: var(--muted); }
.look img { display: block; width: 100%; height: auto; }
.look[data-slot="thumb"] { flex: none; width: 30px; height: 40px; border-radius: 4px; }
.look[data-slot="thumb"] img { height: 100%; object-fit: cover; object-position: top; }
.look[data-slot="feed"] { width: 160px; height: 100px; margin-top: 6px; }
.look[data-slot="feed"] img { height: 100%; object-fit: cover; object-position: top; }
.look[data-slot="now"] { flex: none; width: 168px; }
.looks { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; }
.looks > [data-slot="phone"] { flex: 0 0 200px; }
.looks > [data-slot="desktop"] { flex: 1 1 320px; min-width: 0; max-width: 1280px; }
.looks > figure { margin: 0; display: flex; flex-direction: column; gap: 6px; }
.looks[data-compare] { gap: 20px; }
.looks[data-compare] > * { flex: 1 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
@media (max-width: 640px) {
  .looks:not([data-compare]):not([data-look] .looks) { flex-direction: column; }
  .looks > [data-slot="phone"] { flex-basis: auto; width: 200px; }
}

/* ---- list rows ---- */
.list > li + li { border-top: 1px solid var(--border); }
.row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 14px; min-height: 40px;
  transition: background-color 100ms var(--ease);
}
a.flow-row { min-height: 44px; }
.row:focus-visible { outline-offset: -2px; }
a.row:hover, .row[data-nav]:hover { background: var(--muted); color: inherit; }
.list li[aria-current="true"] > .row { background: var(--muted); }
/* A tree: the rows under a row hang from a rule, a step in. */
.row-children { list-style: none; margin: 0 0 0 22px; padding: 0; border-left: 1px solid var(--border); }
.row-children > li { border-top: 1px solid var(--border); }
@media (max-width: 719px) { .row-children { margin-left: 12px; } }
/* A bare tree (/family, docs/design/areas/family.md): names and a line each; indentation is the only structure. */
.list.bare-tree > li, .list.bare-tree .row-children > li { border: 0; }
.list.bare-tree .row-children { border-left: 0; margin-left: var(--tree-indent, 20px); }
.list.bare-tree .row { padding-top: 10px; padding-bottom: 10px; }
.list.bare-tree .row-title, .list.bare-tree .row-meta { white-space: normal; overflow: visible; overflow-wrap: anywhere; }
/* A row's look thumbs (/review): inset like a row, side by side at any width; the link's hit area grows to 44px. */
.row-children > [data-look] { padding: 8px 14px; }
[data-look] .looks { flex-wrap: nowrap; gap: 10px; align-items: center; }
[data-look] a.look { position: relative; overflow: visible; }
[data-look] a.look::after { content: ""; position: absolute; inset: -7px; }
a.row:hover .row-title { color: var(--accent); }
.row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.row-title {
  font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: color 100ms var(--ease);
}
/* One honest line: everything in it is inline, so text-overflow actually
   has a block box to ellipsize (a flex container would silently ignore it)
   and nothing can wrap out from under the row's padding. */
.row-meta {
  display: block; font-size: 12.5px; color: var(--muted-fg); line-height: 1.5;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.row-meta .byline { display: inline; }
/* A note an agent wrote (#73): its own clamped line inside the meta, leaving
   room for the who and when after it; the whole text is the title. */
.row-note {
  display: inline-block; max-width: min(60ch, calc(100% - 14ch)); vertical-align: bottom;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.row-facts { display: flex; flex-wrap: wrap; gap: 0 16px; margin: 0; font-size: 12.5px; color: var(--muted-fg); line-height: 1.5; }
.row-facts > div { display: flex; gap: 6px; min-width: 0; }
.row-facts dt { font-weight: 550; }
.row-facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.row-meta .avatar { width: 16px; height: 16px; font-size: var(--fs-min); vertical-align: -0.28em; }
.row-meta .byline-name { margin-left: 4px; }
.row-lead { color: var(--faint); display: inline-flex; flex: none; }
/* A control beside a link row, outside the link: the row takes the width, the control keeps its own. */
.list > li.has-after { display: flex; align-items: center; flex-wrap: wrap; }
.list > li.has-after > .row, .list > li.has-after > details { flex: 1 1 0; min-width: 0; }
.row-after { flex: none; padding: 0 14px 0 0; }
/* A settings row's acts (Accounts): always visible, wrapping, a full line under 640px. */
.setting-list > li.has-after > .row-after { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; }
@media (max-width: 640px) { .setting-list > li.has-after > .row-after { flex-basis: 100%; justify-content: flex-start; padding: 0 14px 10px; } }
/* An origin's error, notes and acts (Settings › Connected accounts): a block of their own under the row, at every width. */
.setting-list[data-origins] > li.has-after > .row-after, .setting-list[data-bets] > li.has-after > .row-after { flex-basis: 100%; display: block; min-width: 0; padding: 0 14px 12px; overflow-wrap: anywhere; }
.list > li.has-after > .row-children { flex-basis: 100%; }
/* A disk's alert reasons (Settings › Machines, docs/design/areas/machines.md): a line under its folded row, inset to the title. */
.row-children > li[data-disk] > .row-after { display: block; padding: 0 14px 10px 40px; overflow-wrap: anywhere; }
.row-children > li[data-disk] > .row-after > p { margin: 0; }
.archived-list .row-title, .archived-list .row-meta { white-space: normal; overflow-wrap: anywhere; }
.moved-from { margin: 8px 0 0; overflow-wrap: anywhere; }
@media (max-width: 640px) {
  .archived-list .list > li.has-after > .row { flex-basis: 100%; }
  .archived-list .row-after { width: 100%; display: flex; justify-content: flex-end; gap: 8px; padding: 0 14px 10px; }
}
.row-trail { display: flex; align-items: center; gap: 8px; flex: none; }
/* The leading glyph is the row's state; a badge repeating it is noise. */
.row[data-state="open"] .row-lead { color: var(--success); }
.row[data-state="closed"] .row-lead { color: var(--danger); }
.row[data-state="merged"] .row-lead { color: var(--merged); }
.row[data-state="draft"] .row-lead { color: var(--muted-fg); }
/* A row that folds is a <summary>: its lead is the caret, turned when open. */
summary.row { cursor: pointer; list-style: none; }
summary.row:hover { background: var(--muted); }
details[open] > summary.row > .row-lead { transform: rotate(90deg); }
/* A report's open body: block children in reading order, never one flex line. */
.report-body { padding: 0 14px 14px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; min-width: 0; overflow-wrap: anywhere; }
.report-body form { margin: 0; }
/* A count with its glyph: comments on a row, members on a team. */
.count {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12.5px; color: var(--muted-fg); font-variant-numeric: tabular-nums;
}
.count .ico { width: 14px; height: 14px; }
/* A group of them — issues and pulls on a repo row, in one muted cluster. */
.counts { display: inline-flex; align-items: center; gap: 10px; flex: none; }
/* Secondary actions are always in the DOM, revealed without layout shift. */
.row-actions { opacity: 0; transition: opacity 120ms var(--ease); }
.row:hover .row-actions, .row:focus-within .row-actions { opacity: 1; }
/* Settings controls are the point of their row, never revealed by hover:
   they wrap under the text before they would clip, at any width. */
.row-fields { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.row-fields .input { min-width: 0; max-width: 100%; }
/* A number beside its label in a settings row stays a few digits wide. */
.row-fields .input[type="number"] { width: 5em; }
.row-fields .check { align-items: center; }
.setting-list .row { flex-wrap: wrap; align-items: flex-start; }
.setting-list .row-main { flex: 1 1 18rem; }
.setting-list .row-title, .setting-list .row-meta { white-space: normal; overflow: visible; overflow-wrap: anywhere; }
.setting-list .record-value { user-select: all; }
.setting-list .row-trail { flex: 0 1 auto; max-width: 100%; }
@media (max-width: 640px) { .setting-list .row-trail { flex-basis: 100%; } }
@media (pointer: coarse) { .row-actions { opacity: 1; } .row { min-height: 44px; } }
.row[data-state="closed"] .row-title, .row[data-state="merged"] .row-title { color: var(--muted-fg); }

/* ---- edit row: a list row whose body is a small form ---- */
.edit-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 14px;
}
.row-trail > .edit-row, .settings-block > .edit-row { padding: 0; }
.edit-row > .input { flex: 1 1 160px; width: auto; min-width: 0; }
.edit-row .btn { flex: none; }
.label-open { color: var(--muted-fg); font-size: 13px; text-decoration: underline; text-underline-offset: 2px; }
.label-open:hover { color: var(--fg); }
/* A swatch and its hex, as one control-shaped thing. */
.color-field {
  display: inline-flex; align-items: center; gap: 8px; flex: none;
  min-height: 36px; padding: 0 10px 0 4px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card);
}
.color-field:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent); }
.color-field input[type="color"] {
  appearance: none; -webkit-appearance: none; flex: none;
  width: 26px; height: 26px; padding: 0; border: 0; border-radius: 999px;
  background: none; cursor: pointer;
}
.color-field input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.color-field input[type="color"]::-webkit-color-swatch { border: 1px solid var(--border-strong); border-radius: 999px; }
.color-field input[type="color"]::-moz-color-swatch { border: 1px solid var(--border-strong); border-radius: 999px; }
@media (pointer: coarse) { .color-field { min-height: 44px; } }
@media (max-width: 719px) {
  .edit-row { align-items: stretch; }
  .edit-row > .input { flex-basis: 100%; }
  .edit-row .color-field, .edit-row .btn { flex: 1 1 auto; justify-content: center; }
  .label-open { display: inline-flex; align-items: center; min-height: 44px; padding: 0 8px; }
}

/* ---- table ---- */
.table { width: 100%; font-size: 13px; }
.table th {
  text-align: left; font-weight: 550; font-size: 12.5px; color: var(--muted-fg);
  padding: 8px 12px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.table td {
  padding: 9px 12px; border-top: 1px solid var(--border);
  font-variant-numeric: tabular-nums; vertical-align: middle;
}
.table tbody tr:first-child td { border-top: none; }
.table[data-dense] td, .table[data-dense] th { padding: 5px 10px; }
.table .num { text-align: right; }
.table-scroll { overflow-x: auto; scrollbar-width: thin; }
/* The data browser: a cell's JSON keeps its shape, and the sorted column is marked by its aria-sort. */
.table td pre { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; font-size: inherit; }
.table[data-sortable] th[aria-sort] a { color: var(--fg); }
.table[data-sortable] th[aria-sort="ascending"] a::after { content: " \2191"; color: var(--muted-fg); }
.table[data-sortable] th[aria-sort="descending"] a::after { content: " \2193"; color: var(--muted-fg); }
/* The row's name stays in view while a narrow screen scrolls the figures. */
.table[data-sticky-lead] th:first-child,
.table[data-sticky-lead] td:first-child {
  position: sticky; left: 0; z-index: 1; background: var(--card);
}

/* A sub-row (data-sub) is a split of the row above: indented under it, its
   label cut with an ellipsis so a long "model · prompt" cannot widen the
   sticky lead cell past a phone's width. */
.table tr[data-sub] td:first-child {
  padding-left: 24px; max-width: 14rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---- tabs (navigation links, never role=tab) ---- */
.tabs {
  min-width: 0; max-width: 100%; display: flex; gap: 2px; align-items: stretch;
  border-bottom: 1px solid var(--border);
  overflow-x: auto; scrollbar-width: none;
  scroll-snap-type: x proximity;
  mask-image: linear-gradient(90deg, var(--fg) 0 calc(100% - 20px), transparent);
}
.tabs::-webkit-scrollbar { display: none; }
.tabs > a {
  position: relative; display: inline-flex; align-items: center; gap: 6px;
  padding: 0 12px; min-height: 40px; white-space: nowrap;
  scroll-snap-align: start;
  color: var(--muted-fg); font-size: 14px;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  transition: color 120ms var(--ease), background-color 120ms var(--ease);
}
.tabs > a:hover { color: var(--fg); background: var(--muted); }
.tabs > a[aria-current="page"] { color: var(--fg); font-weight: 550; }
.tabs > a[aria-current="page"]::after {
  content: ""; position: absolute; left: 8px; right: 8px; bottom: -1px;
  top: calc(100% - 1px); border-radius: 2px 2px 0 0; background: var(--fg);
}
@media (min-width: 720px) { .tabs { mask-image: none; } }

/* ---- segmented control (radios in a GET form, or links) ---- */
.seg {
  display: inline-flex; align-items: center; gap: 2px; flex: none;
  padding: 2px; background: var(--muted); border-radius: var(--radius);
  max-width: 100%; overflow-x: auto; scrollbar-width: none;
}
@media (max-width: 420px) { .seg > a, .seg > label { padding: 0 8px; } }
.seg > a, .seg > label {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 28px; padding: 0 10px; border-radius: var(--radius-sm);
  font-size: 13px; font-weight: 500; color: var(--muted-fg);
  white-space: nowrap; cursor: pointer; margin: 0;
  transition: background-color 120ms var(--ease), color 120ms var(--ease);
}
.seg > a:hover, .seg > label:hover { color: var(--fg); }
.seg > label input { position: absolute; opacity: 0; pointer-events: none; }
.seg > a[aria-current="page"], .seg > label:has(input:checked) {
  background: var(--card); color: var(--fg); box-shadow: var(--shadow-1);
}
.seg > label:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }
@media (pointer: coarse) { .seg > a, .seg > label { min-height: 36px; } }

/* ---- menu (details; correct with zero JavaScript) ---- */
.menu { position: relative; flex: none; }
.menu > summary { list-style: none; }
.menu > summary::after {
  content: ""; width: 0; height: 0; margin-left: 2px;
  border: 3.5px solid transparent; border-top-color: currentColor;
  opacity: .55; transform: translateY(2px);
  transition: transform 160ms var(--ease);
}
.menu[open] > summary::after { transform: translateY(-1px) rotate(180deg); }
.menu > summary.btn-icon::after, .menu > summary[data-caret="none"]::after { content: none; }
.menu-panel {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 30;
  min-width: 220px; max-width: min(320px, calc(100vw - 32px)); padding: 5px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-2);
  animation: pop 140ms var(--ease) both;
  max-height: min(70vh, 480px); overflow-y: auto; scrollbar-width: none;
}
.menu[data-align="start"] > .menu-panel { right: auto; left: 0; }
@keyframes pop { from { opacity: 0; transform: translateY(-4px); } }
.menu-title {
  display: block; padding: 6px 10px 4px;
  font-size: var(--fs-min); font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--faint);
}
.menu-item {
  display: flex; width: 100%; align-items: center; gap: 8px;
  padding: 7px 10px; border: 0; border-radius: var(--radius-sm);
  background: none; color: var(--fg); font-size: 14px;
  text-align: left; cursor: pointer;
  transition: background-color 100ms var(--ease);
}
.menu-item:hover, .menu-item:focus-visible { background: var(--muted); color: var(--fg); }
.menu-item[aria-current="true"] { font-weight: 550; }
.menu-item[aria-disabled="true"] { cursor: not-allowed; opacity: .65; }
.menu-item[aria-disabled="true"]:hover { background: none; }
.menu-item small { display: block; }
.menu-item[aria-disabled="true"] .grow { white-space: normal; }
.menu-item .ico { color: var(--faint); }
.menu-item .grow { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.menu-sep { border: 0; border-top: 1px solid var(--border); margin: 5px 4px; }
/* No anchor positioning: browsers that accept anchor-name but not
   position-area would keep position: fixed and park the panel at the
   viewport's corner. Absolute-inside-the-details works everywhere. */

/* ---- disclosure: what a person sometimes needs, closed until asked for ---- */
.disclosure > summary {
  cursor: pointer; font-weight: 560; list-style: none; color: var(--muted-fg);
  display: flex; align-items: center; gap: 6px; padding: 6px 0; min-height: 44px;
}
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary::before {
  content: "›"; display: inline-block; color: var(--faint);
  transition: transform 120ms var(--ease);
}
.disclosure[open] > summary::before { transform: rotate(90deg); }
.disclosure > summary:hover { color: var(--accent); }

/* ---- topbar search (always a real form, so JS-off still searches) ---- */
.topbar-search {
  display: flex; align-items: center; gap: 6px;
  min-width: 0; width: clamp(140px, 22vw, 240px);
  padding: 0 8px; min-height: 32px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card); color: var(--muted-fg);
  transition: border-color 140ms var(--ease);
}
.topbar-search:focus-within { border-color: var(--accent); }
.topbar-search input {
  flex: 1; min-width: 0; border: 0; background: none; outline: none;
  font-size: 16px; color: var(--fg);
}
.topbar-search kbd { flex: none; }

/* ---- theme swatch: the colour chip beside each theme in the menu's picker ---- */
.swatch {
  display: inline-block; flex: none; position: relative;
  width: 20px; height: 20px; border-radius: 999px;
  border: 1px solid var(--border-strong);
}
.swatch::after { content: ""; position: absolute; inset: 6px; border-radius: 999px; }

/* ---- dialog (progressive: every dialog has a real page behind it) ---- */
.dialog {
  /* The reset zeroes every margin, which takes away the UA's margin: auto
     that centres a top-layer dialog — so a dialog must say so itself. */
  margin: auto;
  width: min(560px, calc(100vw - 32px)); padding: 0;
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--card); color: var(--fg);
  box-shadow: var(--shadow-2);
}
.dialog::backdrop { background: color-mix(in srgb, var(--bg) 62%, #0008); backdrop-filter: blur(3px); }
.dialog[open] { animation: pop 140ms var(--ease) both; }
.dialog-head { display: flex; align-items: center; gap: 8px; padding: 14px 16px 0; }
.dialog-head h2 { flex: 1; }
.dialog-body { padding: 12px 16px; }
.dialog-foot { display: flex; gap: 8px; justify-content: flex-end; padding: 12px 16px 16px; }
.dialog[data-side="bottom"] {
  width: 100%; max-width: 100%; margin: auto auto 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0; border-bottom: 0;
}
@media (max-width: 719px) {
  .dialog { width: 100%; max-width: 100%; margin: auto auto 0; border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
}

/* ---- tell the crew, in place: fixed, so nothing shifts ---- */
.tell-here { position: fixed; left: 0; right: 0; bottom: 0; z-index: 50; width: min(620px, 100%); margin: 0 auto; padding: 8px; }
.tell-picture { max-width: 100%; height: auto; }
.tell-here .comment-form { margin: 0; box-shadow: var(--shadow-2); }

/* ---- command palette ---- */
/* A dialog centres itself with its own auto margins, which the reset zeroes
   — so anything that wants to be centred has to say so again. */
.palette { width: min(620px, calc(100vw - 24px)); margin: 12dvh auto auto; }
@media (max-width: 719px) {
  .palette { width: 100%; max-width: 100%; margin: auto auto 0; }
}
.palette .palette-input {
  width: 100%; border: 0; border-bottom: 1px solid var(--border); border-radius: 0;
  min-height: 48px; padding: 0 16px; background: none; font-size: 15px; box-shadow: none;
}
.palette .palette-input:focus-visible { box-shadow: none; border-color: var(--border); }
/* A height, not a ceiling: the dialog must not jump as rows come and go
   under a query. */
.palette-list {
  height: min(46dvh, 420px); overflow-y: auto; overscroll-behavior: contain;
  padding: 6px; scrollbar-width: thin;
}
.palette-group + .palette-group { margin-top: 4px; }
/* Headings and details are text people read (a recent page's detail says
   where it was), so they take --muted-fg: --faint is 2.3:1 on the selected
   row in light. The icon alone stays faint. */
.palette-heading {
  padding: 8px 10px 4px;
  font-size: var(--fs-min); font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted-fg);
}
.palette-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 10px; border: 0; border-radius: var(--radius-sm);
  background: none; color: var(--fg); font-size: 14px; text-align: left;
  text-decoration: none; cursor: pointer;
}
.palette-item[hidden] { display: none; }
.palette-item .grow { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.palette-item .ico { color: var(--faint); }
.palette-item .cat {
  flex: none; max-width: 45%; margin-left: auto;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12.5px; color: var(--muted-fg);
}
/* One highlight. The pointer moves it (the script listens) rather than
   painting a second one under the cursor; the finder keeps plain hover. */
.palette-item[aria-selected="true"], .finder .palette-item:hover { background: var(--muted); }
/* --muted-fg is 4.40:1 on that highlight in light; the detail takes --fg there. */
.palette-item[aria-selected="true"] .cat { color: var(--fg); }
.palette-foot {
  display: flex; align-items: center; gap: 10px; padding: 8px 14px;
  border-top: 1px solid var(--border); font-size: 12.5px; color: var(--faint);
}
.palette-empty {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  height: 100%; margin: 0; color: var(--muted-fg); font-size: 13px; text-align: center;
}

/* ---- toast / flash ---- */
.toast {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 16px 0 0; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--card); box-shadow: var(--shadow-1);
  font-size: 14px;
  animation: pop 160ms var(--ease) both;
}
.toast .ico { margin-top: 1px; }
.toast[data-tone="success"] {
  border-color: color-mix(in srgb, var(--success) 34%, transparent);
  background: color-mix(in srgb, var(--success) 8%, var(--card));
}
.toast[data-tone="success"] .ico { color: var(--success); }
.toast[data-tone="danger"] {
  border-color: color-mix(in srgb, var(--danger) 34%, transparent);
  background: color-mix(in srgb, var(--danger) 8%, var(--card));
}
.toast[data-tone="danger"] .ico { color: var(--danger); }
.toast[data-tone="attn"] {
  border-color: color-mix(in srgb, var(--attn) 34%, transparent);
  background: color-mix(in srgb, var(--attn) 8%, var(--card));
}
.toast[data-tone="attn"] .ico { color: var(--attn); }
.toast .toast-body { flex: 1; min-width: 0; }
.toast code { display: block; margin-top: 6px; }

/* ---- tooltip ---- */
[data-tip] { position: relative; }
[data-tip]::after {
  content: attr(data-tip); position: absolute; z-index: 40;
  bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  padding: 4px 8px; border-radius: var(--radius-sm);
  background: var(--primary); color: var(--primary-fg);
  font-size: 12.5px; font-weight: 500; white-space: nowrap;
  opacity: 0; pointer-events: none; transition: opacity 120ms var(--ease);
}
[data-tip][data-tip-side="bottom"]::after { bottom: auto; top: calc(100% + 6px); }
[data-tip]:hover::after, [data-tip]:focus-visible::after { opacity: 1; }
@media (pointer: coarse) { [data-tip]::after { display: none; } }

/* ---- page head: title, actions, subtitle ---- */
.page-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 20px 0 14px;
}
.page-head h1 { min-width: 0; overflow-wrap: anywhere; }
.page-head > .page-head-sub { flex-basis: 100%; margin-top: -4px; }

/* ---- breadcrumbs ---- */
.crumbs {
  display: flex; align-items: center; gap: 4px; min-width: 0;
  font-size: 14px; overflow: hidden;
}
.crumbs a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* On a phone the crumbs would be squeezed to "y… / c."; the page header
   right below says where you are, in full. */
@media (max-width: 719px) { .topbar .crumbs { display: none; } }
/* The dot between facts on a line (a where strip, a row's meta); the crumbs
   keep their own for the flex rule. */
.sep { color: var(--faint); }
.row-meta .sep { margin: 0 3px; }
.crumbs .sep { color: var(--faint); flex: none; }
.crumbs [aria-current="page"] { font-weight: 550; }
.crumbs.mono, .crumbs.mono a { font-family: var(--mono); font-size: 12.5px; }

/* ---- pagination ---- */
.pager {
  display: flex; align-items: center; gap: 8px; justify-content: center;
  margin-top: 12px; font-size: 13px; color: var(--muted-fg);
}
.pager .spacer { flex: 1; }

/* ---- timeline ---- */
.timeline { position: relative; display: flex; flex-direction: column; gap: 12px; }
.timeline::before {
  content: ""; position: absolute; left: 13px; top: 8px; bottom: 8px;
  width: 2px; background: var(--border);
}
.tl-item { position: relative; padding-left: 36px; min-width: 0; }
.tl-item .tl-dot {
  position: absolute; left: 4px; top: 6px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 999px;
  background: var(--muted); border: 1px solid var(--border); color: var(--muted-fg);
}
.tl-item[data-tone="success"] .tl-dot { color: var(--success); border-color: color-mix(in srgb, var(--success) 40%, var(--border)); }
.tl-item[data-tone="danger"] .tl-dot { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); }
.tl-item[data-tone="merged"] .tl-dot { color: var(--merged); border-color: color-mix(in srgb, var(--merged) 40%, var(--border)); }
.tl-item[data-kind="event"] {
  font-size: 13px; color: var(--muted-fg);
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  min-height: 32px;
}
.tl-earlier { margin: 0; padding-left: 36px; color: var(--muted-fg); font-size: 13px; }
.tl-item[data-kind="comment"] { padding-bottom: 16px; }
.tl-item[data-kind="event"] > .card { flex-basis: 100%; margin: 4px 0 0; color: var(--fg); font-size: 14px; }
.tl-item[data-kind="event"] > .comment-body { flex-basis: 100%; min-width: 0; margin: 4px 0 0; padding: 0; color: var(--fg); font-size: 14px; }

/* ---- comment card ---- */
.comment .card-head { background: var(--muted); font-size: 13px; }
.comment .comment-body { padding: 2px 16px 8px; }
.comment-row { min-width: 0; }
.comment-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 13px; min-height: 28px; }
.comment-row .comment-body { padding: 4px 0 0; }
.comment-form { margin-top: 16px; padding: 12px; overflow: visible; }
.comment-form textarea { margin-bottom: 10px; }
/* The thread's composer is plain lines under the timeline, like the home one. */
.comment-form:not(.card) { padding: 0; margin-top: 16px; }

/* ---- empty state ---- */
.empty {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 48px 20px; text-align: center; color: var(--muted-fg);
}
.empty .ico { color: var(--faint); width: 20px; height: 20px; }
.empty h2, .empty .empty-title {
  font-size: 15px; font-weight: 600; color: var(--fg); text-wrap: balance; margin: 0;
  overflow-wrap: anywhere;
}
.empty p { font-size: 13px; max-width: 320px; text-wrap: pretty; margin: 0; }
.empty .btn { margin-top: 8px; }

/* ---- board panel grid: a board's panels, on /boards and pinned in the studio ---- */
.bgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
.bp-w2 { grid-column: span 2; }
.bp-w3 { grid-column: span 3; }
.bgrid h2 { font-size: 14px; }
@media (max-width: 720px) { .bgrid { grid-template-columns: minmax(0, 1fr); } .bp-w2, .bp-w3 { grid-column: auto; } }

/* Home's slot for pinned panels holds one panel row until the fragment lands, then the panels size it. */
.home-panels-slot[data-refresh] { min-height: 240px; margin-bottom: 16px; }

/* ---- settings shell ---- */
.settings { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; margin-top: 12px; }
.settings-nav {
  min-width: 0; display: none; flex-direction: column; gap: 14px;
}
.settings-nav a, .settings-jump-list a {
  display: flex; align-items: center; min-height: 28px; padding: 0 8px;
  font-size: 13px; color: var(--muted-fg); border-radius: var(--radius-sm);
}
.settings-nav a:hover, .settings-jump-list a:hover { background: var(--muted); color: var(--fg); }
.settings-nav a[aria-current="page"], .settings-jump-list a[aria-current="page"] { color: var(--fg); font-weight: 550; background: var(--muted); }
.settings-nav a[hidden], .settings-group[hidden] { display: none; }
.settings-group { display: flex; flex-direction: column; gap: 1px; }
.settings-group-name { margin: 0 0 2px; padding: 0 8px; font-size: 12.5px; font-weight: 500; color: var(--muted-fg); }
.settings-filter { width: 100%; font-size: 16px; }
.settings-jump { border: 1px solid var(--border); border-radius: var(--radius); background: var(--card); }
.settings-jump > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  min-height: 44px; padding: 0 12px; font-weight: 550; cursor: pointer; list-style: none;
}
.settings-jump > summary::-webkit-details-marker { display: none; }
.settings-jump[open] > summary .ico { transform: rotate(180deg); }
.settings-jump-list { display: grid; gap: 12px; padding: 4px 6px 12px; border-top: 1px solid var(--border); }
.settings-jump-list .settings-group-name { margin-top: 8px; }
.settings-jump-list a { min-height: 40px; font-size: 14px; }
.settings-main { min-width: 0; max-width: 860px; }
.settings-main > .card, .settings-main > .stack > .card, .settings-main > form > .card {
  border: 0; border-radius: 0; background: transparent; box-shadow: none; overflow: visible;
}
.settings-main > .card + .card, .settings-main > .stack > .card + .card { margin-top: 20px; }
.settings-main .card > .card-head {
  padding: 0 0 8px; background: transparent; border-bottom: 1px solid var(--border);
}
.settings-main .card > .card-head > .ico { display: none; }
.settings-main .card > .card-head :is(h2, h3) { font-size: 14px; font-weight: 600; }
.settings-main .card > .card-body { padding: 8px 0 0; }
.settings-main .card > .card-foot { padding: 10px 0 0; background: transparent; }
.settings-main .card > .list > li { padding-left: 0; padding-right: 0; }
.settings-main .card > .list .row { padding: 8px 0; gap: 10px; font-size: 13px; }
.settings-main .card > .list .row-lead { display: none; }
.settings-main .card > .card-body > p.muted.small { margin: 0 0 6px; }
@media (min-width: 860px) {
  .settings { grid-template-columns: 184px minmax(0, 1fr); gap: 40px; margin-top: 16px; }
  .settings-jump { display: none; }
  .settings-nav {
    display: flex; position: sticky; top: calc(var(--topbar-h) + 16px); align-self: start;
    max-height: calc(100dvh - var(--topbar-h) - 32px); overflow-y: auto; scrollbar-width: none;
  }
  .settings-filter { font-size: 13px; min-height: 30px; }
}

/* ---- settings content: status rows, blocks, a segmented control ---- */
.settings-block { margin-top: 24px; }
.settings-block:first-child { margin-top: 0; }
.settings-block > h2, .settings-block > .bar > :is(h2, h3) { font-size: 14px; font-weight: 600; margin: 0; }
.settings-block > h2 { margin-bottom: 8px; }
.settings-block > .bar { gap: 12px; flex-wrap: wrap; }
.settings-block > p { margin-top: 8px; }
.status-rows { margin: 24px 0 0; border-top: 1px solid var(--border); }
.status-row {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 2px 16px; align-items: center;
  padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 13px;
}
.status-row > dt { font-weight: 550; }
.status-row > dd { margin: 0; min-width: 0; }
.status-act { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; }
.status-act:empty { display: none; }
@media (min-width: 640px) {
  .status-row { grid-template-columns: 168px minmax(0, 1fr) auto; }
  .status-act { justify-content: flex-end; }
}
.segmented { display: inline-flex; padding: 2px; gap: 2px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--muted); }
.segmented form { display: contents; }
.segmented button, .segmented-on {
  display: inline-flex; align-items: center; min-height: 28px; padding: 0 12px;
  font: inherit; font-size: 13px; color: var(--muted-fg); background: transparent; border: 0; border-radius: var(--radius-sm); cursor: pointer;
}
.segmented button:hover { color: var(--fg); }
.segmented-on { color: var(--fg); font-weight: 550; background: var(--card); box-shadow: var(--shadow-1); cursor: default; }

.setting-table td { vertical-align: middle; }
.setting-table td { padding-top: 6px; padding-bottom: 6px; }
.setting-table td:first-child { max-width: 0; }
.setting-table td:first-child > :is(strong, span) { white-space: nowrap; }
.setting-table td:not(:first-child) { width: 1%; white-space: nowrap; }
.status-row .row-fields .input[type="number"] { width: 72px; }
.status-row .row-fields { flex-wrap: wrap; }
.status-row select.input { width: auto; }
.setting-table .row-fields { flex-wrap: nowrap; }
.setting-table .row-fields .input { width: 96px; }
@media (max-width: 639px) {
  .setting-table thead { display: none; }
  .setting-table, .setting-table tbody, .setting-table tr, .setting-table td { display: block; }
  .setting-table tr { padding: 10px 0; border-bottom: 1px solid var(--border); }
  .setting-table td { padding: 2px 0; border: 0; }
  .setting-table td:first-child { max-width: none; }
  .setting-table td:not(:first-child) { width: auto; }
}

/* ---- sticky primary action (thumb reach on a phone) ---- */
.sticky-action {
  position: sticky; bottom: 0; z-index: 8;
  display: flex; gap: 8px; align-items: center;
  padding: 10px 0 max(10px, env(safe-area-inset-bottom));
  background: linear-gradient(to top, var(--bg) 62%, transparent);
}
.sticky-action .btn { flex: 1; }
@media (min-width: 720px) { .sticky-action { position: static; background: none; padding: 0; } .sticky-action .btn { flex: none; } }

/* ---- live updates ---- */
.live-news {
  position: fixed; left: 0; right: 0; bottom: 20px; z-index: 25;
  display: flex; justify-content: center; pointer-events: none;
}
.live-news .badge {
  pointer-events: auto; min-height: 36px; padding: 0 14px; font-size: 13px;
  background: var(--card); box-shadow: var(--shadow-2);
  animation: pop 200ms var(--ease) both;
}

}

/* iOS zooms the whole page when a focused field is set below 16px, and the
   zoom drags the scroll with it. On a touch screen every field is 16px, so
   the page stays exactly where the reader left it. */
@media (pointer: coarse) {
  input, textarea, select, .input, .input[data-size="sm"], .topbar-search input,
  .palette .palette-input { font-size: 16px; }
}

/* Forced colours drop box-shadow rings and author colours: the focus ring is
   an outline the system paints. */
@media (forced-colors: active) {
  .input:focus-visible, .palette .palette-input:focus-visible { outline: 2px solid Highlight; outline-offset: 1px; }
  .color-field:focus-within { outline: 2px solid Highlight; outline-offset: 1px; }
}

/* Asked for less motion, the page keeps every state and loses the movement.
   `!important` because a bare `*` has no specificity: every class rule above
   that sets an animation or transition would win. Durations collapse rather
   than `animation: none`, so `animationend` still fires (src/web/live.ts
   removes its flash class on it). A busy loader stops turning and dims. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .btn[aria-busy="true"] .ico-loader { opacity: .6; }
}

@layer components {
#app-head.studio-just-changed, #app-previews.studio-just-changed { animation: studio-flash 1.1s var(--ease); border-radius: var(--radius); }
@keyframes studio-flash { 0% { background-color: color-mix(in srgb, var(--accent) 14%, transparent); } 100% { background-color: transparent; } }
@media (prefers-reduced-motion: reduce) { #app-head.studio-just-changed, #app-previews.studio-just-changed { animation: none; } }

.badge[data-variant="accent"] { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 34%, transparent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.badge[data-word="working"] svg { animation: spin 1.1s linear infinite; }
@media (prefers-reduced-motion: reduce) { .badge[data-word="working"] svg { animation: none; } }

/* A timeline of the design system's cards; the card's own margin spaces them. */
.feed { display: grid; gap: 0; }
.feed > .card:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.feed > .card[hidden] { display: none; }
/* The Like form sits in the card's flow; its count has a fixed width so a press moves nothing. */
.feed .like { display: inline-block; margin: 0; }
.feed .like [data-likes] { display: inline-block; min-width: 3ch; text-align: end; font-variant-numeric: tabular-nums; }
.feed .card-foot > details { flex: 1 1 100%; }
/* Your apps: a narrow column on a desk, a tab away on a phone. */
/* An admin's tick boxes are always shown (no Select toggle); 24 px to tap. */
#live-apps input[type="checkbox"] { width: 24px; height: 24px; }
@media (max-width: 899px) {
  #live-apps { display: none; }
}
/* Home's living pipeline (#8015): two lists side by side on a desk. Each list always holds three rows, so nothing below moves. */
.moving { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.moving > * { min-width: 0; }
@media (min-width: 700px) {
  .moving { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.moving .row { min-height: 44px; }
.tell-box > input[name="text"] { flex: 1 1 14rem; min-width: 0; }
@media (max-width: 600px) {
  .feed .bar .btn { padding: 8px 10px; }
  .feed .disclosure > summary { min-height: 44px; display: flex; align-items: center; }
}
@media (forced-colors: active) {
  .feed > .card:focus-visible { outline: 2px solid Highlight; }
}

@media (max-width: 600px) {
  .feed .card-head { row-gap: 2px; }
  .feed .bar .btn { min-height: 44px; }
}
}

@layer components {
.board { --pad: clamp(16px, 2.2vw, 32px); display: flex; flex-direction: column; min-height: 100dvh; }
.board > header, .board > .stack { padding: 12px var(--pad) 0; }
.board > #notes { padding: 8px var(--pad) 0; }
.board > .money-line { padding: 8px var(--pad) 0; }
#notes ul { list-style: none; margin: 4px 0 0; padding: 0; max-height: 30dvh; overflow: auto; }
#notes li > * { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; min-height: 44px; overflow-wrap: anywhere; }
#notes li > a { display: block; padding-block: 12px; min-height: 0; }
/* The spend line's way to the fleet graph: a 44px target beside it, wrapping under it on a phone. */
#returns { display: flex; flex-wrap: wrap; align-items: center; column-gap: 12px; }
#returns-graph { display: inline-flex; align-items: center; min-height: 44px; padding-inline: 8px; }
.board #board-live { display: inline-flex; align-items: center; }
.board #board-clock { min-width: 5ch; text-align: right; }
.board [data-started] { min-width: 7ch; text-align: right; }
.board-grid { flex: 1; display: grid; gap: var(--pad); padding: 16px var(--pad) var(--pad); min-height: 0; }
.board-region { min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 12px; }
.board-region > h2 { display: flex; align-items: center; gap: 8px; margin: 0; }
.board-region[data-fresh] > h2 { color: var(--accent); }
.board-region .row-lead img { display: block; border: 1px solid var(--border); border-radius: 4px; object-fit: cover; object-position: top; }
.board-region .row-main > meter { margin-top: 4px; }
.board [data-window] > meter { width: 56px; }

/* Wide: four regions fill the window, each list scrolling on its own. */
@media (min-width: 1100px) {
  .board { height: 100dvh; min-height: 0; }
  .board-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: repeat(2, minmax(0, 1fr)); }
  .board-region > .card { min-height: 0; overflow: auto; scrollbar-width: thin; }
  .board[data-focus] .board-grid { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); }
}
/* One region, full bleed. */
.board[data-focus] .board-region { display: none; }
.board[data-focus="working"] #working, .board[data-focus="landed"] #landed,
.board[data-focus="decided"] #decided, .board[data-focus="today"] #today { display: flex; }
/* Read from across the room: one region, or the wall mode, at a larger
   scale — the same rows, every size in proportion. Nobody is at the keys. */
.board[data-focus] .board-region > * { zoom: 1.3; }
.board[data-wall] .board-region > *, .board[data-wall] > .stack { zoom: 1.4; }
.board[data-wall] { cursor: none; }
.board[data-wall] #notes :is(.input, .btn) { display: none; }
}


@layer content {

/* ---- page furniture ---- */
.repo-head { margin: 18px 0 0; view-transition-name: repo-head; }
.repo-title {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 20px; font-weight: 620; letter-spacing: -0.02em; line-height: 1.3;
}
.repo-title .muted, .repo-title .sep { font-weight: 400; }
/* A phone has no hover: a link under the title is 44px tall, and stays in its sentence. */
@media (max-width: 640px) {
  .repo-head p.muted.small a { display: inline-block; padding: 12px 0; min-height: 44px; box-sizing: border-box; }
}
.repo-head p.muted.small { margin-top: 4px; text-wrap: pretty; }
.repo-head .tabs, .repo-head .repo-nav { margin-top: 12px; }
.repo-nav { display: flex; align-items: flex-start; gap: 4px; border-bottom: 1px solid var(--border); }
.repo-nav .tabs { margin-top: 0; border-bottom: 0; flex: 1 1 auto; }
.repo-nav .menu { margin-top: 4px; }

/* Provenance and pinning: one line under the title, so a <form> never has to
   live inside the <h1>. */
.repo-origin,
.repo-where {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 6px; min-height: 26px;
}

/* The where strip: three places, dots and words. The dot carries the state
   and the colour; the word is never coloured, so a strip reads as one fact
   rather than as three competing badges. */
.where {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  min-width: 0; font-size: 12.5px;
}
.where-place {
  display: inline-flex; align-items: center; gap: 5px;
  max-width: 100%; padding: 2px 6px; border-radius: var(--radius-sm);
  border: 1px solid transparent; background: none;
  color: var(--muted-fg); font: inherit; text-decoration: none;
  white-space: nowrap; cursor: default;
}
a.where-place, button.where-place { cursor: pointer; }
a.where-place:hover, button.where-place:hover {
  border-color: var(--border); background: var(--muted); color: var(--fg);
}
.where-place .ico { color: var(--faint); flex: none; }
/* A thumb needs more than a 12px word to land on. */
@media (pointer: coarse) { .where-place { min-height: 32px; padding: 4px 8px; } }
/* The dot is the place's aria-hidden span: ● ○ ◆ are decoration, and the
   state and the word beside them already say what they mean. */
.where-place > span[aria-hidden="true"] { font-size: var(--fs-min); line-height: 1; }
/* Accent is interaction everywhere else in the product; here it is the one
   place a page is *reading from*, which is the page's own subject. */
.where-place[data-state="reading"] { color: var(--fg); font-weight: 560; }
.where-place[data-state="reading"] > span[aria-hidden="true"] { color: var(--accent); }
.where-place[data-state="present"] > span[aria-hidden="true"] { color: var(--success); }
.where-place[data-state="absent"] { color: var(--faint); }
.where-place[data-state="absent"] > span[aria-hidden="true"] { color: var(--faint); }
.where-pin { margin-left: auto; }
/* Inside a list row the strip is text, not a layout: the row promises one
   honest line with an ellipsis, and only inline children can keep it. */
.row-meta .where { display: inline; }
.row-meta .where-place { display: inline; padding: 0; }
.row-meta .where-place .ico { display: none; }
.row-meta .where-place > span[aria-hidden="true"] { margin-right: 3px; }
.row-title a { color: inherit; text-decoration: none; }
.row-title a:hover { color: var(--accent); }
/* The signed-in home (#9378). Its rows already clip one line and its
   sections are grid cells with min-width 0 (feed_style.ts); what is left is a
   long app name, which wraps inside its chip, and the tell box's input and
   select, which may shrink. The chip row is server-rendered, so a wrapped
   chip is its final height on first paint. */
#live-chips a, .home-doors a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; display: inline-flex; align-items: center; min-height: 44px; padding: 0 6px; box-sizing: border-box; }
#live-chips a:hover, #live-chips a:focus-visible, .home-doors a:hover, .home-doors a:focus-visible { text-decoration-thickness: 2px; }
#live-chips a { max-width: 100%; overflow-wrap: anywhere; }
.home-doors { display: flex; flex-wrap: wrap; gap: 4px 12px; }
.step-body { padding: 4px 16px 16px 44px; }
.step-body > :first-child { margin-top: 0; }
.step-body > :last-child { margin-bottom: 0; }
@media (max-width: 719px) { .step-body { padding-left: 16px; } }
.tell-box .input { min-width: 0; max-width: 100%; }
.row-trail form { display: inline-flex; }

/* "Where it lives": the origin, when it was last fetched, the button that
   fetches it now, and where a push actually lands — one block, because they
   are one fact about the repository. */
.where-block {
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border);
}
.where-block h3 { margin-bottom: 6px; }

/* A live browse: quiet, above the content, and never in the way of it. */
.live-note {
  display: flex; align-items: flex-start; gap: 8px;
  margin-top: 12px; padding: 8px 12px;
  border: 1px solid color-mix(in srgb, var(--accent) 34%, transparent);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  color: var(--muted-fg); font-size: 13px;
}
.live-note .ico { color: var(--accent); flex: none; margin-top: 1px; }
.live-note p { text-wrap: pretty; }
.live-note strong { color: var(--fg); }

/* A mirror in flight. One row per stage, in the order they happen; the row
   is a §5 row whose badge says which of the three states it is in. */
.stages { list-style: none; margin: 0; padding: 0; }
.stages li[data-state="todo"] .row-title { color: var(--faint); }
.origin-chip {
  display: inline-flex; align-items: center; gap: 6px;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 2px 8px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--muted); color: var(--muted-fg);
  font-size: 12.5px; text-decoration: none;
}
a.origin-chip:hover { border-color: var(--border-strong); color: var(--fg); }
.origin-chip .ico { color: var(--faint); flex: none; }
/* An imported author is the origin's login, so it wears the origin's mark
   where a local avatar would be. */
.byline.origin-by { display: inline-flex; align-items: center; gap: 5px; }
.byline.origin-by .ico { color: var(--faint); }

/* Why an issue closes, beside the button that closes it. */
.form-actions select[name="reason"] { width: auto; }
.form-actions input[name="into"] { display: none; width: 7em; }
.form-actions:has(select[name="reason"] option[value="split"]:checked) input[name="into"] { display: inline-block; }
/* On a phone the Markdown hint takes its own line, so the reason, Close and
   Comment stay together on the next one instead of Comment wrapping alone. */
@media (max-width: 480px) {
  .comment-form .form-actions > .muted.small { flex-basis: 100%; }
  .comment-form .form-actions > .spacer { display: none; }
  .comment-form .form-actions > :last-child { margin-left: auto; }
  /* The reason select, Close and Comment must fit 332 px with room to
     spare: a tighter gap and a narrower select. */
  .comment-form .form-actions { gap: 6px; }
  .comment-form .form-actions select[name="reason"] { padding-inline: 8px 24px; max-width: 84px; }
  /* Words carry the buttons here; their icons give back the width a 360 px
     row needs for "Close issue", and the buttons keep their full height. */
  .comment-form .form-actions .btn .ico { display: none; }
}

/* A device code is read aloud across a room and typed on a phone: it is the
   one place in the product where type is deliberately large. */
.device-code {
  margin: 12px 0; padding: 12px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--muted);
  font-family: var(--mono); font-size: clamp(24px, 6vw, 40px);
  font-variant-numeric: tabular-nums; letter-spacing: 0.14em;
  text-align: center; user-select: all; word-break: break-all;
}
/* An issue's page (#9384): other people's words wrap, the columns shrink, code scrolls in its box. */
[data-tell] { overflow-wrap: anywhere; }
[data-tell] .split > * { min-width: 0; }
[data-tell] .page-head-sub { flex-wrap: wrap; }
[data-tell] .comment-body img { max-width: 100%; height: auto; }
[data-tell] pre { max-width: 100%; overflow-x: auto; }
[data-apps], [data-apps-page], [data-bet-card], [data-explore], [data-family], [data-forges], [data-milestone], [data-new-repo], [data-now], [data-people] { overflow-wrap: anywhere; }
/* /new (#9830): a long owner name or refused value stays inside the form on a phone. */
[data-new-repo] form, [data-new-repo] .error { min-width: 0; max-width: 100%; }
[data-new-repo] select.input { text-overflow: ellipsis; }
/* /explore (#9370): rows wrap rather than truncate a long name or description. */
[data-explore] .row-title, [data-explore] .row-meta { white-space: normal; overflow: visible; }
[data-explore] .row { flex-wrap: wrap; }
[data-explore] .row-main { flex: 1 1 14rem; }
/* The forges pages (#9372): a row's trail of badges and buttons drops under its text on a phone and wraps. */
[data-forges] .row-title, [data-forges] .row-meta { white-space: normal; overflow: visible; }
[data-forges] .row-trail { flex-wrap: wrap; }
@media (max-width: 719px) {
  [data-forges] .row { flex-wrap: wrap; }
  [data-forges] .row-trail { flex: 1 1 100%; justify-content: flex-start; }
}
[data-bet-card] ul, [data-bet-card] p { margin-block: 8px; }
[data-bet-card] ul { padding-inline-start: 16px; }
/* The bound is on what a disclosure opens, not on the row: the page scrolls, a long issue list scrolls inside its own details. */
[data-bet-card] details ul { max-height: 40vh; overflow-y: auto; }
[data-bet-actions] { align-items: flex-start; }

.bar > .device-code { flex: 1 1 auto; }

.repo-actions { display: flex; align-items: center; gap: 6px; margin-left: auto; }


/* A list's six words fit a phone without pushing the page sideways in a
   filter bar drawn with §5's .bar: a little less padding there, and a
   scroll inside the bar as the last resort. */
.bar .seg { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
@media (max-width: 420px) { .bar .seg > a { padding: 0 8px; } }

.direction-text { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 13px; color: var(--muted-fg); margin: 6px 0 0; }

.chart-box { color: var(--accent); aspect-ratio: 720 / 260; max-width: 720px; }
.chart-box .chart { display: block; width: 100%; height: auto; }
.chart-box text { fill: var(--muted-fg); font-family: var(--mono); }
.chart-box circle { fill: var(--accent); }
.chart-box .big { fill: var(--fg); font-family: inherit; }
.chart-box.is-table { aspect-ratio: auto; height: 260px; overflow: auto; }
/* A board panel sizes its chart from here, after .chart-box: the grid itself
   is §5's board (components.ts), but this layer is where .chart-box is drawn. */
.bgrid .chart-box { max-width: none; }
.bp-h2 .chart-box { aspect-ratio: 720 / 400; }
.bp-h3 .chart-box { aspect-ratio: 720 / 540; }
.bp-h2 .chart-box.is-table { height: 400px; }
.bp-h3 .chart-box.is-table { height: 540px; }
#summary { display: flex; flex-wrap: wrap; gap: 6px; }
#summary .pill { max-width: 100%; white-space: normal; }
/* The stacked bar chart's series colours, for its bars (fleet-graph.ts).
   Okabe–Ito, told apart with common colour-vision deficiencies; the eighth,
   the folded "others", is grey. */
.fg-s0 { fill: var(--series-0); color: var(--series-0); }
.fg-s1 { fill: var(--series-1); color: var(--series-1); }
.fg-s2 { fill: var(--series-2); color: var(--series-2); }
.fg-s3 { fill: var(--series-3); color: var(--series-3); }
.fg-s4 { fill: var(--series-4); color: var(--series-4); }
.fg-s5 { fill: var(--series-5); color: var(--series-5); }
.fg-s6 { fill: var(--series-6); color: var(--series-6); }
.fg-s7 { fill: var(--series-7); color: var(--series-7); }
/* The money line (studio/money_line.ts, #510, #11056, #11102): the
   slider's word ("spend: balanced") is the board's one link to Settings →
   Economics, in the accent; the gap takes the warning tint for a loss and
   the text colour otherwise. The accent on --bg holds 4.5:1 in every theme
   (test/themes.test.ts), so the small text reads. The word never breaks
   inside itself, so the line wraps between its parts. Two rows of 24px,
   the first wrapping once on a phone, so the reserved height is the real
   one; the chart a fixed box, so nothing shifts when the figures arrive. */
.money-gap[data-sign="down"] { color: var(--attn); }
.money-spend { color: var(--accent); white-space: nowrap; }
.money-line { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; }
.money-line > p { margin: 0; line-height: 24px; min-height: 48px; }
.money-line > p > span { display: block; }
@media (max-width: 480px) { .money-line > p { min-height: 72px; } }
.money-chart { display: block; width: 240px; height: 48px; flex: none; }
.money-chart polyline { fill: none; stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.money-cost { stroke: var(--muted-fg); }
.money-revenue { stroke: var(--fg); }
.money-band [data-sign="up"] { fill: color-mix(in srgb, var(--fg) 10%, transparent); }
.money-band [data-sign="down"] { fill: color-mix(in srgb, var(--attn) 22%, transparent); }
.restore-command { margin: 8px 0 0; padding: 8px 10px; font-size: 12.5px; white-space: pre-wrap; word-break: break-all; background: var(--muted); border-radius: var(--radius); }
form.inline { display: inline; margin-left: auto; }

/* The studio's front door: the page a visitor reads first. It is a page, not a
   screen, so its type runs past the working scale (docs/design/areas/front.md). */
.door { --door-gap: clamp(96px, 11vw, 128px); }
.door h1 { font-size: clamp(2.375rem, 5.4vw, 4.5rem); font-weight: 500; letter-spacing: -0.03em; line-height: 1.04; text-wrap: initial; }
.door h1 .muted { color: var(--muted-fg); }
.door h2 { font-size: clamp(1.75rem, 3.2vw, 2.5rem); font-weight: 500; letter-spacing: -0.025em; line-height: 1.1; }
.door h3 { font-size: 20px; font-weight: 500; letter-spacing: -0.015em; }
.door-support { max-width: 62ch; font-size: 16px; line-height: 1.55; color: var(--muted-fg); text-wrap: pretty; }
.door-hero { padding-top: clamp(48px, 8vw, 104px); }
.door-under { display: grid; gap: 56px; margin-top: 28px; }
.door-lead { display: flex; flex-direction: column; align-items: flex-start; gap: 24px; min-width: 0; }
.door-lead .bar { gap: 8px; flex-wrap: wrap; }
.door-agent { display: flex; flex-direction: column; gap: 8px; width: 100%; max-width: 520px; font-size: 13px; color: var(--muted-fg); }
.door-agent a { margin-left: 8px; color: var(--fg); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--border-strong); }
/* On the input's own tinted ground the muted color falls short of AA; the words are the thing to copy. */
.door-agent .input { color: var(--fg); }
.door-live { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.door-figures { display: flex; flex-wrap: wrap; gap: 12px 36px; padding-bottom: 20px; border-bottom: 1px solid var(--border); }
.door-figure { display: flex; flex-direction: column; gap: 2px; }
.door-figure strong { font-size: clamp(1.75rem, 2.8vw, 2.25rem); font-weight: 500; letter-spacing: -0.03em; line-height: 1.1; }
.door-now { display: flex; align-items: center; gap: 8px; margin-top: 6px; font-family: var(--mono); font-size: 12.5px; color: var(--muted-fg); }
.door-ledger { display: flex; flex-direction: column; gap: 10px; margin: 0; padding: 0; list-style: none; }
.door-ledger li { display: flex; flex-direction: column; min-width: 0; }
.door-ledger a { color: var(--fg); }
.door-when { display: block; }
.door-section { margin-top: var(--door-gap); scroll-margin-top: 72px; }
.door-section > h2 + .door-support { margin-top: 12px; }
.door-shelf { display: grid; margin-top: 44px; gap: 40px 24px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.door-shelf > .card { min-width: 0; margin: 0; padding-top: 14px; border: 0; border-top: 1px solid var(--border-strong); border-radius: 0; background: transparent; box-shadow: none; overflow: visible; }
.door-kick { margin: 0 0 14px; font-family: var(--mono); font-size: 12.5px; color: var(--muted-fg); }
.door-kick span { color: var(--fg); }
.door-shelf .look { aspect-ratio: 16 / 9; transition: border-color 0.15s ease; }
.door-shelf .look:hover { border-color: var(--border-strong); }
.door-shelf .look img { height: 100%; object-fit: cover; object-position: top; }
.door-shelf .card-body { padding: 14px 0 0; gap: 4px; }
.door-shelf .card-body strong { font-size: 16px; font-weight: 500; letter-spacing: -0.015em; overflow-wrap: anywhere; }
.door-line { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; min-height: 3em; line-height: 1.5; }
.door-verbs { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 10px 0 0; font-family: var(--mono); font-size: 12.5px; }
.door-verbs a { min-height: 24px; color: var(--muted-fg); }
.door-verbs a:hover { color: var(--fg); }
.door-verbs .door-verb-first { color: var(--fg); font-weight: 600; text-decoration: underline; text-underline-offset: 4px; }
.door-more { margin-top: 36px; }
.door-steps { display: grid; gap: 32px; margin: 44px 0 0; padding: 0; list-style: none; counter-reset: door-step; }
.door-steps li { counter-increment: door-step; display: flex; flex-direction: column; gap: 6px; padding-top: 14px; border-top: 1px solid var(--border-strong); }
.door-steps li::before { content: counter(door-step, decimal-leading-zero); margin-bottom: 18px; font-family: var(--mono); font-size: 12.5px; color: var(--muted-fg); }
.door-steps p, .door-points dd { margin: 0; font-size: 15px; line-height: 1.55; color: var(--muted-fg); text-wrap: pretty; }
.door-split { display: grid; gap: 32px; }
.door-split > * { min-width: 0; }
.door-pulse { margin: 72px 0 0; }
.door-pulse svg { display: block; width: 100%; height: clamp(72px, 10vw, 120px); fill: var(--fg); }
.door-pulse-quiet { fill: var(--border-strong); }
.door-pulse rect:hover { fill: var(--accent); }
.door-pulse figcaption { margin-top: 10px; }
.door-org { margin-top: 64px; padding-top: 18px; border-top: 1px solid var(--border); color: var(--muted-fg); }
.door-org a { color: var(--fg); }
.door-proof { display: flex; flex-wrap: wrap; gap: 4px 28px; margin: 28px 0 0; padding: 0; list-style: none; font-family: var(--mono); font-size: 12.5px; line-height: 1.8; color: var(--muted-fg); }
.door-proof li::before { content: "[*] "; color: var(--fg); }
.door-points { display: grid; gap: 28px; margin: 36px 0 0; }
.door-points dt { margin-bottom: 4px; font-size: 16px; font-weight: 500; }
.door-points dd { max-width: 58ch; }
.door-code { margin: 0; padding: 18px 20px; overflow-x: auto; border-radius: var(--radius); background: var(--muted); font-family: var(--mono); font-size: 13px; line-height: 1.7; }
.door-packs { margin: 8px 0 0; color: var(--muted-fg); }
.door-packs .door-kick { display: block; margin-bottom: 8px; }
.door-press-row { display: grid; gap: 12px; }
.door-press { display: flex; flex-direction: column; gap: 6px; padding: 16px 18px; border: 1px solid var(--border); border-radius: var(--radius); }
.door-press h3 { margin: 0; font-size: 16px; font-weight: 500; }
.door-press p { margin: 0; }
.door-press-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.door-press-actions [data-slot]:empty { display: none; }
@media (max-width: 559px) {
  .door-wide { display: none; }
}
@media (min-width: 720px) {
  .door-shelf { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .door-points { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; }
  .door-steps { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; }
  .door-press-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .door-split { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 48px; }
}
@media (min-width: 1000px) {
  .door-under:has(> .door-live) { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 72px; }
}
@media (prefers-reduced-motion: no-preference) {
  .door-now .dot { animation: door-pulse 2s ease-in-out infinite; }
  @keyframes door-pulse { 50% { opacity: 0.35; } }
}

.front-admin { max-width: 1040px; margin-inline: auto; }
.front-pick { gap: 8px; }
.front-pick form.inline { margin-left: 0; }
.card[data-front-settings] .bar { padding: 12px 16px; gap: 8px 12px; }
.card[data-front-settings] .bar:has(> [name=repo]) { flex-wrap: nowrap; }
.card[data-front-settings] .bar > [name=repo] { flex: 1; min-width: 0; }
.card[data-front-settings] label .input { width: 4.5em; margin-left: 4px; }
.card[data-front-settings] .small { padding: 0 16px 14px; }
@media (max-width: 520px) {
  /* Two to a row on a phone: a few live apps in one screen, not a scroll. */
  .stack[data-shelf] { gap: 10px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Every page grid, in one rule: a grid item's automatic minimum size is its
   *content*, so a column with a long unbreakable line pushes the page wider
   than the phone rather than letting its own ellipsis do the work. A zero
   min-width is what makes truncation inside a grid actually truncate. */
.split > * { min-width: 0; }
.split { grid-template-columns: minmax(0, 1fr); overflow-wrap: anywhere; }

/* A repository's head page at 390 px: the head, the About rail and the body
   wrap an unbroken name, description or branch; the branch picker shrinks and
   its label truncates; README code and tables scroll inside their own box. */
.repo-head, .split > aside { overflow-wrap: anywhere; }
.bar > .menu { flex: 0 1 auto; min-width: 0; max-width: 100%; }
.bar > .menu > summary { max-width: 100%; min-width: 0; }
.bar > .menu > summary .truncate { min-width: 0; }
.prose img { max-width: 100%; height: auto; }
.prose pre, .prose table { max-width: 100%; overflow-x: auto; }
.prose table { display: block; }

/* The generic two-column page: content, then a sidebar that sticks. */
.split { display: grid; gap: 16px; margin-top: 16px; align-items: start; }
@media (min-width: 960px) {
  .split { grid-template-columns: minmax(0, 1fr) 260px; gap: 24px; }
  .split > aside { position: sticky; top: calc(var(--topbar-h) + 16px); }
}

/* Flows: sources left, the repository between, followers right (#9595). The
   hub is a name and two text arrows, decoration only and hidden from reading order;
   stacked on a phone, the arrows turn down. The name wraps and its column is
   capped so a long one cannot squeeze the two sides. */
.flow-map { display: grid; gap: 16px; margin-top: 16px; grid-template-columns: minmax(0, 1fr); overflow-wrap: anywhere; }
.flow-map > * { min-width: 0; }
.flow-hub { display: flex; flex-direction: column; align-items: center; gap: 4px; color: var(--muted); }
.flow-hub .flow-arrow { display: inline-block; transform: rotate(90deg); }
.flow-hub .flow-name { color: var(--fg); max-width: 100%; text-align: center; }
@media (min-width: 900px) {
  .flow-map { grid-template-columns: minmax(0, 1fr) minmax(0, max-content) minmax(0, 1fr); gap: 24px; align-items: start; }
  .flow-hub { flex-direction: row; align-self: center; max-width: 24ch; gap: 12px; }
  .flow-hub .flow-arrow { transform: none; }
}

/* The studio's wide rail (home, an app): a column of cards that runs taller
   than a screen, so it scrolls with the page instead of sticking, sits flush
   under the tabs or header, and takes its two columns from 900px. */
.split[data-rail="wide"] { margin-top: 0; }
@media (min-width: 900px) {
  .split[data-rail="wide"] { grid-template-columns: minmax(0, 1fr) 320px; gap: 24px; }
  .split[data-rail="wide"] > aside { position: static; }
}

/* ---- code view ---- */
.code { overflow-x: auto; scrollbar-width: thin; }
.code table { width: 100%; }
.code td { padding: 0 12px; vertical-align: top; }
.code tr { scroll-margin-top: calc(var(--topbar-h) + 12px); }
.code .ln {
  width: 1%; min-width: 44px; padding: 0 10px; text-align: right; user-select: none;
  color: var(--faint); font-family: var(--mono); font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  border-right: 1px solid var(--border);
}
.code .ln a { color: inherit; display: block; }
.code .ln a:hover { color: var(--accent); }
.code pre { white-space: pre; line-height: 1.55; min-height: 1.55em; font-variant-ligatures: none; }
.code tr:hover { background: color-mix(in srgb, var(--muted) 55%, transparent); }
.code tr:target, .code tr[data-hl] {
  background: color-mix(in srgb, var(--attn) 16%, transparent);
}
.code tr:target .ln, .code tr[data-hl] .ln { color: var(--attn); }

/* ---- csv view: the header stays under the bar, the first column on phones ---- */
.csv-tools { display: flex; align-items: center; gap: 12px; padding: 8px 12px; border-bottom: 1px solid var(--border); }
.csv-tools[hidden], .csv-view tr[hidden] { display: none; }
.csv-tools .input { max-width: 260px; }
.csv-scroll { overflow: auto; max-height: 75vh; scrollbar-width: thin; }
.csv-view th { position: sticky; top: 0; z-index: 2; background: var(--card); user-select: none; }
.csv-sort {
  font: inherit; color: inherit; background: none; border: 0; padding: 0;
  text-align: inherit; cursor: pointer;
}
.csv-sort:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
.csv-view th:first-child { z-index: 3; }
.csv-view td { max-width: 40ch; overflow-wrap: anywhere; }
.csv-view th[aria-sort="ascending"]::after { content: " \25B2"; font-size: 12.5px; }
.csv-view th[aria-sort="descending"]::after { content: " \25BC"; font-size: 12.5px; }
.csv-view .num { text-align: right; }
.csv-more { padding: 10px 12px; margin: 0; }

/* A notebook (render/notebook.ts): cells are rows with space between, never boxes. */
.nb-cell { margin: 0 0 28px; min-width: 0; }
.nb pre { max-width: 100%; overflow-x: auto; margin: 8px 0; }
.nb-img { display: block; max-width: 100%; height: auto; margin: 8px 0; }
.nb-cap { color: var(--muted-fg); font-size: 12.5px; margin-top: 8px; }

/* A terminal log (render/log.ts): SGR colours as fixed classes, theme tokens only. */
.ansi-red { color: var(--danger); }
.ansi-green { color: var(--success); }
.ansi-yellow { color: var(--attn); }
.ansi-blue { color: var(--tok-number); }
.ansi-magenta { color: var(--merged); }
.ansi-cyan { color: var(--tok-property); }
.ansi-gray { color: var(--tok-comment); }
.ansi-b { font-weight: 700; }
.ansi-u { text-decoration: underline; }

/* ---- syntax tokens (colors come from the active theme) ----
   Two layers, exactly as the tokenizer emits them: a colour class every
   consumer understands, and — where the web can say something finer — a kind
   painted over it: .tok-string.tok-regex is a regex, and dropping the second
   class leaves a string. Order matters and specificity does not: the kind
   rules come last, so they win at equal weight. */
.tok-keyword { color: var(--tok-keyword); }
.tok-string { color: var(--tok-string); }
.tok-comment { color: var(--tok-comment); font-style: italic; }
.tok-number { color: var(--tok-number); }
.tok-function { color: var(--tok-function); }
.tok-type { color: var(--tok-type); }
.tok-constant { color: var(--tok-constant); }
.tok-meta { color: var(--tok-meta); }
/* Punctuation and operators sit *below* the text colour on purpose: they are
   the scaffolding of a line, and colouring them loudly makes code shout. */
.tok-operator { color: var(--tok-operator); }
.tok-punctuation { color: var(--tok-punctuation); }
/* the refinements */
.tok-property { color: var(--tok-property); }
.tok-tag { color: var(--tok-tag); }
.tok-attribute { color: var(--tok-attribute); }
.tok-regex { color: var(--tok-regex); }
.tok-variable { color: var(--tok-variable); }
.tok-decorator { color: var(--tok-decorator); }
.tok-heading { color: var(--tok-heading); font-weight: 600; }
.tok-emphasis { color: var(--tok-emphasis); font-style: italic; }
.tok-link { color: var(--tok-link); }
.tok-inserted { color: var(--add-fg); }
.tok-deleted { color: var(--del-fg); }

/* A rendered Markdown blob wears the same frame its source does: one card,
   one path header, and the switch between the two views in it. */
.rail-facts { margin: 12px 0 0; display: grid; gap: 12px; font-size: 13px; }
.rail-fact > dt { color: var(--muted-fg); font-size: 12.5px; }
.rail-fact > dd { margin: 2px 0 0; min-width: 0; overflow-wrap: anywhere; }
.blob-view { margin-left: 8px; }
.blob-view .seg { font-size: 12.5px; }
/* An audio or video file, played inline (render/player.ts). The video is as
   wide as the pane and no wider; height follows its own aspect ratio. */
.media-pane .media-player { display: block; width: 100%; max-width: 100%; }
.media-pane video.media-player { height: auto; max-height: 80vh; background: var(--muted); border-radius: var(--radius-sm); }

/* An HTML file's page in a sandboxed frame: one hairline, a fixed height, so nothing shifts. */
.html-frame { display: block; width: 100%; height: 80vh; min-height: 480px; border: 1px solid var(--border); border-radius: var(--radius-sm); color-scheme: light; }
@media (max-width: 600px) { .html-frame { height: 60vh; min-height: 360px; } }
/* A PDF in the browser's own viewer: a fixed frame, so nothing shifts. */
.pdf-view { overflow: hidden; }
.pdf-frame { display: block; width: 100%; height: 80vh; min-height: 480px; border: 0; }
.pdf-fallback { padding: 16px 20px; display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
/* A phone: a shorter frame, so a thumb can scroll the page past it. */
@media (max-width: 600px) { .pdf-frame { height: 60vh; min-height: 360px; } }

/* A font specimen: set in the font itself once the script has loaded it from
   the media route; until then (or without script) in the page's own face. */
/* ---- gpx view: the outline scales to the column; its facts are status rows ---- */
.gpx-view { margin: 0; }
.gpx-view svg { display: block; max-width: 100%; height: auto; margin: 0 auto; color: var(--fg); }
.gpx-view .status-rows { margin-top: 12px; }
.gj-view { margin: 0; }
.gj-view svg { display: block; max-width: 100%; height: auto; margin: 0 auto; color: var(--fg); }
.gj-table { overflow-x: auto; max-width: 100%; }
.gj-table:focus-visible { outline: 1px solid var(--fg); outline-offset: 2px; }
.gj-table table { width: 100%; font-size: 13px; }
.gj-table th, .gj-table td { text-align: left; padding: 3px 8px; overflow-wrap: anywhere; }
.font-view { padding: 16px 20px; }
.font-name { margin: 0 0 12px; font-size: 1.75rem; line-height: 1.3; overflow-wrap: anywhere; }
.font-line { margin: 0 0 10px; line-height: 1.4; overflow-wrap: anywhere; }
.font-s { font-size: 14px; } .font-m { font-size: 1.5rem; } .font-l { font-size: 3rem; line-height: 1.2; }
.font-view.font-ready .font-name, .font-view.font-ready .font-line { font-family: "ForgeSpecimen", sans-serif; }

/* ---- image view ---- */
.imgview-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; padding: 4px 16px; font-size: 12.5px; border-bottom: 1px solid var(--border); }
.imgview-dim { min-width: 9ch; }
.imgview-pane { overflow: auto; min-height: 160px; max-height: 80vh; text-align: center; padding: 12px;
  background: repeating-conic-gradient(color-mix(in srgb, var(--fg) 8%, var(--bg)) 0 25%, transparent 0 50%) 0 0 / 16px 16px; }
.imgview-zoom { margin-left: auto; }
.imgview-img { max-width: 100%; height: auto; cursor: zoom-in; vertical-align: middle; }
.imgview-pane.is-actual { text-align: left; cursor: grab; }
.imgview-pane.is-actual .imgview-img { max-width: none; cursor: zoom-out; }

/* ---- prose (markdown) ---- */
.prose { padding: 16px 20px; font-size: 15px; line-height: 1.65; overflow-wrap: anywhere; }
/* Prose that is the page itself, not a card: it keeps the page's own edge and measure. */
.prose.prose-page { padding: 0; max-width: 72ch; }
.prose > * { max-width: var(--measure); }
.prose h1, .prose h2, .prose h3, .prose h4 { margin: 24px 0 8px; }
.prose h1 { font-size: 20px; }
.prose h2 { font-size: 16px; }
.prose h3 { font-size: 15px; }
.prose h1:first-child, .prose h2:first-child, .prose h3:first-child { margin-top: 0; }
.prose h1, .prose h2 { padding-bottom: 6px; border-bottom: 1px solid var(--border); }
.prose p, .prose ul, .prose ol, .prose blockquote { margin: 12px 0; text-wrap: pretty; }
.prose ul { list-style: disc; padding-left: 24px; }
.prose ol { list-style: decimal; padding-left: 24px; }
.prose li::marker { color: var(--faint); }
.prose pre {
  background: var(--muted); border: 1px solid var(--border);
  border-radius: var(--radius); max-width: none;
  padding: 12px 14px; overflow-x: auto; margin: 14px 0; scrollbar-width: thin;
}
/* Written text kept as typed (a commit message, a report): plain muted mono, wraps, never scrolls sideways. */
.prose[data-text="message"] { padding: 0; margin: 8px 0 4px; font-size: 12.5px; line-height: 1.5; }
.prose[data-text="message"] pre {
  background: none; border: 0; border-radius: 0; padding: 0; margin: 0;
  font-family: var(--mono); color: var(--muted-fg);
  white-space: pre-wrap; overflow-wrap: anywhere; overflow: visible;
}
/* A fold in prose (an issue's "Where this came from"): the global reset hides the marker, so the chevron is drawn here;
   the summary is a native, focusable, Enter/Space control with a row-high target. */
.prose details { margin: 12px 0; }
.prose summary { cursor: pointer; padding: 10px 0; min-height: 44px; color: var(--muted-fg); font-size: 13px; }
.prose summary::before { content: "\25B8"; display: inline-block; width: 1.2em; }
.prose details[open] > summary::before { content: "\25BE"; }
.prose details > ul { margin-top: 0; font-size: 13px; }
.prose code { background: var(--muted); border: 1px solid var(--border); padding: 1px 5px; border-radius: 4px; }
.prose pre code { background: none; border: none; padding: 0; }
.prose blockquote {
  border-left: 3px solid color-mix(in srgb, var(--accent) 45%, var(--border));
  padding-left: 12px; color: var(--muted-fg);
}
.prose a {
  color: var(--accent); text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent) 35%, transparent);
  text-underline-offset: 3px; transition: text-decoration-color 140ms var(--ease);
}
.prose a:hover { text-decoration-color: currentColor; }
.prose img { border-radius: var(--radius-sm); }
.prose table { width: 100%; font-size: 14px; margin: 14px 0; }
.prose th, .prose td { padding: 6px 10px; border: 1px solid var(--border); text-align: left; }
.prose th { background: var(--muted); font-weight: 600; }
.prose .ta-c { text-align: center; }
.prose .ta-r { text-align: right; }
.prose hr { border: 0; border-top: 1px solid var(--border); margin: 20px 0; }

/* ---- diff viewer ---- */
.diff { display: flex; flex-direction: column; gap: 12px; }
.change-line { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin: 0 0 12px; font-size: 13px; }
.change-line a { display: inline-flex; align-items: center; gap: 6px; padding: 12px 0; line-height: 16px; color: inherit; }
.change-files { list-style: none; margin: 0 0 12px; padding: 0; font-size: 13px; }
.change-files li { display: flex; flex-wrap: wrap; gap: 0 8px; align-items: center; }
.change-files a { padding: 12px 0; line-height: 16px; color: inherit; overflow-wrap: anywhere; }
@media (pointer: coarse) { .change-line a, .change-files a { padding: 14px 0; } }
.diff-summary { padding: 10px 14px; font-size: 13px; }
.diff-summary .add, .change-line .add, .change-files .add { color: var(--add-fg); font-weight: 600; font-variant-numeric: tabular-nums; }
.diff-summary .del, .change-line .del, .change-files .del { color: var(--del-fg); font-weight: 600; font-variant-numeric: tabular-nums; }

.diff-file {
  /* Pure-CSS windowing: off-screen files cost nothing until scrolled to. */
  content-visibility: auto;
  contain-intrinsic-size: auto 480px;
}
.diff-head {
  position: sticky; top: calc(var(--topbar-h) - 1px); z-index: 5;
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px; cursor: pointer; list-style: none;
  /* Opaque: code scrolling under a blur is noise, not depth. */
  background: var(--muted); border-bottom: 1px solid var(--border);
}
.diff-head::before {
  content: ""; width: 0; height: 0; flex: none; margin-right: 2px;
  border: 4px solid transparent; border-left-color: var(--faint);
  transition: transform 160ms var(--ease);
}
.diff-file[open] > .diff-head::before { transform: rotate(90deg) translateX(1px); }
.diff-file:not([open]) > .diff-head { border-bottom: none; }
.diff-path {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12.5px; font-family: var(--mono);
}
.diff-stat {
  font-family: var(--mono); font-size: 12.5px; white-space: nowrap;
  font-variant-numeric: tabular-nums; display: inline-flex; gap: 6px;
}
.diff-stat .add { color: var(--add-fg); }
.diff-stat .del { color: var(--del-fg); }
.diff > p.muted { margin: 12px 0 0; padding: 0 4px; }
.diff-note { padding: 20px 16px; text-align: center; color: var(--muted-fg); font-size: 13px; }
.diff-stub p { margin: 0 0 10px; }
.diff-stub .diff-stat { display: inline-flex; }
.diff-viewed {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  font-size: 12.5px; color: var(--muted-fg); cursor: pointer; margin: 0;
}
.diff-viewed input { accent-color: var(--accent); margin: 0; }
/* "Viewed" is the authority: a checked file stays collapsed and steps back,
   with no JavaScript and no server state to keep in sync. */
.diff-file:has(.diff-viewed input:checked) > .diff-head { opacity: .6; }
.diff-file:has(.diff-viewed input:checked) > .diff-body { display: none; }
.diff-file:has(.diff-viewed input:checked) > .diff-head { border-bottom: none; }

.diff-body { overflow-x: auto; scrollbar-width: thin; }
.diff-table { width: 100%; font-family: var(--mono); font-size: 12.5px; }
.diff-table td { padding: 0; vertical-align: top; }
.dn {
  width: 1%; min-width: 40px; padding: 0 8px; text-align: right;
  color: var(--faint); user-select: none;
  white-space: nowrap; border-right: 1px solid var(--border);
  font-variant-numeric: tabular-nums;
}
/* The cell never wraps; the code itself is what is pre-formatted. Keeping that on the
   inner span means a stray newline in the markup costs one collapsed space
   instead of a rendered blank line and a six-space indent. */
.dc {
  width: 100%; padding: 0 8px 0 12px; white-space: nowrap;
  border-left: 3px solid transparent;
  font-variant-ligatures: none;
}
.dcx { display: inline-block; white-space: pre; min-height: 1.5em; } /* blank lines keep height */
/* The +/-/space marker lives in ::before so selecting and copying skip it. */
.dc::before { content: attr(data-mark) " "; color: var(--faint); }
.dl[data-k="add"] .dc { background: var(--add-bg); border-left-color: var(--add-edge); }
.dl[data-k="add"] .dn { background: color-mix(in srgb, var(--add-bg) 60%, transparent); }
.dl[data-k="add"] .dc::before { color: var(--add-fg); }
.dl[data-k="del"] .dc { background: var(--del-bg); border-left-color: var(--del-edge); }
.dl[data-k="del"] .dn { background: color-mix(in srgb, var(--del-bg) 60%, transparent); }
.dl[data-k="del"] .dc::before { color: var(--del-fg); }
/* Intra-line change: a second layer — saturation plus underline, never hue alone. */
.dl[data-k="add"] .wd { background: var(--wd-add); text-decoration: underline; text-underline-offset: 2px; border-radius: 2px; }
.dl[data-k="del"] .wd { background: var(--wd-del); text-decoration: underline; text-underline-offset: 2px; border-radius: 2px; }
.dh .dc { background: var(--muted); border-left-color: transparent; padding: 2px 8px 2px 12px; color: var(--muted-fg); }
.dh .dc::before { content: ""; }
.nonl { color: var(--del-fg); opacity: .7; padding-left: 8px; }
.dl:target .dc, .dl[data-hl] .dc { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--attn) 55%, transparent); }
/* line-number doubles as the comment affordance */
.dn-comment {
  color: var(--faint); display: block; position: relative;
  transition: background-color 100ms var(--ease), color 100ms var(--ease);
}
.dn-comment:hover { color: var(--accent-fg); background: var(--accent); border-radius: 4px; }
/* review comments ride under their line, full width */
.dc-review {
  padding: 8px 12px; background: var(--muted);
  border-left: 3px solid var(--accent); white-space: normal; font-family: var(--font);
}
.dc-review .comment-form { margin: 0; padding: 0; }
/* An open thread is prose under its line, not a card: head and body start at the code column,
   since .dc-review pads 12px past the 3px edge exactly as .dc does. */
.dc-thread { display: grid; gap: 10px; min-width: 0; }
.dc-thread .comment-body { overflow-wrap: anywhere; }
/* A settled thread is one line plus a disclosure: the point of resolving is
   to get an answered question out of the way of the unanswered ones. */
.dc-review .card-body > .muted .ico { width: 14px; height: 14px; color: var(--success); }

/* ---- review verdicts ---- */
/* A verdict passed before the latest push is history, not a position: it
   keeps its words and loses its colour. */
.verdict-stale { color: var(--muted-fg); background: none; }
.verdict-stale .ico { width: 12px; height: 12px; }
.review-card .review-verdicts { border: 0; padding: 0; margin: 0; display: grid; gap: 10px; }
.review-verdicts .check .hint {
  display: block; font-size: 12.5px; color: var(--muted-fg); margin-top: 1px;
}
.review-card textarea { width: 100%; }
.reviews-chip {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-top: 6px; font-size: 13px; color: var(--muted-fg);
}
.reviews-chip .ico { width: 14px; height: 14px; }
.reviews-chip .ok { display: inline-flex; align-items: center; gap: 4px; color: var(--success); }
.reviews-chip .bad { display: inline-flex; align-items: center; gap: 4px; color: var(--danger); }

/* ---- apps, runs, and the crew ---- */
/* Settings › Crew on a phone (#9373): a long name or brief breaks, never widens the page. */
[data-crew-settings] { overflow-wrap: anywhere; min-width: 0; }
/* The strip a repo home wears when it runs: state, commit, URL, previews,
   and the way to the App page — one line, in the repo header's own voice. */
.app-strip {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 12px; padding: 8px 12px; font-size: 13px;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
}
.app-strip > .ico { color: var(--muted-fg); flex: none; }
.app-strip .spacer { flex: 1; }
/* One environment: name and state in the head, the facts and the reason it
   failed in the body. A card rather than a row so a deploy error has a whole
   line to be read on. The facts and the error read the same wherever they
   are shown — a pull's preview, the studio head — so they are not scoped to
   the card. */
.env-facts { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; color: var(--muted-fg); overflow-wrap: anywhere; }
.env-error { color: var(--danger); font-size: 13px; margin-top: 6px; overflow-wrap: anywhere; text-wrap: pretty; }
/* The checks line inside the merge box, in the reviews chip's voice. */
.checks-line {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-top: 6px; font-size: 13px; color: var(--muted-fg);
}
.checks-line .ico { width: 14px; height: 14px; }
.checks-line .ok { display: inline-flex; align-items: center; gap: 4px; color: var(--success); }
.checks-line .bad { display: inline-flex; align-items: center; gap: 4px; color: var(--danger); }
.checks-line .now { display: inline-flex; align-items: center; gap: 4px; color: var(--attn); }
.check-words { margin: 4px 0 0; min-height: 1.4em; }
/* Reserved only while the run is open: pins arriving never move the log. */
/* A plain block, not .stack: a flex column would shrink the clipped cards to fit 9em. */
[data-pins] { max-height: 9em; overflow-y: auto; }
[data-check-progress][data-state="queued"] [data-pins], [data-check-progress][data-state="running"] [data-pins] { height: 9em; }
[data-pins] .card + .card { margin-top: 12px; }
[data-pins] pre { margin: 4px 0 0; white-space: pre-wrap; font-size: var(--fs-min); }
/* A run, live: a transcript with a speaker column, bounded so the page
   head stays reachable, and a composer that sits under it. */
#run-live { position: relative; }
.run-log {
  margin: 0; padding: 8px 0; max-height: calc(100dvh - 300px); min-height: 12em; overflow: auto;
  background: none; border: 0; border-radius: 0;
  font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; tab-size: 4;
}
.run-log .row { padding: 2px 0; min-height: 0; align-items: flex-start; }
.run-log .row-lead { flex: 0 0 72px; justify-content: flex-start; overflow: hidden; }
.run-log .row-lead .badge { overflow: hidden; text-overflow: ellipsis; }
.run-log .row-title { font-weight: 400; white-space: pre-wrap; overflow: visible; }
.run-log [data-line="tool"] .row-title { font-family: var(--mono); font-size: 12.5px; color: var(--faint); }
.run-log [data-line="tool"] b { color: var(--fg); font-weight: 600; }
.run-log [data-line="forge"] .row-title { color: var(--faint); font-style: italic; }
.run-log [data-line="pulse"] i { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--faint); margin-right: 4px; animation: run-pulse 1.2s infinite ease-in-out; }
.run-log [data-line="pulse"] i:nth-child(2) { animation-delay: .2s; }
.run-log [data-line="pulse"] i:nth-child(3) { animation-delay: .4s; }
@keyframes run-pulse { 0%, 80%, 100% { opacity: .25; } 40% { opacity: 1; } }
#run-jump {
  position: sticky; bottom: 6px; float: right; margin-top: 6px; border-radius: 999px; box-shadow: var(--shadow-2);
}
#run-steer {
  position: sticky; bottom: 0; gap: 6px; padding: 10px 12px; background: var(--bg);
  border: 0; border-top: 1px solid var(--border); border-radius: 0; box-shadow: none;
}
#run-steer textarea { min-height: 38px; max-height: 160px; resize: none; }
#run-steer .bar .muted { flex: 1 1 200px; }
/* A tail beside a running row (studio/app.ts): the same log, a peek at it
   — fixed height so nothing around it shifts as lines arrive, and it
   scrolls itself rather than the page. */
.run-log.log-tail { max-height: 8.5em; min-height: 0; margin: 6px 0 0; font-size: 12.5px; }
.table .truncate { max-width: 34ch; display: inline-block; vertical-align: bottom; }

/* ---- proposing a change ---- */
/* The editor's commit block, when the commit is a contribution: the whole
   outcome in one sentence before anybody types. */
.editor-target.propose > legend { display: inline-flex; align-items: center; gap: 6px; }
.propose-line { margin: 0 0 14px; text-wrap: pretty; }
.propose-line .hint { display: block; margin-top: 2px; font-size: 12.5px; color: var(--muted-fg); }
/* The commit block's inputs sit inline beside a radio; the propose card's
   are ordinary fields, and want the full column. */
.editor-target.propose .input {
  display: block; width: 100%; min-width: 0; margin-left: 0;
}

/* A diff card is narrower inside a two-column PR page; its header wraps
   instead of squeezing the path to nothing. */
.diff-file { container-type: inline-size; }
@container (max-width: 420px) {
  .diff-head { flex-wrap: wrap; }
  .diff-stat { margin-left: auto; }
}

/* ---- the code browser: explorer beside content ---- */
/* One grid, two behaviours. Below 900px the explorer is the "Files" drawer
   above the content and its <summary> is the handle; above it, the summary
   goes away and the column simply is. The element is always [open], so no
   layout depends on a script having toggled anything.

   Above 900px there are three columns: the tree, the divider, the file. The
   tree's width is one custom property, `--ex-w`, so the divider's script
   has exactly one thing to set and the stylesheet keeps the fallback. */
.code-layout { display: grid; gap: 12px; margin-top: 12px; align-items: start; }
/* The files page (#9376): long names wrap, code scrolls in its own .code box. */
.code-layout { overflow-wrap: anywhere; }
.code-layout > #code-main { min-width: 0; }
.code-layout #code-main > * { min-width: 0; }
.code-layout #code-main .bar { flex-wrap: wrap; }
.code-layout > #code-main[aria-busy="true"] { opacity: .55; transition: opacity 120ms var(--ease); }
/* The divider is nothing until a script can drag it, and nothing on one
   column either. */
.code-layout > [data-split] { display: none; }

.explorer-panel { min-width: 0; }
.explorer-panel:not([open]) > summary { border-radius: var(--radius-sm); }
.explorer-panel > summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card); font-weight: 550; list-style: none;
}
.explorer-panel > summary::-webkit-details-marker { display: none; }
.explorer-panel > summary .ico { color: var(--faint); }
.explorer-panel > summary .mono { font-size: 12.5px; }
.explorer-panel[open] > summary { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }

.explorer {
  border: 1px solid var(--border); border-top: none;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  background: var(--card);
  max-height: 45dvh; overflow: auto; overscroll-behavior: contain;
  scrollbar-width: thin;
  padding: 4px 0 8px;
}
.explorer > div { display: flex; gap: 6px; padding: 6px 8px; flex-wrap: wrap; }
.explorer > div .btn { flex: 1; justify-content: flex-start; }

.explorer ul { margin: 0; padding: 0; list-style: none; }
.explorer ul ul { padding-left: 12px; border-left: 1px solid var(--border); margin-left: 10px; }
.ex-file, .ex-dir > summary, .ex-more {
  display: flex; align-items: center; gap: 6px;
  padding: 3px 10px; min-height: 26px;
  font-size: 13px; color: var(--muted-fg);
  overflow: hidden; cursor: pointer; list-style: none;
}
.ex-dir > summary::-webkit-details-marker { display: none; }
@media (pointer: coarse) { .ex-file, .ex-dir > summary, .ex-more { min-height: 44px; } }
.explorer ul .ico { color: var(--faint); flex: none; width: 14px; height: 14px; }
.ex-dir > summary > .ico { transition: transform 120ms var(--ease); }
.ex-dir[open] > summary > .ico { transform: rotate(90deg); }
.ex-dir > summary { font-weight: 500; color: var(--fg); }
.ex-file:hover, .ex-dir > summary:hover, .ex-more:hover { background: var(--muted); color: var(--fg); }
.ex-file[aria-current="page"] {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--fg); font-weight: 550;
}
.ex-file:focus-visible { outline-offset: -2px; }
.ex-dir > summary[data-current] { color: var(--accent); }
.ex-more { color: var(--accent); font-size: 12.5px; }
.explorer li > .muted { display: block; padding: 3px 10px 3px 16px; font-size: 12.5px; color: var(--faint); }

@media (min-width: 900px) {
  .code-layout {
    grid-template-columns: minmax(0, var(--ex-w, 260px)) auto minmax(0, 1fr);
    gap: 0 6px;
  }
  /* The tree stays put while the file scrolls past. Sticky needs a parent
     as tall as the row to move within, so the panel stretches to the row
     and the details' content box stretches to the panel — all three rules
     only work together. */
  .explorer-panel { align-self: stretch; }
  /* On a wide screen the column is not a disclosure at all — it just is.
     Where this pseudo-element is understood the handle goes away too; where
     it is not, the handle stays and one click opens the column, which is why
     the element ships closed rather than open. */
  .explorer-panel::details-content {
    content-visibility: visible; block-size: auto; min-block-size: 100%;
  }
  .explorer {
    border-top: 1px solid var(--border); border-radius: var(--radius);
    position: sticky; top: calc(var(--topbar-h) + 12px);
    max-height: calc(100dvh - var(--topbar-h) - 32px);
  }
  /* The divider: a 12px lane with a hairline down its middle, sticky to the
     same band as the tree so there is always something to grab. The line
     thickens and takes the accent under the pointer, on focus and while
     dragging; the lane itself stays transparent. */
  :root.js .code-layout > [data-split] {
    display: block; position: sticky; align-self: stretch;
    top: calc(var(--topbar-h) + 12px);
    max-height: calc(100dvh - var(--topbar-h) - 32px);
    width: 12px; cursor: col-resize; touch-action: none;
    border-radius: var(--radius-sm);
  }
  .code-layout > [data-split]::before {
    content: ""; position: absolute; inset: 0 -4px;
  }
  .code-layout > [data-split]::after {
    content: ""; position: absolute; top: 0; bottom: 0; left: 50%;
    width: 1px; margin-left: -0.5px; background: var(--border);
    transition: background-color 120ms var(--ease), width 120ms var(--ease), margin-left 120ms var(--ease);
  }
  .code-layout > [data-split]:hover::after, .code-layout > [data-split]:focus-visible::after, .code-layout[data-dragging] > [data-split]::after {
    width: 3px; margin-left: -1.5px; background: var(--accent);
  }
  .code-layout > [data-split]:focus-visible { outline-offset: 0; }
  /* While a drag is on, nothing beneath the pointer may select or steal
     the cursor. */
  .code-layout[data-dragging] { cursor: col-resize; user-select: none; -webkit-user-select: none; }
  .code-layout[data-dragging] > #code-main, .code-layout[data-dragging] .explorer-panel { pointer-events: none; }
}
@supports selector(::details-content) {
  @media (min-width: 900px) {
    .explorer-panel > summary { display: none; }
  }
}
@media (min-width: 900px) and (pointer: coarse) {
  /* A finger needs 44px: the lane keeps its width and the hit area grows
     under it, into the padding on either side. */
  .code-layout > [data-split]::before { inset: 0 -16px; }
}
@media (min-width: 1200px) {
  .code-layout { grid-template-columns: minmax(0, var(--ex-w, 300px)) auto minmax(0, 1fr); }
}

/* ---- the finder ---- */
.finder { width: min(720px, calc(100vw - 24px)); }
@media (max-width: 719px) { .finder { width: 100%; max-width: 100%; } }
.finder .palette-item .cat {
  font-family: var(--mono); font-size: var(--fs-min);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 45%;
}
.finder .palette-item .grow { font-family: var(--mono); font-size: 12.5px; }

/* ---- the editor ---- */
.editor-head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 12px 0 0; padding: 8px 10px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.editor-head input[name="path"] { flex: 1 1 16rem; min-width: 0; }
.editor-head .btn[aria-selected="true"] { color: var(--fg); font-weight: 550; }

.editor-wrap {
  display: flex; align-items: stretch;
  border: 1px solid var(--border); border-top: none;
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--card); overflow: hidden;
  /* The ceiling lives here, on the thing that holds all three layers, so the
     gutter, the mirror and the textarea are always exactly as tall as each
     other and scroll as one. */
  max-height: 70dvh;
}
.editor-gutter {
  flex: none; width: 3.5rem; padding: 10px 8px 10px 0;
  text-align: right; user-select: none;
  font-family: var(--mono); font-size: var(--editor-fs); line-height: 1.55;
  color: var(--faint); background: var(--muted);
  border-right: 1px solid var(--border);
  overflow: hidden;
}
.editor-gutter span { display: block; }

/* The overlay. The mirror holds the syntax-coloured text and the textarea
   sits on top of it with transparent text and a visible caret, so one grid
   cell and one set of metrics serve both — any divergence in font, padding,
   line height or tab size would put the caret in the wrong place. Neither
   wraps: the editor scrolls horizontally instead of reflowing, which is what
   a code editor does. */
.editor-wrap > div:last-child {
  position: relative; display: grid; flex: 1; min-width: 0; min-height: 0;
}
#editor-mirror,
textarea.editor {
  grid-area: 1 / 1;
  margin: 0; border: none; background: none;
  padding: 10px 12px; min-height: 14rem;
  font-family: var(--mono); font-size: var(--editor-fs); line-height: 1.55;
  tab-size: 2; white-space: pre;
  overflow: auto;
}
.editor-wrap[data-mirrored] #editor-mirror,
.editor-wrap[data-mirrored] textarea.editor { min-height: 0; }
textarea.editor { resize: vertical; field-sizing: content; }
textarea.editor:focus-visible { outline: none; }
#editor-mirror {
  overflow: hidden; pointer-events: none; user-select: none;
  color: var(--fg);
}
/* Only when the mirror is live does the textarea's own text step aside — with
   no script (or no bundle) the plain textarea is what you see. */
.editor-wrap:not([data-mirrored]) #editor-mirror { display: none; }
.editor-wrap[data-mirrored] textarea.editor {
  color: transparent;
  caret-color: var(--fg);
  -webkit-text-fill-color: transparent;
}
.editor-wrap[data-mirrored] textarea.editor::selection {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
}
#editor-mirror > div {
  display: block; min-height: 1.55em; min-width: 100%; width: max-content;
}
#editor-mirror > [aria-current] {
  background: color-mix(in srgb, var(--muted) 75%, transparent);
}
.editor-wrap { --editor-fs: 12.5px; }
.editor-wrap:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent); }
/* Touch screens zoom a field set under 16px; the gutter, mirror and textarea share the size so they stay aligned. */
@media (pointer: coarse) { .editor-wrap { --editor-fs: 16px; } }
/* The ring above is a shadow, which forced colours drop; the textarea's own outline is off, so draw one. */
@media (forced-colors: active) { .editor-wrap:focus-within { outline: 2px solid Highlight; outline-offset: 2px; } }
#editor-preview {
  border: 1px solid var(--border); border-top: none;
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--card); min-height: 12rem;
}
.editor-commit { margin-top: 12px; }
.editor-target { border: 0; padding: 0; margin: 4px 0 0; }
.editor-target legend { font-weight: 600; margin-bottom: 6px; }
.editor-target .check { display: flex; }
.editor-target .check + .check { margin-top: 10px; }
.editor-target .check .hint { display: block; font-size: 12.5px; color: var(--muted-fg); }
.editor-target .input { display: inline-block; width: auto; min-width: 14rem; margin-left: 6px; }
.editor-target .input:disabled { opacity: .55; }
#f-pull-block { margin: 12px 0 0 26px; padding-left: 12px; border-left: 2px solid var(--border); }
#f-pull-block .field { margin-bottom: 10px; }

/* ---- branches ---- */
.branch-row .row-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.branch-row .row-meta { white-space: normal; overflow-wrap: anywhere; }
.branch-row .row-trail { flex: 0 1 auto; flex-wrap: wrap; gap: 4px 12px; }
.branch-row .branch-del { color: var(--muted-fg); }
.branch-row .branch-del:hover, .branch-row .branch-del:focus-visible { color: var(--danger); }
@media (max-width: 719px) {
  .branch-row { flex-wrap: wrap; }
  .branch-row .row-trail { flex: 1 1 100%; justify-content: flex-start; }
}
.branch-div { display: inline-flex; gap: 8px; font-size: 12.5px; }
.branch-div .ahead { color: var(--add-fg); }
.branch-div .behind { color: var(--del-fg); }

/* ---- search results ---- */
.code-hit .row-title { font-size: 12.5px; }
.code-line {
  font-size: 12.5px; white-space: pre; overflow-x: auto;
  scrollbar-width: none; color: var(--muted-fg);
}
.code-line::-webkit-scrollbar { display: none; }
.code-line mark, .row-title mark {
  background: color-mix(in srgb, var(--attn) 35%, transparent);
  color: var(--fg); border-radius: 2px; padding: 0 1px;
}

}
/* What needs you, pinned on the home: the bulk step's select as wide as
   its words, not the column. */
#needs-you #asks-bulk select { width: auto; max-width: 100%; }
#needs-you #asks-bulk .input[name="reason"] { flex: 1 1 12rem; width: auto; min-width: 0; }
/* A phone shows the top asks and one "N more" that opens in place to all
   of them; a wider screen shows ASKS_SHOWN and its own "N more" past that.
   Only where a details element can be held open: elsewhere both summaries
   stay, so every ask is still a tap away. */
@supports selector(::details-content) {
  @media (max-width: 480px) {
    #needs-you #asks-more > summary { display: none; }
    #needs-you #asks-more::details-content { content-visibility: visible; }
    #needs-you #asks-more > .stack { margin-top: 0; }
  }
  @media (min-width: 481px) {
    #needs-you #asks-phone-more > summary { display: none; }
    #needs-you #asks-phone-more::details-content { content-visibility: visible; }
    #needs-you #asks-phone-more > .stack { margin-top: 0; }
  }
}
/* Flow (#8698): the week's pipes. Width is spend; a valve is drawn open,
   half-open (a share) or shut, in tokens. */
.pipes { width: 100%; height: auto; display: block; }
.pipe { fill: none; stroke: currentColor; opacity: .5; }
.pipe-out { color: var(--series-3); }
.pipe-out.pipe-valve-shut { stroke-dasharray: 4 4; opacity: .35; }
.pipe-valve rect { fill: var(--bg); stroke: var(--border); stroke-width: 1.5; }
.pipe-valve-share rect { stroke: var(--series-1); }
.pipe-valve-shut rect { stroke: var(--series-5); fill: var(--bg); }
.pipe-label { font-size: 12.5px; fill: var(--fg); }
.pipe-repo { font-size: 12.5px; fill: var(--muted-fg); }
.valve-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 4px 0; }
/* A valve row's name and body are sentences, not one clipped line (#9323): they wrap inside the row. */
.valve-name, .valve-body { white-space: normal; overflow-wrap: anywhere; }
.valve-name, .valve-body { display: block; }
.valve-range { flex: 1 1 12rem; min-width: 8rem; }
/* The week on Next up (#8704): the cut line and a row's cost range. */
.next-week { opacity: 0.55; }
.cut-line { list-style: none; padding: 6px 16px; font-size: 13px; color: var(--muted-fg); border-top: 2px dashed var(--series-1); border-bottom: 1px solid var(--border); background: var(--bg); }
.estimate { color: var(--fg); font-variant-numeric: tabular-nums; }
/* The config form (#7336): nested objects as quiet fieldsets, scalar
   arrays as a wrapping row of chips, object arrays as cards. */
.config-group { border-left: 2px solid var(--border); padding-left: 12px; }
.config-group > legend { font-weight: 600; margin-bottom: 8px; }
.config-card { border-top: 1px solid var(--border); padding: 12px 0; margin: 0; }
.config-chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.config-chips > li { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.config-chips .input { width: auto; min-width: 8rem; }
.config-chips .field { margin: 0; display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.config-diff { overflow-x: auto; white-space: pre; margin: 0; }
.config-diff > [data-op="add"] { background: var(--add-bg); color: var(--add-fg); }
.config-diff > [data-op="del"] { background: var(--del-bg); color: var(--del-fg); }
/* Reduced motion: the pulses hold still at a legible level, the scroll-tied
   fade stays at its resting width, and these transitions land at once. */
@media (prefers-reduced-motion: reduce) {
  .run-log [data-line="pulse"] i { animation: none; }
  .run-log [data-line="pulse"] i { opacity: .6; }
  .ex-dir > summary > .ico, .code-layout > #code-main[aria-busy="true"], .code-layout > [data-split]::after { transition: none; }
}


@layer content {
.model3d { margin: 0; }
.model3d-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.model3d-head .row-facts { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0; }
.model3d-tools { display: inline-flex; gap: 6px; }
.model3d-stage { position: relative; aspect-ratio: 4 / 3; max-height: 70dvh; width: 100%; display: grid; place-items: center; touch-action: none; }
.model3d-stage > canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
}


@layer content {
.gcode-view { margin: 0; }
.gcode-nav { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 0; }
.gcode-nav > .btn { min-height: 44px; }
.gcode-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; order: -1; flex: 1 1 100%; }
.gcode-form input { width: 6em; min-height: 44px; }
.gcode-form .btn { min-height: 44px; }
.gcode-view svg { display: block; width: 100%; height: auto; max-height: 70dvh; color: var(--fg); }
@media (min-width: 640px) {
  .gcode-form { order: 0; flex: 0 1 auto; }
}
}


@layer utilities {
.muted { color: var(--muted-fg); }
.small { font-size: 13px; }
.num { font-variant-numeric: tabular-nums; }
.grow { flex: 1; min-width: 0; }
.spacer { flex: 1; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nowrap { white-space: nowrap; }
.break { overflow-wrap: anywhere; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.stack-tight { gap: 4px; }
.bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.bar:has(> .field) { align-items: flex-end; }
.bar > .field { margin: 0; }
.mt { margin-top: 12px; }
.mb { margin-bottom: 12px; }
.narrow { max-width: 400px; margin: 8dvh auto 0; }
.narrow-wide { max-width: 760px; }
.hide-sm { display: none; }
/* Revealed by the shell script — a control that needs JavaScript must not be
   on the page when there is none to run. */
.js-only { display: none; }
:root.js .js-only { display: inline-flex; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
[hidden] { display: none !important; }
[data-region] { display: contents; }

@media (min-width: 720px) {
  .shell { padding: 0 24px 96px; }
  .topbar { padding: 8px 24px; }
  .foot { padding: 20px 24px 36px; }
  .hide-sm { display: inline-flex; }
  .hide-lg { display: none; }
}

/* viewport-fit=cover lets the page run to the glass, so the chrome steps
   in from the notch, the rounded corners and the home indicator itself.
   max() keeps the ordinary gutter wherever the inset is zero, which is
   everywhere but a phone held sideways or an installed app. */
@supports (padding: max(0px)) {
  .topbar {
    padding-top: max(8px, env(safe-area-inset-top));
    padding-left: max(12px, env(safe-area-inset-left));
    padding-right: max(12px, env(safe-area-inset-right));
  }
  .shell {
    padding-left: max(16px, env(safe-area-inset-left));
    padding-right: max(16px, env(safe-area-inset-right));
  }
  .foot { padding-bottom: max(36px, env(safe-area-inset-bottom)); }
  @media (min-width: 720px) {
    .topbar {
      padding-left: max(24px, env(safe-area-inset-left));
      padding-right: max(24px, env(safe-area-inset-right));
    }
    .shell {
      padding-left: max(24px, env(safe-area-inset-left));
      padding-right: max(24px, env(safe-area-inset-right));
    }
  }
}

@media print {
  .topbar, .foot, .live-news, .sticky-action, .toast, [data-print-hide] { display: none !important; }
  .card { box-shadow: none; }
  /* A page that prints alone (an app's statement) drops the repository's chrome. */
  body:has([data-print-alone]) :is(.repo-nav, .settings-jump, .settings-nav) { display: none !important; }
}
}

.swatch[data-t="light"] { background: linear-gradient(160deg, #fafafa 50%, #ffffff 50%); border-color: #d4d4d8; }
.swatch[data-t="light"]::after { background: #2563eb; }
.swatch[data-t="paper"] { background: linear-gradient(160deg, #f2f0e5 50%, #fffcf0 50%); border-color: #cecdc3; }
.swatch[data-t="paper"]::after { background: #205ea6; }
.swatch[data-t="dawn"] { background: linear-gradient(160deg, #faf4ed 50%, #fffaf3 50%); border-color: #cecacd; }
.swatch[data-t="dawn"]::after { background: #286983; }
.swatch[data-t="dark"] { background: linear-gradient(160deg, #09090b 50%, #111113 50%); border-color: #3f3f46; }
.swatch[data-t="dark"]::after { background: #58a6ff; }
.swatch[data-t="midnight"] { background: linear-gradient(160deg, #16161e 50%, #1a1b26 50%); border-color: #3b4261; }
.swatch[data-t="midnight"]::after { background: #7aa2f7; }
.swatch[data-t="aurora"] { background: linear-gradient(160deg, #272c36 50%, #2e3440 50%); border-color: #4c566a; }
.swatch[data-t="aurora"]::after { background: #88c0d0; }
.swatch[data-t="system"] { background: linear-gradient(105deg, #fafafa 50%, #09090b 50%); border-color: #d4d4d8; }
.swatch[data-t="system"]::after { background: linear-gradient(105deg, #2563eb 50%, #58a6ff 50%); }

.pick-bar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 0 0 8px; }
.pick-bar[hidden] { display: none; }
.pick-bar { max-height: 96px; overflow-y: auto; }
.pick-chips { display: contents; }
.pick-chip {
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
  padding: 2px 8px; font: inherit; font-size: 12.5px; cursor: pointer;
  color: var(--fg); background: var(--muted); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.pick-chip:hover { border-color: var(--border-strong); }
.pick-bar .input { flex: 1; min-width: 160px; }
.pick-list {
  max-height: 168px; overflow-y: auto; overscroll-behavior: contain;
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 4px 8px;
}
.pick-list .check { display: flex; padding: 3px 0; }
.pick-list [hidden] { display: none; }
.pick-count { margin: 6px 0 0; }
