/* ============================================================
   COMMAND CENTER — Blueprint design system · single entry point
   ------------------------------------------------------------
   Link ONLY this file from a page; it pulls in the four verbatim
   design sources (ported 1:1 from claude.ai/design) and then
   applies the choices the design landed on:
     · JetBrains Mono everywhere (vendored, no CDN)
     · MONO accent (greyscale "signal" colour)
     · blueprint variant: 0 radius · hairline · grid + scanlines
   Theme/density live on <html> (data-theme, data-density,
   data-scanlines); the blueprint variant lives on the root
   element (class "oh-root" + data-v="blueprint").
   ============================================================ */

/* @import rules must come first. Order matters: later files override earlier. */
@import "theme.css";      /* reset · theme tokens · app shell · command palette */
@import "operhud.css";    /* 4 type sizes · variant system · bento home · HUD page · readouts */
@import "blocks.css";     /* bp-* components: buttons, inputs, table, kanban, modal, ... + gallery chrome */
@import "blocks2.css";    /* bp-* v2: overlays, charts, lists/trees, indicators, terminal */

/* ------------------------------------------------------------
   VENDORED FONT — JetBrains Mono (latin subset, ~21KB/weight)
   ------------------------------------------------------------ */
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("/static/fonts/jetbrains-mono-400.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("/static/fonts/jetbrains-mono-500.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("/static/fonts/jetbrains-mono-600.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("/static/fonts/jetbrains-mono-700.woff2") format("woff2");
}

/* ------------------------------------------------------------
   LOCKED CHOICES — one typeface, MONO accent (overrides theme.css)
   These come AFTER the @imports so they win the cascade.
   ------------------------------------------------------------ */
:root {
  /* the whole UI is one mono typeface — hierarchy comes from weight/colour/spacing/caps */
  --sans: "JetBrains Mono", ui-monospace, monospace;
  --mono: "JetBrains Mono", ui-monospace, monospace;
}

/* MONO accent — greyscale "system signal", no glow (the blueprint look) */
:root, [data-theme="dark"] {
  --accent:      oklch(0.78 0.006 240);
  --accent-2:    oklch(0.70 0.02 240);
  --accent-ink:  oklch(0.16 0.01 240);
  --accent-soft: color-mix(in oklch, var(--accent) 14%, transparent);
  --accent-line: color-mix(in oklch, var(--accent) 38%, transparent);
  --glow:        transparent;
}
[data-theme="light"] {
  --accent:      oklch(0.46 0.01 240);
  --accent-2:    oklch(0.40 0.02 240);
  --accent-ink:  oklch(0.98 0.005 240);
  --accent-soft: color-mix(in oklch, var(--accent) 10%, transparent);
  --accent-line: color-mix(in oklch, var(--accent) 30%, transparent);
  --glow:        transparent;
}

/* ------------------------------------------------------------
   GLUE — bits the prototype did in JS/markup, done here in CSS
   ------------------------------------------------------------ */

/* the vendored icons render as inline <svg class="bpi-svg"> (see web/icons.py).
   make them behave like the prototype's icon spans inside flex rows. */
.bpi-svg { display: inline-block; vertical-align: middle; flex: none; }

/* live "pulse" indicators (oh-live, oh-rail-dot) reference this keyframe;
   it lived in a direction file the gallery never loaded, so define it here. */
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

/* file-tree chevron rotates open (the prototype set this inline per-node;
   JS toggles .open on the caret instead). */
.bp-tree-cv.open > .bpi-svg { transform: rotate(90deg); transition: transform .14s ease; }

/* select / dropdown caret rotation already handled by blocks.css via .open;
   keep the icon centred regardless of set. */
.bp-select-btn .cv, .bp-acc-h .cv { display: grid; place-items: center; }

/* overlays must stay viewport-fixed wherever they sit in the tree. operhud.css's
   `.oh-root > *:not(.oh-grid-bg){position:relative}` (specificity 0,2,0) otherwise drops a scrim
   into the layout. This descendant rule matches that specificity and, declared later, wins — so a
   modal/drawer scrim works at any depth inside the root. */
.oh-root .bp-modal-scrim, .oh-root .bp-drawer-scrim { position: fixed; }

/* Same trap for the notification tray (a direct child of .oh-root): the rule above forces it
   position:relative — dropping it into the shell grid as a flexible row that balloons to fill the
   slack a short page leaves, pushing the content far down — and z-index:1 (behind content). Restore
   the fixed, on-top placement it declares in blocks.css. (Its top/right offsets aren't clobbered.) */
.oh-root > .cc-notify { position: fixed; z-index: 250; }

/* overlays are server-rendered into the DOM and revealed by JS (blocks.js) toggling [hidden];
   [hidden] already means display:none, but be explicit so an open scrim lays out as designed. */
.bp-modal-scrim[hidden], .bp-drawer-scrim[hidden], .palette-scrim[hidden],
.bp-menu[hidden], .bp-dd-menu[hidden], .bp-pop-card[hidden],
.palette-item[hidden], .palette-group[hidden],
[data-tab-panel][hidden], [data-tree-children][hidden],
[data-filter-item][hidden] { display: none; }

/* ------------------------------------------------------------
   CONNECTOR SETTINGS — searchable checkbox pickers (project allow-list /
   label exclusion-list on /connectors/todoist). Token-only, no new look.
   ------------------------------------------------------------ */
.cc-pick-list { margin-top: 10px; max-height: 320px; overflow-y: auto; display: flex;
  flex-direction: column; gap: 2px; border: 1px solid var(--line); padding: 6px; }
.cc-pick-list .bp-choice { width: 100%; justify-content: flex-start; padding: 5px 7px; }
.cc-pick-list .bp-choice:hover { background: var(--accent-soft); }
.cc-pick-note { color: var(--text-2); font-size: var(--t4); margin-top: 8px; }
.cc-pick-empty { color: var(--text-2); font-size: var(--t4); padding: 8px 4px; }
.cc-pick-warn { grid-column: 1 / -1; }
/* Landing-project single choice — native radios in the same list shell. */
.cc-pick-radio { display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 5px 7px; font-size: var(--t3); color: var(--text-1); cursor: pointer; }
.cc-pick-radio:hover { background: var(--accent-soft); }
.cc-pick-radio input[type="radio"] { accent-color: var(--accent); margin: 0; }
.cc-actions { display: flex; gap: 10px; align-items: center; margin-top: 14px; }

/* ------------------------------------------------------------
   BREATHING ROOM — wider canvas + taller table rows by default,
   plus a real "comfy" density. data-density lives on <html>
   ("compact" is the shell default; the top-bar toggle flips it
   to "comfy" and blocks.js persists the choice). theme.css's
   density tokens are barely consumed by the bp-* components, so
   the mode is applied here, at the high-traffic surfaces.
   ------------------------------------------------------------ */
.bp-content-inner { max-width: 1260px; }
.bp-table th, .bp-table td { padding: 11px 12px; }

[data-density="comfy"] .bp-content { padding: 34px 38px 90px; }
[data-density="comfy"] .bp-spec { padding: 22px; }
[data-density="comfy"] .oh-readout .oh-panel { padding: 18px 20px; }
[data-density="comfy"] .bp-table th,
[data-density="comfy"] .bp-table td { padding: 13px 14px; }
[data-density="comfy"] .cc-target-row { padding: 12px 14px; }
[data-density="comfy"] .cc-prompt-card { padding: 16px 18px; }
[data-density="comfy"] .cc-prompt-grid { gap: 18px; }

/* Clickable connector card (whole panel is the link). */
.cc-card-link { display: block; text-decoration: none; color: inherit; }
.cc-card-link .cc-card { transition: border-color .14s ease, background .14s ease; }
.cc-card-link:hover .cc-card { border-color: var(--accent); background: var(--accent-soft); }
.cc-card-cue { display: inline-flex; align-items: center; gap: 5px; color: var(--text-2);
  font-size: var(--t4); text-transform: uppercase; letter-spacing: .08em; }
.cc-card-link:hover .cc-card-cue { color: var(--accent); }

/* Card-as-button via [data-card-href] (blocks.js): cards that contain interactive children
   (buttons, forms) can't be wrapped in an <a>, so JS navigates instead. Same hover read. */
[data-card-href] { cursor: pointer; transition: border-color .14s ease, background .14s ease; }
[data-card-href]:hover { border-color: var(--accent); background: var(--accent-soft); }
[data-card-href]:hover .cc-card-cue { color: var(--accent); }

/* Icon picker (icon_pick component): the chosen tile reads as selected. */
.cc-iconpick [data-icon-val].on { border-color: var(--accent); color: var(--accent);
  background: var(--accent-soft); }

/* "Saving…" overlay shown while a filter save re-syncs (blocks.js reveals it on submit).
   Scoped under .oh-root so it beats operhud's `.oh-root > *{position:relative}` (0,2,0) — otherwise
   the overlay drops into normal flow at the bottom of the page instead of covering it. */
.oh-root .cc-overlay { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center;
  background: color-mix(in oklch, var(--bg-1) 92%, transparent);
  -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); }
.oh-root .cc-overlay[hidden] { display: none; }
.cc-overlay-card { position: relative; min-width: 280px; padding: 26px 30px; text-align: center;
  border: 1px solid var(--line); background: var(--bg-2); }
.cc-overlay-title { font-size: var(--t2); letter-spacing: .14em; }
.cc-overlay-sub { color: var(--text-2); font-size: var(--t4); margin-top: 12px;
  animation: pulse 1.3s ease-in-out infinite; }
.cc-overlay-bar { position: relative; height: 3px; margin-top: 16px; overflow: hidden;
  background: var(--line); }
.cc-overlay-bar > span { position: absolute; top: 0; left: 0; height: 100%; width: 40%;
  background: var(--accent); animation: cc-indet 1.1s ease-in-out infinite; }
@keyframes cc-indet { 0% { left: -40%; } 100% { left: 100%; } }

