:root {
  /* surfaces */
  --background: 240 20% 99%;
  --foreground: 240 10% 3.9%;
  --card: 0 0% 100%;
  --card-2: 240 20% 97.5%;
  --muted: 240 4.8% 95.9%;
  --muted-foreground: 240 4% 44%;
  --accent: 240 4.8% 95.5%;
  --border: 240 6% 92.5%;
  --border-strong: 240 6% 85%;
  --input: 240 6% 83%;

  /* brand */
  --primary: 238 72% 56%;
  --primary-hover: 238 72% 50%;
  --primary-foreground: 0 0% 100%;
  --primary-muted: 238 60% 96%;
  --ring: 238 72% 56%;

  /* semantic */
  --destructive: 0 72% 48%;
  --destructive-foreground: 0 0% 100%;
  --success: 145 55% 38%;
  --success-dot: 145 63% 43%;
  --warning: 32 90% 44%;

  /* radius scale */
  --radius: 0.5rem;
  --radius-lg: 0.75rem;
  --radius-md: calc(var(--radius) - 2px);
  --radius-sm: calc(var(--radius) - 4px);
  --radius-full: 999px;

  /* elevation scale */
  --shadow-sm: 0 1px 2px hsl(240 8% 12% / 0.05);
  --shadow-md: 0 4px 12px hsl(240 8% 12% / 0.08), 0 1px 3px hsl(240 8% 12% / 0.05);
  --shadow-lg: 0 12px 32px hsl(240 8% 12% / 0.12), 0 2px 8px hsl(240 8% 12% / 0.06);
  /* directional (down-right) shadow with negative spread so nothing bleeds left —
     for the collapsed-file-pane popup, which sits flush against the strip. */
  --shadow-pop: 8px 9px 28px -8px hsl(240 8% 12% / 0.16);
  --shadow: var(--shadow-sm); /* back-compat alias */

  /* type + spacing */
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --text-xs: 0.75rem;
  --text-sm: 0.8125rem;
  --text-base: 0.9375rem;
  --text-md: 1.0625rem;
  --text-lg: 1.25rem;
  --text-xl: 1.625rem;
  --space-1: .25rem; --space-2: .5rem; --space-3: .75rem; --space-4: 1rem;
  --space-5: 1.5rem; --space-6: 2rem; --space-8: 3rem;

  /* syntax highlighting */
  --syn-comment: 240 4% 55%;
  --syn-keyword: 265 60% 52%;
  --syn-string: 145 45% 38%;
  --syn-number: 25 72% 45%;
  --syn-func: 215 72% 48%;
}
/* dark palette — the shared (non-theme) tokens for dark. Applied for explicit
 * dark mode (`[data-mode="dark"]`), and for system mode under an OS dark
 * preference. Light is the base `:root` above; each theme re-tints its own
 * surfaces for dark in the theme section below. */
[data-mode="dark"] {
  --background: 240 10% 3.9%;
  --foreground: 0 0% 98%;
  --card: 240 10% 6.5%;
  --card-2: 240 10% 8.5%;
  --muted: 240 3.7% 15.9%;
  --muted-foreground: 240 5% 65%;
  --accent: 240 3.7% 15.9%;
  --border: 240 4% 18%;
  --border-strong: 240 4% 26%;
  --input: 240 4% 24%;
  --primary: 234 89% 74%;
  --primary-hover: 234 89% 80%;
  --primary-foreground: 240 10% 8%;
  --primary-muted: 234 40% 22%;
  --ring: 234 89% 74%;
  --destructive: 0 72% 62%;
  --destructive-foreground: 0 0% 100%;
  --success: 145 55% 58%;
  --success-dot: 145 63% 52%;
  --warning: 38 92% 62%;
  --shadow-sm: 0 1px 2px hsl(0 0% 0% / 0.5);
  --shadow-md: 0 2px 6px hsl(0 0% 0% / 0.55), 0 8px 24px hsl(0 0% 0% / 0.35);
  --shadow-lg: 0 12px 32px hsl(0 0% 0% / 0.6);
  --shadow-pop: 8px 9px 28px -8px hsl(0 0% 0% / 0.55);
  --shadow: var(--shadow-sm);
  --syn-comment: 240 5% 55%;
  --syn-keyword: 265 84% 80%;
  --syn-string: 145 55% 68%;
  --syn-number: 30 90% 70%;
  --syn-func: 210 90% 74%;
}
@media (prefers-color-scheme: dark) {
  [data-mode="system"] {
    --background: 240 10% 3.9%; --foreground: 0 0% 98%;
    --card: 240 10% 6.5%; --card-2: 240 10% 8.5%;
    --muted: 240 3.7% 15.9%; --muted-foreground: 240 5% 65%; --accent: 240 3.7% 15.9%;
    --border: 240 4% 18%; --border-strong: 240 4% 26%; --input: 240 4% 24%;
    --primary: 234 89% 74%; --primary-hover: 234 89% 80%; --primary-foreground: 240 10% 8%;
    --primary-muted: 234 40% 22%; --ring: 234 89% 74%;
    --destructive: 0 72% 62%; --destructive-foreground: 0 0% 100%;
    --success: 145 55% 58%; --success-dot: 145 63% 52%; --warning: 38 92% 62%;
    --shadow-sm: 0 1px 2px hsl(0 0% 0% / 0.5);
    --shadow-md: 0 2px 6px hsl(0 0% 0% / 0.55), 0 8px 24px hsl(0 0% 0% / 0.35);
    --shadow-lg: 0 12px 32px hsl(0 0% 0% / 0.6); --shadow-pop: 8px 9px 28px -8px hsl(0 0% 0% / 0.55); --shadow: var(--shadow-sm);
    --syn-comment: 240 5% 55%; --syn-keyword: 265 84% 80%; --syn-string: 145 55% 68%;
    --syn-number: 30 90% 70%; --syn-func: 210 90% 74%;
  }
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  font: 15px/1.6 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}
a { color: hsl(var(--primary)); }

/* header / nav */
header.nav {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: .35rem; flex-wrap: wrap;
  padding: .55rem .85rem;
  background: hsl(var(--background) / 0.72);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid hsl(var(--border));
}
header.nav .brand { display: inline-flex; align-items: center; gap: .4rem; font-weight: 650; color: hsl(var(--foreground)); text-decoration: none; padding: .35rem .5rem; }
header.nav .brand .icon { width: 1.05rem; height: 1.05rem; color: hsl(var(--primary)); }
header.nav a.navlink {
  color: hsl(var(--muted-foreground)); text-decoration: none;
  font-size: .875rem; font-weight: 500;
  padding: .4rem .6rem; border-radius: var(--radius-md);
  transition: background .12s ease, color .12s ease;
}
header.nav a.navlink:hover { background: hsl(var(--accent)); color: hsl(var(--foreground)); }
/* active page (set client-side from location.pathname) — subtle by default */
header.nav a.navlink.on, header.nav summary.navlink.on { color: hsl(var(--primary)); font-weight: 560; }
form.search { position: relative; margin-left: auto; flex: 0 1 15rem; min-width: 7rem; }
form.search .icon { position: absolute; left: .55rem; top: 50%; transform: translateY(-50%); width: 1rem; height: 1rem; color: hsl(var(--muted-foreground)); pointer-events: none; }
form.search input {
  width: 100%; appearance: none;
  background: hsl(var(--card)); color: hsl(var(--foreground));
  border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-md);
  padding: .45rem .6rem .45rem 2rem; font-size: .875rem;
  transition: border-color .12s ease, box-shadow .12s ease;
}
form.search input::placeholder { color: hsl(var(--muted-foreground)); }
form.search input:focus-visible, .login-input:focus-visible {
  outline: none; border-color: hsl(var(--ring));
  box-shadow: 0 0 0 3px hsl(var(--ring) / 0.25);
}

/* nav dropdowns (Tracking / Ops) + the user menu — zero-JS via <details> */
header.nav .dropdown { position: relative; }
header.nav .dropdown > summary { list-style: none; cursor: pointer; }
header.nav .dropdown > summary::-webkit-details-marker { display: none; }
header.nav summary.drop::after { content: "▾"; font-size: .7em; margin-left: .3rem; opacity: .65; }
header.nav .dropdown[open] > summary.navlink { background: hsl(var(--accent)); color: hsl(var(--foreground)); }
header.nav .dropdown-panel {
  position: absolute; top: calc(100% + .35rem); left: 0; z-index: 40;
  min-width: 12rem; display: flex; flex-direction: column; gap: .05rem;
  background: hsl(var(--card)); border: 1px solid hsl(var(--border));
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg); padding: .35rem;
}
header.nav .dropdown-panel.right { left: auto; right: 0; }
header.nav .dropdown-panel a.navlink { display: block; }
header.nav .dropdown-panel .menu-theme { padding: .1rem .3rem .5rem; margin: 0 0 .3rem; }
header.nav .dropdown-panel .logout { margin-top: .1rem; }
header.nav .user-btn {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; border-radius: var(--radius-full); flex: none;
  color: hsl(var(--muted-foreground)); background: hsl(var(--card)); border: 1px solid hsl(var(--border-strong));
}
header.nav .user-btn::-webkit-details-marker { display: none; }
header.nav .user-btn svg { width: 1.1rem; height: 1.1rem; }
header.nav .dropdown.user { margin-left: .4rem; }
header.nav .dropdown.user[open] .user-btn { color: hsl(var(--foreground)); background: hsl(var(--accent)); }

/* layout */
main { max-width: 46rem; margin: 0 auto; padding: 1.3rem 1rem 4rem; }
h1 { font-size: 1.85rem; font-weight: 630; letter-spacing: -0.022em; line-height: 1.15; margin: .1rem 0 .4rem; }
h2 { font-size: var(--text-lg); font-weight: 620; letter-spacing: -0.015em; line-height: 1.25; margin: 2rem 0 .4rem; }
h3 { font-size: var(--text-md); font-weight: 620; letter-spacing: -0.01em; line-height: 1.3; margin: 1.2rem 0 .25rem; }
.subtitle { color: hsl(var(--muted-foreground)); font-size: 1rem; margin: .2rem 0 1.6rem; }
.journals-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap; }
.journals-head .subtitle { margin-bottom: 1rem; }
.empty { color: hsl(var(--muted-foreground)); padding: 1.1rem .9rem; margin: 0; text-align: center; font-size: .9rem; }

/* dashboard summary strip: a wrapping row of at-a-glance figure cards. Purely a
   snapshot at page load (refreshes on reload), so no client state. */
