@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: #dfe6d7;
  --fg: #1e2a21;
  --card: #f5f7f0;
  --muted: #d3dccb;
  --muted-fg: #4f5f53;
  --faint: #86958a;
  --border: #c4cfbd;
  --border-strong: #aebcab;
  --primary: #9c4830;
  --primary-fg: #fdf8f3;
  --accent: #9c4830;
  --accent-fg: #fdf8f3;
  --danger: #a8283a;
  --success: #3b7046;
  --attn: #9a6614;
  --merged: #86537a;
  --add-bg: #d5e8cc;
  --add-fg: #2f6a3a;
  --add-edge: #5b9566;
  --del-bg: #f6ddd6;
  --del-fg: #a8283a;
  --del-edge: #c45a4a;
  --wd-add: #b5d6a7;
  --wd-del: #efbfb3;
  --shadow-1: 0 1px 2px rgb(30 42 33 / 0.06);
  --shadow-2: 0 8px 24px rgb(30 42 33 / 0.12);
  --tok-keyword: #a24f37;
  --tok-string: #3b6b45;
  --tok-comment: #66746a;
  --tok-number: #2f5f72;
  --tok-function: #7a4a6e;
  --tok-type: #8a5a14;
  --tok-constant: #2f5f72;
  --tok-meta: #4f6b2a;
  --tok-property: #2f5f72;
  --tok-operator: #56655a;
  --tok-punctuation: #8a978d;
  --tok-tag: #3b6b45;
  --tok-attribute: #8a5a14;
  --tok-regex: #3b7046;
  --tok-variable: #8a5a14;
  --tok-decorator: #7a4a6e;
  --tok-heading: #a24f37;
  --tok-emphasis: #1e2a21;
  --tok-link: #9c4830;
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) {
  --bg: #171e19;
  --fg: #e4eadf;
  --card: #1f2821;
  --muted: #28322a;
  --muted-fg: #a2b0a3;
  --faint: #6d7c70;
  --border: #2f3a31;
  --border-strong: #435044;
  --primary: #e58a6d;
  --primary-fg: #1a120e;
  --accent: #ec9478;
  --accent-fg: #1a120e;
  --danger: #f07a80;
  --success: #8fc492;
  --attn: #ddb25e;
  --merged: #c79ac0;
  --add-bg: #1d3122;
  --add-fg: #8fc492;
  --add-edge: #5f9a66;
  --del-bg: #3a2222;
  --del-fg: #f07a80;
  --del-edge: #c45a5a;
  --wd-add: #2d4f33;
  --wd-del: #5c2b2c;
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.45);
  --shadow-2: 0 12px 32px rgb(0 0 0 / 0.5);
  --tok-keyword: #ec9478;
  --tok-string: #a8cf9a;
  --tok-comment: #7d8c80;
  --tok-number: #8cc2cf;
  --tok-function: #d4a6cc;
  --tok-type: #e3bb72;
  --tok-constant: #8cc2cf;
  --tok-meta: #b7cf7a;
  --tok-property: #8cc2cf;
  --tok-operator: #a2b0a3;
  --tok-punctuation: #76857a;
  --tok-tag: #a8cf9a;
  --tok-attribute: #e3bb72;
  --tok-regex: #8fc492;
  --tok-variable: #e3bb72;
  --tok-decorator: #d4a6cc;
  --tok-heading: #ec9478;
  --tok-emphasis: #f2f5ee;
  --tok-link: #ec9478;
  color-scheme: dark;
}
}
:root[data-theme="sage"] {
  --bg: #dfe6d7;
  --fg: #1e2a21;
  --card: #f5f7f0;
  --muted: #d3dccb;
  --muted-fg: #4f5f53;
  --faint: #86958a;
  --border: #c4cfbd;
  --border-strong: #aebcab;
  --primary: #9c4830;
  --primary-fg: #fdf8f3;
  --accent: #9c4830;
  --accent-fg: #fdf8f3;
  --danger: #a8283a;
  --success: #3b7046;
  --attn: #9a6614;
  --merged: #86537a;
  --add-bg: #d5e8cc;
  --add-fg: #2f6a3a;
  --add-edge: #5b9566;
  --del-bg: #f6ddd6;
  --del-fg: #a8283a;
  --del-edge: #c45a4a;
  --wd-add: #b5d6a7;
  --wd-del: #efbfb3;
  --shadow-1: 0 1px 2px rgb(30 42 33 / 0.06);
  --shadow-2: 0 8px 24px rgb(30 42 33 / 0.12);
  --tok-keyword: #a24f37;
  --tok-string: #3b6b45;
  --tok-comment: #66746a;
  --tok-number: #2f5f72;
  --tok-function: #7a4a6e;
  --tok-type: #8a5a14;
  --tok-constant: #2f5f72;
  --tok-meta: #4f6b2a;
  --tok-property: #2f5f72;
  --tok-operator: #56655a;
  --tok-punctuation: #8a978d;
  --tok-tag: #3b6b45;
  --tok-attribute: #8a5a14;
  --tok-regex: #3b7046;
  --tok-variable: #8a5a14;
  --tok-decorator: #7a4a6e;
  --tok-heading: #a24f37;
  --tok-emphasis: #1e2a21;
  --tok-link: #9c4830;
  color-scheme: light;
}
:root[data-theme="moss"] {
  --bg: #171e19;
  --fg: #e4eadf;
  --card: #1f2821;
  --muted: #28322a;
  --muted-fg: #a2b0a3;
  --faint: #6d7c70;
  --border: #2f3a31;
  --border-strong: #435044;
  --primary: #e58a6d;
  --primary-fg: #1a120e;
  --accent: #ec9478;
  --accent-fg: #1a120e;
  --danger: #f07a80;
  --success: #8fc492;
  --attn: #ddb25e;
  --merged: #c79ac0;
  --add-bg: #1d3122;
  --add-fg: #8fc492;
  --add-edge: #5f9a66;
  --del-bg: #3a2222;
  --del-fg: #f07a80;
  --del-edge: #c45a5a;
  --wd-add: #2d4f33;
  --wd-del: #5c2b2c;
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.45);
  --shadow-2: 0 12px 32px rgb(0 0 0 / 0.5);
  --tok-keyword: #ec9478;
  --tok-string: #a8cf9a;
  --tok-comment: #7d8c80;
  --tok-number: #8cc2cf;
  --tok-function: #d4a6cc;
  --tok-type: #e3bb72;
  --tok-constant: #8cc2cf;
  --tok-meta: #b7cf7a;
  --tok-property: #8cc2cf;
  --tok-operator: #a2b0a3;
  --tok-punctuation: #76857a;
  --tok-tag: #a8cf9a;
  --tok-attribute: #e3bb72;
  --tok-regex: #8fc492;
  --tok-variable: #e3bb72;
  --tok-decorator: #d4a6cc;
  --tok-heading: #ec9478;
  --tok-emphasis: #f2f5ee;
  --tok-link: #ec9478;
  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);
  --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; }

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-family: var(--mono);
  font-weight: 660; letter-spacing: -0.02em; font-size: 15px;
}
.wordmark .mark { width: 22px; height: 22px; flex: none; overflow: visible; }
.wordmark .mark-chip { stroke: var(--accent); stroke-width: 1.6; }
.wordmark .mark-trace { stroke: var(--merged); stroke-width: 1.8; }
.wordmark .mark-pad { fill: var(--accent); }
/* A terminal caret after the name, blinking like it is waiting for input. */
.wordmark-name::after {
  content: "_"; color: var(--accent);
  animation: wordmark-caret 1.1s steps(1) infinite;
}
@keyframes wordmark-caret { 50% { opacity: 0; } }
.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;
  color: var(--faint); 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; }