/* ─── Page transitions — per-block "CRT power-cycle" + text fade ──────────────────────────────
   Instead of cycling the whole page, each MAIN BLOCK animates on its own. JS-driven (blocks.js)
   so the feedback is INSTANT on click, not deferred until the next page loads.

     · Bordered boxes (panels, tiles, cards…) → CRT power-cycle: collapse to a bright scanline on
       leave, power on by expanding from the line on arrival. blocks.js finds them by their computed
       border and keeps only the TOP-LEVEL ones, so a table inside a panel rides the panel (no
       recursion). Each box pivots about its OWN centre. The pinch is purely VERTICAL — no jitter.
     · Free text / titles (.oh-hero, .bp-sec-h) → a clean opacity FADE. (This used to be a glitch
       that shook the text side-to-side; that jitter is removed everywhere — nothing shakes now.)
     · The top bar and the grid background never animate — blocks.js only scans `.oh-root`'s
       content children, never `.bp-top` / `.oh-grid-bg`.

   blocks.js adds these classes per element. Durations are mirrored by the *_MS constants there.
   Tune the look in the keyframes below. Reduced-motion → no animation (and content shown at once).

   PERFORMANCE RULE for every keyframe here: animate ONLY transform / opacity / clip-path — these
   run on the compositor. No `filter` (it forced an extra render surface per box and ran on the
   main thread in some engines — the source of visible jank when a whole dashboard cycled at once).
   The collapse must END at opacity 0: with fill-mode `both` the element HOLDS its last frame until
   the next page actually arrives (network time included), so a visible end state lingered as a
   thin bright line across the screen. */
.cc-box-out  { animation: cc-crt-out  160ms cubic-bezier(.55, 0, .9, .35) both; will-change: transform, opacity; }
.cc-box-in   { animation: cc-crt-in   260ms cubic-bezier(.16, .9, .2, 1)  both; will-change: transform, opacity; }
.cc-text-out { animation: cc-fade-out 140ms ease both; }
.cc-text-in  { animation: cc-fade-in  220ms ease both; }

@keyframes cc-crt-out {
  0%   { transform: scaleY(1);    opacity: 1;   }
  70%  { transform: scaleY(.03);  opacity: .85; }
  100% { transform: scaleY(.002); opacity: 0;   } /* fully off — nothing left behind */
}
@keyframes cc-crt-in {
  0%   { transform: scaleY(.02);  opacity: 0; }
  18%  { transform: scaleY(.08);  opacity: 1; } /* the power-on line: visible for ~45ms, then... */
  100% { transform: scaleY(1);    }             /* ...rapid expansion (strong ease-out) */
}
/* Text fade — pure opacity, NO transform/skew/clip. The old version slice-shifted the text
   side-to-side ("jitter"); that's intentionally gone so titles just fade with the boxes. */