.stats-strip { display: flex; flex-wrap: wrap; gap: .7rem; margin: 0 0 1.6rem; }
.stats-strip .stat { flex: 1 1 8.5rem; min-width: 8.5rem; background: hsl(var(--card)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-lg); padding: .65rem .85rem; }
/* A stat that links to its page: no underline, subtle hover affordance. */
.stats-strip a.stat-link { display: block; text-decoration: none; color: inherit; transition: border-color .12s ease, background .12s ease; }
.stats-strip a.stat-link:hover { border-color: hsl(var(--primary)); background: hsl(var(--accent)); }
.stats-strip .stat-num { font-size: 1.55rem; font-weight: 640; line-height: 1.05; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.stats-strip .stat-label { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .04em; color: hsl(var(--muted-foreground)); margin-top: .15rem; }
.stats-strip .stat-sub { font-size: var(--text-xs); color: hsl(var(--muted-foreground)); margin-top: .2rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stats-strip .stat.prim .stat-num { color: hsl(var(--primary)); }
.stats-strip .stat.warn .stat-num { color: hsl(var(--warning)); }
.stats-strip .stat.over { border-color: hsl(var(--destructive) / .4); }
.stats-strip .stat.over .stat-num { color: hsl(var(--destructive)); }
.stats-strip .stat.ok .stat-num { color: hsl(var(--success)); }
.stats-strip .stat-fail { color: hsl(var(--destructive)); }

/* KB landing: the "Trust" header row carrying the Verify-all action */
.kb-trust-head { display: flex; align-items: center; justify-content: space-between; gap: .75rem; margin: 0 0 .6rem; }
.kb-trust-head h2 { margin: 0; font-size: 1rem; }
.kb-trust-head form.inline { margin: 0; }

/* KB landing: a card per top-level collection — its recursive document count
   and, for provenance-bearing kinds, the derived trust mix (●/◐/○). */
.kb-collections { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: .6rem; margin: 0 0 1.6rem; }
.kb-col { display: flex; flex-direction: column; gap: .45rem; text-decoration: none; color: inherit; background: hsl(var(--card)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-lg); padding: .6rem .8rem; transition: border-color .12s ease, background .12s ease; }
.kb-col:hover { border-color: hsl(var(--primary)); background: hsl(var(--accent)); }
.kb-col-head { display: flex; align-items: baseline; gap: .5rem; }
.kb-col-n { font-size: 1.35rem; font-weight: 640; line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.kb-col-name { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .04em; color: hsl(var(--muted-foreground)); }
/* the trust mix: three tinted counts, monospace glyph + number */
.trust-mix { display: flex; flex-wrap: wrap; gap: .5rem; font-size: var(--text-xs); font-variant-numeric: tabular-nums; }
.trust-mix .trust { display: inline-flex; align-items: center; gap: .18rem; }
.trust.ok { color: hsl(var(--success)); }
.trust.warn { color: hsl(var(--warning)); }
.trust.muted { color: hsl(var(--muted-foreground)); }

/* the per-item trust pill on a KB document's detail page */
.trust-badge { display: inline-flex; align-items: center; gap: .3rem; font-size: var(--text-xs); font-weight: 500; padding: .12rem .55rem; border-radius: var(--radius-full); background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); border: 1px solid transparent; white-space: nowrap; }
.trust-badge .trust-dot { line-height: 1; }
.trust-badge.ok { color: hsl(var(--success)); background: hsl(var(--success) / .12); border-color: hsl(var(--success) / .3); }
.trust-badge.warn { color: hsl(var(--warning)); background: hsl(var(--warning) / .12); border-color: hsl(var(--warning) / .3); }
/* KB entry upstream-sources pane: a collapsible list of the `sources.citekeys`
   the entry is built on, shown below the toolbar. Collapsed by default. */
.kb-upstream { margin: .5rem 0 1rem; border: 1px solid hsl(var(--border)); border-radius: var(--radius-md); background: hsl(var(--card)); }
.kb-upstream > summary { display: flex; align-items: center; justify-content: space-between; gap: .6rem; padding: .5rem .8rem; cursor: pointer; list-style: none; user-select: none; }
.kb-upstream > summary::-webkit-details-marker { display: none; }
.kb-upstream-title::before { content: "\25B8"; display: inline-block; color: hsl(var(--muted-foreground)); transition: transform .12s ease; }
.kb-upstream[open] .kb-upstream-title::before { transform: rotate(90deg); }
.kb-upstream-title { display: inline-flex; align-items: center; gap: .4rem; font-weight: 560; }
.kb-upstream-counts { display: inline-flex; gap: .3rem; }
.kb-upstream > .card { border: none; border-top: 1px solid hsl(var(--border)); border-radius: 0; margin: 0; box-shadow: none; }

/* pane grid: on wide (desktop) viewports a page that carries `.pane-grid` tiles
   its `.pane` sections into columns instead of one long scroll. Opt-in, so only
   pages that use it widen — reading pages keep the narrow single column. Below
   the breakpoint (or without `:has()` support) it stays a plain block → the
   sections stack exactly as before, so mobile is unchanged. */
@media (min-width: 60rem) {
  /* Page width is one explicit knob: a `w-*` class the shared `shell` layout puts
     on `main` (no more sniffing the first child). `[data-theme]` scoping lifts
     specificity above the per-theme `main` rules (e.g. journal caps main at
     42rem) so a page's declared width wins on every theme. On desktop the main
     container always fills the viewport (max-width: 100%); the classes are kept
     for compatibility and now differ only in default side padding.
       `w-wide` — the default (app/list/detail pages).
       `w-full` — the terminal etc. Narrow on mobile regardless. */
  [data-theme] main.w-wide { max-width: 100%; }
  [data-theme] main.w-full { max-width: 100%; padding-left: 1rem; padding-right: 1rem; }
  /* Wrapped flex rows, not `grid-template-columns: repeat(auto-fit, …)`: a fixed
     track count leaves a hole whenever a row carries fewer panes than there are
     tracks, and `auto-fit` only collapses a track that is *entirely* empty — a
     full-width band (`.pane-full`) spans every track and so keeps them all
     alive. That is what stranded the dashboard's two-pane rows in the left two
     thirds with the right third blank. Flex rows have no tracks: each row splits
     the full width evenly between exactly the panes that landed on it. `26rem`
     is the wrap threshold (the old track minimum), not a final width — every
     pane then grows to its share of the row; `min-width: 0` keeps that share
     even when a pane's content (a wide table) would rather be wider. Same
     mechanism as `.stats-strip` above. */
  .pane-grid { display: flex; flex-wrap: wrap; gap: 1rem 1.5rem; align-items: flex-start; }
  .pane-grid > * { flex: 1 1 26rem; min-width: 0; }
  .pane-grid > .pane > h2 { margin-top: .4rem; }
  /* a pane that spans the full width of the row instead of sharing it */
  .pane-grid > .pane-full, .pane-grid > .span-full { flex-basis: 100%; }
  /* a section that should stay a single, normal-width column on a widened page */
  .single-col { max-width: 46rem; }
  /* `.strip-fit` — a long strip that should read as one row of figures. A flex
     line breaks on each item's basis *clamped by min-width*, and `.stat` pins
     both at 8.5rem, so eleven tiles broke after ten and left the eleventh alone
     on the next line, where `flex-grow` stretched that single card across the
     whole page. Two knobs fix that, and both are needed:
       `flex-basis`/`min-width` at 6rem move the break past eleven tiles for any
       viewport from ~1200px up, which is where the strip is read. It costs
       nothing above that: the tiles still grow to fill the row, so the rendered
       result is identical — the line just breaks later. Forbidding the break
       outright (nowrap) is worse; near the 60rem breakpoint eleven tiles are
       ~78px and the labels spill out of them.
       `max-width` bounds what a break can stranded: below ~1200px the tail
       still wraps, but a leftover tile now stops at a card's width instead of
       spanning the page. It never binds on a full row (eleven tiles are 220px
       even at 2560px), only on the short one.
     Opt-in, so the strips elsewhere keep the wider tiles their shorter sets
     want, and inert below the breakpoint, where mobile stacks them two abreast. */
  .stats-strip.strip-fit .stat { flex-basis: 6rem; min-width: 6rem; max-width: 24rem; }
}
/* a grid item that spans every column of its grid — `.proj-dash` and the other
   real grids (inert below the desktop breakpoint, and inside `.pane-grid`, which
   is flex: there the `flex-basis: 100%` above is what makes it full width). */
.span-full { grid-column: 1 / -1; }
/* pane header: title on the left, a "see all" action on the right */
.pane-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
/* `min-width: 0` lets the heading shrink below its flex-item default (which
   would otherwise hold the row at the title's full intrinsic width); a long
   unbroken title (an underscore-slug project name with no spaces to wrap at)
   still needs `overflow-wrap: anywhere` to break onto the next line instead of
   forcing the whole row into horizontal scroll on narrow viewports. */
.pane-head h2 { margin: .4rem 0; min-width: 0; overflow-wrap: anywhere; }
/* a bit of breathing room below a pane's header, before its body */
.card.tool > .pane-head { margin-bottom: .55rem; }

/* breadcrumb */
nav.crumb { display: flex; align-items: center; flex-wrap: wrap; gap: .1rem; color: hsl(var(--muted-foreground)); font-size: .82rem; margin-bottom: 1rem; }
nav.crumb a { color: hsl(var(--muted-foreground)); text-decoration: none; padding: .12rem .35rem; border-radius: var(--radius-sm); transition: background .1s ease, color .1s ease; }
nav.crumb a:hover { background: hsl(var(--accent)); color: hsl(var(--foreground)); }
nav.crumb .sep .icon { width: .85rem; height: .85rem; opacity: .55; }
nav.crumb .here { color: hsl(var(--foreground)); padding: .12rem .35rem; }

/* card + rows */
.card { background: hsl(var(--card)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-lg); overflow: hidden; box-shadow: none; margin: .4rem 0 1.3rem; }
.card.interactive { transition: box-shadow .16s ease, border-color .16s ease; }
.card.interactive:hover { box-shadow: var(--shadow-sm); border-color: hsl(var(--border-strong)); }
a.row { position: relative; display: flex; align-items: center; gap: .7rem; padding: .68rem .85rem; color: hsl(var(--foreground)); text-decoration: none; transition: background .12s ease; }
/* subtle, inset row divider (gap left & right) instead of an edge-to-edge line */
a.row::before { content: ""; position: absolute; top: 0; left: .85rem; right: .85rem; height: 1px; background: hsl(var(--border) / .55); }
.card > a.row:first-child::before, a.row:first-child::before { content: none; }
a.row:hover { background: hsl(var(--accent)); }
a.row:hover .row-icon { color: hsl(var(--primary)); }
a.row:active { background: hsl(var(--primary-muted)); }
.row-icon { flex: none; display: inline-flex; color: hsl(var(--muted-foreground)); transition: color .12s ease; }
.row-icon .icon { width: 1.05rem; height: 1.05rem; }
.row-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .92rem; }
.badge { margin-left: auto; flex: none; max-width: 45%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--text-xs); color: hsl(var(--muted-foreground)); background: hsl(var(--muted)); border: none; padding: .08rem .5rem; border-radius: var(--radius-full); }
a.row.stacked { flex-direction: column; align-items: stretch; gap: .25rem; }
.row-top { display: flex; align-items: center; gap: .6rem; }
.snippet { color: hsl(var(--muted-foreground)); font-size: .82rem; padding-left: 1.75rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* grouped search results: a category heading + count above each result card */
.search-group + .search-group { margin-top: 1.25rem; }
h2.search-cat { display: flex; align-items: baseline; gap: .5rem; }
h2.search-cat .search-count { font-size: .8rem; font-weight: 500; color: hsl(var(--muted-foreground)); font-variant-numeric: tabular-nums; }
/* category filter bar: a row of toggle chips above the grouped results */
.search-filter { display: flex; flex-wrap: wrap; gap: .4rem; margin: .2rem 0 1.25rem; }
.search-filter .chip {
  cursor: pointer; font: inherit; font-size: .82rem; line-height: 1;
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .38rem .7rem; border-radius: 999px;
  border: 1px solid hsl(var(--border)); background: hsl(var(--card));
  color: hsl(var(--muted-foreground));
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.search-filter .chip:hover { background: hsl(var(--accent)); color: hsl(var(--foreground)); }
.search-filter .chip.active { background: hsl(var(--primary-muted)); border-color: hsl(var(--primary)); color: hsl(var(--primary)); font-weight: 560; }
.search-filter .chip .chip-count { font-variant-numeric: tabular-nums; opacity: .8; }

/* literature: external search + ingest */
.lit-search { display: flex; gap: .5rem; margin: .3rem 0 1.25rem; max-width: 640px; }
.lit-search .login-input { flex: 1; margin: 0; }
.lit-group + .lit-group { margin-top: 1.5rem; }
.lit-list { display: flex; flex-direction: column; gap: .75rem; margin-top: .6rem; }
.lit-hit { border: 1px solid hsl(var(--border)); border-radius: var(--radius-lg); padding: .85rem 1rem; background: hsl(var(--card)); }
.lit-hit-head { display: flex; align-items: baseline; justify-content: space-between; gap: .75rem; }
.lit-title { font-size: .98rem; font-weight: 600; margin: 0; line-height: 1.35; }
.lit-byline { color: hsl(var(--muted-foreground)); font-size: .82rem; margin: .3rem 0 0; }
.lit-abstract { margin: .5rem 0 0; }
.lit-abstract summary { cursor: pointer; font-size: .8rem; color: hsl(var(--primary)); width: max-content; }
.lit-abstract p { font-size: .84rem; color: hsl(var(--foreground)); margin: .4rem 0 0; line-height: 1.5; }
.lit-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem; margin-top: .7rem; }
.lit-note { font-size: .8rem; color: hsl(var(--muted-foreground)); }
.lit-abstract-body { font-size: .88rem; line-height: 1.55; margin: .2rem 0 0; }
.lit-bibtex { margin: .3rem 0 0; padding: .7rem .8rem; background: hsl(var(--muted)); border-radius: var(--radius-md); overflow-x: auto; font-size: .8rem; }
/* literature library: faceted browse */
.lib-active { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin: .2rem 0 1rem; font-size: .85rem; color: hsl(var(--muted-foreground)); }
/* library server-side sort control (above the record list) */
.lib-sort { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin: 0 0 .8rem; }
.lib-sort-label { color: hsl(var(--muted-foreground)); text-transform: uppercase; letter-spacing: .04em; font-size: .7rem; font-weight: 600; margin-right: .1rem; }
.lib-sort-link { text-decoration: none; color: hsl(var(--muted-foreground)); font-size: .82rem; padding: .16rem .5rem; border-radius: var(--radius-sm); }
.lib-sort-link:hover { background: hsl(var(--accent)); color: hsl(var(--foreground)); }
.lib-sort-link.active { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); font-weight: 600; }
.lib-layout { display: flex; flex-direction: column; gap: 1.1rem; }
/* Mobile: the facets collapse into a "Filters" drawer (checkbox toggle) so the
   records show first; a sr-only checkbox keeps it keyboard-accessible. */
.lib-facets-check { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.lib-facets-toggle { cursor: pointer; user-select: none; width: max-content; display: inline-flex; align-items: center; gap: .4rem; font-weight: 600; font-size: .9rem; padding: .45rem .8rem; border: 1px solid hsl(var(--border)); border-radius: var(--radius-sm); background: hsl(var(--card)); }
.lib-facets-toggle::before { content: "▸"; color: hsl(var(--muted-foreground)); font-size: .8em; }
.lib-facets-check:checked ~ .lib-facets-toggle { margin-bottom: .8rem; }
.lib-facets-check:checked ~ .lib-facets-toggle::before { content: "▾"; }
.lib-facets-check:focus-visible ~ .lib-facets-toggle { outline: 2px solid hsl(var(--primary)); outline-offset: 2px; }
.lib-facets { display: none; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: .6rem 1.2rem; align-content: start; }
.lib-facets-check:checked ~ .lib-facets { display: grid; }
/* Per-facet "N more" overflow toggle. */
.facet-more { margin-top: .1rem; }
.facet-more > summary { cursor: pointer; list-style: none; font-size: .78rem; color: hsl(var(--primary)); padding: .1rem .4rem; }
.facet-more > summary::-webkit-details-marker { display: none; }
.facet-more[open] > summary { color: hsl(var(--muted-foreground)); }
.facet-group { min-width: 0; }
.facet-title { font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: hsl(var(--muted-foreground)); margin: 0 0 .3rem; }
.facet-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .06rem; }
.facet-link { display: flex; justify-content: space-between; gap: .5rem; padding: .16rem .4rem; border-radius: var(--radius-sm); font-size: .82rem; color: hsl(var(--foreground)); text-decoration: none; }
.facet-link:hover { background: hsl(var(--accent)); }
.facet-link.active { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); font-weight: 560; }
.facet-val { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.facet-count { flex: none; font-variant-numeric: tabular-nums; color: hsl(var(--muted-foreground)); }
.lib-list { list-style: none; margin: .2rem 0 0; padding: 0; }
.lib-row { display: flex; gap: .8rem; align-items: baseline; padding: .55rem .4rem; border-top: 1px solid hsl(var(--border)); text-decoration: none; color: inherit; }
.lib-row:hover { background: hsl(var(--accent)); }
.lib-list li:first-child .lib-row { border-top: none; }
.lib-year { flex: none; width: 3rem; font-variant-numeric: tabular-nums; font-size: .82rem; color: hsl(var(--muted-foreground)); }
.lib-body { min-width: 0; flex: 1; }
.lib-title { display: block; font-weight: 560; font-size: .92rem; line-height: 1.35; }
.lib-byline { display: block; font-size: .8rem; color: hsl(var(--muted-foreground)); margin-top: .1rem; }
.lib-badges { flex: none; display: flex; align-items: center; gap: .4rem; }
.lib-status { font-size: .68rem; text-transform: uppercase; letter-spacing: .03em; padding: .08rem .4rem; border-radius: var(--radius-sm); background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); white-space: nowrap; }
.lib-status.status-verified { background: hsl(145 45% 92%); color: hsl(145 55% 28%); }
.lib-status.status-needs_review { background: hsl(38 90% 92%); color: hsl(30 70% 34%); }
.lib-status.status-unverifiable { background: hsl(0 70% 94%); color: hsl(0 60% 42%); }
/* PDF / markdown / summary in-store indicator (library table, TOC rows, summary page) */
.toc-pdf, .toc-md, .toc-sum { font-size: .66rem; font-weight: 600; padding: .08rem .38rem; border-radius: var(--radius-sm); }
.toc-pdf.have, .toc-md.have, .toc-sum.have { background: hsl(var(--success) / .15); color: hsl(var(--success)); }
.toc-pdf.missing, .toc-md.missing, .toc-sum.missing { background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); }
/* The actionable badges that are real <button>s (start-conversion "no MD", write-summary "no SUM"),
   not the <a>/<span> every other store badge is — strip the browser's native
   button chrome so it renders pixel-identical to its siblings. */