/* 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: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; } }

/* 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; }
.field .error { display: block; font-size: 12.5px; color: var(--danger); margin-top: 6px; font-weight: 500; }
.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; }
.error-note {
  display: block; color: var(--danger); font-size: 13px; font-weight: 500;
  padding: 8px 12px; margin: 0 0 12px;
  border: 1px solid color-mix(in srgb, var(--danger) 32%, transparent);
  background: color-mix(in srgb, var(--danger) 10%, transparent);
  border-radius: var(--radius-sm);
}

/* ---- 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;
}
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); } }

/* 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; }
.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);
}

.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; }
:is(.stack, .split, .timeline) > .card + .card { margin-top: 0; }
.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="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);
}
.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 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; }
.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; }
.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 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;
}
.edit-row > .preview { flex: none; }
.edit-row > .input { flex: 1 1 160px; width: auto; min-width: 0; }
.edit-row .btn { flex: none; }
/* 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; }
.color-field .hex { font-family: var(--mono); font-size: 12.5px; color: var(--muted-fg); }
@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; }
}

/* ---- 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 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: thin;
}
.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 switcher ---- */
.theme-option {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 10px; margin: 0; border-radius: var(--radius-sm);
  font-size: 14px; font-weight: 400; cursor: pointer;
  transition: background-color 100ms var(--ease);
}
.theme-option:hover { background: var(--muted); }
.theme-option input { position: absolute; opacity: 0; pointer-events: none; }
.theme-option .tick {
  margin-left: auto; color: var(--accent); opacity: 0;
  transition: opacity 140ms var(--ease);
}
.theme-option:has(input:checked) { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.theme-option:has(input:checked) .tick { opacity: 1; }
.theme-option:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }
.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; }
.theme-apply { margin: 6px 10px 8px; }