@keyframes cc-fade-out {
  0%   { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes cc-fade-in {
  0%   { opacity: 0; }
  100% { opacity: 1; }
}

/* Flash guard: keep animated content hidden until blocks.js has tagged it for the power-on, so
   nothing shows un-animated for a frame. `.cc-prep` is set pre-paint by the inline <head> script
   and removed by blocks.js (or its own failsafe timer if JS never runs). The persistent top-bar
   controls (brand, Home link, search, theme, logout AND the breadcrumb) and the grid stay shown —
   only the page meta (`.bp-top-meta`) is hidden alongside the main content so it fades in with
   everything else, while those controls read as static across the navigation. The crumb used to be
   hidden + faded here too, but clicking an ancestor (A>B>C → B) then animated the whole crumb out
   and the new one in — rusty; it now swaps instantly like the other persistent controls. */
.cc-prep .oh-root > *:not(.bp-top):not(.oh-grid-bg),
.cc-prep .bp-top-meta { visibility: hidden; }

/* ─── Tables — their own, calmer treatment (NOT the CRT pinch) ────────────────────────────────
   A big table under the CRT scaleY pinch jitters and distorts badly — the
   motion is far more visible on a tall grid than on a compact panel. So any block that IS or
   CONTAINS a `.bp-table` opts out of `cc-box-*`/`cc-text-*` and uses these instead (blocks.js routes
   it). The look: a top-down "scanline reveal" — the rows wipe in from the top edge, no horizontal
   shift and no vertical squash. This drives BOTH the page transition (leave/arrive) AND in-place
   data refreshes (show/hide completed, post-sync), so every table — now and future — animates the
   same way. Durations mirrored by the *_MS constants in blocks.js. Same compositor-only +
   end-at-opacity-0 rules as the CRT keyframes above. */
.cc-table-out { animation: cc-table-out 160ms cubic-bezier(.55, 0, .9, .35) both; transform-origin: top center; will-change: clip-path, opacity; }
.cc-table-in  { animation: cc-table-in  260ms cubic-bezier(.16, .9, .2, 1)  both; transform-origin: top center; will-change: clip-path, opacity; }
@keyframes cc-table-out {
  0%   { opacity: 1; clip-path: inset(0 0 0 0);   }
  100% { opacity: 0; clip-path: inset(0 0 94% 0); }
}
@keyframes cc-table-in {
  0%   { opacity: 0; clip-path: inset(0 0 94% 0); }
  35%  { opacity: 1; }
  100% { opacity: 1; clip-path: inset(0 0 0 0);   }
}

/* In-place refresh "busy" state — a region whose data is being re-fetched (blocks.js adds it during
   the fetch, then swaps the new HTML in under cc-table-in / a skeleton fade). Dim + lock clicks so a
   stale table reads as pending without collapsing the layout. The side widgets instead show skeleton
   placeholders (the `skeleton` component markup, injected by blocks.js) during their fetch. */
.cc-busy { opacity: .5; pointer-events: none; transition: opacity .14s ease; }
.cc-region { position: relative; }
.cc-skel-fade { animation: cc-frag-in 260ms cubic-bezier(.16, .9, .2, 1) both; transform-origin: top; }

/* In-page fragment swaps (skeleton → loaded content) keep using document.startViewTransition in
   blocks.js, tagged `view-transition-class: cc-frag` — a quick power-on echo, scoped to the box. */
@keyframes cc-frag-out { to { opacity: 0; } }
@keyframes cc-frag-in  { from { opacity: 0; transform: scaleY(.6); } to { opacity: 1; transform: scaleY(1); } }

/* ─── Target rows — a target as its own block (goal cards + goal detail) ─────────────────────
   Label + window caption on the head line, then the bar line: progress (flex) + the "+1" button.
   The caption no longer shares the bar's row, so every bar in a list is the SAME width.
   `.cc-target-row` is excluded from box detection in blocks.js (CONTROL_SEL) — these are row
   furniture, not panels; they ride their container (or fade) instead of CRT-pinching one by one. */
.cc-target-row { border: 1px solid var(--line-soft); padding: 10px 12px;
  display: flex; flex-direction: column; gap: 8px; }
.cc-target-head { display: flex; align-items: baseline; gap: 10px; }
.cc-target-label { flex: 1; min-width: 0; font-size: var(--t3); font-weight: 600;
  color: var(--text); overflow-wrap: anywhere; }
.cc-target-cap { font-size: var(--t4); color: var(--text-2); white-space: nowrap; }
.cc-target-bar { display: flex; align-items: center; gap: 10px; }
.cc-target-bar > .bp-progress { flex: 1; min-width: 0; }

/* Hover-revealed card action (e.g. the Edit button on a goal card): invisible until the card is
   hovered or the control is keyboard-focused, so the cap stays quiet. */
.oh-panel .cc-hover-action { opacity: 0; transition: opacity .14s ease; }
.oh-panel:hover .cc-hover-action, .oh-panel:focus-within .cc-hover-action { opacity: 1; }

/* Watch-list prompt cards — the dashboard's dedicated section (one bordered card per light). */
.cc-prompt-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
  gap: 14px; align-items: start; margin-bottom: 22px; }
.cc-prompt-card { position: relative; border: 1px solid var(--line);
  background: var(--oh-panel-bg, var(--bg-1)); padding: 13px 15px;
  display: flex; flex-direction: column; gap: 9px; }
.cc-prompt-title { font-size: var(--t3); font-weight: 600; color: var(--text); }
.cc-prompt-body { font-size: var(--t4); color: var(--text-2); line-height: 1.5; }

/* Voice journal (/journal + /journal/capture) — the captain's log. The recorder fills the
   viewport: the page → panel → stage chain is a flex column, the scope grows so the waveform's
   centreline sits mid-screen, and the transcript is a full-height read-only terminal (bp-term
   clothes, no input). The REC light pulses with opacity only (motion perf rule). */
.cc-journal-page { display: flex; flex-direction: column; padding-bottom: 26px; }
.cc-journal-page .bp-content-inner { flex: 1; display: flex; flex-direction: column;
  min-height: 0; width: 100%; }
.cc-journal-page .oh-panel { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.cc-journal-stage { flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr 380px;
  gap: 20px; align-items: stretch; }
@media (max-width: 900px) { .cc-journal-stage { grid-template-columns: 1fr; } }
.cc-journal-left { display: flex; flex-direction: column; gap: 14px; min-width: 0;
  min-height: 0; }
.cc-journal-scope { position: relative; flex: 1; min-height: 220px;
  border: 1px solid var(--line-soft); background: var(--bg-2); }
.cc-journal-scope canvas { display: block; width: 100%; height: 100%; }
.cc-journal-status { display: flex; align-items: center; gap: 14px; font-size: var(--t4);
  color: var(--text-2); letter-spacing: .08em; text-transform: uppercase; flex: none; }
.cc-journal-status #journal-state { color: var(--text); font-weight: 600; }
.cc-journal-rec { width: 8px; height: 8px; border-radius: 50%; background: var(--text-2);
  flex: none; }
.cc-journal-rec.is-live { background: oklch(62% .19 25); animation: cc-rec-pulse 1.4s ease-in-out
  infinite; }
@keyframes cc-rec-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
.cc-journal-controls { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  flex: none; }
.cc-journal-hint { font-size: var(--t4); color: var(--text-2); }
.cc-journal-hint kbd { font-size: 10px; border: 1px solid var(--line); padding: 1px 5px; }
@media (pointer: coarse) { .cc-journal-hint { display: none; } }
.cc-journal-error { font-size: var(--t3); color: var(--text); border: 1px solid var(--line);
  border-left: 2px solid oklch(62% .19 25); padding: 10px 12px; flex: none; }
.cc-journal-term { min-height: 0; height: 100%; }
.cc-journal-term .bp-term-body { max-height: none; }
.cc-journal-feed { color: var(--text); }
.cc-journal-lost { color: var(--text-2); font-size: var(--t4); }
.cc-journal-prose { margin: 0; font-size: var(--t3); line-height: 1.7; color: var(--text);
  white-space: pre-wrap; overflow-wrap: anywhere; }
.cc-journal-card { cursor: pointer; }
/* Typed-entry (keyboard) path — the quick-write box (/journal) + the Write stage (/journal/capture).
   .bp-seg only styles <button>; the mode strip uses <a> links, so mirror the look here. */
.cc-journal-modes { margin-bottom: 14px; }
.cc-journal-modes a { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t4);
  letter-spacing: .08em; text-transform: uppercase; color: var(--text-1); border-right: 1px solid
  var(--line); padding: 7px 13px; text-decoration: none; }
.cc-journal-modes a:last-child { border-right: 0; }
.cc-journal-modes a:hover { color: var(--text); background: var(--accent-soft); }
.cc-journal-modes a.on { color: var(--accent-ink); background: var(--accent); }
.cc-journal-write { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
.cc-journal-write-input { width: 100%; background: var(--bg-1); border: 1px solid var(--line);
  color: var(--text); font: inherit; font-size: var(--t3); line-height: 1.6; padding: 10px 12px;
  resize: vertical; }
.cc-journal-write-input:focus { border-color: var(--accent-line); outline: none; }
.cc-journal-write-actions { display: flex; justify-content: flex-end; }
@media (max-width: 900px) {
  .cc-journal-page .oh-panel { flex: none; }
  .cc-journal-stage { flex: none; }
  .cc-journal-scope { min-height: 200px; flex: none; height: 220px; }
  .cc-journal-term { height: auto; min-height: 260px; }
  .cc-journal-term .bp-term-body { max-height: 320px; }
}
@media (prefers-reduced-motion: reduce) {
  .cc-journal-rec.is-live { animation: none; }
  .cc-journal-term .bp-term-cursor.on { animation: none; }
}

@media (prefers-reduced-motion: reduce) {
  .cc-box-out, .cc-box-in, .cc-text-out, .cc-text-in,
  .cc-table-out, .cc-table-in, .cc-skel-fade { animation: none; }
  .cc-prep .oh-root > *, .cc-prep .bp-top * { visibility: visible; }
}
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(.cc-frag) { animation: cc-frag-out 120ms ease both; }
  ::view-transition-new(.cc-frag) { animation: cc-frag-in 260ms cubic-bezier(.16, .9, .2, 1) both;
    transform-origin: top; }
}

/* ─── Second brain (/wiki) — rendered note markdown + resolved wikilinks ──────────────────────
   The body is markdown-rendered to HTML (web/wiki_render.py); style it on-brand within the four
   type sizes. Links stay greyscale-accent; dangling [[links]] read as muted/unfinished. */
.cc-wiki-prose { font-size: var(--t3); line-height: 1.7; color: var(--text); overflow-wrap: anywhere; }
.cc-wiki-prose h1, .cc-wiki-prose h2, .cc-wiki-prose h3 { color: var(--text); font-weight: 700;
  letter-spacing: .02em; margin: 1.4em 0 .5em; }
.cc-wiki-prose h1 { font-size: var(--t2); }
.cc-wiki-prose h2 { font-size: var(--t2); }
.cc-wiki-prose h3 { font-size: var(--t3); text-transform: uppercase; color: var(--text-2); }
.cc-wiki-prose > :first-child { margin-top: 0; }
.cc-wiki-prose p { margin: 0 0 .9em; }
.cc-wiki-prose ul, .cc-wiki-prose ol { margin: 0 0 .9em; padding-left: 1.4em; }
.cc-wiki-prose li { margin: .25em 0; }
.cc-wiki-prose a { color: var(--accent); text-decoration: none; border-bottom: 1px solid var(--line); }
.cc-wiki-prose a:hover { border-bottom-color: var(--accent); }
.cc-wiki-prose code { font-family: inherit; font-size: var(--t4); background: var(--bg-1);
  border: 1px solid var(--line); padding: .05em .35em; }
.cc-wiki-prose pre { background: var(--bg-1); border: 1px solid var(--line); padding: 12px;
  overflow-x: auto; margin: 0 0 .9em; }
.cc-wiki-prose pre code { background: none; border: 0; padding: 0; }
.cc-wiki-prose blockquote { margin: 0 0 .9em; padding-left: 12px; border-left: 2px solid var(--line);
  color: var(--text-2); }
/* Resolved wikilink; entity link; dangling link (to a note that doesn't exist yet). */
.cc-wiki-link { color: var(--accent); text-decoration: none; border-bottom: 1px solid var(--line); }
.cc-wiki-link:hover { border-bottom-color: var(--accent); }
.cc-wiki-link.entity { border-bottom-style: dashed; }
.cc-wiki-link.dangling { color: var(--text-2); border-bottom: 1px dashed var(--warn); cursor: help; }
/* Inline link to a live entity's detail page (a project/goal name inside a card or section). Quiet
   by default — only the hover underline marks it as clickable, so it doesn't shout inside cards. */
.cc-entity-link { color: var(--text); text-decoration: none; cursor: pointer; }
.cc-entity-link:hover { text-decoration: underline; text-underline-offset: 2px; }
@media (max-width: 900px) {
  .cc-wiki-detail { grid-template-columns: 1fr !important; }
}

/* ─── Second brain (/wiki) — Obsidian-style split: graph stage left, compact catalogue right ──
   The graph canvas (wiki-graph.js) fills the left half via the flex chain (main → inner → panel →
   stage, each flex:1 + min-height:0); the right half scrolls its own card list so the graph stays
   put. Cards are the compact variant — the catalogue lives in half the width here. */
.cc-wiki-page { display: flex; flex-direction: column; padding-bottom: 26px; }
.cc-wiki-page .bp-content-inner { flex: 1; display: flex; flex-direction: column; min-height: 0;
  width: 100%; max-width: 1680px; }
.cc-wiki-stage { flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 20px;
  align-items: stretch; }
.cc-wiki-left { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.cc-wiki-graph-panel { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.cc-wiki-graph-body { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 10px; }
.cc-wiki-graph { position: relative; flex: 1; min-height: 320px; border: 1px solid var(--line-soft);
  background: var(--bg-2); }
.cc-wiki-graph canvas { display: block; width: 100%; height: 100%; cursor: grab; }
.cc-wiki-graph canvas.is-node { cursor: pointer; }
.cc-wiki-graph canvas.is-grabbing { cursor: grabbing; }
.cc-wiki-graph-foot { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; flex: none;
  font-size: var(--t4); color: var(--text-2); }
.cc-graph-legend { display: flex; gap: 12px; flex-wrap: wrap; letter-spacing: .06em;
  text-transform: uppercase; }
.cc-graph-hint { margin-left: auto; white-space: nowrap; }
.cc-wiki-right { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.cc-wiki-cards { flex: 1; min-height: 0; overflow-y: auto; padding-right: 2px; }
.cc-wiki-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px; align-items: start; }
.cc-wiki-card.bp-spec { padding: 12px 14px; }
.cc-wiki-card .bp-spec-cap { margin-bottom: 9px; }
[data-density="comfy"] .cc-wiki-card.bp-spec { padding: 16px; }
.cc-note-excerpt { font-size: var(--t4); color: var(--text-2); line-height: 1.55;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
@media (max-width: 1100px) {
  /* Stack: the graph becomes a fixed-height band, the cards flow and the page scrolls normally. */
  .cc-wiki-page { display: block; }
  .cc-wiki-stage { display: flex; flex-direction: column; }
  .cc-wiki-graph-panel { flex: none; }
  .cc-wiki-graph { flex: none; height: 340px; min-height: 0; }
  .cc-wiki-cards { flex: none; overflow: visible; }
}

/* ─── Calendar (/calendar) — month grid + the "this week" home strip ─────────────────────────
   Blueprint cells: hairline borders, no radius, today framed in the mono accent, out-of-month days
   faded. Each tracked calendar wears one tone from the curated palette below (assigned/edited on
   /connectors/gcal); an event chip carries it as a left-tick (a small dot of colour, not a flood —
   the text stays mono). The same day-cell vocabulary scales down into the home "this week" strip. */

/* Curated calendar palette — eight muted, well-separated hues. Kept low-chroma so they read as
   quiet signal squares on both the dark and light blueprint backgrounds, not a rainbow. Tone keys
   (cal-1..cal-8) are mirrored in web/calendar_palette.py. */
:root {
  --cal-1: oklch(0.68 0.12 250);  /* Blue    */
  --cal-2: oklch(0.71 0.10 195);  /* Teal    */
  --cal-3: oklch(0.72 0.13 150);  /* Green   */
  --cal-4: oklch(0.72 0.09 120);  /* Olive   */
  --cal-5: oklch(0.77 0.12 75);   /* Amber   */
  --cal-6: oklch(0.66 0.16 25);   /* Rose    */
  --cal-7: oklch(0.64 0.16 330);  /* Magenta */
  --cal-8: oklch(0.63 0.13 295);  /* Violet  */
}

.cc-cal-toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.cc-cal-title { font-size: var(--t2); font-weight: 700; color: var(--text); letter-spacing: .04em;
  text-transform: uppercase; }
.cc-cal-spacer { flex: 1; }

.cc-cal-head { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; margin-bottom: 8px; }
.cc-cal-head span { font-size: var(--t4); color: var(--text-2); letter-spacing: .08em;
  text-transform: uppercase; padding-left: 2px; }

/* The month is a stack of week rows; each row carries the 7 day cells + an absolutely-positioned
   overlay that draws multi-day bars + location ribbons ACROSS cells (the grid itself stays put). */
.cc-cal-weeks { display: flex; flex-direction: column; gap: 8px; }
.cc-cal-week { position: relative; }
.cc-cal-grid7 { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; }
.cc-cal-cell { border: 1px solid var(--line); background: var(--bg-2); min-height: 106px;
  padding: 7px 8px; display: flex; flex-direction: column; gap: 5px; min-width: 0; }
/* reserves the vertical band the week's ribbons/bars occupy, so single-day chips sit below them */
.cc-cal-spanpad { flex: none; height: var(--span-h, 0px); }
.cc-cal-cell.is-out { opacity: .42; }
.cc-cal-cell.is-today { border-color: var(--accent); }
.cc-cal-daynum { font-size: var(--t4); color: var(--text-2); font-variant-numeric: tabular-nums; }
.cc-cal-cell.is-today .cc-cal-daynum { color: var(--accent); font-weight: 700; }

/* Each event chip is its own faintly tone-tinted block (no link underline) — the tint + the colour
   tick delimit one event from the next, calmer than an underline. */
.cc-cal-ev { display: flex; align-items: baseline; gap: 6px; font-size: var(--t4); color: var(--text);
  border-left: 2px solid var(--cal-tone, var(--accent-soft)); padding: 1px 5px 1px 6px;
  line-height: 1.4; min-width: 0; text-decoration: none;
  background: color-mix(in oklch, var(--cal-tone, var(--accent)) 10%, transparent); }
.cc-cal-ev:hover { background: color-mix(in oklch, var(--cal-tone, var(--accent)) 22%, transparent); }
.cc-cal-ev .t { color: var(--text-2); flex: none; font-variant-numeric: tabular-nums; }
.cc-cal-ev .x { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* All-day events have no time anchor, so give them a slightly stronger wash of their tone. */
.cc-cal-ev.is-allday {
  background: color-mix(in oklch, var(--cal-tone, var(--accent)) 20%, transparent); }
.cc-cal-more { font-size: var(--t4); color: var(--text-2); padding-left: 6px; }
[data-density="comfy"] .cc-cal-cell { min-height: 126px; padding: 10px; }

/* Per-week overlay: bars + ribbons live in a 7-col grid laid exactly over the week's cells, with
   one grid row per lane (heights set inline). It starts below the day-number row. */
.cc-cal-overlay { position: absolute; left: 0; right: 0; top: var(--ovl-top, 25px);
  display: grid; grid-template-columns: repeat(7, 1fr); column-gap: 8px; pointer-events: none; }
.cc-cal-overlay > a { pointer-events: auto; align-self: start; min-width: 0; text-decoration: none;
  overflow: hidden; white-space: nowrap; }
[data-density="comfy"] .cc-cal-week { --ovl-top: 28px; }

/* Multi-day event bar — a chip stretched across the days it covers. */
.cc-cal-bar { display: flex; align-items: center; gap: 6px; height: 19px; margin: 0 1px;
  padding: 0 6px; font-size: var(--t4); color: var(--text);
  border-left: 2px solid var(--cal-tone, var(--accent));
  background: color-mix(in oklch, var(--cal-tone, var(--accent)) 24%, var(--bg-2)); }
.cc-cal-bar .t { color: var(--text-2); flex: none; font-variant-numeric: tabular-nums; }
.cc-cal-bar .x { overflow: hidden; text-overflow: ellipsis; }
.cc-cal-bar.cont-l { margin-left: 0; border-left: none; padding-left: 8px; }
.cc-cal-bar.cont-r { margin-right: 0; }

/* Location ribbon — a thin tone rectangle FRAMING the days you're there (full cell height, raised
   over the date row), with the place name riding on the top edge of the first cell. Notes travel
   without taking an event slot. The frame is its own full-height overlay layer. */
.cc-cal-frames { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(7, 1fr);
  grid-template-rows: 1fr; column-gap: 8px; pointer-events: none; z-index: 1; }
.cc-cal-ribbon { grid-row: 1; align-self: stretch; position: relative; pointer-events: none;
  border: 1.5px solid var(--cal-tone, var(--accent)); }
.cc-cal-ribbon.cont-l { border-left: none; }
.cc-cal-ribbon.cont-r { border-right: none; }
/* the label straddles the top border (legend-style), in the bright calendar tone — not washed out */
.cc-cal-ribbon-tag { position: absolute; top: 0; left: 6px; transform: translateY(-50%);
  display: inline-flex; align-items: center; gap: 4px; height: 13px; padding: 0 5px;
  max-width: calc(100% - 12px); background: var(--bg-1); color: var(--cal-tone, var(--accent));
  font-size: 9px; letter-spacing: .05em; text-transform: uppercase; white-space: nowrap;
  text-decoration: none; pointer-events: auto; }
.cc-cal-ribbon-tag .bpi-svg { color: var(--cal-tone, var(--accent)); flex: none; }
.cc-cal-ribbon-tag .x { overflow: hidden; text-overflow: ellipsis; }

/* Calendar legend — name + tone swatch for each tracked calendar, under the toolbar. */
.cc-cal-legend { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: -4px 0 16px; }
.cc-cal-legend-item { display: inline-flex; align-items: center; gap: 7px; font-size: var(--t4);
  color: var(--text-2); letter-spacing: .02em; }
.cc-cal-dot { width: 9px; height: 9px; flex: none; background: var(--cal-tone, var(--accent));
  border: 1px solid color-mix(in oklch, var(--cal-tone, var(--accent)) 55%, var(--line)); }

/* "This week" home strip — the month-grid day cell, scaled for the bento (a wide panel). */
.cc-week-strip { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.cc-week-day { border: 1px solid var(--line); background: var(--bg-2); min-height: 88px; padding: 6px;
  display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.cc-week-day.is-today { border-color: var(--accent); }
.cc-week-dow { display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--t4); color: var(--text-2); letter-spacing: .06em; text-transform: uppercase; }
.cc-week-day.is-today .cc-week-dow { color: var(--accent); }
.cc-week-dow b { color: var(--text); font-weight: 700; }
.cc-week-ev { font-size: var(--t4); color: var(--text); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; border-left: 2px solid var(--cal-tone, var(--accent-soft));
  padding-left: 5px; }
.cc-week-empty { font-size: var(--t4); color: var(--text-2); opacity: .5; }

/* Per-calendar colour picker on /connectors/gcal — a row per calendar (checkbox + a strip of tone
   swatches). The list does NOT scroll (unlike the Todoist pickers) so a swatch row never clips. */
.cc-cal-pick-list { margin-top: 10px; display: flex; flex-direction: column; gap: 2px;
  border: 1px solid var(--line); padding: 6px; }
.cc-cal-pick-row { display: flex; align-items: center; gap: 12px; padding: 4px 6px; }
.cc-cal-pick-row .bp-choice { flex: 1; min-width: 0; justify-content: flex-start; }
.cc-sw-group { display: inline-flex; gap: 4px; flex: none; }
.cc-sw { width: 16px; height: 16px; padding: 0; flex: none; cursor: pointer; background: var(--sw);
  border: 1px solid color-mix(in oklch, var(--sw) 55%, var(--line)); opacity: .45;
  transition: opacity .12s ease; }
.cc-sw:hover { opacity: .8; }
.cc-sw.on { opacity: 1; box-shadow: 0 0 0 1px var(--bg-2), 0 0 0 2px var(--sw); }
/* The swatch dot used inline in the legend/help text + the calendar dropdown options. */
.cc-swatch { display: inline-block; width: 10px; height: 10px; vertical-align: -1px;
  background: var(--sw); border: 1px solid color-mix(in oklch, var(--sw) 55%, var(--line)); }

/* Custom select — a visible keyboard-focus ring + the arrow-key "active" option (blocks.js). */
.bp-select-btn:focus-visible { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent);
  outline: none; }
.bp-menu-item.active { background: var(--accent-soft); color: var(--text); }

/* Two-up form rows (the event modal's start/end date + time pairs). The default .bp-field
   min-width (220px) would push the second field out of the ~460px modal — let them shrink. */
.cc-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.cc-form-row .bp-field { min-width: 0; }

@media (max-width: 760px) {
  .cc-cal-cell { min-height: 78px; }
  .cc-cal-ev .t { display: none; }
}

/* ---- Phone kiosk: large, touch-first, portrait-friendly (the sideloaded webview) ---- */
/* Breathing room top + bottom so content clears the notch / status bar / gesture area on a phone
   (env(safe-area-inset-*) honours the cutout — needs viewport-fit=cover, set on the kiosk page). */
/* The shared top bar is a fixed 46px, too short for the 3-line clock → it clipped. Let the kiosk
   bar grow to fit, pad it below the notch, and shrink the clock so it sits cleanly inside. */
.bp-top.cc-kiosk-top {
  height: auto;
  min-height: 58px;
  align-items: center;
  padding-top: calc(env(safe-area-inset-top, 0px) + 12px);
  padding-bottom: 10px;
}
.cc-kiosk-top .oh-clock { font-size: var(--t2); line-height: 1.15; }
.cc-kiosk-top .oh-date,
.cc-kiosk-top .oh-status-line { font-size: var(--t4); }
.cc-kiosk .bp-content-inner {
  padding-top: 28px;
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 56px);
}
.cc-kiosk .cc-kiosk-presence { display: flex; align-items: center; gap: 12px; margin: 18px 0 6px; }
.cc-kiosk .cc-prompt-card { padding: 16px; }
.cc-kiosk .cc-prompt-card .cc-prompt-title { font-size: var(--t2); font-weight: 500; }
/* Big tap targets — an old phone behind glass needs forgiving hit areas. */
.cc-kiosk .cc-prompt-card .bp-btn { min-height: 46px; padding: 0 20px; font-size: var(--t3); }
.cc-kiosk form { margin: 0; }

/* Battery indicator in the kiosk top bar. */
.cc-kiosk-battery { display: flex; align-items: center; gap: 4px; font-size: var(--t4);
  color: var(--text-2); margin-right: 12px; white-space: nowrap; }
.cc-kiosk-battery.warn { color: #d4a017; }
.cc-kiosk-battery.err { color: var(--tone-err); }

/* App launcher grid — 2 columns of square tiles. */
.cc-kiosk-app-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 22px; }
.cc-kiosk-app-tile { aspect-ratio: 1; border: 1px solid var(--line); display: flex;
  flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  text-decoration: none; color: var(--text);
  transition: border-color .14s ease, background .14s ease; cursor: pointer; position: relative; }
.cc-kiosk-app-tile:hover, .cc-kiosk-app-tile:active { border-color: var(--accent);
  background: var(--accent-soft); }
.cc-kiosk-app-tile.stub { opacity: .38; pointer-events: none; }
.cc-kiosk-app-tile-label { font-size: var(--t3); font-weight: 600; text-transform: uppercase;
  letter-spacing: .08em; }
.cc-kiosk-app-tile-badge { position: absolute; top: 10px; right: 10px; }

/* Back nav on sub-pages (e.g. watchlist). */
.cc-kiosk-back { display: inline-flex; align-items: center; gap: 6px; text-decoration: none;
  color: var(--text-2); font-size: var(--t4); text-transform: uppercase; letter-spacing: .08em;
  margin-bottom: 18px; }
.cc-kiosk-back:hover { color: var(--text); }

/* ── /hermes full-width tab layout ─────────────────────────────────────────── */

/* Page shell: full width, no max-width cap, fills viewport height below topbar */
.cc-hermes-page {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 0 20px 16px;
  box-sizing: border-box;
  width: 100%;
}

/* Section header row: title + meta on left, tab buttons on right */
.cc-hermes-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 0 12px;
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}
.cc-hermes-sec-n { color: var(--accent); font-size: var(--t4); margin-right: 2px; }
.cc-hermes-sec-t { font-size: var(--t3); font-weight: 600; text-transform: uppercase;
  letter-spacing: .08em; }
.cc-hermes-meta  { font-size: var(--t4); color: var(--text-2); margin-left: 8px; }
.cc-hermes-tabs-nav { margin-left: auto; display: flex; gap: 0; }

/* Tab buttons */
.cc-tab-btn {
  font-family: inherit;
  font-size: var(--t4);
  text-transform: uppercase;
  letter-spacing: .08em;
  background: none;
  border: 1px solid var(--line);
  color: var(--text-2);
  padding: 4px 16px;
  cursor: pointer;
  margin-left: -1px; /* collapse borders */
}
.cc-tab-btn:first-child { margin-left: 0; }
.cc-tab-btn.cc-tab-active {
  border-color: var(--accent);
  color: var(--accent);
  z-index: 1;
  position: relative;
}
.cc-tab-btn:hover:not(.cc-tab-active) { color: var(--text); border-color: var(--text-2); }

/* Tab content area: fills remaining height */
.cc-hermes-tab-wrap {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin-top: 0;
}
.cc-hermes-tab {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.cc-hermes-tab[hidden] { display: none !important; }

/* Session selector bar — horizontal strip above the terminal */
.cc-sess-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-bottom: 1px solid var(--line);
  border-top: 1px solid var(--line);
  background: var(--bg-1);
  flex-shrink: 0;
  overflow-x: auto;
  white-space: nowrap;
}
.cc-sess-bar-label { font-size: var(--t4); color: var(--text-2); margin-right: 4px; }

/* Individual session chips in the bar */
.cc-sess-chip {
  font-family: inherit;
  font-size: var(--t4);
  background: none;
  border: 1px solid var(--line);
  color: var(--text-2);
  padding: 2px 10px;
  cursor: pointer;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cc-sess-chip:hover  { border-color: var(--accent); color: var(--accent); }
.cc-sess-chip.active { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }

/* Chip + its hover-revealed × delete box. The × is a sibling overlaid on the chip's right edge
   (room reserved via padding so it never covers the title), revealed on hover/focus like a
   browser tab's close button — no layout shift, and never a button nested inside a button. */
.cc-sess-chip-wrap { position: relative; display: inline-flex; flex-shrink: 0; }
.cc-sess-chip-wrap .cc-sess-chip { max-width: 200px; padding-right: 22px; }
.cc-sess-x {
  position: absolute;
  right: 1px; top: 1px; bottom: 1px;
  display: flex;
  align-items: center;
  padding: 0 6px;
  font-family: inherit;
  font-size: var(--t3);
  line-height: 1;
  background: var(--bg-1);
  border: 0;
  color: var(--text-2);
  cursor: pointer;
  opacity: 0;
  transition: opacity .12s linear;
}
.cc-sess-chip-wrap:hover .cc-sess-x,
.cc-sess-chip-wrap:focus-within .cc-sess-x { opacity: 1; }
.cc-sess-chip-wrap:has(.cc-sess-chip.active) .cc-sess-x { background: var(--accent-soft); }
.cc-sess-x:hover { color: var(--tone-err); }

/* New-session button */
.cc-sess-new {
  font-family: inherit;
  font-size: var(--t4);
  background: none;
  border: 1px solid var(--line);
  color: var(--text-2);
  padding: 2px 10px;
  cursor: pointer;
  flex-shrink: 0;
}
.cc-sess-new:hover { border-color: var(--accent); color: var(--accent); }

/* Status indicator */
.cc-term-status { font-size: var(--t4); color: var(--text-2); margin-left: auto; flex-shrink: 0; }
.cc-term-status.ok  { color: var(--tone-ok);  }
.cc-term-status.err { color: var(--tone-err); }

/* xterm container — fills all remaining height, stable dimensions for correct rendering */
#cc-hermes-term {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  /* bg-0 so xterm background blends */
  background: var(--bg-0);
  /* Small inset so the term canvas never clips the border */
  padding: 4px;
  box-sizing: border-box;
}

/* Board tab: scrollable */
.cc-hermes-board-tab {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 0;
}

/* ============================================================
   HOME — editable bento (free 2D grid; web/home_widgets.py owns the sizing model)
   Overrides operhud.css's fixed bento. 12 columns × a base row unit (--oh-unit), dense-packed.
   Each tile spans --w columns × --h row units and FILLS that cell (no align-items:center, no
   per-tile absolute height) — so tiles never float with gaps and never scroll: the widget's row
   count is chosen so its content always fits.
   ============================================================ */
.oh-bento {
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: var(--oh-unit, 40px);
  grid-auto-flow: row dense;
  align-items: stretch;
}
[data-density="comfy"] .oh-bento { --oh-unit: 44px; gap: 18px; }
.oh-bento > .oh-w {
  grid-column: span var(--w, 4);
  grid-row: span var(--h, 4);
  min-height: 0; min-width: 0; overflow: hidden;   /* fills its cell; clips rather than scrolls */
}
/* no scrolling inside a home tile — bodies are already capped, so neutralise inherited scroll */
.oh-bento .oh-list, .oh-bento .oh-readout, .oh-bento .oh-tasklist { overflow: visible; }

/* narrow screens: one column, natural height (no squeeze, no cut, no scroll) */
@media (max-width: 720px) {
  .oh-bento { grid-template-columns: 1fr; grid-auto-rows: auto; }
  .oh-bento > .oh-w {
    grid-column: 1 / -1; grid-row: auto;
    min-height: calc(var(--h, 4) * var(--oh-unit, 40px));
  }
}

/* ---- edit mode: chrome injected by home.js, present ONLY while editing ---- */
.oh-edit-row { display: flex; align-items: center; gap: 12px; margin-top: 14px; }

.oh-bento.is-editing .oh-w { position: relative; }   /* anchor the absolute handles */
.oh-bento.is-editing > .oh-w { outline: 1px dashed var(--accent-line); outline-offset: -1px; }
.oh-bento.is-editing > .oh-w.is-grabbing { opacity: .4; }
/* freeze a tile's own buttons/forms/links while editing — but NOT the injected handles */
.oh-bento.is-editing > .oh-w > :not(.oh-w-grip):not(.oh-w-remove):not(.oh-w-resize),
.oh-trayed > :not(.oh-w-grip) { pointer-events: none; user-select: none; }

/* the three injected handles: drag (top-left), remove × (top-right), resize corner (bottom-right) */
.oh-w-grip, .oh-w-remove, .oh-w-resize {
  position: absolute; z-index: 6; display: grid; place-items: center; touch-action: none;
  background: color-mix(in oklch, var(--bg-1) 84%, var(--accent) 16%);
  border: 1px solid var(--accent-line); color: var(--text-1); font-family: var(--mono);
}
.oh-w-grip { top: 5px; left: 5px; width: 22px; height: 22px; cursor: grab; }
.oh-w-grip:active { cursor: grabbing; }
.oh-w-remove { top: 5px; right: 5px; width: 22px; height: 22px; cursor: pointer; font-size: var(--t3); line-height: 1; }
.oh-w-remove:hover { border-color: var(--err); color: var(--err); }
.oh-w-resize { right: 4px; bottom: 4px; width: 18px; height: 18px; cursor: nwse-resize; }
.oh-w-grip:hover, .oh-w-resize:hover { border-color: var(--accent); color: var(--accent); }
@media (max-width: 720px) { .oh-w-resize { display: none; } }   /* meaningless when stacked */

/* floating Reset / Cancel / Save toolbar (created on enter, removed on exit → never lingers) */
.oh-edit-fab {
  position: fixed; right: 22px; bottom: 22px; z-index: 60;
  display: flex; align-items: center; gap: 8px;
  padding: 9px 11px; border: 1px solid var(--accent-line); background: var(--accent-soft);
  box-shadow: 0 6px 26px rgba(0, 0, 0, .4);
}
.oh-edit-fab .oh-fab-hint {
  font-size: var(--t4); letter-spacing: .04em; color: var(--text-2); margin-right: 4px;
}

/* the tray of removed widgets, revealed below the grid only in edit mode */
.oh-tray {
  display: flex; flex-wrap: wrap; gap: 13px; align-items: flex-start;
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line);
}
.oh-tray[hidden] { display: none; }   /* explicit — class display:flex would beat the UA [hidden] */
.oh-tray::before {
  content: "TRAY · drag a tile up to add it back"; flex: 1 0 100%;
  font-size: var(--t4); letter-spacing: .08em; text-transform: uppercase; color: var(--text-2);
}
.oh-trayed {
  position: relative; width: 230px; height: 116px; overflow: hidden;
  outline: 1px dashed var(--accent-line); outline-offset: -1px;
}
/* a trayed tile is already removed — only its grip (drag up to re-add) stays live */
.oh-trayed .oh-w-remove, .oh-trayed .oh-w-resize { display: none; }

/* ------------------------------------------------------------
   SCRATCHPAD — the brainstorm board (staging sandbox with Luna)
   ------------------------------------------------------------ */
/* full-bleed, full-height page: the stage fills the viewport both ways (no 1260px cap here) */
.cc-sb-main { display: flex; flex-direction: column; padding-bottom: 22px; }
.cc-sb-main .bp-content-inner {
  flex: 1; min-height: 0; max-width: none; display: flex; flex-direction: column;
}

.cc-sb-board {
  display: flex; flex-direction: column; gap: 14px; min-height: 0; min-width: 0;
}
.cc-sb-head { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.cc-sb-brand { display: flex; flex-direction: column; gap: 3px; }
.cc-sb-brand b { font-size: var(--t2); font-weight: 600; letter-spacing: .01em; }
.cc-sb-sub { font-size: var(--t4); color: var(--text-2); letter-spacing: .04em; }
.cc-sb-controls { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.cc-sb-controls form { display: inline; }
.cc-sb-staged {
  display: inline-flex; align-items: center; gap: 7px; font-size: var(--t4);
  color: var(--text-1); letter-spacing: .06em; text-transform: uppercase;
}
.cc-sb-dot { width: 6px; height: 6px; background: var(--accent); display: inline-block; }

/* five fixed lanes in two rows: Tasks+Calendar split the top half, the other three the bottom.
   Each row flexes to half the board's height; a lane scrolls its own cards when they overflow. */
.cc-sb-lanes { display: grid; gap: 14px; flex: 1; min-height: 0; }
.cc-sb-lanes-top { grid-template-columns: repeat(2, 1fr); }
.cc-sb-lanes-bottom { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1100px) {
  .cc-sb-lanes-top, .cc-sb-lanes-bottom { grid-template-columns: 1fr 1fr; }
}
.cc-sb-lane {
  display: flex; flex-direction: column; gap: 10px; min-width: 0; min-height: 0;
  border: 1px solid var(--line); background: var(--bg-1); padding: 12px; overflow: hidden;
}
.cc-sb-lane-head { display: flex; align-items: center; gap: 9px; }
.cc-sb-lane-ico { color: var(--text-1); display: inline-flex; }
.cc-sb-lane-meta { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.cc-sb-lane-name { font-size: var(--t3); font-weight: 600; color: var(--text); }
.cc-sb-lane-blurb { font-size: var(--t4); color: var(--text-2); }
.cc-sb-lane-count {
  margin-left: auto; font-size: var(--t4); color: var(--text-2);
  border: 1px solid var(--line); padding: 0 6px; font-variant-numeric: tabular-nums;
}
.cc-sb-lane-head { flex: 0 0 auto; }
.cc-sb-cards { display: flex; flex-direction: column; gap: 9px; flex: 1; min-height: 0; overflow-y: auto; }
.cc-sb-empty {
  font-size: var(--t4); color: var(--text-2); letter-spacing: .06em; text-transform: lowercase;
  border: 1px dashed var(--line-soft); padding: 12px; text-align: center;
}

/* one staged card — hairline, 0 radius (the "hud" style, not a tilted post-it) */
.cc-sb-card {
  border: 1px solid var(--line); border-left: 2px solid var(--accent-line);
  background: var(--bg-2); padding: 9px 10px; display: flex; flex-direction: column; gap: 5px;
}
.cc-sb-card-head { display: flex; align-items: center; gap: 6px; }
/* the type tag (Goal/Project/Target/Event/…) — so a mixed lane is legible at a glance */
.cc-sb-card-kind {
  font-size: var(--t4); color: var(--text-1); letter-spacing: .07em; text-transform: uppercase;
  border: 1px solid var(--line-soft); padding: 0 5px; line-height: 1.5;
}
.cc-sb-card-title { font-size: var(--t3); color: var(--text); line-height: 1.4; }
.cc-sb-card-ref, .cc-sb-card-meta { font-size: var(--t4); color: var(--text-2); }
.cc-sb-card-meta { letter-spacing: .02em; }
.cc-sb-card-ref { letter-spacing: .03em; }
.cc-sb-card-err { font-size: var(--t4); color: var(--err); letter-spacing: .02em; }
.cc-sb-card[data-state="committed"] { border-left-color: var(--ok); opacity: .7; }
.cc-sb-card[data-state="failed"] { border-left-color: var(--err); }
.cc-sb-card[data-state="resolved"] { border-left-color: var(--line-soft); opacity: .6; }

/* card head: badge on the left, hover-revealed actions pushed right */
.cc-sb-card-actions { margin-left: auto; display: flex; gap: 2px; }
.cc-sb-card-actions form { display: inline; }
/* the title is an inline edit form — input reads like static text until focused */
.cc-sb-card-edit { display: flex; align-items: center; gap: 6px; }
/* the display title: kanban-title size, wraps to at most 2 lines (no sharp cut) */
.cc-sb-card-title {
  font-size: var(--t3); line-height: 1.4; color: var(--text); cursor: text; padding: 2px 4px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere;
}
/* with JS (cc-can-edit) the edit form hides until the title is clicked; without JS both render */
.cc-sb-card.cc-can-edit .cc-sb-card-edit { display: none; }
.cc-sb-card.cc-can-edit.is-editing .cc-sb-card-edit { display: flex; }
.cc-sb-card.cc-can-edit.is-editing .cc-sb-card-title { display: none; }
.cc-sb-card.is-editing .cc-sb-card-save { opacity: 1; }
.cc-sb-card-input {
  flex: 1; min-width: 0; background: transparent; border: 1px solid transparent;
  color: var(--text); line-height: 1.4; padding: 2px 4px; font: inherit;
  font-size: var(--t3);  /* after `font: inherit` — the shorthand resets size (the too-big bug) */
}
.cc-sb-card-input:hover { border-color: var(--line-soft); }
.cc-sb-card-input:focus { border-color: var(--accent-line); background: var(--bg-1); outline: none; }
.cc-sb-card-save { opacity: 0; }
.cc-sb-card:focus-within .cc-sb-card-save { opacity: 1; }

.cc-sb-commit-notice {
  border: 1px solid var(--err); border-left: 2px solid var(--err); background: var(--bg-2);
  color: var(--text); font-size: var(--t4); padding: 8px 10px; letter-spacing: .02em;
}
.cc-sb-body { display: flex; flex-direction: column; gap: 14px; flex: 1; min-height: 0; }

/* page: chat pinned to the left at a fixed width + board filling the rest, both full height.
   Stacks (and releases its height) under a narrow viewport. */
.cc-sb-page {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: 360px 1fr; gap: 20px; align-items: stretch;
}
@media (max-width: 860px) {
  .cc-sb-page { grid-template-columns: 1fr; min-height: 0; height: auto; display: flex; flex-direction: column; }
}

/* the chat-with-Luna pane — full height, the message feed scrolls, the send box stays pinned */
.cc-sb-chat { display: flex; flex-direction: column; gap: 12px; min-height: 0; }
.cc-sb-chat-head { display: flex; align-items: center; gap: 9px; flex: 0 0 auto; }
.cc-sb-msgs { display: flex; flex-direction: column; gap: 12px; flex: 1; min-height: 0; overflow-y: auto; }
.cc-sb-msgs-empty {
  font-size: var(--t4); color: var(--text-2); letter-spacing: .04em;
  border: 1px dashed var(--line-soft); padding: 12px; text-align: center;
}
.cc-sb-msg { display: flex; flex-direction: column; gap: 3px; }
.cc-sb-msg-who {
  font-size: var(--t4); color: var(--text-2); letter-spacing: .08em; text-transform: uppercase;
}
.cc-sb-msg-text {
  font-size: var(--t3); color: var(--text); line-height: 1.5; border: 1px solid var(--line);
  border-left: 2px solid var(--line-soft); background: var(--bg-2); padding: 7px 9px;
}
/* your line: a verbatim, clearly-quoted echo — inset, accent quote bar, italic, whitespace kept */
.cc-sb-msg-user { margin-left: 20px; }
.cc-sb-msg-user .cc-sb-msg-who { color: var(--accent); }
.cc-sb-msg-user .cc-sb-msg-text {
  border-left: 3px solid var(--accent); background: var(--bg-1);
  color: var(--text-1); font-style: italic; white-space: pre-wrap;
}
/* Luna's line: rendered markdown, full width, accent hairline */
.cc-sb-msg-luna .cc-sb-msg-text { border-left-color: var(--accent-line); }

/* markdown inside Luna's bubble — tight, on-brand (no rounded corners, mono code, hairline rules) */
.cc-sb-md > :first-child { margin-top: 0; }
.cc-sb-md > :last-child { margin-bottom: 0; }
.cc-sb-md p { margin: 0 0 8px; }
.cc-sb-md ul, .cc-sb-md ol { margin: 0 0 8px; padding-left: 18px; }
.cc-sb-md li { margin: 2px 0; }
.cc-sb-md li::marker { color: var(--text-2); }
.cc-sb-md h1, .cc-sb-md h2, .cc-sb-md h3, .cc-sb-md h4 {
  font-size: var(--t3); font-weight: 600; color: var(--text); margin: 10px 0 6px;
  letter-spacing: .02em;
}
.cc-sb-md strong { color: var(--text); font-weight: 600; }
.cc-sb-md em { color: var(--text-1); }
.cc-sb-md a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.cc-sb-md code {
  font-family: var(--mono); font-size: .92em; background: var(--bg-1);
  border: 1px solid var(--line); padding: 0 4px;
}
.cc-sb-md pre {
  background: var(--bg-1); border: 1px solid var(--line); border-left: 2px solid var(--accent-line);
  padding: 8px 10px; margin: 0 0 8px; overflow-x: auto;
}
.cc-sb-md pre code { border: 0; background: none; padding: 0; }
.cc-sb-md blockquote {
  margin: 0 0 8px; padding-left: 10px; border-left: 2px solid var(--line-soft); color: var(--text-1);
}
.cc-sb-md hr { border: 0; border-top: 1px solid var(--line); margin: 10px 0; }

.cc-sb-chat-form { display: flex; gap: 8px; align-items: center; flex: 0 0 auto; }
.cc-sb-chat-input {
  flex: 1; min-width: 0; background: var(--bg-1); border: 1px solid var(--line); color: var(--text);
  font: inherit; font-size: var(--t3); padding: 7px 9px;
}
.cc-sb-chat-input:focus { border-color: var(--accent-line); outline: none; }
/* send box while a turn is in flight — visibly inert so it's clear you're waiting on Luna */
.cc-sb-chat-input:disabled { opacity: .55; cursor: default; }
.cc-sb-chat-form button:disabled { opacity: .4; pointer-events: none; }
/* "Luna is thinking…" — three dots that pulse while the (slow) turn is in flight. Compositor-only
   (opacity/transform), so it stays cheap per ui-motion-calm-no-jitter. */
.cc-sb-dots { display: inline-flex; gap: 5px; align-items: center; height: 1em; }
.cc-sb-dots i {
  width: 5px; height: 5px; background: var(--accent-line); border-radius: 0;
  opacity: .35; animation: cc-sb-blink 1.1s ease-in-out infinite;
}
.cc-sb-dots i:nth-child(2) { animation-delay: .18s; }
.cc-sb-dots i:nth-child(3) { animation-delay: .36s; }
@keyframes cc-sb-blink {
  0%, 80%, 100% { opacity: .35; transform: scale(.85); }
  40% { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) { .cc-sb-dots i { animation: none; opacity: .6; } }
/* commit-report modal: a summary line over the failed-card table, with the retry/close footer. */
.cc-sb-report-sum { font-size: var(--t3); color: var(--text-2); margin-bottom: 12px; line-height: 1.5; }
.cc-sb-report-foot { display: flex; gap: 8px; justify-content: flex-end; }
/* ── Luna web chat ──────────────────────────────────────────────────────────────────────────
   A first-class conversational page: a history sidebar (dedicated sections by origin) + the chat
   pane. Full-height like the scratchpad; the feed + composer reuse the .cc-sb-msg* chat styles. */
.cc-luna-main { display: flex; flex-direction: column; padding-bottom: 22px; }
/* Use the horizontal space: an explicit 90% width — the base ``margin: 0 auto`` would otherwise
   shrink-wrap this flex-column item to the composer's width and centre it as a narrow strip. */
.cc-luna-main .bp-content-inner {
  flex: 1; min-height: 0; max-width: none; width: 90%; margin: 0 auto;
  display: flex; flex-direction: column;
}
.cc-luna-page {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: 300px 1fr; gap: 20px; align-items: stretch;
}
/* keep replies readable inside the now-wide pane — bubbles cap at a comfortable measure, and
   your own line right-aligns (classic chat), Luna's stays left */
.cc-luna-pane .cc-sb-msg-text { max-width: 860px; }
.cc-luna-pane .cc-sb-msg-user { align-items: flex-end; margin-left: auto; }
/* desktop: the drawer chrome doesn't exist */
.cc-luna-drawer-btn, .cc-luna-scrim { display: none; }

/* phone: the chat IS the page; conversations slide in as an off-canvas drawer */
@media (max-width: 860px) {
  .cc-luna-main .bp-content-inner { width: 100%; }
  .cc-luna-main { padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
  .cc-luna-page { display: flex; flex-direction: column; min-height: 0; }
  .cc-luna-pane { flex: 1; min-height: 0; }
  .cc-luna-drawer-btn { display: inline-flex; }
  /* one-line header: a long thread title must not shove Call/Speak off-screen */
  .cc-luna-pane-head { align-items: center; }
  .cc-luna-pane-title { flex: 1; min-width: 0; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; }
  .cc-luna-sidebar {
    position: fixed; z-index: 120; top: 0; bottom: 0; left: 0;
    width: min(320px, 85vw); padding: calc(14px + env(safe-area-inset-top)) 14px 14px;
    background: var(--bg-1); border-right: 1px solid var(--line);
    transform: translateX(-102%); transition: transform .18s ease;
    overflow-y: auto;
  }
  .cc-luna-page.is-drawer-open .cc-luna-sidebar { transform: translateX(0); }
  .cc-luna-scrim { position: fixed; inset: 0; z-index: 110;
    background: color-mix(in oklch, var(--bg) 55%, transparent); }
  .cc-luna-page.is-drawer-open .cc-luna-scrim { display: block; }
}
@media (prefers-reduced-motion: reduce) { .cc-luna-sidebar { transition: none; } }

/* sidebar: New chat + the dedicated origin sections, the list scrolls if it overflows */
.cc-luna-sidebar { display: flex; flex-direction: column; gap: 12px; min-height: 0; }
.cc-luna-side-head b { font-size: var(--t2); font-weight: 600; letter-spacing: .01em; }
.cc-luna-new { flex: 0 0 auto; }
.cc-luna-new button { width: 100%; justify-content: center; }
.cc-luna-sections { display: flex; flex-direction: column; gap: 14px; flex: 1; min-height: 0; overflow-y: auto; }
/* a section is a native <details>: the <summary> is the collapsible head (caret rotates on open) */
.cc-luna-section { display: flex; flex-direction: column; gap: 5px; }
.cc-luna-section-head {
  display: flex; align-items: center; gap: 6px; cursor: pointer; user-select: none;
  font-size: var(--t4); color: var(--text-2); letter-spacing: .08em; text-transform: uppercase;
  padding: 2px 0; list-style: none;
}
.cc-luna-section-head::-webkit-details-marker { display: none; }  /* drop the native triangle */
.cc-luna-section-head::before {
  content: "›"; display: inline-block; flex: 0 0 auto; font-size: var(--t3);
  transition: transform .14s ease; color: var(--text-3, var(--text-2));
}
.cc-luna-section[open] > .cc-luna-section-head::before { transform: rotate(90deg); }
.cc-luna-section-head:hover { color: var(--text); }
.cc-luna-section-label { flex: 1; }
.cc-luna-section-count {
  flex: 0 0 auto; font-size: var(--t4); color: var(--text-3, var(--text-2)); letter-spacing: .04em;
}
.cc-luna-section-muted .cc-luna-section-head { color: var(--text-3, var(--text-2)); opacity: .8; }
.cc-luna-section-rows { display: flex; flex-direction: column; gap: 4px; padding-top: 4px; }
/* a conversation row — a web thread (link + delete) or a clickable read-only foreign one */
.cc-luna-sess {
  display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left;
  font-family: inherit; font-size: var(--t3); color: var(--text-1);
  background: var(--bg-2); border: 1px solid var(--line); border-left: 2px solid var(--line-soft);
  padding: 7px 9px; cursor: pointer;
}
.cc-luna-sess:hover { border-left-color: var(--accent-line); color: var(--text); }
.cc-luna-sess.is-active { border-left-color: var(--accent); color: var(--text); background: var(--bg-1); }
/* the clickable label of a web-chat row (the delete form sits beside it) */
.cc-luna-sess-link {
  flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 8px;
  color: inherit; font: inherit; text-decoration: none;
}
.cc-luna-sess-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cc-luna-sess-sub { font-size: var(--t4); color: var(--text-2); flex: 0 0 auto; letter-spacing: .04em; }
.cc-luna-sess-foreign { background: transparent; }
/* delete (trash) — hover-revealed, sits at the row's trailing edge */
.cc-luna-sess-delform { flex: 0 0 auto; display: flex; align-items: center; }
.cc-luna-sess .cc-hover-action { opacity: 0; transition: opacity .14s ease; }
.cc-luna-sess:hover .cc-hover-action, .cc-luna-sess:focus-within .cc-hover-action { opacity: .7; }
.cc-luna-sess-del:hover { color: var(--danger, #e5484d); opacity: 1; }
.cc-luna-empty {
  font-size: var(--t4); color: var(--text-2); letter-spacing: .04em;
  border: 1px dashed var(--line-soft); padding: 10px; text-align: center;
}

/* pane: header (thread title) over the feed + composer; reuses .cc-sb-msgs / .cc-sb-chat-form */
.cc-luna-pane { display: flex; flex-direction: column; gap: 12px; min-height: 0; }
.cc-luna-pane-head {
  flex: 0 0 auto; border-bottom: 1px solid var(--line); padding-bottom: 9px;
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
}
.cc-luna-pane-title { font-size: var(--t2); font-weight: 600; color: var(--text); letter-spacing: .01em; }
.cc-luna-foreign-tag {
  flex: 0 0 auto; font-size: var(--t4); color: var(--text-2); letter-spacing: .06em;
  text-transform: uppercase; border: 1px solid var(--line-soft); padding: 2px 7px;
}
.cc-luna-form { margin-top: 2px; }
.cc-luna-form .cc-sb-chat-input { flex: 1; }

/* voice-out: the auto-speak toggle (header) + a per-reply speaker button revealed on hover */
.cc-luna-speak-toggle { flex: 0 0 auto; align-self: center; }
.cc-luna-speak-toggle[aria-pressed="true"] { color: var(--accent); border-color: var(--accent-line); }
.cc-luna-msg-head { display: flex; align-items: center; gap: 7px; }
.cc-luna-speak { padding: 0; line-height: 1; color: var(--text-2); }
.cc-luna-speak:hover { color: var(--accent); }
.cc-luna-pane-actions { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }

/* call mode: an amplitude orb (square, blueprint) + status + controls. The full-screen scrim +
   positioning come from the shared .cc-overlay primitive (scoped under .oh-root); we only style
   the contents here. */
.cc-call-inner { display: flex; flex-direction: column; align-items: center; gap: 26px; text-align: center; }
.cc-call-orb {
  width: 180px; height: 180px; display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--line); position: relative;
}
.cc-call-orb::before { content: ""; position: absolute; inset: -5px; border: 1px solid var(--line-soft); }
.cc-call-orb-core {
  width: 92px; height: 92px; background: var(--bg-2); border: 1px solid var(--accent-line);
  transition: transform .06s linear; will-change: transform;
}
.cc-call[data-call-state="speaking"] .cc-call-orb-core { border-color: var(--accent); background: var(--bg-1); }
.cc-call[data-call-state="thinking"] .cc-call-orb-core { opacity: .55; }
.cc-call-status { font-size: var(--t2); color: var(--text); letter-spacing: .04em; }
.cc-call-caption { font-size: var(--t3); color: var(--text-2); max-width: 540px; min-height: 1.2em; line-height: 1.5; }
.cc-call-controls { display: flex; gap: 12px; }
.cc-call-mute[aria-pressed="true"] { color: var(--accent); border-color: var(--accent-line); }
@media (prefers-reduced-motion: reduce) { .cc-call-orb-core { transition: none; } }

/* ============================================================
   MOBILE — ≤720px shell + touch affordances
   Root cause of the clipped phone layout: .bp-top is a no-wrap
   flex row whose min-content width (~900px) forces the whole
   .bp-shell grid wider than the viewport; everything below lays
   out at that width and clips. Let the bar shrink to icons and
   every page reflows.
   ============================================================ */
/* dynamic viewport height: mobile URL bars shrink 100vh's real estate */
@supports (height: 100dvh) { .bp-shell { height: 100dvh; } }

@media (max-width: 720px) {
  .bp-top { gap: 8px; padding: 0 10px; height: auto; min-height: 46px;
    padding-top: env(safe-area-inset-top); }
  .bp-top > * { min-width: 0; }
  .bp-top .bp-wordmark, .bp-top-meta, .bp-top [data-density-toggle],
  .bp-top-txt, .bp-top .top-action kbd, .bp-top [data-theme-label] { display: none; }
  /* breadcrumb: current leaf only, ellipsized */
  .bp-crumb a, .bp-crumb .sep { display: none; }
  .bp-top-tag { overflow: hidden; }
  .bp-crumb .cur { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* content gutters sized for a phone */
  .bp-content { padding: 18px 14px calc(60px + env(safe-area-inset-bottom)); }
  .oh-inner { padding: 18px 14px 48px; }
  /* comfortable focus without layout jump; 16px stops iOS input auto-zoom */
  .cc-sb-chat-input, .cc-journal-write-input { font-size: 16px; }
  /* home: the drag/resize layout editor is a pointer tool */
  .oh-edit-row { display: none; }
  /* home hero: numbers wrap instead of clipping */
  .oh-hero h1 { font-size: calc(var(--t1) * .82); }
  /* stat tiles (min-width 150px) wrap instead of slicing at the panel edge */
  .oh-stats { flex-wrap: wrap; }
  /* journal quick-write: full-width primary action, easy thumb target */
  .cc-journal-write-actions { justify-content: stretch; }
  .cc-journal-write-actions .bp-btn { flex: 1; justify-content: center; }
  /* journal/capture: recorder buttons span the row */
  .cc-journal-controls .bp-btn { flex: 1; justify-content: center; }
}

/* touch: hover-revealed actions don't exist under a finger — keep them visible at rest */
@media (pointer: coarse) {
  .oh-root .cc-hover-action { opacity: .65; }
}

/* ── /luna whiteboard panel — the staging board beside the chat ──────────────────────────────
   Closed (no data-board-open) the region renders empty and the page keeps its two columns; open,
   the page grows a third column on wide screens and a right-hand drawer below 1200px (mirroring
   the conversations drawer on the left). Lanes reuse the cc-sb-* card/lane styles, stacked as one
   scrollable column. */
.cc-luna-board { display: none; }
.cc-luna-page:has(> .cc-luna-board[data-board-open]) {
  grid-template-columns: 300px minmax(0, 1fr) minmax(320px, 380px);
}
.cc-luna-board[data-board-open] {
  display: flex; flex-direction: column; gap: 12px; min-height: 0; min-width: 0;
}
.cc-luna-board .cc-sb-head { align-items: center; flex-wrap: nowrap; }
.cc-luna-board-lanes {
  display: flex; flex-direction: column; gap: 12px; flex: 1; min-height: 0; overflow-y: auto;
}
.cc-luna-board-lanes .cc-sb-lane { flex: 0 0 auto; overflow: visible; }
/* the thinking-row narration ("3 on the board") — quiet meta next to the pulsing dots */
.cc-luna-board-hint {
  margin-left: 10px; font-size: var(--t4); color: var(--text-2); letter-spacing: .05em;
}

/* below the 3-column comfort point the open board becomes a right-hand drawer; the Whiteboard
   button slides it in, the scrim (shared with the conversations drawer) closes it */
@media (max-width: 1200px) {
  .cc-luna-page:has(> .cc-luna-board[data-board-open]) { grid-template-columns: 300px 1fr; }
  .cc-luna-board[data-board-open] {
    position: fixed; z-index: 120; top: 0; bottom: 0; right: 0;
    width: min(400px, 92vw); padding: calc(14px + env(safe-area-inset-top)) 14px 14px;
    background: var(--bg-1); border-left: 1px solid var(--line);
    transform: translateX(102%); transition: transform .18s ease;
    overflow-y: auto;
  }
  .cc-luna-page.is-board-open .cc-luna-board[data-board-open] { transform: translateX(0); }
  /* the scrim's fixed-overlay styling lives in the 860px block for the conversations drawer;
     restate it here so the board drawer gets a working scrim between 860 and 1200px too */
  .cc-luna-scrim { position: fixed; inset: 0; z-index: 110;
    background: color-mix(in oklch, var(--bg) 55%, transparent); }
  .cc-luna-page.is-board-open .cc-luna-scrim { display: block; }
}
@media (max-width: 860px) {
  /* the phone page is a flex column — the fixed drawer opts out of the flow either way */
  .cc-luna-page:has(> .cc-luna-board[data-board-open]) { display: flex; flex-direction: column; }
}
@media (prefers-reduced-motion: reduce) { .cc-luna-board[data-board-open] { transition: none; } }

/* ── /scratchpad — the whiteboard as a full page (the braindump glance surface) ──────────────
   Same #luna-board region + cc-sb-* card styles as the /luna embed; here the lanes spread into
   kanban-style columns and the region long-polls /scratchpad/wait (data-board-live). */
.cc-scratchpad-main .bp-content-inner { max-width: 1600px; }
.cc-scratchpad-page .cc-luna-board { display: flex; flex-direction: column; gap: 14px; }
/* Reshaped board: Tasks (the widest — topic groups live here) · Calendar · a side column
   holding Session notes over the cramped Goals & Projects corner. */
.cc-scratchpad-page .cc-luna-board-lanes {
  display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 14px; overflow: visible; align-items: start;
}
@media (max-width: 980px) {
  .cc-scratchpad-page .cc-luna-board-lanes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .cc-scratchpad-page .cc-luna-board-lanes { grid-template-columns: 1fr; }
}
.cc-sb-side { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

/* topic groups — the storm turning into small cards under its own heading */
.cc-sb-groups { display: flex; flex-direction: column; gap: 14px; }
.cc-sb-group-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  padding-bottom: 4px; border-bottom: 1px solid var(--line); margin-bottom: 8px;
}
.cc-sb-group-name {
  font-size: var(--t4); font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text);
}
.cc-sb-group.is-loose .cc-sb-group-name { color: var(--text-2); font-weight: 400; }
.cc-sb-group-count { font-size: var(--t4); color: var(--text-2); }

/* blockers — a question card pinned inside its topic group */
.cc-sb-card[data-kind="question"] { border-left: 2px solid var(--warn); background: var(--bg-1); }

/* session notes panel (replaces the Ideas lane) */
.cc-sb-notes-text { font-size: var(--t3); color: var(--text); white-space: pre-wrap; }
.cc-sb-notes-edit summary {
  cursor: pointer; font-size: var(--t4); color: var(--text-2); letter-spacing: .06em;
  text-transform: uppercase; list-style: none; width: max-content;
}
.cc-sb-notes-edit summary::-webkit-details-marker { display: none; }
.cc-sb-notes-edit summary:hover { color: var(--text); }
.cc-sb-notes-edit form { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.cc-sb-notes-input {
  width: 100%; background: var(--bg-1); border: 1px solid var(--line); color: var(--text);
  font: inherit; font-size: var(--t3); padding: 8px; resize: vertical;
}
.cc-sb-notes-input:focus { outline: none; border-color: var(--accent); }

/* backbone corner — deliberately cramped until its real redesign */
.cc-sb-backbone { border: 1px solid var(--line); padding: 8px 10px; }
.cc-sb-backbone summary {
  cursor: pointer; display: flex; align-items: center; gap: 8px; list-style: none;
  font-size: var(--t4); letter-spacing: .06em; text-transform: uppercase; color: var(--text-2);
}
.cc-sb-backbone summary::-webkit-details-marker { display: none; }
.cc-sb-backbone summary:hover { color: var(--text); }
.cc-sb-backbone summary .cc-sb-lane-count { margin-left: auto; }
.cc-sb-backbone[open] > .cc-sb-cards { margin-top: 8px; }

/* ── week load strip (/scratchpad only) — existing (dim) vs staged (accent) per day ──────────
   The doability view: a hairline 7-column row above the lanes; ⚠ marks a crowded day. */
.cc-sb-week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  border: 1px solid var(--line); flex: 0 0 auto; }
.cc-sb-week-day { display: flex; flex-direction: column; gap: 6px; min-height: 66px;
  padding: 8px 10px; border-left: 1px solid var(--line); min-width: 0; }
.cc-sb-week-day:first-child { border-left: 0; }
.cc-sb-week-day.is-today { background: var(--accent-soft); }
.cc-sb-wk-head { display: flex; justify-content: space-between; gap: 6px;
  font-size: var(--t4); color: var(--text-2); text-transform: uppercase; letter-spacing: .06em; }
.cc-sb-week-day.is-today .cc-sb-wk-head { color: var(--text); }
.cc-sb-wk-warn { color: var(--warn); }
.cc-sb-wk-ticks { display: flex; flex-wrap: wrap; gap: 3px; min-height: 10px; }
.cc-sb-wk-tick { width: 8px; height: 10px; background: var(--text-2); opacity: .35; }
.cc-sb-wk-tick.is-staged { background: var(--accent); opacity: 1; }
.cc-sb-wk-count { font-size: var(--t4); color: var(--text-2); }
.cc-sb-wk-count b { color: var(--accent); font-weight: 600; }
.cc-sb-wk-count.is-free { opacity: .5; }
@media (max-width: 720px) {
  /* phones keep the counts, drop the tick art — the numbers carry the truth */
  .cc-sb-wk-ticks { display: none; }
  .cc-sb-week-day { min-height: 0; padding: 6px 8px; }
}
.cc-scratchpad-page .cc-luna-board-lanes .cc-sb-lane { min-height: 160px; }
.cc-scratchpad-page .cc-sb-commit-notice { grid-column: 1 / -1; }
/* this page IS the board — undo the /luna right-hand-drawer treatment at narrow widths */
@media (max-width: 1200px) {
  .cc-scratchpad-page .cc-luna-board[data-board-open] {
    position: static; width: auto; transform: none; padding: 0;
    border-left: 0; background: transparent; overflow-y: visible;
  }
}
/* idle state — no open session yet; cards land here live once a braindump starts */
.cc-sb-idle {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; min-height: 320px; border: 1px dashed var(--line); text-align: center; padding: 28px;
}
.cc-sb-idle .cc-sb-sub { max-width: 420px; }
.cc-sb-idle-ico { color: var(--text-2); }

/* ── who's who (/people) ────────────────────────────────────────────────────────────────────
   The roster is a scan-and-correct list, so it stays breathable: the same wide-card grid as the
   goals board rather than a dense table. Everything else reuses the wiki's card + prose styles. */
.cc-people-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 18px;
}
.cc-people-card { cursor: pointer; }
.cc-people-detail { max-width: 900px; }

/* The edit fold-out. Closed by default — reading the page is the common act, correcting it is not. */
.cc-people-edit > summary {
  cursor: pointer; font-size: var(--t4); color: var(--text-2); text-transform: uppercase;
  letter-spacing: .08em; padding: 8px 0; border-top: 1px solid var(--line); list-style: none;
}
.cc-people-edit > summary::-webkit-details-marker { display: none; }
.cc-people-edit > summary::before { content: "+ "; }
.cc-people-edit[open] > summary::before { content: "– "; }
.cc-people-edit > summary:hover { color: var(--text); }
.cc-people-form { display: flex; flex-direction: column; gap: 14px; padding-top: 6px; }
.cc-people-form label { display: flex; flex-direction: column; gap: 6px; }
.cc-people-label {
  font-size: var(--t4); color: var(--text-2); text-transform: uppercase; letter-spacing: .08em;
}
.cc-people-input {
  width: 100%; background: var(--bg-1); border: 1px solid var(--line); color: var(--text);
  font: inherit; font-size: var(--t3); line-height: 1.6; padding: 10px; resize: vertical;
}
.cc-people-input:focus { outline: none; border-color: var(--accent); }

@media (max-width: 720px) {
  .cc-people-grid { grid-template-columns: 1fr; gap: 14px; }
}
.cc-people-bar { display: flex; gap: 12px; align-items: center; margin-bottom: 18px; }
.cc-people-bar .bp-inp { max-width: 320px; }
@media (max-width: 720px) { .cc-people-bar { flex-wrap: wrap; } }