button.toc-pdf, button.toc-md, button.toc-sum { border: none; margin: 0; font: inherit; font-size: .66rem; font-weight: 600; line-height: inherit; appearance: none; -webkit-appearance: none; cursor: pointer; }
/* literature type tag (Paper / Book / Report …) — outlined to sit apart from the filled store badges */
.lit-type { font-size: .66rem; font-weight: 600; padding: .08rem .38rem; border-radius: var(--radius-sm); color: hsl(var(--muted-foreground)); border: 1px solid hsl(var(--border-strong)); }
/* full bibliographic citation below a title (record + summary pages) */
.lit-citation { color: hsl(var(--muted-foreground)); font-size: .92rem; line-height: 1.55; margin: .6rem 0 1.5rem; max-width: 54rem; }
.lit-citation em { font-style: italic; }
.lit-citation a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
/* "already saved" label replacing the Save-issue button on a saved live view */
.issue-saved { display: inline-flex; align-items: center; font-size: .82rem; font-weight: 600; color: hsl(var(--primary)); background: hsl(var(--primary-muted)); padding: .3rem .6rem; border-radius: var(--radius-sm); }
/* Settings: browser-PDF-fetcher status + setup steps */
.pill { font-size: .72rem; font-weight: 600; padding: .12rem .5rem; border-radius: 999px; background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); }
.pill:empty { display: none; }
.pill.ok { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); }
.pill.bad { background: hsl(var(--destructive) / .14); color: hsl(var(--destructive)); }
.setup-steps { margin: .5rem 0 .7rem 1.2rem; padding: 0; display: flex; flex-direction: column; gap: .6rem; }
.setup-steps li { line-height: 1.7; }
.fetch-pdf-btn.needs-setup { opacity: .7; }
.lib-pager { display: flex; align-items: center; gap: .8rem; margin-top: 1rem; }
.lib-page { font-size: .82rem; color: hsl(var(--muted-foreground)); font-variant-numeric: tabular-nums; }
/* record management: inline edit form + verify/delete */
.lit-edit summary { cursor: pointer; font-size: .85rem; color: hsl(var(--primary)); width: max-content; }
.lit-edit-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: .6rem .9rem; margin: .7rem 0; }
.lit-field { display: flex; flex-direction: column; gap: .2rem; font-size: .78rem; color: hsl(var(--muted-foreground)); }
.lit-field.lit-field-wide { margin: 0 0 .7rem; }
.lit-field input, .lit-field textarea { font: inherit; font-size: .85rem; color: hsl(var(--foreground)); background: hsl(var(--background)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-md); padding: .35rem .5rem; width: 100%; }
.lit-field textarea { resize: vertical; }
.lit-manage-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .8rem; }
/* collections: research-topic cards */
.coll-filter { display: block; max-width: 26rem; margin: .2rem 0 1rem; }
.coll-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: .8rem; margin-top: .3rem; }
.coll-card { border: 1px solid hsl(var(--border)); border-radius: var(--radius-lg); padding: .8rem .9rem; background: hsl(var(--card)); display: flex; flex-direction: column; gap: .3rem; }
.coll-name { font-weight: 600; font-size: .92rem; text-transform: capitalize; text-decoration: none; color: hsl(var(--foreground)); }
.coll-name:hover { color: hsl(var(--primary)); }
.coll-count { font-size: .78rem; color: hsl(var(--muted-foreground)); font-variant-numeric: tabular-nums; }
/* Push actions to the card bottom so rows with 1- and 2-line titles align. */
.coll-actions { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: auto; padding-top: .35rem; }
/* journals: followed-journal chips + issue TOC */
.journal-chips { display: flex; flex-wrap: wrap; gap: .4rem; margin: .2rem 0 1rem; }
.journal-chips .chip { font-size: .82rem; padding: .28rem .7rem; text-decoration: none; }
.jrnl-num { max-width: 9rem; }
.toc-list { list-style: none; margin: .6rem 0 0; padding: 0; }
.toc-item { display: flex; gap: .8rem; align-items: baseline; padding: .6rem .3rem; border-top: 1px solid hsl(var(--border)); }
.toc-list li:first-child { border-top: none; }
.toc-pages { flex: none; width: 4.5rem; font-variant-numeric: tabular-nums; font-size: .8rem; color: hsl(var(--muted-foreground)); }
.toc-body { flex: 1; min-width: 0; }
.toc-title { display: block; font-weight: 560; font-size: .9rem; line-height: 1.35; }
.toc-authors { display: block; font-size: .8rem; color: hsl(var(--muted-foreground)); margin-top: .1rem; }
.toc-actions { flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
/* health tab: metric tiles + duplicate-DOI groups */
.health-metrics { display: flex; flex-wrap: wrap; gap: .7rem; margin: .3rem 0 .3rem; }
.health-metric { display: flex; flex-direction: column; min-width: 8rem; padding: .6rem .8rem; border: 1px solid hsl(var(--border)); border-radius: var(--radius-md); text-decoration: none; color: inherit; }
.health-metric:hover { background: hsl(var(--accent)); }
.health-num { font-size: 1.5rem; font-weight: 640; font-variant-numeric: tabular-nums; line-height: 1.1; }
.health-label { font-size: .78rem; color: hsl(var(--muted-foreground)); }
.health-metric.warn .health-num { color: hsl(30 70% 40%); }
.health-metric.bad .health-num { color: hsl(0 62% 46%); }
.health-metric.ok .health-num { color: hsl(145 50% 32%); }
.health-dups { margin-top: .6rem; }
.health-dups summary { cursor: pointer; font-size: .85rem; color: hsl(var(--primary)); width: max-content; }
.health-dup-keys { display: inline-flex; flex-wrap: wrap; gap: .5rem; margin-left: .5rem; }
@media (min-width: 60rem) {
  .lib-layout { display: grid; grid-template-columns: minmax(13rem, 16rem) 1fr; gap: 1.6rem; align-items: start; }
  /* Permanent sidebar on wide screens: drop the drawer toggle, always show it. */
  .lib-facets-toggle { display: none; }
  .lib-facets { display: flex !important; flex-direction: column; gap: 1rem; }
}
/* On a phone the one-line row (year | title | badges) crushes the title into a
   sliver — the fixed-width badges won't yield — so stack the columns as rows:
   year + badges share a top line (badges pushed right, wrapping as needed), the
   title and byline take the full width below. */
@media (max-width: 640px) {
  .lib-row { flex-wrap: wrap; align-items: center; row-gap: .3rem; }
  .lib-year { order: 1; }
  .lib-badges { order: 2; margin-left: auto; flex-wrap: wrap; justify-content: flex-end; }
  .lib-body { order: 3; flex-basis: 100%; }
}
/* select-submit molecule: a menu choice committed with a button — the
   application status panel, the todo-inbox project filter, etc. One row, the
   select and button gap-spaced (not touching). */
.select-submit { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin: 0; }
.select-field { display: flex; align-items: center; gap: .4rem; font-size: .8rem; color: hsl(var(--muted-foreground)); }
.select-label { white-space: nowrap; }
.select-submit-field { font: inherit; font-size: .85rem; color: hsl(var(--foreground)); background: hsl(var(--background)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-md); padding: .38rem .55rem; }
/* The Claude-commands pane-head's model picker — a bare select (no submit of its
   own); every skill-run button on the page reads its value on submit. */
.model-select { font: inherit; font-size: .82rem; color: hsl(var(--foreground)); background: hsl(var(--background)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-md); padding: .3rem .5rem; }
/* history pane: a deliverable's *.toml lifecycle timeline (newest first) */
.history-list { list-style: none; margin: .3rem 0 0; padding: 0; }
.history-row { display: flex; gap: .75rem; padding: .55rem 0; border-top: 1px solid hsl(var(--border)); }
.history-row:first-child { border-top: none; }
.history-date { flex: none; width: 6.2rem; font-variant-numeric: tabular-nums; font-size: .8rem; color: hsl(var(--muted-foreground)); padding-top: .1rem; }
.history-body { min-width: 0; }
.history-head { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.history-kind, .history-decision { font-size: .8rem; color: hsl(var(--muted-foreground)); }
.history-decision { font-weight: 560; color: hsl(var(--foreground)); }
.history-journal { font-size: .8rem; font-weight: 560; color: hsl(var(--foreground)); }
.history-note { margin: .25rem 0 0; font-size: .84rem; color: hsl(var(--foreground)); line-height: 1.45; }
/* deliverables pane: the target journal's submission package (wf-deliverables),
   rendered as a `.dash` table; cells top-align so long `Contents` line up with badges */
.deliverables table.dash td { vertical-align: top; }
.deliverable-doc { font-weight: 560; color: hsl(var(--foreground)); }
.deliverable-format { font-size: .72rem; text-transform: uppercase; letter-spacing: .03em; color: hsl(var(--muted-foreground)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-sm); padding: .05rem .3rem; }
/* PDF/MD store badges: a group cell, and the link form (a.toc-*) drops the
   underline and gains a pointer + subtle hover so it reads as an actionable pill. */
.store-cell { display: inline-flex; gap: .3rem; align-items: center; }
a.toc-pdf, a.toc-md, a.toc-sum { text-decoration: none; cursor: pointer; }
a.toc-pdf:hover, a.toc-md:hover, a.toc-sum:hover, button.toc-pdf:hover, button.toc-md:hover, button.toc-sum:hover { filter: brightness(1.08); text-decoration: none; }
.deliverable-file { font-size: .8rem; font-variant-numeric: tabular-nums; }
.deliverable-file.present { color: hsl(var(--foreground)); text-decoration: none; border-bottom: 1px dotted hsl(var(--border-strong)); }
.deliverable-file.present:hover { border-bottom-color: hsl(var(--foreground)); }
.deliverable-file.missing { color: hsl(var(--destructive, 0 72% 51%)); }
.deliverable-contents { font-size: .8rem; color: hsl(var(--muted-foreground)); line-height: 1.4; word-break: break-word; }
/* Submission-readiness tab: the headline verdict banner + the gate/history
   status atoms. The banner tints its whole surface by outcome so readiness is
   legible at a glance before any table is read. */
.readiness-banner { display: flex; align-items: center; gap: 1rem; padding: 1rem 1.15rem; border-radius: var(--radius); border: 1px solid; }
.readiness-banner.ready { background: hsl(var(--success) / .08); border-color: hsl(var(--success) / .5); }
.readiness-banner.not-ready { background: hsl(var(--destructive) / .07); border-color: hsl(var(--destructive) / .45); }
.readiness-mark { font-size: 2rem; line-height: 1; font-weight: 700; }
.readiness-banner.ready .readiness-mark { color: hsl(var(--success)); }
.readiness-banner.not-ready .readiness-mark { color: hsl(var(--destructive)); }
.readiness-text { display: flex; flex-direction: column; gap: .15rem; }
.readiness-title { font-size: 1.2rem; font-weight: 680; letter-spacing: -0.01em; }
.readiness-banner.ready .readiness-title { color: hsl(var(--success)); }
.readiness-banner.not-ready .readiness-title { color: hsl(var(--destructive)); }
.readiness-sub { color: hsl(var(--muted-foreground)); font-size: .88rem; }
/* Pass/fail/warn status pills reused across the gate-checks and history tables. */
.gate-pass, .gate-fail, .gate-warn { font-size: .74rem; font-weight: 640; text-transform: uppercase; letter-spacing: .03em; padding: .05rem .4rem; border-radius: var(--radius-sm); white-space: nowrap; }
.gate-pass { color: hsl(var(--success)); background: hsl(var(--success) / .12); }
.gate-fail { color: hsl(var(--destructive)); background: hsl(var(--destructive) / .1); }
.gate-warn { color: hsl(var(--warning)); background: hsl(var(--warning) / .12); }
.gate-checks td, .review-history td { vertical-align: top; }
.gate-ensures { color: hsl(var(--muted-foreground)); font-size: .85rem; line-height: 1.4; }
/* KB linter-health pane: reuses the readiness banner + gate pills; just spacing. */
.kb-health .readiness-banner { margin: .3rem 0 .8rem; }
.kb-health h3 { margin: 1rem 0 .4rem; font-size: .95rem; }
/* At-a-glance submission-gate signal on the Deliverables pane header — a tinted
   pill that links to the full breakdown on the Submission tab. */
.ready-signal { display: inline-flex; align-items: center; gap: .35rem; font-size: .82rem; font-weight: 600; padding: .2rem .55rem; border-radius: var(--radius-sm); text-decoration: none; border: 1px solid; white-space: nowrap; }
.ready-signal .ready-mark { font-weight: 700; }
.ready-signal.ready { color: hsl(var(--success)); background: hsl(var(--success) / .12); border-color: hsl(var(--success) / .35); }
.ready-signal.not-ready { color: hsl(var(--destructive)); background: hsl(var(--destructive) / .1); border-color: hsl(var(--destructive) / .35); }
.ready-signal:hover { filter: brightness(1.05); text-decoration: none; }
/* search-submit busy state: spinner tinted for the primary button, width pinned
   so swapping "Search" → "Searching…" doesn't reflow the row. */
.lit-search .btn { min-width: 7.5rem; justify-content: center; }
@media (max-width: 640px) { .lit-search .btn { min-width: auto; } }
.lit-search .btn[aria-busy] { pointer-events: none; }
.lit-search .btn .spinner { width: .8rem; height: .8rem; border-color: hsl(var(--primary-foreground) / .35); border-top-color: hsl(var(--primary-foreground)); }

/* button */
.btn {
  display: inline-flex; align-items: center; gap: .45rem;
  background: hsl(var(--primary)); color: hsl(var(--primary-foreground));
  border: 1px solid transparent; border-radius: var(--radius-md);
  padding: .5rem .9rem; font-size: .875rem; font-weight: 500; line-height: 1;
  text-decoration: none; cursor: pointer; box-shadow: var(--shadow-sm);
  transition: background .13s ease, box-shadow .13s ease, transform .06s ease, border-color .13s ease;
}
.btn:hover { background: hsl(var(--primary-hover)); }
.btn:active { transform: translateY(1px); box-shadow: none; }
/* An inline icon inside a button (e.g. the download glyph): sized to the label,
   never the SVG's intrinsic default — the `.icon` class carries no base size. */
.btn .icon { width: 1.05em; height: 1.05em; flex: none; }
.btn.ghost { background: hsl(var(--card)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--border-strong)); }
.btn.ghost:hover { background: hsl(var(--accent)); border-color: hsl(var(--border-strong)); }
/* Web-triggered skill buttons (the /tender + handoff resume actions). */
.tool-actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin: .5rem 0; }
.tool-run {
  font: inherit; font-size: .85rem; cursor: pointer; line-height: 1;
  padding: .4rem .8rem; border-radius: var(--radius-md);
  background: hsl(var(--card)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--border-strong));
  transition: background .13s ease, color .13s ease, border-color .13s ease;
}
.tool-run:hover { background: hsl(var(--primary)); color: hsl(var(--primary-foreground)); border-color: transparent; }
.needs-input { border-left: 3px solid hsl(var(--primary)); }
.paused-run + .paused-run { margin-top: .75rem; padding-top: .75rem; border-top: 1px solid hsl(var(--border)); }
.paused-run-id { margin: 0 0 .25rem; font-size: .9rem; }
.run-list { list-style: none; margin: 0; padding: 0; }
.run-item { padding: .6rem 0; border-top: 1px solid hsl(var(--border)); }
.run-item:first-child { border-top: none; }
.run-head { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.run-label { font-weight: 600; }
.run-status { font-size: .82rem; padding: .1rem .45rem; border-radius: var(--radius-sm); background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); }
.run-status.ok { color: hsl(var(--primary)); }
.run-status.failed { color: hsl(var(--destructive, 0 70% 55%)); }
.run-out { margin-top: .4rem; }
.run-out summary { cursor: pointer; color: hsl(var(--muted-foreground)); font-size: .85rem; }
.run-toolbar { display: flex; gap: .5rem; flex-wrap: wrap; margin: .5rem 0 .25rem; }
.run-age { font-size: .78rem; color: hsl(var(--muted-foreground)); }
.btn.ghost:active { transform: translateY(1px); box-shadow: none; }
.btn.sm { padding: .34rem .62rem; font-size: .8rem; gap: .3rem; border-radius: var(--radius-sm); }
/* native file input styled as a ghost button so it matches the surface */
input[type=file] { font-size: .82rem; color: hsl(var(--muted-foreground)); max-width: 100%; }
input[type=file]::file-selector-button { font: inherit; font-weight: 500; margin-right: .6rem; padding: .34rem .62rem; border-radius: var(--radius-sm); border: 1px solid hsl(var(--border-strong)); background: hsl(var(--card)); color: hsl(var(--foreground)); cursor: pointer; transition: background .12s ease; }
input[type=file]::file-selector-button:hover { background: hsl(var(--accent)); }
.btn.ghost.danger { color: hsl(var(--destructive)); border-color: hsl(var(--destructive) / .35); }
.btn.ghost.danger:hover { background: hsl(var(--destructive) / .10); border-color: hsl(var(--destructive) / .55); color: hsl(var(--destructive)); }

/* focus rings (keyboard) */
a:focus-visible, input:focus-visible, .btn:focus-visible, a.row:focus-visible {
  outline: 2px solid transparent; outline-offset: 2px;
  box-shadow: 0 0 0 2px hsl(var(--background)), 0 0 0 4px hsl(var(--ring));
  border-radius: calc(var(--radius) - 2px);
}

/* rendered markdown */
.content { line-height: 1.7; }
.doc-photo { float: right; width: 160px; margin: 0 0 1rem 1.4rem; }
.doc-photo img { width: 100%; height: auto; border-radius: var(--radius); border: 1px solid hsl(var(--border)); display: block; }
.content h1, .content h2, .content h3, .content h4 { line-height: 1.3; font-weight: 600; margin: 1.6em 0 .5em; }
.content h2 { font-size: 1.25rem; padding-bottom: .3rem; border-bottom: 1px solid hsl(var(--border)); }
.content h3 { font-size: 1.08rem; }
.content p { margin: .8em 0; }
.content a { color: hsl(var(--primary)); text-decoration: none; }
.content a:hover { text-decoration: underline; }
.content code { font-family: var(--mono); background: hsl(var(--muted)); padding: .12em .35em; border-radius: var(--radius-sm); font-size: .875em; }
.content pre { background: hsl(var(--muted)); padding: .9rem 1rem; border-radius: var(--radius); overflow-x: auto; border: 1px solid hsl(var(--border)); }
.content pre code { background: none; padding: 0; }
.content blockquote { border-left: 2px solid hsl(var(--border)); margin: 1em 0; padding: .1rem 0 .1rem 1rem; color: hsl(var(--muted-foreground)); }
.content ul, .content ol { padding-left: 1.35rem; }
.content img { max-width: 100%; height: auto; border-radius: var(--radius); }
.content hr { border: none; border-top: 1px solid hsl(var(--border)); margin: 1.5em 0; }
.content table { border-collapse: collapse; width: 100%; font-size: .9rem; margin: 1em 0; display: block; overflow-x: auto; }
.content th { background: hsl(var(--muted)); font-weight: 600; text-align: left; }
.content th, .content td { border: 1px solid hsl(var(--border)); padding: .45rem .7rem; }

embed.pdf { width: 100%; height: 80vh; border: 1px solid hsl(var(--border)); border-radius: var(--radius); margin-top: .4rem; background: hsl(var(--muted)); }

/* hamburger menu — hidden on wide screens (the top bar is used there) */
.menu { display: none; }

/* Narrow phones, and any short viewport (landscape phones), swap the tall top
   bar for the floating hamburger so it doesn't eat the screen. */
@media (max-width: 640px), (max-height: 520px) {
  /* Swap the top bar for a floating bottom-left hamburger. */
  header.nav { display: none; }
  main { padding: 1.1rem .8rem 5.5rem; }
  .pdf-title { display: none; }

  .menu { display: block; position: fixed; bottom: 1rem; left: 1rem; z-index: 60; }
  summary.menu-btn {
    list-style: none; cursor: pointer;
    width: 3rem; height: 3rem; border-radius: 999px;
    display: flex; align-items: center; justify-content: center;
    background: hsl(var(--primary)); color: hsl(var(--primary-foreground));
    box-shadow: 0 4px 14px hsl(0 0% 0% / 0.28);
    /* Above the open sheet so tapping it toggles the menu closed. */
    position: relative; z-index: 61;
  }
  summary.menu-btn::-webkit-details-marker { display: none; }
  summary.menu-btn .icon { width: 1.4rem; height: 1.4rem; }
  /* Open menu: a near-full-screen sheet inset by a margin, scrollable, with the
     nav links laid out in two columns so the whole map fits without overflow. */
  .menu-panel {
    position: fixed; inset: .75rem; z-index: 60;
    display: flex; flex-direction: column; gap: .55rem;
    overflow-y: auto; overscroll-behavior: contain;
    background: hsl(var(--card)); border: 1px solid hsl(var(--border));
    border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
    /* extra bottom room so the last rows clear the floating menu button */
    padding: .9rem 1rem 4.5rem;
  }
  .menu-links { columns: 2; column-gap: 1.1rem; }
  .menu-links a.navlink, .menu-links .menu-section { break-inside: avoid; }
  .menu-section { font-size: .68rem; font-weight: 650; text-transform: uppercase; letter-spacing: .06em; color: hsl(var(--muted-foreground)); padding: .55rem .6rem .15rem; }
  .menu-panel a.navlink {
    display: block;
    color: hsl(var(--foreground)); text-decoration: none; font-size: .9rem;
    padding: .5rem .6rem; border-radius: calc(var(--radius) - 2px);
  }
  .menu-panel a.navlink:hover { background: hsl(var(--accent)); }
  .menu-panel a.navlink.on { color: hsl(var(--primary)); font-weight: 560; background: hsl(var(--primary-muted)); }
  .menu-panel form.search { position: relative; margin: 0; flex: none; }
  .menu-panel form.search input { width: 100%; }
}