/* ---- 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-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; }
.palette-heading {
  padding: 8px 10px 4px;
  font-size: var(--fs-min); font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--faint);
}
.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 .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(--faint);
}
/* 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); }
.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; } }

/* ---- 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; }
.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-item[data-kind="comment"] .card { margin: 0; }
.tl-item[data-kind="event"] > .card { flex-basis: 100%; margin: 4px 0 0; color: var(--fg); font-size: 14px; }
.tl-item[data-kind="event"] > .card .comment-body { padding: 8px 12px; }

/* ---- comment card ---- */
.comment .card-head { background: var(--muted); font-size: 13px; }
.comment .comment-body { padding: 2px 16px 8px; }
.comment-form { margin-top: 16px; padding: 12px; overflow: visible; }
.comment-form textarea { margin-bottom: 10px; }

/* ---- 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;
}
.empty p { font-size: 13px; max-width: 320px; text-wrap: pretty; margin: 0; }
.empty .btn { margin-top: 8px; }
.card.empty { border-style: dashed; box-shadow: none; }

/* ---- settings shell ---- */
.settings { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; margin-top: 16px; }
.settings-nav {
  min-width: 0; display: flex; gap: 2px; overflow-x: auto; scrollbar-width: none;
  border-bottom: 1px solid var(--border);
}
.settings-nav::-webkit-scrollbar { display: none; }
.settings-nav a {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0 12px; min-height: 36px; white-space: nowrap;
  font-size: 14px; color: var(--muted-fg); border-radius: var(--radius-sm);
}
.settings-nav a:hover { background: var(--muted); color: var(--fg); }
.settings-nav a[aria-current="page"] { color: var(--fg); font-weight: 550; background: var(--muted); }
.settings-main { min-width: 0; }
@media (min-width: 860px) {
  .settings { grid-template-columns: 190px minmax(0, 1fr); gap: 32px; }
  .settings-nav {
    flex-direction: column; border-bottom: 0; position: sticky;
    top: calc(var(--topbar-h) + 16px); align-self: start;
  }
}

/* ---- 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; }
.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) {
  /* "What you asked for" is a tab on a phone: the first post comes next.
     !important, as [hidden] is: .bar sits in a later cascade layer. */
  .feed-head { display: none !important; }
  #live-apps { display: none; }
}
@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; }
#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; }
.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 ---- */
.page-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 20px 0 14px;
}
.page-head h1 { min-width: 0; }
.page-head .sub { flex-basis: 100%; color: var(--muted-fg); font-size: 13px; margin-top: -4px; }

.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 .owner { font-weight: 400; color: var(--muted-fg); }
.repo-title .slash { color: var(--faint); font-weight: 400; }
.repo-audience {
  flex: 1 1 16ch; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 13px; font-weight: 400; letter-spacing: 0; color: var(--muted-fg);
}
a.repo-audience:hover { color: var(--fg); }
/* A phone has no hover for the title: the whole sentence, on its own line. */
@media (max-width: 640px) {
  .repo-audience { flex-basis: 100%; white-space: normal; text-overflow: clip; }
  a.repo-audience { display: block; padding: 12px 0; min-height: 44px; box-sizing: border-box; }
}
.repo-desc { margin-top: 4px; color: var(--muted-fg); font-size: 13px; text-wrap: pretty; }
.repo-lineage { margin-top: 3px; font-size: 12.5px; color: var(--faint); }
.repo-head .tabs { margin-top: 12px; }

/* 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-sep { color: var(--faint); }
.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-meta .where-sep { margin: 0 3px; }
.row-title a { color: inherit; text-decoration: none; }
.row-title a:hover { color: var(--accent); }
.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;
}
.break { overflow-wrap: anywhere; }
[data-apps] { overflow-wrap: anywhere; }

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

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

.repo-layout { display: grid; gap: 16px; margin-top: 16px; align-items: start; }
@media (min-width: 960px) {
  .repo-layout { grid-template-columns: minmax(0, 1fr) 280px; gap: 24px; }
  .repo-layout > aside { position: sticky; top: calc(var(--topbar-h) + 16px); }
}

.issue-head { margin: 20px 0 14px; }
.issue-head h1 { font-size: clamp(20px, 1rem + 1.4vw, 26px); letter-spacing: -0.025em; }
.issue-head h1 .number { font-weight: 400; color: var(--muted-fg); }
.issue-meta {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 8px; font-size: 13px; color: var(--muted-fg);
}

.tok { white-space: nowrap; }

.filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.filters form { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.filters .search { min-width: 180px; flex: 1; max-width: 320px; }
/* A list's six words fit a phone without pushing the page sideways: a
   little less padding there, and a scroll inside the bar as the last resort. */