/* full-page PDF viewer */
body.pdfview { height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
/* the reusable pdf.js viewer: fills the standalone page, or a bounded card frame
   when `.inline`, or the whole screen when fullscreened from an inline embed. */
.pdf-viewer { display: flex; flex-direction: column; min-height: 0; }
body.pdfview .pdf-viewer { flex: 1; }
.pdf-viewer.inline { height: 74vh; border: 1px solid hsl(var(--border)); border-radius: var(--radius); overflow: hidden; background: hsl(var(--card-2)); }
.pdf-viewer:fullscreen { height: 100vh; width: 100vw; border: none; border-radius: 0; }
/* The embedded terminal: fills its (wide) pane, or the whole screen when the
   Fullscreen toggle requests fullscreen on it. */
.term-embed:fullscreen { width: 100vw; height: 100vh; border-radius: 0; padding: 4px; background: #0b0b0e; }
.term-head { display: flex; align-items: center; gap: .6rem; }
.pdf-toolbar {
  display: flex; align-items: center; gap: .35rem; padding: .4rem .55rem;
  border-bottom: 1px solid hsl(var(--border));
  background: hsl(var(--background) / 0.82);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  backdrop-filter: saturate(180%) blur(12px);
}
.pdf-title { flex: 1; min-width: 0; font-size: .85rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tb-group { display: inline-flex; align-items: center; gap: .05rem; }
.tb-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; border: none; background: none;
  color: hsl(var(--foreground)); border-radius: var(--radius-md);
  cursor: pointer; text-decoration: none; flex: none;
  transition: background .12s ease, color .12s ease, transform .06s ease;
}
.tb-btn:hover { background: hsl(var(--accent)); }
.tb-btn:active { transform: translateY(1px); }
.tb-btn .icon { width: 1.15rem; height: 1.15rem; }
.pdf-pageind { font-size: .8rem; color: hsl(var(--muted-foreground)); min-width: 2.8rem; text-align: center; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* `scrollbar-gutter: stable` reserves the scrollbar's width up front, so the
   width `pdfview.js` measures to fit pages is the same before and after the
   page list grows tall enough to need one — otherwise every page renders
   slightly too wide once the vertical scrollbar appears, forcing a stray
   horizontal scrollbar. */
#pdf-container { flex: 1; overflow: auto; scrollbar-gutter: stable; background: hsl(var(--muted)); display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 12px; }
#pdf-container:empty::before { content: 'Loading…'; color: hsl(var(--muted-foreground)); font-size: .85rem; margin: auto; }
/* `flex-shrink: 0` is load-bearing: the holders carry the page height *before*
   the canvas renders into them, and a column flex container would otherwise
   shrink every unrendered holder to nothing — leaving the viewer unscrollable
   until rendering catches up, and a restored scroll offset clamped to the top. */
.pdf-page { background: #fff; box-shadow: var(--shadow-md); border-radius: var(--radius-sm); position: relative; flex-shrink: 0; }
.pdf-page canvas { display: block; }
.pdf-error { color: hsl(var(--muted-foreground)); padding: 2rem; }
/* pdf.js text layer (4.10.38) — transparent, selectable text over the canvas. */
.textLayer { position: absolute; text-align: initial; inset: 0; overflow: clip; opacity: 1; line-height: 1; text-size-adjust: none; forced-color-adjust: none; transform-origin: 0 0; caret-color: CanvasText; z-index: 0; }
.textLayer :is(span, br) { color: transparent; position: absolute; white-space: pre; cursor: text; transform-origin: 0% 0%; }
.textLayer span.markedContent { top: 0; height: 0; }
.textLayer ::selection { background: rgba(0 0 255 / 0.25); }
.textLayer br::selection { background: transparent; }
.textLayer .endOfContent { display: block; position: absolute; inset: 100% 0 0; z-index: 0; cursor: default; user-select: none; }
.textLayer.selecting .endOfContent { top: 0; }
/* PDF dark (invert) toggle — inverts only the page canvas, not the text layer. */
#pdf-container.inverted .pdf-page { background: #1a1a1a; }
#pdf-container.inverted .pdf-page canvas { filter: invert(1) hue-rotate(180deg); }
.tb-btn[aria-pressed="true"] { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); }

/* sign-in */
.login {
  min-height: 100dvh; display: flex; align-items: center; justify-content: center; padding: 1rem;
  background: radial-gradient(120% 120% at 50% 0%, hsl(var(--primary-muted)) 0%, hsl(var(--background)) 55%);
}
.login-card { width: 100%; max-width: 22rem; padding: 1.6rem; display: flex; flex-direction: column; box-shadow: var(--shadow-lg); border-radius: var(--radius-lg); }
.login-brand { display: inline-flex; align-items: center; gap: .5rem; font-weight: 680; font-size: 1.1rem; }
.login-brand .icon { width: 1.3rem; height: 1.3rem; color: hsl(var(--primary)); }
.login-card .subtitle { margin: .5rem 0 1rem; }
.login-input {
  width: 100%; margin-bottom: .8rem; appearance: none;
  background: hsl(var(--card)); color: hsl(var(--foreground));
  border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-md);
  padding: .55rem .7rem; font-size: .95rem;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.login .btn { width: 100%; justify-content: center; }
.login-error { color: hsl(var(--destructive)); font-size: .85rem; margin: 0 0 .7rem; }

/* tools */
.card.tool { padding: 1.35rem 1.45rem; display: block; }
.card.tool h2 { margin: 0 0 .15rem; font-size: 1.15rem; border: none; padding: 0; }
.tool-note { color: hsl(var(--muted-foreground)); font-size: .88rem; margin: .1rem 0 .7rem; }
.card.tool .login-input { margin-bottom: .55rem; }
/* saved-issue archive: collapsed by default, a Volume / Year / Issues table */
.issue-archive-wrap { margin-top: .6rem; }
.archive-summary { cursor: pointer; user-select: none; font-weight: 600; font-size: .95rem; padding: .2rem 0; }
.archive-summary:hover { color: hsl(var(--primary)); }
.archive-count { font-weight: 400; font-size: .8rem; color: hsl(var(--muted-foreground)); margin-left: .5rem; }
.issue-archive { width: 100%; border-collapse: collapse; margin-top: .5rem; font-size: .9rem; }
.issue-archive th, .issue-archive td { padding: .4rem .55rem; text-align: left; vertical-align: baseline; border-top: 1px solid hsl(var(--border) / .5); }
.issue-archive tr:first-child th, .issue-archive tr:first-child td { border-top: none; }
.ia-vol { font-weight: 600; white-space: nowrap; width: 6rem; }
.ia-year { color: hsl(var(--muted-foreground)); white-space: nowrap; width: 4rem; font-variant-numeric: tabular-nums; }
.ia-issues { display: flex; flex-wrap: wrap; gap: .3rem; }
.ia-issue { display: inline-flex; align-items: baseline; gap: .3rem; text-decoration: none; padding: .12rem .45rem; border: 1px solid hsl(var(--border)); border-radius: .35rem; color: hsl(var(--foreground)); font-variant-numeric: tabular-nums; }
.ia-issue:hover { background: hsl(var(--muted)); }
.ia-issue.active { background: hsl(var(--primary)); color: hsl(var(--primary-foreground)); border-color: hsl(var(--primary)); }
.ia-n { font-size: .72rem; color: hsl(var(--muted-foreground)); }
.ia-issue.active .ia-n { color: hsl(var(--primary-foreground)); opacity: .85; }
/* prev/next issue navigation in the TOC pane title */
.issue-nav { display: flex; gap: .35rem; }
.issue-nav-btn { min-width: 2rem; text-align: center; font-size: 1.05rem; line-height: 1; }
.issue-nav-btn.disabled { opacity: .4; pointer-events: none; }
/* paper.toml metadata + recent commits in the project Status pane */
.paper-title { font-size: .95rem; font-weight: 600; line-height: 1.35; margin: .1rem 0 .6rem; }
.paper-meta { display: grid; grid-template-columns: max-content 1fr; gap: .2rem .8rem; margin: 0 0 .7rem; font-size: .86rem; }
.paper-meta dt { color: hsl(var(--muted-foreground)); }
.paper-meta dd { margin: 0; min-width: 0; }
.status-pill { display: inline-block; font-size: .72rem; font-weight: 600; padding: .1rem .5rem; border-radius: var(--radius-full); background: hsl(var(--primary-muted)); color: hsl(var(--primary)); text-transform: capitalize; }
.commit-head { font-size: .7rem; font-weight: 620; text-transform: uppercase; letter-spacing: .06em; color: hsl(var(--muted-foreground)); margin: 1rem 0 .45rem; }
.commit-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .35rem; }
.commit-list li { display: flex; gap: .55rem; align-items: baseline; font-size: .82rem; min-width: 0; }
.commit-hash { font-family: var(--mono); color: hsl(var(--primary)); flex: none; }
.commit-subj { color: hsl(var(--foreground)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Actions-page skill + nix-app grids: wrap-flow buttons under a small group
   label, with each group's long tail behind a "more" expander. */
.group-label { display: block; font-size: .7rem; font-weight: 620; text-transform: uppercase; letter-spacing: .06em; color: hsl(var(--muted-foreground)); margin-bottom: .1rem; }
.count { font-size: .68rem; font-weight: 600; color: hsl(var(--muted-foreground)); background: hsl(var(--muted)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-full); padding: .02rem .45rem; margin-left: .35rem; }
.skill-group { margin: .3rem 0 1.05rem; }
/* A simple wrap-row of buttons (non-action-table button groups, e.g. component links). */
.btn-row { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .4rem; }
.btn-row form { margin: 0; }
/* Actions as a two-column table: the run button (left, shrink-to-fit) and its
   one-line explanation (right, muted). Shared by the skill groups and Nix apps. */
.action-table { width: 100%; border-collapse: collapse; margin-top: .4rem; }
.action-table td { padding: .28rem .6rem .28rem 0; vertical-align: top; border-bottom: 1px solid hsl(var(--border) / .5); }
.action-table tr:last-child td { border-bottom: 0; }
.action-table .action-cell { white-space: nowrap; width: 1%; }
.action-table .action-cell form { margin: 0; }
.action-table .action-desc { color: hsl(var(--muted-foreground)); font-size: .85rem; line-height: 1.45; }
.action-table .action-desc code { font-family: var(--mono); font-size: .82em; }
details.skill-more { margin-top: .5rem; }
details.skill-more > summary { cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: .3rem; font-size: .72rem; color: hsl(var(--muted-foreground)); }
details.skill-more > summary::-webkit-details-marker { display: none; }
details.skill-more > summary::before { content: "\25B8"; font-size: .8em; transition: transform .15s ease; }
details.skill-more[open] > summary::before { transform: rotate(90deg); }
table.stats { border-collapse: collapse; font-size: .85rem; margin-top: .4rem; }
table.stats td { padding: .18rem .8rem .18rem 0; vertical-align: top; }
table.stats td:first-child { color: hsl(var(--muted-foreground)); white-space: nowrap; }
/* Word-count "By section" table: full width, wrapping section names, and the
   count/budget columns pinned right so long titles never push them off-screen. */
table.stats.wc-sections { width: 100%; table-layout: auto; }
table.stats.wc-sections td:first-child { white-space: normal; word-break: break-word; color: hsl(var(--foreground)); padding-right: .6rem; }
table.stats.wc-sections td.num { text-align: right; white-space: nowrap; padding-right: .35rem; font-variant-numeric: tabular-nums; width: 1%; }
table.stats.wc-sections td.sub { text-align: right; white-space: nowrap; padding: .18rem 0 .18rem 0; color: hsl(var(--muted-foreground)); font-variant-numeric: tabular-nums; width: 1%; }
.wc-budget.over { color: hsl(var(--destructive)); }
.wc-budget.warn { color: hsl(var(--warning)); }

/* session management (Sessions page + project cards) */
form.inline { display: inline; margin: 0; }
.chip { display: inline-flex; align-items: center; gap: .4rem; font-size: var(--text-xs); color: hsl(var(--muted-foreground)); background: hsl(var(--muted)); border: none; padding: .16rem .6rem; border-radius: var(--radius-full); }
.chip code { background: none; padding: 0; color: hsl(var(--foreground)); font-family: var(--mono); font-size: .95em; }
.dot { width: .5rem; height: .5rem; border-radius: var(--radius-full); background: hsl(var(--success-dot)); flex: none; box-shadow: 0 0 0 3px hsl(var(--success-dot) / .16); }
@media (prefers-reduced-motion: no-preference) {
  .dot { animation: dot-pulse 2.4s ease-in-out infinite; }
  @keyframes dot-pulse {
    0%, 100% { box-shadow: 0 0 0 3px hsl(var(--success-dot) / .16); }
    50%      { box-shadow: 0 0 0 4px hsl(var(--success-dot) / .30); }
  }
}
/* Claude sessions grouped by zellij session — the three-level hierarchy made
   explicit: (1) the card heading is the project/scope, (2) "Zellij session"
   is the ONE labelled line naming the underlying zellij session + its live
   status (never duplicated elsewhere on the card), (3) "Claude tabs" labels
   the list of individual `claude` processes running inside it. */
.session-group + .session-group { margin-top: 1.1rem; padding-top: 1.1rem; border-top: 1px solid hsl(var(--border)); }
.session-group-head { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; }
.session-group-head .group-label { display: inline; margin-bottom: 0; margin-right: .1rem; }
.session-name { font-family: var(--mono); font-size: .82rem; background: none; padding: 0; color: hsl(var(--foreground)); }
.session-badge { font-size: .6rem; font-weight: 650; text-transform: uppercase; letter-spacing: .05em; padding: .06rem .42rem; border-radius: var(--radius-full); }
.session-badge.live { color: hsl(var(--success)); background: hsl(var(--success) / .12); }
/* Start-session/Start-Claude forms reuse the select-submit molecule (defined
   above) for its gap-spaced select+button row — no bespoke spacing here. */
.session-group form.select-submit { margin: .5rem 0; }
.session-group > .group-label { display: block; margin: .7rem 0 .3rem; }
.sessions-empty { color: hsl(var(--muted-foreground)); font-size: .88rem; margin: 0; padding: .7rem; text-align: center; background: hsl(var(--card-2)); border: 1px dashed hsl(var(--border-strong)); border-radius: var(--radius-md); }
.session-list { list-style: none; margin: 0; padding: 0; background: transparent; border: none; }
.session-row { position: relative; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; row-gap: .35rem; gap: .6rem; padding: .62rem .55rem; margin: 0 -.55rem; border-radius: var(--radius-sm); transition: background .12s ease; }
.session-row::before { content: ""; position: absolute; top: 0; left: 1rem; right: 1rem; height: 1px; background: hsl(var(--border) / .55); }
.session-list > .session-row:first-child::before { content: none; }
.session-row:hover { background: hsl(var(--accent)); }
.session-id { font-family: var(--mono); font-size: .86rem; background: none; padding: 0; }
/* The two groups a session-row lays out between: the tab id (+ model badge)
   on the left, Peek/Stop actions on the right — exactly one gap, sized by
   `justify-content: space-between` on the row, instead of several competing
   `margin-left: auto` elements stretching unpredictably on narrow viewports. */
.session-row-main { display: flex; align-items: center; gap: .4rem; min-width: 0; }
.session-row .session-act { display: inline-flex; align-items: center; gap: .25rem; flex: none; }
/* A muted inline note — "untracked" model, "No Claude tabs." — dimmer than
   surrounding text without the heavier `.sessions-empty` block treatment. */
.muted { color: hsl(var(--muted-foreground)); font-size: .84rem; }
/* An unrecognized ("Other") zellij session: id + Stop on one line, its Claude
   tab badges wrapping onto their own full-width line below — never spilling
   past the card edge, however many tabs are running. */
.session-row.other-session { flex-wrap: wrap; }
.session-tabs { flex-basis: 100%; display: flex; flex-wrap: wrap; gap: .3rem; }
.sessions-foot { margin-top: .6rem; }
/* version control page: stats strip + changes/commits/bookmarks panes */
.vcs-st { font-family: var(--mono); font-size: .72rem; font-weight: 700; width: 1.5rem; flex: none; text-align: center; color: hsl(var(--muted-foreground)); }
.stats-strip .stat-num code.stat-branch { font-family: var(--mono); font-size: 1.05rem; font-weight: 600; letter-spacing: 0; }
.push-count { font-variant-numeric: tabular-nums; background: hsl(var(--primary-muted)); color: hsl(var(--primary)); border-radius: var(--radius-full); padding: 0 .4rem; margin-left: .1rem; }
.session-row .commit-subj { flex: 1; min-width: 0; font-size: .88rem; }
.commit-link { display: flex; align-items: baseline; gap: .55rem; flex: 1; min-width: 0; text-decoration: none; color: inherit; }
.commit-link:hover .commit-subj { color: hsl(var(--primary)); }
.session-bookmark { font-family: var(--mono); font-size: .78rem; background: none; padding: 0; white-space: pre-wrap; word-break: break-word; line-height: 1.45; }
details.commits-more { margin-top: .5rem; }
details.commits-more > summary { cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: .3rem; font-size: .78rem; color: hsl(var(--muted-foreground)); }
details.commits-more > summary::-webkit-details-marker { display: none; }
details.commits-more > summary::before { content: "\25B8"; font-size: .8em; transition: transform .15s ease; }
details.commits-more[open] > summary::before { transform: rotate(90deg); }
/* job spinner (reduced-motion neutralised by the global block) */
.spinner { display: inline-block; width: .85rem; height: .85rem; vertical-align: -1px; border: 2px solid hsl(var(--border-strong)); border-top-color: hsl(var(--primary)); border-radius: 50%; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* inbox todos */
/* Leading control gutter: fixed-size, glyph centred on the title's first line, so
   the checkbox / run icons align with each other and the title. The run column is
   reserved (`.todo-run-slot`) on done rows in runnable projects → titles line up. */
.todo-check, .todo-run, .todo-run-slot, .todo-wontfix, .todo-wontfix-slot { flex: none; width: 1.5rem; height: 1.5rem; }
.todo-check, .todo-run, .todo-wontfix { display: inline-flex; align-items: center; justify-content: center; background: none; border: none; cursor: pointer; line-height: 1; color: hsl(var(--muted-foreground)); padding: 0; }
.todo-check { font-size: 1.05rem; }
.todo-run { font-size: .85rem; }
.todo-wontfix { font-size: .95rem; }
.todo-check:hover, .todo-run:hover, .todo-wontfix:hover { color: hsl(var(--primary)); }
.todo-wontfix.active { color: hsl(var(--primary)); }
.todo-run-slot, .todo-wontfix-slot { display: inline-block; }
/* The reject + run buttons in a right-aligned column at the end of the row. */
.todo-actions { display: inline-flex; align-items: center; gap: .25rem; flex: none; margin-left: auto; }
.todo-text { font-size: .95rem; line-height: 1.5rem; min-width: 0; }
.todo-row { align-items: flex-start; gap: .1rem; }
.filter-row .filter-action { margin-left: auto; }
.todo-main { min-width: 0; display: flex; flex-direction: column; gap: .25rem; }
.todo-meta { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; font-size: .75rem; margin-top: .1rem; }
.todo-due { color: hsl(var(--muted-foreground)); white-space: nowrap; font-variant-numeric: tabular-nums; }
.todo-due.todo-overdue, .todo-overdue { color: hsl(var(--destructive)); font-weight: 640; }
.todo-prio { padding: .05rem .35rem; border-radius: var(--radius-sm); font-weight: 640; border: none; background: hsl(var(--muted)); }
.todo-prio.p1 { color: hsl(var(--destructive)); border-color: hsl(var(--destructive) / .5); }
.todo-prio.p2 { color: hsl(var(--foreground)); }
.todo-prio.p3 { color: hsl(var(--muted-foreground)); }
.todo-tag { color: hsl(var(--primary)); }
.todo-llm { padding: .05rem .3rem; border-radius: var(--radius-sm); background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); text-transform: uppercase; letter-spacing: .04em; font-size: .64rem; }
.todo-text.done { text-decoration: line-through; color: hsl(var(--muted-foreground)); }
/* inbox filter bar */
/* the inbox filter toolbar sits on the page, not in a boxed card */
.card.tool.filter-bar { background: transparent; border: none; box-shadow: none; padding: .2rem 0 1.4rem; }
.filter-bar { display: flex; flex-direction: column; gap: .6rem; }
.filter-row { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem; }
.filter-label { font-size: .7rem; text-transform: uppercase; letter-spacing: .07em; color: hsl(var(--muted-foreground)); min-width: 3.4rem; margin-right: .3rem; flex: none; }
.chip { font-size: .8rem; padding: .32rem .74rem; border-radius: 999px; border: none; background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); text-decoration: none; white-space: nowrap; transition: background .12s ease, color .12s ease; }
.chip:hover { background: hsl(var(--accent)); color: hsl(var(--foreground)); }
.chip.active { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); font-weight: 600; }
/* kind badge */
.kind-badge { font-size: .62rem; text-transform: uppercase; letter-spacing: .04em; padding: .08rem .4rem; border-radius: var(--radius-sm); border: none; background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); font-weight: 600; }
.kind-paper { color: hsl(var(--primary)); border-color: hsl(var(--primary) / .5); }
.kind-application { color: hsl(28 80% 45%); border-color: hsl(28 80% 45% / .5); }
.kind-referee { color: hsl(160 60% 38%); border-color: hsl(160 60% 38% / .5); }
.kind-personal { color: hsl(280 45% 55%); border-color: hsl(280 45% 55% / .5); }
.kind-grant { color: hsl(210 70% 50%); border-color: hsl(210 70% 50% / .5); }
/* expandable todo detail + edit form */
.todo-details { min-width: 0; flex: 1; }
.todo-summary { list-style: none; cursor: pointer; display: flex; flex-direction: column; gap: .25rem; padding: 0; }
.todo-summary::-webkit-details-marker { display: none; }
.todo-summary:hover .todo-text { color: hsl(var(--primary)); }
details.todo-details[open] > .todo-summary { margin-bottom: .5rem; }
.todo-edit { display: flex; flex-direction: column; gap: .5rem; padding: .6rem; background: hsl(var(--muted)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-md); }
.todo-edit label { display: flex; flex-direction: column; gap: .2rem; font-size: .72rem; color: hsl(var(--muted-foreground)); }
.todo-edit input, .todo-edit select, .todo-edit textarea { appearance: none; background: hsl(var(--card)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-sm); padding: .35rem .45rem; font: inherit; font-size: .85rem; }
.todo-edit textarea { resize: vertical; font-family: var(--mono); }
.todo-edit-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; }
.todo-edit-actions { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.todo-id { font-size: .7rem; color: hsl(var(--muted-foreground)); }
@media (max-width: 640px) { .todo-edit-grid { grid-template-columns: 1fr; } }
/* project-page todos */
.project-todos { margin-top: 1rem; }
.todo-add { margin: .3rem 0 .7rem; gap: .4rem; }
.todo-add-input { flex: 1; appearance: none; background: hsl(var(--card)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-md); padding: .35rem .55rem; font: inherit; font-size: .85rem; }
/* CV render (applications page) */
.cv-card { margin-top: 1.4rem; }
.cv-source { color: hsl(var(--muted-foreground)); font-size: .78rem; }
.cv-section { margin: .8rem 0; }
.cv-section h3 { margin: 0 0 .35rem; font-size: .82rem; text-transform: uppercase; letter-spacing: .04em; color: hsl(var(--muted-foreground)); }
.cv-map { display: grid; grid-template-columns: max-content 1fr; gap: .15rem .8rem; margin: 0; }
.cv-map dt { color: hsl(var(--muted-foreground)); font-size: .85rem; }
.cv-map dd { margin: 0; font-size: .88rem; }
.cv-entries { display: flex; flex-direction: column; gap: .4rem; }
.cv-entry { padding: .4rem .55rem; border: 1px solid hsl(var(--border)); border-radius: var(--radius-md); display: flex; flex-wrap: wrap; gap: .1rem .9rem; font-size: .86rem; }
.cv-field { white-space: normal; }
.cv-k { color: hsl(var(--muted-foreground)); }
.cv-scalar { font-size: .88rem; margin: 0; }
.cv-count { color: hsl(var(--muted-foreground)); font-weight: 400; }
.cv-pub { flex-direction: column; gap: .1rem; }
.cv-pub-main { font-size: .88rem; }
.cv-pub-venue { color: hsl(var(--muted-foreground)); font-size: .82rem; font-style: italic; }
.cv-pubgroup { margin: .5rem 0 .1rem; font-size: .8rem; font-weight: 620; }
.cv-pubgroup:first-child { margin-top: 0; }
/* drafted dossiers (applications page) */
.dossiers-card { margin-top: 1.4rem; }
.draft-card { margin-top: 1.4rem; }
.draft-note { margin: 0 0 .5rem; }
.draft-row { align-items: center; gap: .6rem; justify-content: space-between; }
.draft-title { min-width: 0; font-size: .9rem; }
.dossier-row { align-items: center; gap: .6rem; }
.dossier-main { min-width: 0; display: flex; flex-direction: column; gap: .3rem; flex: 1; }
.dossier-slug { font-weight: 620; font-size: .9rem; overflow-wrap: anywhere; }
.dossier-card { font-size: .78rem; color: hsl(var(--muted-foreground)); text-decoration: none; }
.dossier-card:hover { color: hsl(var(--primary)); }
.dossier-status { padding: .02rem .3rem; border-radius: var(--radius-sm); background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); font-size: .68rem; text-transform: uppercase; letter-spacing: .03em; }
.dossier-links { display: flex; flex-wrap: wrap; gap: .3rem; }
.dossier-actions { display: flex; gap: .3rem; flex: none; align-items: center; }
/* cv.yaml editor */
.cv-edit { display: flex; flex-direction: column; gap: .6rem; }
.cv-edit-area { width: 100%; min-height: 60vh; box-sizing: border-box; appearance: none; background: hsl(var(--card)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-md); padding: .7rem .8rem; font-family: var(--mono); font-size: .82rem; line-height: 1.5; tab-size: 2; resize: vertical; }
.cv-edit-area:focus-visible { outline: none; border-color: hsl(var(--ring)); box-shadow: 0 0 0 3px hsl(var(--ring) / .25); }
.cv-edit-bar { display: flex; gap: .5rem; }
.cv-err { color: hsl(var(--destructive)); }
@media (max-width: 640px) { .cv-map { grid-template-columns: 1fr; gap: 0; } .cv-map dt { margin-top: .35rem; } }
.vcs-msg { width: 100%; margin: .2rem 0 .6rem; appearance: none; background: hsl(var(--card)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-md); padding: .5rem .6rem; font-family: var(--mono); font-size: .85rem; resize: vertical; min-height: 3rem; }
.vcs-msg:focus-visible { outline: none; border-color: hsl(var(--ring)); box-shadow: 0 0 0 3px hsl(var(--ring) / .25); }

/* dashboard tables */
table.dash { border-collapse: collapse; width: 100%; font-size: .88rem; }
table.dash td { padding: .55rem .7rem; border-top: 1px solid hsl(var(--border) / .5); vertical-align: top; font-variant-numeric: tabular-nums; }
table.dash tr:first-child td { border-top: none; }
/* inset the table so its row dividers have a gap at the card's left & right */
.card:not(.tool):has(> table.dash) { padding: 0 .9rem; }
table.dash tr { transition: background .1s ease; }
table.dash tr:hover td { background: hsl(var(--accent)); }
/* title and detail (e.g. institution/location) share the flexible width; fit,
   status and deadline stay compact (shrink to their content). */
.dash-title a { text-decoration: none; }
.dash-title { overflow-wrap: anywhere; }
/* Health tab's Source column: a file:line path — long and unbroken (no
   spaces), so it needs to wrap mid-string rather than force the row (and the
   whole table) into horizontal overflow. */
.dash-source { overflow-wrap: anywhere; font-size: .82rem; }
.dash-status { color: hsl(var(--muted-foreground)); white-space: nowrap; width: 1%; }
.dash-detail { color: hsl(var(--muted-foreground)); }
.dash-fit { text-align: center; white-space: nowrap; width: 1%; }
/* Record metadata: keep the label column on one line (was wrapping "Citek/ey"). */
table.lit-meta td.dash-detail { white-space: nowrap; }
/* Wide data tables scroll rather than clip columns / wrap titles one word per
   line on a phone; the record-metadata table stacks instead (below). */
@media (max-width: 640px) {
  .card:has(> table.dash) { overflow-x: auto; }
  table.dash:not(.lit-meta) { min-width: 30rem; }
}
/* data-table component: horizontal-scroll wrapper, sortable headers, pager */
.dt-scroll { overflow-x: auto; }
.dt-filter-bar { margin: 0 0 .7rem; font-size: .85rem; color: hsl(var(--muted-foreground)); }
.dt-filter-bar select { margin-left: .3rem; font: inherit; padding: .15rem .4rem; border: 1px solid hsl(var(--border)); border-radius: var(--radius-sm); background: hsl(var(--background)); color: hsl(var(--foreground)); }
table.dash thead th .dt-sort { background: none; border: 0; margin: 0; padding: 0; font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; cursor: pointer; display: inline-flex; align-items: baseline; gap: .25rem; }
table.dash thead th .dt-sort:hover { color: hsl(var(--foreground)); }
.dt-ind { font-size: .7em; min-width: .6em; color: hsl(var(--muted-foreground)); }
th[data-dir="asc"] .dt-ind::after { content: "▲"; }
th[data-dir="desc"] .dt-ind::after { content: "▼"; }
.dt-pager { display: flex; align-items: center; justify-content: center; gap: .9rem; margin-top: .9rem; }
.dt-page { font-variant-numeric: tabular-nums; color: hsl(var(--muted-foreground)); font-size: .85rem; }
.dt-pager button[disabled] { opacity: .4; pointer-events: none; }
/* Mobile: stack a data table into per-row cards — the sort headers become a
   compact wrapping "sort" chip bar, and each row shows label:value pairs with
   the title spanning full width. No horizontal scroll / cramped columns. */
@media (max-width: 640px) {
  .data-table .dt-scroll { overflow-x: visible; }
  .data-table table.dash { min-width: 0; display: block; }
  .data-table table.dash thead { display: block; }
  .data-table table.dash thead tr { display: flex; flex-wrap: wrap; gap: .3rem; border: none; margin-bottom: .7rem; }
  .data-table table.dash thead th { display: inline-flex; padding: 0; border: none; width: auto; }
  .data-table table.dash thead th .dt-sort { border: 1px solid hsl(var(--border)); border-radius: 999px; padding: .22rem .6rem; font-size: .68rem; }
  .data-table table.dash thead th[data-dir] .dt-sort { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); border-color: transparent; }
  /* A non-sortable header (Store, Actions) gets the same chip padding/size as
     the sort pills — otherwise it sits as bare cramped text against its rounded
     siblings in the wrapping chip bar, with visibly uneven spacing. */
  .data-table table.dash thead th .dt-label { display: inline-flex; padding: .22rem .6rem; font-size: .68rem; color: hsl(var(--muted-foreground)); }
  .data-table table.dash tbody { display: block; }
  .data-table table.dash tbody tr { display: block; border: 1px solid hsl(var(--border)); border-radius: var(--radius); padding: .55rem .8rem; margin-bottom: .55rem; }
  .data-table table.dash tbody tr:hover td { background: none; }
  .data-table table.dash tbody td { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; padding: .12rem 0; border: none; text-align: right; }
  .data-table table.dash tbody td::before { content: attr(data-label); color: hsl(var(--muted-foreground)); font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .03em; text-align: left; flex: none; }
  .data-table table.dash tbody td:empty { display: none; }
  /* Title spans the row, prominent, no label prefix. */
  .data-table table.dash tbody td.dash-title { display: block; text-align: left; margin-bottom: .35rem; }
  .data-table table.dash tbody td.dash-title::before { display: none; }
  .dt-pager { justify-content: space-between; }
}
/* Record metadata: long unbroken values (citekey, DOI, topic slugs) must wrap,
   and on a phone the label/value pairs stack so nothing is clipped. */
table.lit-meta td { overflow-wrap: anywhere; }
@media (max-width: 640px) {
  table.lit-meta, table.lit-meta tbody, table.lit-meta tr, table.lit-meta td { display: block; }
  table.lit-meta tr { border-top: 1px solid hsl(var(--border) / .5); padding: .35rem 0; }
  table.lit-meta tr:first-child { border-top: none; }
  table.lit-meta td { border: none; padding: .05rem .2rem; }
  table.lit-meta td.dash-detail { color: hsl(var(--muted-foreground)); font-size: .8rem; }
}
.dl-date { white-space: nowrap; color: hsl(var(--muted-foreground)); font-variant-numeric: tabular-nums; width: 1%; }
table.dash thead th { text-align: left; padding: .3rem .7rem .5rem; font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: hsl(var(--muted-foreground)); white-space: nowrap; border-bottom: 1px solid hsl(var(--border)); }
.tag { display: inline-block; font-size: var(--text-xs); color: hsl(var(--muted-foreground)); background: hsl(var(--muted)); padding: .1rem .55rem; border-radius: var(--radius-full); white-space: nowrap; text-transform: capitalize; }
.dash-sub { color: hsl(var(--muted-foreground)); opacity: .85; }
/* tender eligibility sub-line under the title */
.dash-note { font-size: var(--text-xs); color: hsl(var(--muted-foreground)); margin-top: .15rem; max-width: 60ch; }
/* tender detail — labelled field list */
dl.kv { display: grid; grid-template-columns: max-content 1fr; gap: .55rem 1.4rem; margin: 0; align-items: baseline; }
dl.kv dt { font-weight: 600; color: hsl(var(--muted-foreground)); }
dl.kv dd { margin: 0; }
dl.kv dd ul { margin: 0; padding-left: 1.1rem; }
/* discovery fit score (jobs) — a plain colour-coded number, no badge */
.fit-score { font-weight: 650; font-variant-numeric: tabular-nums; color: hsl(var(--muted-foreground)); }
.fit-score.fit-5, .fit-score.fit-4 { color: hsl(142 60% 34%); }
.fit-score.fit-3 { color: hsl(38 75% 40%); }
/* job-search feed list */
.feed-list { list-style: none; margin: .3rem 0 0; padding: 0; }
.feed-list li { font-size: var(--text-xs); line-height: 1.55; }
.feed-list a { color: hsl(var(--muted-foreground)); }
.feed-list a:hover { color: hsl(var(--foreground)); }
.dl-date .overdue { color: hsl(var(--destructive)); font-weight: 620; }