.filters .seg { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
@media (max-width: 420px) { .filters .seg > a { padding: 0 8px; } }
/* The same three reaches for a filter bar drawn with §5's .bar. */
.bar .search { min-width: 180px; flex: 1; max-width: 320px; }
.bar .seg { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
@media (max-width: 420px) { .bar .seg > a { padding: 0 8px; } }

.commit-head .card-body { padding: 14px 16px; }
.commit-body {
  white-space: pre-wrap; font-family: var(--mono); font-size: 12.5px;
  color: var(--muted-fg); margin: 8px 0 4px;
}

/* A subscription's headroom for people: a small number beside its windows. */
.headroom { display: flex; align-items: center; gap: 6px; }
.headroom .input { width: 5em; }
/* On a phone an account's controls go under its name, not over it. */
@media (max-width: 640px) {
  .row:has(.headroom) { flex-wrap: wrap; }
  .row:has(.headroom) .row-trail { flex-basis: 100%; flex-wrap: wrap; }
}
/* Settings → Flags: a flag's controls wrap under its text on a phone, never sideways. */
.flag-form { flex-wrap: wrap; justify-content: flex-end; max-width: 100%; }
@media (max-width: 640px) {
  .row:has(.flag-form) { flex-wrap: wrap; }
  .row:has(.flag-form) .row-trail { flex-basis: 100%; min-width: 0; }
  .flag-form { justify-content: flex-start; }
  .flag-form .input { min-width: 0; flex: 1 1 8rem; }
}
.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; }
.bp-h2 .chart-box.is-table { height: 400px; }
.bp-h3 .chart-box.is-table { height: 540px; }
.bform { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 12px; margin-bottom: 8px; }
.bform .qf { display: flex; flex-direction: column; gap: 4px; flex: 1 1 140px; min-width: 0; }
.bform .qf > span { font-size: 12.5px; font-weight: 600; color: var(--fg); }
.bform .field { margin: 0; flex: 1 1 140px; min-width: 0; }
.bform .btn { flex: none; }
.bt-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); gap: 2px 16px; font-family: var(--mono); font-size: 12.5px; margin-top: 8px; }
.bt-row { display: grid; grid-template-columns: 10ch minmax(40px, 1fr) auto auto; align-items: center; gap: 8px; min-width: 0; }
.bt-row > .bt-val:last-child { grid-column: span 2; }
.bt-name { color: var(--muted-fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bt-val { text-align: right; white-space: nowrap; }
.bt-hist { color: var(--accent); letter-spacing: -1px; overflow: hidden; max-width: 15ch; }
.bt-bar { width: 100%; height: 8px; appearance: none; background: var(--muted); border: 0; border-radius: var(--radius-sm); overflow: hidden; }
.bt-bar::-webkit-meter-bar { background: var(--muted); border: 0; height: 8px; }
.bt-bar::-webkit-meter-optimum-value, .bt-bar::-webkit-meter-suboptimum-value { background: var(--accent); }
.bt-bar::-webkit-meter-even-less-good-value { background: var(--danger); }
.bt-bar::-moz-meter-bar { background: var(--accent); }
.bt-bar:-moz-meter-sub-optimum::-moz-meter-bar { background: var(--accent); }
.bt-bar:-moz-meter-sub-sub-optimum::-moz-meter-bar { background: var(--danger); }
.table-wrap { overflow-x: auto; max-width: 100%; }
#summary { display: flex; flex-wrap: wrap; gap: 6px; }
#summary .pill { max-width: 100%; white-space: normal; }
.bt-procs { font-size: 12.5px; }
.bt-procs th, .bt-procs td { padding: 2px 8px; white-space: nowrap; }
.bt-group th, .bt-group td { background: var(--muted); font-weight: 600; }
.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 .chart-box { max-width: none; }
.bp-h2 .chart-box { aspect-ratio: 720 / 400; }
.bp-h3 .chart-box { aspect-ratio: 720 / 540; }
.bgrid h2 { font-size: 14px; }
.bmanage { display: grid; gap: 8px; }
@media (max-width: 720px) { .bgrid { grid-template-columns: minmax(0, 1fr); } .bp-w2, .bp-w3 { grid-column: auto; } }
/* 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 records a domain waits on: type, name, value — as a zone file reads. */
.domain-records { margin: 6px 0 2px; padding: 8px 10px; font-size: 12.5px; line-height: 1.6; white-space: pre; overflow-x: auto; scrollbar-width: thin; background: var(--muted); border-radius: var(--radius); }
.policy-line {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 12px 0 0; font-size: 13px; color: var(--muted-fg);
}
.policy-line .ico { color: var(--faint); flex: none; }
.policy-line b { color: var(--fg); font-weight: 600; }
.policy-line[data-tone="mismatch"] .ico { color: var(--danger); }
.policy-line[data-tone="ok"] .ico { color: var(--success); }
form.inline { display: inline; margin-left: auto; }

/* The studio's front door: the public apps, live first, as pictures. */
.stack[data-shelf] {
  display: grid; gap: 16px; max-width: 1040px; margin-inline: auto;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}

/* The featured repository: its picture and its crew at work, side by side
   on a desk, stacked on a phone. */
.front-featured {
  display: grid; gap: 0; max-width: 1040px; margin-inline: auto;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  border: 1px solid var(--border); border-radius: var(--radius);
  overflow: hidden; background: var(--card);
}
.front-featured-look img { display: block; width: 100%; height: auto; background: var(--muted); }
.front-featured-body { display: grid; align-content: center; gap: 8px; padding: 20px 24px; min-width: 0; }
.front-featured-body > * { min-width: 0; }
.front-featured-body h2 { font-size: 20px; letter-spacing: -0.02em; }
.front-featured-body h2 a { color: inherit; text-decoration: none; }
.front-featured-body p { color: var(--muted-fg); text-wrap: pretty; }
.front-featured:not(:has(.front-featured-look)) { grid-template-columns: 1fr; }
.front-crew { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.front-live {
  width: 8px; height: 8px; border-radius: 50%; background: var(--success);
  animation: run-pulse 1.6s ease-in-out infinite;
}
.front-issues { display: grid; gap: 4px; font-size: 14px; list-style: none; padding: 0; margin: 0; }
.front-issues li { min-width: 0; }
.front-issues a { color: inherit; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.front-more { text-align: center; }
.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)); }
}
@media (max-width: 720px) {
  .front-featured { grid-template-columns: 1fr; }
  .front-featured-body { padding: 16px; }
}