/* preformatted blocks — shared base, then per-use differences */
.tool-output, pre.codeblock, .screen {
  font-family: var(--mono); overflow: auto;
  border: 1px solid hsl(var(--border)); border-radius: var(--radius);
}
.tool-output { background: hsl(var(--muted)); padding: .85rem; white-space: pre-wrap; word-break: break-word; font-size: .82rem; line-height: 1.5; }
.screen { background: hsl(var(--muted)); padding: .85rem; white-space: pre; max-height: 70vh; font-size: .78rem; line-height: 1.35; }

/* page header row (title + inline action, e.g. Edit) */
.page-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
/* See `.pane-head h2` above — same fix, same reason (long unbroken project/job/
   grant/review titles forcing horizontal scroll on mobile otherwise). */
.page-head h1 { margin: .1rem 0 .35rem; min-width: 0; overflow-wrap: anywhere; }
/* Project header: the breadcrumb lives in the header row (no bottom margin) with
   its current segment enlarged to act as the page title — replacing the old
   separate crumb line + big H1, so it costs one row instead of two-plus. */
.proj-crumb-head { margin-bottom: .7rem; }
.proj-crumb-head .crumb { margin-bottom: 0; min-width: 0; }
.proj-crumb-head .crumb .here { font-size: 1.35rem; font-weight: 620; letter-spacing: -0.02em; color: hsl(var(--foreground)); overflow-wrap: anywhere; }
.head-actions { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }

/* project-detail secondary nav: a right-aligned bar of section links at title
   height. Each opens that section's own page; `.active` is the current one. */
.section-nav { display: flex; align-items: center; gap: .1rem; flex-wrap: wrap; justify-content: flex-end; }
.section-link { font-size: .85rem; color: hsl(var(--muted-foreground)); text-decoration: none; padding: .32rem .62rem; border-radius: var(--radius-sm); transition: background .12s ease, color .12s ease; }
.section-link:hover { background: hsl(var(--accent)); color: hsl(var(--foreground)); }
.section-link.active { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); font-weight: 600; }
@media (max-width: 640px) {
  /* On phones the section bar runs flush-left. Without JS it wraps; the overflow
     script (`.js-overflow`) forces a single line and moves the extras into a
     "…" menu. */
  .section-nav { justify-content: flex-start; width: 100%; }
  /* min-width:0 lets the flex item shrink below its content width, so the
     overflow script can measure `scrollWidth > clientWidth` and collapse. */
  /* If the tabs still overflow (measurement race / very narrow), scroll them
     rather than clipping the last tab off-screen. */
  .section-nav.js-overflow { flex-wrap: nowrap; min-width: 0; overflow-x: auto; scrollbar-width: none; }
  .section-nav.js-overflow::-webkit-scrollbar { display: none; }
  .section-link { flex: none; white-space: nowrap; padding: .5rem .7rem; }
}
/* the "…" overflow button + its dropdown of the links that didn't fit */
.section-more { position: relative; }
.section-more > summary { list-style: none; }
.section-more > summary::-webkit-details-marker { display: none; }
.section-more[open] > summary.section-link { background: hsl(var(--accent)); color: hsl(var(--foreground)); }
.section-more-panel {
  position: absolute; top: calc(100% + .35rem); right: 0; z-index: 30;
  display: flex; flex-direction: column; gap: .05rem; min-width: 9rem;
  background: hsl(var(--card)); border: 1px solid hsl(var(--border));
  border-radius: var(--radius); box-shadow: var(--shadow); padding: .3rem;
}
.section-more-panel .section-link { display: block; }
/* When the ⋯ menu is open, stop the nav from clipping: `.js-overflow` sets
   overflow-x:auto on the bar (for the scroll fallback), which per spec also clips
   overflow-y and would hide the dropdown panel that drops below the bar. */
.section-nav.js-overflow:has(.section-more[open]) { overflow: visible; }
/* swipe between sections: the content wrapper that slides (header/submenu stay
   put), plus the prefetched neighbour panels that slide in with the finger. */
.section-body { will-change: transform; }
.swipe-ghost { position: fixed; left: 0; width: 100%; z-index: 5; overflow: hidden; background: hsl(var(--background)); will-change: transform; }

/* project Dashboard + Files preview panes. Stacked by default; a two-column grid
   on desktop. The desktop rule must follow this base rule in source order (equal
   specificity) so `grid` wins over `flex` on a wide viewport. */
.proj-dash, .proj-files { display: flex; flex-direction: column; gap: 1rem; }
.proj-dash-side { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }
@media (min-width: 60rem) {
  /* Dashboard: essentials beside the manuscript preview. Files: the file list
     beside a preview pane. */
  .proj-dash { display: grid; grid-template-columns: minmax(19rem, 23rem) 1fr; gap: 1.3rem; align-items: start; }
  .proj-files { display: grid; grid-template-columns: minmax(15rem, 20rem) 1fr; gap: 1.3rem; align-items: start; }
}
.file-pane, .preview-pane { min-width: 0; } /* let the grid columns shrink */
.preview-img { display: block; max-width: 100%; height: auto; border-radius: var(--radius); }
.preview-code { max-height: 74vh; overflow: auto; }
/* the previewed file's row, and the manuscript-preview panel heading */
a.row.active { background: hsl(var(--primary-muted)); }
a.row.active .row-label { color: hsl(var(--primary)); font-weight: 600; }
/* the parent (`..`) row is a navigation affordance, not a file → muted */
a.row.up .row-label, a.row.up .row-icon { color: hsl(var(--muted-foreground)); }
/* the preview pane is a flush file viewer: the embedded file fills the pane card
   with no inner border or padding. Only the header keeps its inset (divided by a
   rule); the body — iframe / source / image — runs edge to edge. */
.preview-pane > .card.tool { padding: 0; }
.preview-pane > .card.tool > .pane-head { margin: 0; padding: .5rem .85rem; border-bottom: 1px solid hsl(var(--border) / .6); }
.preview-pane .content { padding: .9rem 1.15rem; }
.preview-pane pre.codeblock { margin: 0; box-shadow: none; border-radius: 0; }
.preview-pane .preview-img { border-radius: 0; }
.upload-form { display: inline-flex; align-items: center; gap: .4rem; }

/* editor (CodeMirror). The editor mounts our own `cm-s-wf` theme so the app's
   CSS tokens drive the colours and adapt to dark mode — cm.css (loaded after
   app.css via the page's head_extra) hardcodes a light `.CodeMirror` and
   `.cm-s-default .cm-*` palette, so every rule below carries `.cm-s-wf` (and, for
   the focused selection, the container's own classes) to outrank it regardless
   of load order. The height fills the viewport below the page chrome. */
.editor-path { display: flex; align-items: center; gap: .6rem; margin: .3rem 0 .7rem; }
.editor-path span { font-size: .8rem; color: hsl(var(--muted-foreground)); }
.editor-path input { margin: 0; max-width: 34rem; font-family: var(--mono); font-size: .85rem; }
.editor-box { margin: .5rem 0 .85rem; }
.editor-actions { display: flex; flex-wrap: wrap; gap: .6rem; }
/* Editor beside the live PDF preview — a 2-col grid only while the preview is on
   (a toggled `.live-on` class), otherwise the editor spans full width. */
.editor-workbench { min-width: 0; }
.editor-workbench.live-on { display: grid; grid-template-columns: 1fr 1fr; gap: .8rem; align-items: start; }
.editor-workbench.live-on .editor-box { min-width: 0; }
.editor-live-pane { display: none; min-width: 0; }
.editor-workbench.live-on .editor-live-pane { display: block; }
.live-frame { width: 100%; height: calc(100vh - 14rem); min-height: 20rem; border: 1px solid hsl(var(--border)); border-radius: var(--radius); background: hsl(var(--card)); }
@media (max-width: 860px) { .editor-workbench.live-on { grid-template-columns: 1fr; } .live-frame { height: 70vh; } }
/* Overleaf-style project workspace (the Files tab): tree | editor | live PDF,
   each pane collapsible; a mobile tab bar swaps to one pane at a time. */
/* The workspace breaks out of `main`'s side padding to sit edge-to-edge. main is
   full-width on desktop (max-width:100%, 1rem side padding), so a -1rem negative
   margin reaches the viewport edges — WITHOUT `width:100vw`, which counts the
   vertical scrollbar's width and would push a phantom horizontal scrollbar (and,
   via the 100vh grid, a vertical one too). */
.proj-workspace { position: relative; margin: .3rem -1rem 0; padding: 0 .6rem; box-sizing: border-box; }
/* The workspace fills the viewport height, so `main`'s reading-page bottom padding
   below it is just dead space (sizeGrid subtracts it) — trim it to a small gutter. */
main:has(.proj-workspace) { padding-bottom: .6rem; }
.ws-tabs { display: none; }
/* No-JS fallback height. WORKSPACE_JS's `sizeGrid()` overrides this with the exact
   remaining height (viewport − the grid's top − main's bottom padding), robust to
   the top nav wrapping at narrow widths that a fixed subtraction can't track. The
   14rem here just has to be close — it reserves the top nav + header + main padding
   so the page doesn't scroll before the JS runs. */
.ws-grid { display: flex; gap: .5rem; height: calc(100vh - 14rem); min-height: 24rem; }
/* Fullscreen: the container fills the screen; the grid takes all of it. */
.proj-workspace:fullscreen { padding: .5rem; background: hsl(var(--background)); box-sizing: border-box; margin: 0; width: 100vw; }
.proj-workspace:fullscreen .ws-grid { height: calc(100vh - 1rem); }
/* Floating fullscreen toggle, overlaid bottom-right over the workspace. */
.ws-fullscreen { position: absolute; bottom: 1rem; right: 1.4rem; z-index: 6; width: 2.2rem; height: 2.2rem; display: flex; align-items: center; justify-content: center; font-size: 1.1rem; line-height: 1; border: 1px solid hsl(var(--border-strong)); border-radius: 999px; background: hsl(var(--card)); color: hsl(var(--foreground)); box-shadow: var(--shadow-md); cursor: pointer; opacity: .85; }
.ws-fullscreen:hover { opacity: 1; background: hsl(var(--accent)); }
/* Preview zoom controls, grouped beside the fullscreen toggle. */
.ws-zoom { position: absolute; bottom: 1rem; right: 4.1rem; z-index: 6; display: flex; gap: .35rem; }
.ws-zoom[hidden] { display: none; }
.ws-zoom button { width: 2.2rem; height: 2.2rem; display: flex; align-items: center; justify-content: center; border: 1px solid hsl(var(--border-strong)); border-radius: 999px; background: hsl(var(--card)); color: hsl(var(--foreground)); box-shadow: var(--shadow-md); cursor: pointer; opacity: .85; }
.ws-zoom button:hover { opacity: 1; background: hsl(var(--accent)); }
/* DeepL inline rewrite popup — positioned in JS, relative to `.proj-workspace`,
   near the selection head; starts as a single button, grows to the suggestion. */
.ws-deepl { position: absolute; z-index: 40; }
.ws-deepl[hidden] { display: none; }
/* Recentred on the viewport once results are showing (`deeplCenter` in
   WORKSPACE_JS) — `left`/`top` there target the box's centre, not its
   top-left corner, so this offset by the box's own rendered size is what
   actually lands it in the middle regardless of content length. */
.ws-deepl.centered { transform: translate(-50%, -50%); }
.ws-deepl-btn { border: 1px solid hsl(var(--border-strong)); border-radius: 999px; background: hsl(var(--card)); color: hsl(var(--foreground)); font-size: .78rem; padding: .25rem .7rem; box-shadow: var(--shadow-md); cursor: pointer; }
.ws-deepl-btn:hover { background: hsl(var(--accent)); }
.ws-deepl-btn:disabled { opacity: .6; cursor: default; }
/* Flex column so the original stays pinned at the top and only the options
   list scrolls — the original is the fixed reference for comparison. */
.ws-deepl-result[hidden] { display: none; } /* explicit `display: flex` below would otherwise defeat the `hidden` attribute */
.ws-deepl-result { display: flex; flex-direction: column; width: min(64rem, 94vw); max-height: 65vh; margin-top: .3rem; padding: .55rem .65rem; background: hsl(var(--card)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius); box-shadow: var(--shadow-lg); }
.ws-deepl-original { flex: 0 0 auto; display: flex; flex-direction: column; gap: .3rem; margin: 0 0 .5rem; padding: .5rem .6rem; max-height: 30vh; overflow: auto; background: hsl(var(--card-2)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-sm); }
.ws-deepl-options { flex: 1 1 auto; min-height: 0; overflow: auto; }
.ws-deepl-original .ws-deepl-option-label { color: hsl(var(--muted-foreground)); }
/* One group per DEEPL_VARIANTS style; its alternatives sit side by side in
   `.ws-deepl-group-options`, wrapping to stacked cards on narrow viewports. */
.ws-deepl-group { padding: .5rem 0; border-bottom: 1px solid hsl(var(--border)); }
.ws-deepl-group:last-of-type { border-bottom: none; }
.ws-deepl-group-options { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .35rem; }
.ws-deepl-option { flex: 1 1 12rem; min-width: 9rem; display: flex; flex-direction: column; gap: .35rem; padding: .5rem .6rem; background: hsl(var(--card-2)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-sm); }
.ws-deepl-label { display: block; font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .02em; color: hsl(var(--muted-foreground)); }
/* The option's own sub-label — "Neutral" (pass 1) vs the tone passes
   (Confident/Diplomatic, each a tone chained onto pass 1's output) —
   distinguishing the group's otherwise-unlabelled columns. */
.ws-deepl-option-label { font-size: .68rem; font-weight: 600; color: hsl(var(--primary)); }
.ws-deepl-text { margin: 0; font-size: .82rem; white-space: pre-wrap; flex: 1 1 auto; }
.ws-deepl-words { font-size: .68rem; color: hsl(var(--muted-foreground)); }
.ws-deepl-actions { flex: 0 0 auto; display: flex; gap: .4rem; padding-top: .45rem; }
.ws-pane { display: flex; flex-direction: column; min-width: 0; border: 1px solid hsl(var(--border)); border-radius: var(--radius); background: hsl(var(--card)); overflow: hidden; }
.ws-nav { flex: 0 0 15rem; }
.ws-editor, .ws-preview { flex: 1 1 0; }
/* Drag-to-resize gutters; the JS persists widths as a `--w` custom property on the
   pane + a `.ws-sized` class. The sized rules apply on desktop only, so both the
   collapsed strip (defined later → wins the specificity tie) and the mobile
   single-pane view (its own media query) still take precedence. */
.ws-resize { flex: 0 0 .4rem; cursor: col-resize; background: transparent; border-radius: 999px; }
.ws-resize:hover, .ws-resize.dragging { background: hsl(var(--border-strong)); }
@media (min-width: 861px) {
  .ws-nav.ws-sized { flex: 0 0 var(--w, 15rem); }
  .ws-editor.ws-sized { flex: 0 0 var(--w); }
}
.ws-head { display: flex; align-items: center; gap: .5rem; padding: .3rem .5rem; border-bottom: 1px solid hsl(var(--border)); background: hsl(var(--card-2)); font-size: .82rem; min-height: 2.1rem; }
/* min-width:0 lets the title actually ellipsis-truncate (a flex item's default
   min-width is its content), and the actions keep their natural size (shrink:0)
   so a tight header truncates the title rather than crowding/clipping the buttons. */
.ws-title { font-weight: 560; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.ws-head-actions { margin-left: auto; display: flex; align-items: center; gap: .35rem; flex-shrink: 0; }
/* Preview header word-count badge — tone colours match the Dashboard's
   Word-count pane (`.stats-strip .stat.{warn,over}`). */
.ws-wordcount { font-size: .74rem; color: hsl(var(--muted-foreground)); background: hsl(var(--muted)); border: none; padding: .15rem .55rem; border-radius: var(--radius-full); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ws-wordcount[hidden] { display: none; }
.ws-wordcount.warn { color: hsl(var(--warning)); }
.ws-wordcount.over { color: hsl(var(--destructive)); }
.ws-dirty { color: hsl(var(--primary)); font-size: .7rem; }
.ws-newfile { text-decoration: none; color: hsl(var(--muted-foreground)); font-size: 1.1rem; line-height: 1; padding: 0 .3rem; }
.ws-newfile:hover { color: hsl(var(--primary)); }
.ws-collapse { cursor: pointer; border: none; background: none; color: hsl(var(--muted-foreground)); font-size: 1rem; line-height: 1; padding: .1rem .3rem; }
.ws-collapse:hover { color: hsl(var(--foreground)); }
.ws-body { flex: 1; min-height: 0; overflow: auto; }
.ws-editor .ws-body, .ws-preview .ws-body { overflow: hidden; }
/* The Sync button doubles as a compile-status badge: an inline spinner next to
   "Compiling live view…" while tinymist compiles, then the plain toggle label. */
.ws-sync { white-space: nowrap; }
/* PDF picker in the preview header — matches the small ghost buttons beside it. */
.ws-pdf-pick { max-width: 12rem; padding: .3rem .5rem; font-size: .8rem; color: hsl(var(--foreground)); background: hsl(var(--card)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-sm); cursor: pointer; }
.ws-pdf-pick:hover { background: hsl(var(--accent)); }
.ws-spin-sm { display: inline-block; width: .75em; height: .75em; vertical-align: -.05em; border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%; animation: ws-spin .7s linear infinite; }
@keyframes ws-spin { to { transform: rotate(360deg); } }
/* Overlay modal (`components::modal`): the project terminal and the shortcut
   list. Sized for a terminal by default; `.modal-auto` shrinks the box to its
   content (with its own scroll) for short, text-only panels. */
.modal { position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center; background: hsl(var(--background) / .6); }
.modal[hidden] { display: none; }
.modal-box { width: min(92vw, 1100px); height: min(84vh, 780px); display: flex; flex-direction: column; background: hsl(var(--card)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius); box-shadow: var(--shadow-lg); overflow: hidden; }
.modal-box.modal-auto { width: min(92vw, 40rem); height: auto; max-height: 84vh; }
.modal-head { display: flex; align-items: center; justify-content: space-between; padding: .4rem .7rem; background: hsl(var(--card-2)); border-bottom: 1px solid hsl(var(--border)); font-size: .82rem; }
.modal-close { border: none; background: none; color: hsl(var(--muted-foreground)); font-size: 1rem; line-height: 1; cursor: pointer; padding: .1rem .4rem; border-radius: var(--radius-sm); }
.modal-close:hover, .modal-reset:hover { color: hsl(var(--foreground)); background: hsl(var(--accent)); }
/* A windowed modal: its head is the drag handle, its corner the resize grip.
   The box keeps its centred default until the first drag, which pins an explicit
   rect on it (inline styles from MODAL_WINDOW_JS). */
.modal-window .modal-head { cursor: move; user-select: none; touch-action: none; }
.modal-window .modal-box { position: relative; }
.modal-reset { border: none; background: none; color: hsl(var(--muted-foreground)); font-size: .95rem; line-height: 1; cursor: pointer; padding: .1rem .35rem; border-radius: var(--radius-sm); }
.modal-grip { position: absolute; right: 0; bottom: 0; width: 1.1rem; height: 1.1rem; cursor: nwse-resize; touch-action: none; z-index: 2; }
/* The two lines of the grip, drawn without an extra element. */
.modal-grip::after { content: ""; position: absolute; right: .18rem; bottom: .18rem; width: .55rem; height: .55rem; border-right: 2px solid hsl(var(--border-strong)); border-bottom: 2px solid hsl(var(--border-strong)); }
/* Mid-drag the contents must not eat the pointer — an iframe (the terminal)
   otherwise swallows every move event the moment the cursor crosses it. */
.modal-box.dragging > *:not(.modal-head) { pointer-events: none; }
.modal-body { min-height: 0; overflow: auto; padding: .7rem .9rem 1rem; }
/* Notes editor: a plain textarea filling the modal box, its save row on top. */
.notes-body { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: .6rem .7rem .7rem; gap: .45rem; }
.notes-head { display: flex; align-items: center; justify-content: flex-end; gap: .6rem; }
.notes-state { margin-right: auto; font-size: .78rem; color: hsl(var(--muted-foreground)); }
.notes-state.dirty { color: hsl(var(--warning)); }
.notes-state.err { color: hsl(var(--destructive)); }
.notes-text { flex: 1; min-height: 0; resize: none; width: 100%; padding: .6rem .7rem; font-family: var(--mono); font-size: .85rem; line-height: 1.55; color: hsl(var(--foreground)); background: hsl(var(--card-2)); border: 1px solid hsl(var(--border)); border-radius: var(--radius); }
.notes-text:focus { outline: 2px solid hsl(var(--ring) / .5); outline-offset: 1px; }
.term-frame { flex: 1; width: 100%; border: none; background: #0b0b0e; }
/* Key bindings: the `?` overlay's list and the settings form's rows. */
kbd { font-family: var(--mono); font-size: .78rem; white-space: nowrap; padding: .1rem .35rem; color: hsl(var(--foreground)); background: hsl(var(--card-2)); border: 1px solid hsl(var(--border-strong)); border-bottom-width: 2px; border-radius: var(--radius-sm); }
.keys-scope { color: hsl(var(--muted-foreground)); white-space: nowrap; }
.keys-row { display: grid; grid-template-columns: minmax(0, 1fr) 11rem; gap: .5rem .8rem; align-items: center; padding: .35rem 0; border-top: 1px solid hsl(var(--border) / .5); }
.keys-row:first-of-type { border-top: none; }
.keys-row .keys-label { display: flex; flex-direction: column; gap: .1rem; }
.keys-row input { width: 100%; padding: .3rem .5rem; font-family: var(--mono); font-size: .8rem; color: hsl(var(--foreground)); background: hsl(var(--card)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-sm); }
@media (max-width: 40rem) { .keys-row { grid-template-columns: 1fr; } }
.ws-editor .editor-box { height: 100%; margin: 0; }
.ws-editor .CodeMirror.cm-s-wf { height: 100%; min-height: 0; border: none; border-radius: 0; }
.ws-frame { width: 100%; height: 100%; border: none; background: hsl(var(--card)); display: block; }
.ws-noedit { height: 100%; display: flex; align-items: center; justify-content: center; padding: 1rem; text-align: center; }
/* "Updated on disk" warning in the editor header after an auto-reload; stays until the user saves. */
.ws-updated { font-size: .7rem; color: hsl(var(--warning)); background: hsl(var(--warning) / .12); border: 1px solid hsl(var(--warning) / .3); border-radius: var(--radius-sm); padding: .05rem .35rem; white-space: nowrap; }
.ws-updated:not([hidden]) { animation: wsUpdatedIn .18s ease-out; }
@keyframes wsUpdatedIn { from { opacity: 0; } to { opacity: 1; } }
.ws-img { max-width: 100%; max-height: 100%; object-fit: contain; }
/* file tree */
.ws-tree { padding: .3rem; }
.ws-tree-list { list-style: none; margin: 0; padding: 0; }
.ws-tree-list .ws-tree-list { margin-left: .75rem; border-left: 1px solid hsl(var(--border) / .5); }
.ws-row, .ws-file { display: flex; align-items: center; gap: .35rem; width: 100%; text-align: left; border: none; background: none; color: inherit; cursor: pointer; padding: .13rem .35rem; border-radius: var(--radius-sm); font: inherit; font-size: .84rem; }
.ws-file:hover, .ws-folder > summary:hover { background: hsl(var(--accent)); }
.ws-file.active { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); font-weight: 560; }
.ws-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ws-file .icon, .ws-row .icon { width: 1em; height: 1em; flex: none; color: hsl(var(--muted-foreground)); }
.ws-folder > summary { list-style: none; }
.ws-folder > summary::-webkit-details-marker { display: none; }
/* collapsed pane → a click-to-expand vertical strip */
/* A PDF preview pane fills its pane rather than the fixed inline height the
   card-embedded viewer uses (the pane already has the workspace's height). */
.ws-preview .pdf-viewer.inline { height: 100%; border: none; border-radius: 0; }
.ws-pane.collapsed { flex: 0 0 2.2rem; cursor: pointer; }
.ws-pane.collapsed .ws-body { display: none; }
.ws-pane.collapsed .ws-head { flex-direction: column; height: 100%; border-bottom: none; padding: .5rem .2rem; gap: .6rem; }
.ws-pane.collapsed .ws-title { writing-mode: vertical-rl; }
.ws-pane.collapsed .ws-head-actions { margin-left: 0; }
.ws-pane.collapsed .ws-save, .ws-pane.collapsed .ws-dirty, .ws-pane.collapsed .ws-newfile { display: none; }
/* Collapsed file manager: hovering the strip pops the tree open as a floating
   overlay to its right, layered above the editor WITHOUT reflowing it (the 2.2rem
   strip keeps its place in the flex row); leaving collapses it again. The strip —
   with its expand chevron — stays visible, so clicking it still pins the pane.
   The edges where the strip and the popup meet are squared off (only the outer
   corners stay rounded), so the two read as one continuous surface. */
.ws-nav.collapsed { position: relative; }
.ws-nav.collapsed:hover { overflow: visible; z-index: 20; border-top-right-radius: 0; border-bottom-right-radius: 0; }
.ws-nav.collapsed:hover .ws-body {
  display: block; position: absolute; top: 0; left: 100%; width: var(--w, 15rem); height: 100%;
  background: hsl(var(--card)); border: 1px solid hsl(var(--border)); border-radius: 0 var(--radius) var(--radius) 0;
  box-shadow: var(--shadow-pop); overflow: auto; z-index: 20;
}
@media (max-width: 860px) {
  .ws-tabs { display: flex; gap: .3rem; margin-bottom: .4rem; }
  .ws-tabs button { flex: 1; font: inherit; font-size: .82rem; padding: .35rem; border: 1px solid hsl(var(--border-strong)); background: hsl(var(--card)); color: hsl(var(--foreground)); border-radius: var(--radius-sm); cursor: pointer; }
  .ws-tabs button.active { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); border-color: transparent; font-weight: 560; }
  .ws-grid { height: calc(100vh - 13rem); }
  .ws-pane { display: none; flex: 1 1 auto; }
  .ws-collapse, .ws-resize { display: none; }
  .proj-workspace[data-pane="nav"] .ws-nav,
  .proj-workspace[data-pane="editor"] .ws-editor,
  .proj-workspace[data-pane="preview"] .ws-preview { display: flex; }
}
.CodeMirror.cm-s-wf { height: calc(100vh - 14rem); min-height: 20rem; border: 1px solid hsl(var(--border)); border-radius: var(--radius); background: hsl(var(--card)); color: hsl(var(--foreground)); font-family: var(--mono); font-size: .85rem; line-height: 1.55; }
.cm-s-wf .CodeMirror-gutters { background: hsl(var(--card-2)); border-right: 1px solid hsl(var(--border)); }
.cm-s-wf .CodeMirror-linenumber { color: hsl(var(--muted-foreground)); }
/* Git gutter: a thin colored bar per changed line (added/modified/deleted). */
.ws-git-gutter { width: 4px; }
.ws-git { width: 4px; height: 100%; }
.ws-git-add { background: #2ea043; }
.ws-git-mod { background: #388bfd; }
.ws-git-del { position: relative; }
.ws-git-del::after { content: ''; position: absolute; left: 0; bottom: -3px; width: 0; height: 0; border-left: 5px solid #f85149; border-top: 3px solid transparent; border-bottom: 3px solid transparent; }
/* tinymist LSP diagnostics: wavy underline on the offending span, message as a
   native tooltip (the `title` on the CodeMirror mark). */
.cm-diag { text-decoration: underline wavy; text-decoration-skip-ink: none; text-underline-offset: 2px; text-decoration-thickness: 1px; }
.cm-diag-error { text-decoration-color: hsl(var(--destructive)); }
.cm-diag-warn { text-decoration-color: hsl(var(--warning)); }
.cm-diag-info { text-decoration-color: hsl(var(--primary)); }
/* LSP hover tooltip (docs/signature on mouse-over), rendered from markdown. */
.ws-hover-tip { position: fixed; z-index: 50; max-width: 32rem; max-height: 16rem; overflow: auto; padding: .3rem .55rem; font-size: .8rem; line-height: 1.45; background: hsl(var(--card)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-sm); box-shadow: var(--shadow-md); pointer-events: none; }
.ws-hover-tip p { margin: .3rem 0; }
.ws-hover-tip pre { margin: .3rem 0; padding: .35rem .5rem; background: hsl(var(--muted)); border-radius: var(--radius-sm); font-family: var(--mono); font-size: .76rem; line-height: 1.4; white-space: pre-wrap; overflow-x: auto; }
.ws-hover-tip code { font-family: var(--mono); font-size: .92em; background: hsl(var(--muted)); padding: .05rem .25rem; border-radius: var(--radius-sm); }
.ws-hover-tip pre code { background: none; padding: 0; }
.ws-hover-tip .hh { font-weight: 600; margin: .4rem 0 .1rem; }
.ws-hover-tip hr { border: none; border-top: 1px solid hsl(var(--border)); margin: .35rem 0; }
.ws-hover-tip > :first-child { margin-top: 0; }
.ws-hover-tip > :last-child { margin-bottom: 0; }
/* LSP signature help — the call signature, active parameter bold. */
.ws-sig-tip { position: fixed; z-index: 50; max-width: 40rem; padding: .2rem .5rem; font-family: var(--mono); font-size: .78rem; line-height: 1.4; white-space: pre-wrap; background: hsl(var(--card)); color: hsl(var(--muted-foreground)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-sm); box-shadow: var(--shadow-md); pointer-events: none; }
.ws-sig-tip b { color: hsl(var(--foreground)); font-weight: 600; }
/* Completion popup (show-hint addon) — themed to match the editor. Doubled/scoped
   selectors so these win over show-hint.css, which loads after the app stylesheet. */
.CodeMirror-hints.CodeMirror-hints { z-index: 40; background: hsl(var(--card)); border: 1px solid hsl(var(--border-strong)); border-radius: var(--radius-sm); box-shadow: var(--shadow-md); font-family: var(--mono); font-size: .82rem; }
.CodeMirror-hints .CodeMirror-hint { color: hsl(var(--foreground)); }
.CodeMirror-hints li.CodeMirror-hint-active { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); }
.cm-s-wf .CodeMirror-cursor { border-left: 1.5px solid hsl(var(--foreground)); }
.cm-s-wf .CodeMirror-selected { background: hsl(var(--primary-muted)); }
.cm-s-wf.CodeMirror-focused .CodeMirror-selected { background: hsl(var(--primary-muted)); }
.cm-s-wf .cm-header { color: hsl(var(--primary)); font-weight: 600; }
.cm-s-wf .cm-keyword { color: hsl(var(--syn-keyword)); }
.cm-s-wf .cm-string, .cm-s-wf .cm-string-2 { color: hsl(var(--syn-string)); }
.cm-s-wf .cm-comment { color: hsl(var(--syn-comment)); font-style: italic; }
.cm-s-wf .cm-variable-2, .cm-s-wf .cm-def { color: hsl(var(--syn-func)); }
.cm-s-wf .cm-number { color: hsl(var(--syn-number)); }
.cm-s-wf .cm-link, .cm-s-wf .cm-url { color: hsl(var(--primary)); }
.cm-s-wf .cm-quote { color: hsl(var(--muted-foreground)); }

/* code viewer + highlight.js theme (shadcn tokens, adapts light/dark) */
pre.codeblock {
  background: hsl(var(--card)); padding: .9rem 1rem; margin: .4rem 0 1.3rem;
  box-shadow: var(--shadow-sm); font-size: .8rem; line-height: 1.55; tab-size: 2;
}
pre.codeblock code { background: none; padding: 0; white-space: pre; }
.hljs { color: hsl(var(--foreground)); background: transparent; }
.hljs-comment, .hljs-quote { color: hsl(var(--syn-comment)); font-style: italic; }
.hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-section, .hljs-doctag, .hljs-type, .hljs-name, .hljs-strong { color: hsl(var(--syn-keyword)); }
.hljs-string, .hljs-attr, .hljs-regexp, .hljs-addition, .hljs-meta-string { color: hsl(var(--syn-string)); }
.hljs-number, .hljs-built_in, .hljs-builtin-name, .hljs-literal, .hljs-symbol, .hljs-bullet { color: hsl(var(--syn-number)); }
.hljs-title, .hljs-title.function_, .hljs-function .hljs-title, .hljs-selector-id, .hljs-selector-class { color: hsl(var(--syn-func)); }
.hljs-variable, .hljs-template-variable, .hljs-attribute, .hljs-params { color: hsl(var(--foreground)); }
.hljs-meta, .hljs-comment { color: hsl(var(--syn-comment)); }
.hljs-deletion { color: hsl(var(--destructive)); }

/* utility layer — a deliberately small, composable set (no-Tailwind ethos) */
.u-flex    { display: flex; align-items: center; gap: var(--space-2); }
.u-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.u-stack   { display: flex; flex-direction: column; gap: var(--space-2); }
.u-wrap    { flex-wrap: wrap; }
.u-muted   { color: hsl(var(--muted-foreground)); }
.u-mono    { font-family: var(--mono); }
.u-nums    { font-variant-numeric: tabular-nums; }
.u-truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.u-mt      { margin-top: var(--space-4); }
.u-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* honour reduced-motion: neutralise transitions/animations globally */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; scroll-behavior: auto !important;
  }
}

/* ================= themes × light/dark ================= *
 * `data-theme` (journal|studio|console) picks the identity — fonts, layout,
 * button style, accent; `data-mode` (system|light|dark) picks the palette. Each
 * theme defines LIGHT surface tokens on its base selector and DARK ones in the
 * dark blocks at the end (applied for data-mode=dark, or data-mode=system under
 * an OS dark preference). Server sets both attributes on <html> (defaults
 * theme=journal, mode=system). */

/* self-hosted variable faces (served from /static) */
@font-face { font-family: 'Inter'; src: url('/static/inter.woff2') format('woff2'); font-weight: 100 900; font-style: normal; font-display: swap; }
@font-face { font-family: 'Newsreader'; src: url('/static/serif.woff2') format('woff2'); font-weight: 200 800; font-style: normal; font-display: swap; }

/* type hooks — each theme points these at the faces it wants */
:root { --font-ui: 'Inter', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; --font-head: var(--font-ui); --font-prose: var(--font-ui); }
body { font-family: var(--font-ui); }
h1, h2, h3, .brand, .login-brand { font-family: var(--font-head); }
.content, .prose { font-family: var(--font-prose); }

/* keep native controls (scrollbars, form widgets, the pdf.js UI) in step */
[data-mode="light"] { color-scheme: light; }
[data-mode="dark"] { color-scheme: dark; }
[data-mode="system"] { color-scheme: light dark; }

/* the in-nav switchers (theme J/S/C and mode share this styling) */
.theme-switch { display: inline-flex; gap: 2px; padding: 2px; margin-left: .3rem; background: hsl(var(--muted)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-full); }
.theme-switch .tsw { display: inline-flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem; border-radius: var(--radius-full); font-size: .72rem; font-weight: 650; color: hsl(var(--muted-foreground)); text-decoration: none; }
.theme-switch .tsw:hover { color: hsl(var(--foreground)); }
.theme-switch .tsw.on { background: hsl(var(--card)); color: hsl(var(--foreground)); box-shadow: var(--shadow-sm); }
/* mobile menu: labeled 'Theme'/'Mode' rows with word labels (the compact copies
 * inherited from the nav links are hidden here to avoid a buried duplicate) */
.menu-theme { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding: .1rem .25rem .55rem; margin-bottom: .35rem; border-bottom: 1px solid hsl(var(--border)); }
.menu-theme-label { font-size: .82rem; font-weight: 600; color: hsl(var(--muted-foreground)); }
.menu-panel .theme-switch:not(.wide) { display: none; }
.theme-switch.wide { margin-left: 0; }
.theme-switch.wide .tsw { width: auto; height: auto; padding: .34rem .62rem; font-size: .78rem; }

/* ---- JOURNAL — editorial serif, ink/cream pill buttons, warm paper ---- */
[data-theme="journal"] {
  --background: 38 30% 98.5%; --card: 38 30% 99.3%; --card-2: 38 22% 96.5%;
  --foreground: 30 12% 14%; --muted-foreground: 34 8% 40%;
  --muted: 38 18% 95.5%; --accent: 38 22% 94%;
  --border: 34 16% 88%; --border-strong: 34 16% 80%;
  --primary: 8 56% 44%; --primary-hover: 8 56% 38%; --primary-foreground: 38 30% 98%;
  --primary-muted: 8 50% 95%; --ring: 8 56% 44%;
  --jbtn: 28 22% 16%; --jbtn-fg: 38 30% 97%;
  --radius: .5rem; --radius-lg: .7rem;
  --font-head: 'Newsreader', Georgia, serif; --font-prose: 'Newsreader', Georgia, serif;
}
[data-theme="journal"] h1 { font-weight: 560; letter-spacing: -.008em; font-size: 2.05rem; line-height: 1.1; }
[data-theme="journal"] h2 { font-weight: 560; letter-spacing: 0; }
[data-theme="journal"] .subtitle { font-family: var(--font-head); font-style: italic; font-size: 1.08rem; }
[data-theme="journal"] .content { font-size: 1.08rem; line-height: 1.8; }
[data-theme="journal"] main { max-width: 42rem; }
[data-theme="journal"] .card { box-shadow: none; }
[data-theme="journal"] .session-list { background: transparent; }
[data-theme="journal"] .btn { background: hsl(var(--jbtn)); color: hsl(var(--jbtn-fg)); border: 1px solid hsl(var(--jbtn)); border-radius: var(--radius-full); box-shadow: var(--shadow-sm); font-weight: 600; }
[data-theme="journal"] .btn:hover { filter: brightness(1.3); }
[data-theme="journal"] .btn.ghost { background: transparent; color: hsl(var(--foreground)); border: 1px solid hsl(var(--border-strong)); box-shadow: none; filter: none; }
[data-theme="journal"] .btn.ghost:hover { background: hsl(var(--card-2)); border-color: hsl(var(--foreground)); }
[data-theme="journal"] .btn.ghost.danger { color: hsl(var(--destructive)); border-color: hsl(var(--destructive) / .4); }

/* ---- STUDIO — cool-neutral (obsidian) surfaces, magenta accent, flat cards ---- */
[data-theme="studio"] {
  --background: 240 12% 96.5%; --card: 0 0% 100%; --card-2: 250 14% 94%;
  --foreground: 250 17% 13%; --muted-foreground: 247 9% 42%;
  --muted: 250 13% 94%; --accent: 250 13% 92%;
  --border: 246 14% 89%; --border-strong: 247 11% 80%;
  --primary: 327 74% 48%; --primary-hover: 327 77% 42%; --primary-muted: 327 62% 95%; --primary-foreground: 0 0% 100%; --ring: 327 74% 48%;
  --success: 150 45% 37%; --success-dot: 150 50% 42%; --warning: 32 82% 47%;
  --nav-bg: 240 12% 96%;
  --radius: .5rem; --radius-lg: .8rem;
}
/* flat cards, separated by a hairline in both modes (global .card border, no shadow) */
[data-theme="studio"] .btn { background: hsl(var(--primary)); color: hsl(var(--primary-foreground)); border: 1px solid transparent; box-shadow: none; }
[data-theme="studio"] .btn:hover { background: hsl(var(--primary-hover)); }
[data-theme="studio"] .btn.ghost { background: transparent; color: hsl(var(--foreground)); border: 1px solid hsl(var(--border-strong)); box-shadow: none; }
[data-theme="studio"] .btn.ghost:hover { background: hsl(var(--accent)); }

/* turn the top nav into a left rail on wide screens */
@media (min-width: 641px) {
  [data-theme="studio"] body { display: flex; align-items: stretch; position: relative; }
  [data-theme="studio"] header.nav {
    position: sticky; top: 0; align-self: flex-start; height: 100dvh;
    width: 220px; flex: none; flex-direction: column; align-items: stretch; gap: .12rem;
    background: hsl(var(--nav-bg)); border-bottom: none; border-right: 1px solid hsl(var(--border));
    -webkit-backdrop-filter: none; backdrop-filter: none; padding: .9rem .55rem;
  }
  [data-theme="studio"] header.nav .brand { margin-bottom: .5rem; }
  [data-theme="studio"] header.nav a.navlink,
  [data-theme="studio"] header.nav summary.navlink { font-size: .9rem; padding: .5rem .6rem; }
  /* current page reads as a soft filled pill in the rail */
  [data-theme="studio"] header.nav a.navlink.on,
  [data-theme="studio"] header.nav summary.navlink.on { background: hsl(var(--primary-muted)); color: hsl(var(--primary)); }
  /* group the Tracking/Ops clusters below the top links with a hairline */
  [data-theme="studio"] header.nav > details.dropdown:first-of-type { margin-top: .5rem; padding-top: .6rem; border-top: 1px solid hsl(var(--border)); }
  [data-theme="studio"] header.nav form.search { margin: .5rem 0 0; order: 8; flex: 0 0 auto; }
  /* user/settings menu pinned to the bottom of the rail, opening upward */
  [data-theme="studio"] header.nav .dropdown.user { margin: .5rem 0 0; order: 9; align-self: flex-start; }
  /* In the left rail the user button sits at the far left, so the panel must
     open rightward (into the content). Override the `.right` alignment (which is
     correct only for the top-right nav) so it does not spill off the left edge. */
  [data-theme="studio"] header.nav .dropdown.user .dropdown-panel { top: auto; bottom: calc(100% + .35rem); left: 0; right: auto; }
  [data-theme="studio"] main { flex: 1; min-width: 0; }
}

/* ---- CONSOLE — vibrant violet gradient buttons, glow (light base) ---- */
[data-theme="console"] {
  --background: 240 20% 98.5%; --card: 0 0% 100%; --card-2: 240 22% 97%;
  --foreground: 240 14% 12%; --muted-foreground: 240 6% 45%;
  --muted: 240 8% 95%; --accent: 240 8% 95%; --input: 240 8% 84%;
  --border: 240 8% 90%; --border-strong: 240 8% 84%;
  --primary: 255 82% 60%; --primary-hover: 255 82% 54%; --primary-foreground: 0 0% 100%;
  --primary-muted: 255 70% 96%; --ring: 255 82% 60%;
  --radius-lg: .9rem;
}
[data-theme="console"] .btn { background: linear-gradient(135deg, hsl(258 90% 66%), hsl(240 90% 60%)); color: #fff; border: none; box-shadow: 0 4px 14px hsl(255 90% 55% / .35), inset 0 1px 0 hsl(0 0% 100% / .2); }
[data-theme="console"] .btn:hover { filter: brightness(1.07); background: linear-gradient(135deg, hsl(258 90% 66%), hsl(240 90% 60%)); }
[data-theme="console"] .btn.ghost { background: hsl(var(--card-2)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--border)); box-shadow: none; }
[data-theme="console"] .btn.ghost:hover { background: hsl(var(--accent)); }
[data-theme="console"] .btn.ghost.danger { color: hsl(var(--destructive)); border-color: hsl(var(--destructive) / .4); }
[data-theme="console"] .dot { box-shadow: 0 0 10px hsl(var(--success-dot) / .85); }
[data-theme="console"] .session-list { background: hsl(var(--card-2)); }
[data-theme="console"] header.nav a.navlink.on, [data-theme="console"] .theme-switch .tsw.on { color: hsl(var(--primary)); }

/* ============ per-theme DARK surface tints ============ *
 * Applied for explicit dark mode and for system mode under OS dark. Duplicated
 * across the two conditions (pure CSS cannot share a rule across the media
 * boundary); the shared non-surface dark tokens come from `[data-mode="dark"]`
 * / `[data-mode="system"]` above. */
[data-mode="dark"][data-theme="journal"] {
  --background: 28 14% 10%; --card: 28 13% 13%; --card-2: 28 12% 16.5%;
  --foreground: 38 22% 89%; --muted-foreground: 34 10% 63%;
  --muted: 28 10% 17%; --accent: 28 10% 18%;
  --border: 30 9% 23%; --border-strong: 30 9% 32%;
  --primary: 8 72% 65%; --primary-hover: 8 72% 71%; --primary-muted: 8 45% 22%; --ring: 8 72% 65%;
  --jbtn: 38 32% 90%; --jbtn-fg: 28 24% 12%;
}
[data-mode="dark"][data-theme="studio"] {
  --background: 240 16% 6%; --card: 246 17% 11%; --card-2: 250 16% 14%;
  --foreground: 250 14% 91%; --muted-foreground: 247 8% 60%;
  --muted: 250 15% 15%; --accent: 248 14% 19%; --input: 248 12% 22%;
  --border: 250 14% 17%; --border-strong: 248 12% 27%;
  --primary: 330 82% 66%; --primary-hover: 330 88% 73%; --primary-muted: 328 38% 20%; --primary-foreground: 335 30% 11%; --ring: 330 82% 66%;
  --nav-bg: 242 16% 8%;
}
[data-mode="dark"][data-theme="console"] {
  --background: 240 14% 8%; --card: 240 12% 11%; --card-2: 240 12% 13.5%;
  --foreground: 240 20% 96%; --muted-foreground: 240 8% 62%;
  --muted: 240 10% 16%; --accent: 240 10% 16%; --input: 240 10% 24%;
  --border: 240 10% 20%; --border-strong: 240 10% 28%;
  --primary: 255 90% 74%; --primary-hover: 255 90% 80%; --primary-muted: 255 55% 22%; --ring: 255 90% 74%;
  --destructive: 0 78% 66%; --success: 145 60% 58%; --success-dot: 145 70% 55%;
}
@media (prefers-color-scheme: dark) {
  [data-mode="system"][data-theme="journal"] {
    --background: 28 14% 10%; --card: 28 13% 13%; --card-2: 28 12% 16.5%;
    --foreground: 38 22% 89%; --muted-foreground: 34 10% 63%;
    --muted: 28 10% 17%; --accent: 28 10% 18%;
    --border: 30 9% 23%; --border-strong: 30 9% 32%;
    --primary: 8 72% 65%; --primary-hover: 8 72% 71%; --primary-muted: 8 45% 22%; --ring: 8 72% 65%;
    --jbtn: 38 32% 90%; --jbtn-fg: 28 24% 12%;
  }
  [data-mode="system"][data-theme="studio"] {
    --background: 240 16% 6%; --card: 246 17% 11%; --card-2: 250 16% 14%;
    --foreground: 250 14% 91%; --muted-foreground: 247 8% 60%;
    --muted: 250 15% 15%; --accent: 248 14% 19%; --input: 248 12% 22%;
    --border: 250 14% 17%; --border-strong: 248 12% 27%;
    --primary: 330 82% 66%; --primary-hover: 330 88% 73%; --primary-muted: 328 38% 20%; --primary-foreground: 335 30% 11%; --ring: 330 82% 66%;
    --nav-bg: 242 16% 8%;
  }
  [data-mode="system"][data-theme="console"] {
    --background: 240 14% 8%; --card: 240 12% 11%; --card-2: 240 12% 13.5%;
    --foreground: 240 20% 96%; --muted-foreground: 240 8% 62%;
    --muted: 240 10% 16%; --accent: 240 10% 16%; --input: 240 10% 24%;
    --border: 240 10% 20%; --border-strong: 240 10% 28%;
    --primary: 255 90% 74%; --primary-hover: 255 90% 80%; --primary-muted: 255 55% 22%; --ring: 255 90% 74%;
    --destructive: 0 78% 66%; --success: 145 60% 58%; --success-dot: 145 70% 55%;
  }
}

/* ── detail-page components (application / review / tender pages) ──────────── */
/* status pipeline: a row of step pills with arrows, current step highlighted */
.pipeline { display: flex; gap: .3rem; align-items: center; flex-wrap: wrap; margin: .2rem 0 .7rem; }
.pipe-arrow { color: hsl(var(--muted-foreground)); }
.pipe-step { padding: .1rem .5rem; border-radius: var(--radius-sm); font-size: .75rem; background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); }
.pipe-step.reached { color: hsl(var(--foreground)); }
.pipe-step.current { background: hsl(var(--primary)); color: hsl(var(--primary-foreground)); font-weight: 640; }
.pipe-outcome { margin-left: .3rem; font-weight: 640; }