/* 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 > *, .repo-layout > * { min-width: 0; }

/* 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); }
}

/* 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); }

/* ---- 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); }
.tok-plain { color: inherit; }
/* 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. */
.blob-view { margin-left: 8px; }
.blob-view .seg { font-size: 12.5px; }

/* ---- prose (markdown) ---- */
.prose { padding: 16px 20px; font-size: 15px; line-height: 1.65; overflow-wrap: break-word; }
.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;
}
.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; }
@media (pointer: coarse) { .change-line a { padding: 14px 0; } }
.diff-summary { padding: 10px 14px; font-size: 13px; }
.diff-summary .add, .change-line .add { color: var(--add-fg); font-weight: 600; font-variant-numeric: tabular-nums; }
.diff-summary .del, .change-line .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-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 .card + .card, .dc-review .comment { margin-bottom: 8px; }
.dc-review .comment-form { margin-top: 0; }
/* 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 ---- */
/* 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-card .card-head { gap: 10px; }
.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: 10px 14px 8px; max-height: calc(100dvh - 300px); min-height: 12em; overflow: auto;
  background: var(--muted); border: 1px solid var(--border); border-radius: var(--radius);
  font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; tab-size: 4;
}
#run-live:has(#run-steer) .run-log { border-radius: var(--radius) var(--radius) 0 0; }
.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-top: 0; border-radius: 0 0 var(--radius) var(--radius); 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; }
.code-layout > #code-main { min-width: 0; }
.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-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; }
  }
}
/* 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) {
  .front-live, .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 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; }
.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; }

@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 { display: none !important; }
  .card { box-shadow: none; }
}
}

.swatch[data-t="sage"] { background: linear-gradient(160deg, #dfe6d7 50%, #f5f7f0 50%); border-color: #aebcab; }
.swatch[data-t="sage"]::after { background: #9c4830; }
.swatch[data-t="moss"] { background: linear-gradient(160deg, #171e19 50%, #1f2821 50%); border-color: #435044; }
.swatch[data-t="moss"]::after { background: #ec9478; }
.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, #dfe6d7 50%, #171e19 50%); border-color: #aebcab; }
.swatch[data-t="system"]::after { background: linear-gradient(105deg, #9c4830 50%, #ec9478 50%); }