/* completeness progress bar + its checkpoint list (dossier documents) */
.progress-label { margin: .2rem 0; }
.progress { background: hsl(var(--muted)); border-radius: var(--radius-sm); height: 8px; overflow: hidden; }
.progress-fill { height: 100%; background: hsl(var(--primary)); } /* width set inline (data-driven) */
.checklist { list-style: none; padding: 0; margin: .4rem 0 0; display: flex; flex-wrap: wrap; gap: .2rem 1rem; font-size: .8rem; }
.checklist-item.pending { color: hsl(var(--muted-foreground)); }
.deadline-line { margin: 0; }

/* embedded PDF preview (dossier / manuscript) */

/* a plain vertical list of file links (detail-page file panes) */
.file-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .25rem; }

/* "New review" disclosure form on the reviews page */
.review-new { margin-top: 1.2rem; }
.review-new > summary { cursor: pointer; font-weight: 620; }
.review-new .subtitle { margin: .5rem 0 .2rem; }
.review-form { display: flex; flex-direction: column; gap: .6rem; max-width: 34rem; }
.review-form label { display: flex; flex-direction: column; gap: .2rem; }

/* dedicated "New <item>" pages (Projects/Talks/Reviews) */
.new-form { display: flex; flex-direction: column; gap: .7rem; max-width: 34rem; }
.new-field { display: flex; flex-direction: column; gap: .25rem; }
.new-field > span { font-weight: 560; font-size: .9rem; }
.new-actions { display: flex; gap: .6rem; margin-top: .4rem; }

/* institute members (professors) on a job/application page */
.prof-label { margin: .3rem 0 .2rem; }
.prof-list { display: flex; flex-wrap: wrap; gap: .3rem .7rem; align-items: center; }
.prof-fetch { display: inline-flex; align-items: center; gap: .25rem; }

/* nested todo rows indent by depth (`--todo-depth` set inline) */
.todo-row { margin-left: calc(var(--todo-depth, 0) * 1.1rem); }
