/* ═══════════════════════════════════════════════════════════════════════
   Ashley v2 - "Ink & Signal"

   Design intent: a warm-ink instrument, not a cold tech dashboard.
   - Surfaces are warm neutral (hue ~70) rather than the usual blue-black.
     Warm greys read as ink and paper; blue-black reads as generic SaaS.
   - Exactly one accent, "signal" lime, and it is never a filled button.
     It marks what is alive: now, streaming, Ashley's own voice, focus.
   - Primary actions are solid fg-on-bg (white on ink / ink on paper). This
     removes the coloured-CTA cliche and keeps the accent meaningful.
   - Display type is a real serif. Everything measured is monospace. The
     mix of editorial and instrument is the whole visual argument.
   - Depth comes from layered surfaces and hairlines, not from blur.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1. tokens ──────────────────────────────────────────────────────── */

:root {
  /* warm ink scale */
  --bg-0:  oklch(0.145 0.007 72);   /* app floor */
  --bg-1:  oklch(0.176 0.008 72);   /* rail, topbar */
  --bg-2:  oklch(0.203 0.008 72);   /* panel */
  --bg-3:  oklch(0.238 0.009 72);   /* raised, hover */
  --bg-4:  oklch(0.285 0.010 72);   /* pressed, track */

  --fg:       oklch(0.968 0.005 85);
  --fg-dim:   oklch(0.762 0.011 85);
  --fg-mute:  oklch(0.598 0.012 85);
  --fg-faint: oklch(0.462 0.010 85);

  --line:        oklch(0.30 0.008 72);
  --line-soft:   oklch(0.255 0.007 72);
  --line-strong: oklch(0.38 0.010 72);

  /* the one accent */
  --signal:      oklch(0.855 0.190 124);
  --signal-deep: oklch(0.660 0.155 128);
  --signal-wash: oklch(0.855 0.190 124 / 0.13);
  --signal-line: oklch(0.855 0.190 124 / 0.34);

  /* status, only ever status */
  --jade:  oklch(0.760 0.135 165);
  --amber: oklch(0.825 0.140 78);
  --rose:  oklch(0.688 0.190 18);
  --sky:   oklch(0.760 0.110 236);
  --jade-wash:  oklch(0.760 0.135 165 / 0.14);
  --amber-wash: oklch(0.825 0.140 78 / 0.14);
  --rose-wash:  oklch(0.688 0.190 18 / 0.15);
  --sky-wash:   oklch(0.760 0.110 236 / 0.14);

  /* inverted primary button */
  --solid:    oklch(0.955 0.005 85);
  --solid-fg: oklch(0.175 0.008 72);

  /* A surface that must read as "less than the one next to it" in either
     theme. Cannot be derived from the ink scale, because darkening is a step
     down in dark mode and a step up in light mode. */
  --recede: oklch(0.128 0.005 72);

  /* type */
  --serif: ui-serif, "New York", "Iowan Old Style", Palatino, Georgia, serif;
  --sans: -apple-system, BlinkMacSystemFont, "Inter Tight", Inter, "Segoe UI",
          Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, "JetBrains Mono",
          "Menlo", Consolas, monospace;

  /* radius */
  --r-xs: 6px;
  --r-sm: 9px;
  --r-md: 13px;
  --r-lg: 17px;
  --r-xl: 22px;
  --r-pill: 999px;

  /* elevation, layered rather than one heavy drop */
  --sh-1: 0 1px 0 oklch(1 0 0 / 0.04) inset,
          0 1px 2px oklch(0 0 0 / 0.30);
  --sh-2: 0 1px 0 oklch(1 0 0 / 0.05) inset,
          0 4px 10px oklch(0 0 0 / 0.28),
          0 14px 34px oklch(0 0 0 / 0.20);
  --sh-3: 0 1px 0 oklch(1 0 0 / 0.06) inset,
          0 10px 26px oklch(0 0 0 / 0.36),
          0 34px 70px oklch(0 0 0 / 0.30);

  /* motion */
  --t-fast: 130ms cubic-bezier(0.32, 0.72, 0, 1);
  --t-mid:  200ms cubic-bezier(0.32, 0.72, 0, 1);
  --t-slow: 320ms cubic-bezier(0.32, 0.72, 0, 1);

  /* metrics */
  --rail-w: 66px;
  --rail-open: 214px;
  --topbar-h: 56px;
  --aside-w: 336px;
  --measure: 68ch;

  color-scheme: dark;
}

:root[data-theme="light"] {
  --bg-0:  oklch(0.977 0.006 88);
  --bg-1:  oklch(0.960 0.007 88);
  --bg-2:  oklch(1 0 0);
  --bg-3:  oklch(0.972 0.006 88);
  --bg-4:  oklch(0.935 0.008 88);

  --fg:       oklch(0.215 0.012 72);
  --fg-dim:   oklch(0.430 0.013 72);
  --fg-mute:  oklch(0.560 0.012 72);
  --fg-faint: oklch(0.680 0.010 72);

  --line:        oklch(0.885 0.008 80);
  --line-soft:   oklch(0.925 0.006 80);
  --line-strong: oklch(0.800 0.010 80);

  --signal:      oklch(0.560 0.150 130);
  --signal-deep: oklch(0.470 0.130 132);
  --signal-wash: oklch(0.560 0.150 130 / 0.11);
  --signal-line: oklch(0.560 0.150 130 / 0.30);

  --jade:  oklch(0.520 0.120 165);
  --amber: oklch(0.600 0.130 70);
  --rose:  oklch(0.540 0.180 20);
  --sky:   oklch(0.520 0.120 240);
  --jade-wash:  oklch(0.520 0.120 165 / 0.11);
  --amber-wash: oklch(0.600 0.130 70 / 0.12);
  --rose-wash:  oklch(0.540 0.180 20 / 0.10);
  --sky-wash:   oklch(0.520 0.120 240 / 0.10);

  --solid:    oklch(0.215 0.012 72);
  --solid-fg: oklch(0.985 0.004 88);

  --recede: oklch(0.918 0.009 88);

  --sh-1: 0 1px 2px oklch(0.30 0.02 72 / 0.07);
  --sh-2: 0 2px 6px oklch(0.30 0.02 72 / 0.07),
          0 10px 24px oklch(0.30 0.02 72 / 0.06);
  --sh-3: 0 8px 20px oklch(0.30 0.02 72 / 0.10),
          0 30px 60px oklch(0.30 0.02 72 / 0.10);

  color-scheme: light;
}

/* ── 2. reset and base ──────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg-0);
  color: var(--fg);
  font: 400 15px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-variant-numeric: tabular-nums;
  overscroll-behavior-y: none;
}

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
a { color: inherit; text-decoration: none; }
/* Every icon gets a size by default. An `icon()` dropped somewhere without its
   own svg rule (as happened in `.prop__src`) has no intrinsic size, so in a flex
   row it stretched to fill the container and rendered as a 1000px envelope.
   Component rules and the inline size from `icon(name, size)` both outrank this. */
svg { display: block; width: 1em; height: 1em; flex: 0 0 auto; }

::selection { background: var(--signal-wash); color: var(--fg); }

:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* Scrollbars kept quiet. A loud scrollbar breaks the ink illusion. */
* { scrollbar-width: thin; scrollbar-color: var(--bg-4) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--bg-4); border-radius: 99px;
  border: 3px solid transparent; background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background-color: var(--line-strong); background-clip: content-box; }

/* ── 3. typography ──────────────────────────────────────────────────── */

.display {
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: -0.012em;
  line-height: 1.08;
  font-size: clamp(26px, 3.4vw, 37px);
}

.overline {
  font: 500 10px/1 var(--mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--fg-mute);
}

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.dim { color: var(--fg-dim); }
.mute { color: var(--fg-mute); }
.tnum { font-variant-numeric: tabular-nums; }

h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -0.011em; }
h2 { font-size: 18px; }
h3 { font-size: 15px; }

/* Prose, used for Ashley's answers and every rendered markdown block. */
.prose { font-size: 15px; line-height: 1.62; overflow-wrap: anywhere; }
.prose > *:first-child { margin-top: 0; }
.prose > *:last-child { margin-bottom: 0; }
.prose p { margin: 0 0 0.75em; }
.prose h1, .prose h2, .prose h3 {
  margin: 1.5em 0 0.5em; font-weight: 600; letter-spacing: -0.012em;
}
.prose h1 { font-size: 1.28em; }
.prose h2 { font-size: 1.13em; }
.prose h3 { font-size: 1em; color: var(--fg-dim); }
.prose ul, .prose ol { margin: 0 0 0.8em; padding-left: 1.25em; }
.prose li { margin: 0.2em 0; }
.prose li::marker { color: var(--fg-faint); }
.prose code {
  font: 0.86em/1.4 var(--mono);
  background: var(--bg-3); border: 1px solid var(--line-soft);
  padding: 0.1em 0.36em; border-radius: var(--r-xs);
}
.prose pre {
  margin: 0 0 0.85em; padding: 12px 14px; overflow-x: auto;
  background: var(--bg-1); border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
}
.prose pre code { background: none; border: 0; padding: 0; font-size: 12.5px; }
.prose blockquote {
  margin: 0 0 0.85em; padding: 2px 0 2px 15px;
  border-left: 2px solid var(--signal-line);
  font-family: var(--serif); font-size: 1.04em; color: var(--fg-dim);
}
.prose a { color: var(--fg); border-bottom: 1px solid var(--signal-line); }
.prose a:hover { border-bottom-color: var(--signal); }
.prose hr { border: 0; border-top: 1px solid var(--line-soft); margin: 1.4em 0; }
.prose table {
  width: 100%; border-collapse: collapse; margin: 0 0 0.9em; font-size: 13.5px;
}
.prose th, .prose td {
  text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--line-soft);
}
.prose th { color: var(--fg-mute); font: 500 10px/1 var(--mono);
  letter-spacing: 0.1em; text-transform: uppercase; }
.prose strong { font-weight: 600; }

/* ── 4. shell ───────────────────────────────────────────────────────── */

.shell {
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
  height: 100dvh;
  /* The rail overflows its own track when it expands on hover. */
  overflow: visible;
}

/* rail --------------------------------------------------------------- */

.rail {
  grid-column: 1;
  position: relative;
  display: flex; flex-direction: column;
  gap: 4px; padding: 46px 9px 12px;
  background: var(--bg-1);
  border-right: 1px solid var(--line-soft);
  z-index: 40;
  overflow: hidden;
  transition: width var(--t-mid);
}
/* Ruime bovenmarge houdt de header onder de macOS vensterknoppen, die bij de
   desktopapp linksboven over de webview hangen. De pin zit rechtsboven naast
   het logo op dezelfde hoogte, dus die kan nooit met de knoppen overlappen. */
.rail__pin {
  position: absolute; top: 46px; right: 16px;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  color: var(--fg-mute);
  border-radius: var(--r-sm);
  transition: color var(--t-fast), background var(--t-fast);
}
.rail__pin:hover { color: var(--fg); background: var(--bg-2); }
.rail__pin[aria-pressed="true"] { color: var(--fg); background: var(--bg-3); }
.rail__pin svg { width: 15px; height: 15px; }
.rail__mark {
  display: flex; align-items: center; gap: 11px;
  height: 44px; padding: 0 8px; margin-bottom: 10px;
  border-radius: var(--r-md); overflow: hidden;
}
.rail__glyph {
  flex: 0 0 38px; height: 38px;
  position: relative;
}
/* The Ashley mark (static/v2/img/ashley-mark.png) is a plain alpha silhouette,
   no baked-in color, so it can be masked and painted in whatever color the
   active theme/skin uses for --signal -- same trick as the icons in icons.js
   (stroke: currentColor), just via CSS mask instead of inline SVG since the
   source is a raster mark. No badge/background: just the mark itself. */
.rail__glyph::before {
  content: ''; position: absolute; inset: 0;
  background-color: var(--signal);
  -webkit-mask-image: url('/v2/assets/img/ashley-mark.png');
  mask-image: url('/v2/assets/img/ashley-mark.png');
  -webkit-mask-size: contain; mask-size: contain;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
}
.rail__wordmark {
  font-family: var(--serif); font-size: 20px; letter-spacing: -0.01em;
  white-space: nowrap; opacity: 0; transition: opacity var(--t-fast);
}
.rail__nav { display: flex; flex-direction: column; gap: 2px; }
.rail__foot { margin-top: auto; display: flex; flex-direction: column; gap: 2px; }

.rail__item {
  position: relative;
  display: flex; align-items: center; gap: 12px;
  height: 42px; padding: 0 9px;
  border-radius: var(--r-md);
  color: var(--fg-mute);
  white-space: nowrap; overflow: hidden;
  transition: color var(--t-fast), background var(--t-fast);
}
.rail__item:hover { color: var(--fg); background: var(--bg-3); }
.rail__item[aria-current="page"] { color: var(--fg); background: var(--bg-3); }
/* Active state is a signal rail on the left edge, not a filled pill. */
.rail__item[aria-current="page"]::before {
  content: ""; position: absolute; left: -9px; top: 9px; bottom: 9px;
  width: 2px; border-radius: 0 2px 2px 0; background: var(--signal);
}
.rail__icon, .rail__item > [data-icon] { flex: 0 0 24px; display: grid; place-items: center; }
.rail__icon svg, .rail__item svg { width: 18px; height: 18px; }
.rail__label { font-size: 13.5px; opacity: 0; transition: opacity var(--t-fast); }
.rail__count {
  margin-left: auto; opacity: 0; transition: opacity var(--t-fast);
  font: 500 10.5px/1 var(--mono); color: var(--fg-mute);
  background: var(--bg-4); padding: 3px 6px; border-radius: var(--r-pill);
}
.rail__item[aria-current="page"] .rail__count { color: var(--fg-dim); }

/* Collapsed rail carries a count as a dot so nothing is hidden. */
.rail__pip {
  position: absolute; top: 9px; right: 10px;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--signal);
  transition: opacity var(--t-fast);
}

/* Expand on hover as an overlay: content must not reflow under the cursor.
   The rail stays a grid item and simply takes a width wider than its track,
   so it paints over the surface without leaving the flow. An earlier
   `position: fixed` did the same thing but detached the rail from the grid
   for no gain, since the shell is 100dvh and never scrolls. */
@media (hover: hover) and (min-width: 900px) {
  .rail { width: var(--rail-w); }
  .rail:hover, .rail:focus-within {
    width: var(--rail-open);
    box-shadow: var(--sh-3);
  }
  .rail:hover .rail__label, .rail:focus-within .rail__label,
  .rail:hover .rail__wordmark, .rail:focus-within .rail__wordmark,
  .rail:hover .rail__count, .rail:focus-within .rail__count { opacity: 1; }
  .rail:hover .rail__pip, .rail:focus-within .rail__pip { opacity: 0; }
}

/* Pinned rail: stays open instead of only expanding on hover, and takes real
   layout space so the surface is pushed aside rather than covered. Getting the
   track wider means the adjacent content reflows instead of sitting under the
   rail, which is what "vastmaken" should feel like on a desktop. */
@media (min-width: 900px) {
  .shell:has(.rail--pinned) { grid-template-columns: var(--rail-open) minmax(0, 1fr); }
  .rail.rail--pinned { width: var(--rail-open); }
  .rail--pinned .rail__label,
  .rail--pinned .rail__wordmark,
  .rail--pinned .rail__count { opacity: 1; }
  .rail--pinned .rail__pip { opacity: 0; }
}

.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--fg-faint); margin-left: auto; }
.dot--ok { background: var(--jade); }
.dot--warn { background: var(--amber); }
.dot--bad { background: var(--rose); }
/* "no source configured yet" - deliberately neutral, not red or amber: an
   empty setup is not an outage. Reuses --fg-mute, the same token .tag--mute
   already uses for exactly this "nothing to report" meaning; no new token. */
.dot--mute { background: var(--fg-mute); }
.rail__foot .dot { opacity: 1; }

/* surface and topbar -------------------------------------------------- */

.surface {
  grid-column: 2;
  display: flex; flex-direction: column;
  min-width: 0; height: 100dvh;
  /* Edge-to-edge in the iOS app (viewport-fit=cover): keep content off the
     rounded corner / notch side in landscape. 0 everywhere else. */
  padding-right: env(safe-area-inset-right, 0px);
}

.topbar {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 10px;
  /* Status-bar inset goes ON TOP of the bar height, so the controls keep
     their 52/56px row below it. --topbar-h is used nowhere else, so nothing
     depends on the old fixed height.

     The iPhone app sets --app-top-inset itself (WebShellModel.setInsets)
     rather than leaving this to env(): a web view that draws edge to edge
     reports the inset only while UIKit is also adjusting the scroll view, and
     then the status bar gets counted twice - the header visibly drops the
     moment anything forces a relayout. One number, from the side that knows
     it. env() stays as the fallback for a plain browser. */
  height: calc(var(--topbar-h) + var(--app-top-inset, env(safe-area-inset-top, 0px)));
  padding: var(--app-top-inset, env(safe-area-inset-top, 0px)) 14px 0 18px;
  border-bottom: 1px solid var(--line-soft);
  background: color-mix(in oklab, var(--bg-0) 82%, transparent);
  backdrop-filter: saturate(1.4) blur(14px);
  position: sticky; top: 0; z-index: 30;
}
.topbar__spacer { flex: 1 1 auto; }
/* Scoped to .topbar on purpose: `.iconbtn { display: grid }` lives further down
   this file, and with equal specificity it won, so the hamburger showed at
   every width. On a wide window the rail is already open, which made the button
   look dead. It only has a job below 900px, where the rail is off-canvas. */
.topbar .topbar__menu { display: none; }
.topbar__crumb {
  display: flex; align-items: center; gap: 9px;
  min-width: 0; overflow: hidden;
  font-size: 13.5px; color: var(--fg-dim);
}
/* Without this the crumb refuses to shrink and runs under the actions. */
.topbar__crumb > * { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar__crumb b { font-weight: 600; color: var(--fg); }
.topbar__crumb .sep { color: var(--fg-faint); }
.topbar__actions { display: flex; align-items: center; gap: 7px; }

.omni {
  display: flex; align-items: center; gap: 9px;
  height: 33px; padding: 0 10px 0 11px;
  min-width: 190px;
  color: var(--fg-mute);
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-pill);
  transition: border-color var(--t-fast), color var(--t-fast), background var(--t-fast);
}
.omni:hover { color: var(--fg-dim); border-color: var(--line); background: var(--bg-3); }
.omni svg { width: 14px; height: 14px; }
.omni__text { font-size: 13px; }
.omni__kbd {
  margin-left: auto; font: 500 10.5px/1 var(--mono); color: var(--fg-faint);
  border: 1px solid var(--line-soft); border-radius: 5px; padding: 3px 5px;
}

.notices { padding: 0 var(--pad, 26px); }
.notices:empty { display: none; }

.view {
  flex: 1 1 auto; min-height: 0; min-width: 0;
  overflow: hidden;
  --pad: 26px;
}
.view:focus { outline: none; }

/* ── 5. primitives ──────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 33px; padding: 0 13px;
  font-size: 13.5px; font-weight: 500; white-space: nowrap;
  color: var(--fg-dim);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  box-shadow: var(--sh-1);
  transition: background var(--t-fast), color var(--t-fast),
              border-color var(--t-fast), transform var(--t-fast);
}
.btn:hover:not(:disabled) { color: var(--fg); background: var(--bg-3); border-color: var(--line-strong); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: 0.45; cursor: default; }
.btn svg { width: 15px; height: 15px; }

.btn--primary {
  color: var(--solid-fg); background: var(--solid);
  border-color: transparent; font-weight: 600;
}
.btn--primary:hover:not(:disabled) {
  color: var(--solid-fg);
  background: color-mix(in oklab, var(--solid) 88%, var(--signal));
  border-color: transparent;
}
.btn--ghost { background: none; border-color: transparent; box-shadow: none; }
.btn--ghost:hover:not(:disabled) { background: var(--bg-3); border-color: transparent; }
/* Collapsed by default: destroying a task should cost one extra click. */
.dlg__danger { margin-top: 14px; border-top: 1px solid var(--line-soft); padding-top: 10px; }
.dlg__danger[open] summary { color: var(--rose); }

/* The way out: the source, or the link where the action actually happens. Gets
   the signal colour rather than the blue of Done, because it is not a
   confirmation. As a grey button among the other grey buttons it simply got missed. */
.btn--link {
  color: var(--signal-deep); border-color: var(--signal);
  background: var(--signal-wash); font-weight: 600;
}
.btn--link:hover:not(:disabled) {
  color: var(--signal-deep); border-color: var(--signal-deep);
  background: color-mix(in oklab, var(--signal-wash) 60%, var(--signal) 22%);
}
.btn--link svg { opacity: 0.9; }

/* The link where the action actually happens: the approval page from the mail. Fully
   coloured in, because this is usually why you open the task. */
.btn--go {
  color: var(--solid-fg); background: var(--signal-deep);
  border-color: transparent; font-weight: 600;
}
.btn--go:hover:not(:disabled) {
  color: var(--solid-fg); border-color: transparent;
  background: color-mix(in oklab, var(--signal-deep) 85%, black);
}

.btn--danger { color: var(--rose); }
.btn--danger:hover:not(:disabled) { color: var(--rose); background: var(--rose-wash); border-color: var(--rose); }
.btn--sm { height: 27px; padding: 0 9px; font-size: 12.5px; }
.btn--wide { width: 100%; }

.iconbtn {
  display: inline-grid; place-items: center;
  width: 33px; height: 33px;
  color: var(--fg-mute);
  border: 1px solid transparent; border-radius: var(--r-sm);
  transition: background var(--t-fast), color var(--t-fast);
}
.iconbtn:hover { color: var(--fg); background: var(--bg-3); }
.iconbtn:disabled { opacity: 0.4; cursor: default; }
.iconbtn svg { width: 16px; height: 16px; }
.iconbtn--on { color: var(--fg); background: var(--bg-3); }

.chip {
  display: inline-flex; align-items: center; gap: 5px;
  height: 24px; padding: 0 9px;
  font-size: 12px; color: var(--fg-dim);
  background: var(--bg-3); border: 1px solid transparent;
  border-radius: var(--r-pill); white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
button.chip:hover { color: var(--fg); border-color: var(--line); }
.chip--mono { font: 500 11px/1 var(--mono); letter-spacing: 0.02em; }
.chip--quiet { background: none; border-color: var(--line-soft); color: var(--fg-mute); }
.chip--on { color: var(--fg); background: var(--signal-wash); border-color: var(--signal-line); }
.chip svg { width: 12px; height: 12px; }
/* `display: inline-flex` above beats the UA's `[hidden] { display: none }`,
   so a chip toggled with `el.hidden = true` stayed visible (the "Cc
   toevoegen" chip, which is supposed to disappear once the Cc row is open). */
.chip[hidden] { display: none; }

.tag {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 8px; border-radius: var(--r-xs);
  font: 500 11px/1.35 var(--mono); letter-spacing: 0.02em;
}
.tag--jade  { color: var(--jade);  background: var(--jade-wash); }
.tag--amber { color: var(--amber); background: var(--amber-wash); }
.tag--rose  { color: var(--rose);  background: var(--rose-wash); }
.tag--sky   { color: var(--sky);   background: var(--sky-wash); }
.tag--mute  { color: var(--fg-mute); background: var(--bg-3); }

.panel {
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
}
.panel__head {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 16px; border-bottom: 1px solid var(--line-soft);
}
.panel__head h3 { flex: 1 1 auto; min-width: 0; }
.panel__body { padding: 16px; }

.field {
  height: 33px; padding: 0 10px;
  color: var(--fg);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.field:hover { border-color: var(--line-strong); }
.field:focus {
  outline: none; border-color: var(--signal);
  box-shadow: 0 0 0 3px var(--signal-wash);
}
input[type="date"].field { font: 500 12.5px/1 var(--mono); min-width: 122px; }
select.field { padding-right: 6px; font-size: 13px; }

.divider { height: 1px; background: var(--line-soft); border: 0; margin: 0; }

.empty {
  display: grid; place-items: center; gap: 11px;
  padding: 44px 22px; text-align: center;
  color: var(--fg-mute);
}
.empty__glyph {
  width: 38px; height: 38px; display: grid; place-items: center;
  border: 1px dashed var(--line); border-radius: var(--r-md);
  color: var(--fg-faint);
}
.empty__glyph svg { width: 18px; height: 18px; }
.empty h3 { color: var(--fg-dim); font-weight: 500; }
.empty p { margin: 0; max-width: 42ch; font-size: 13.5px; line-height: 1.5; }

.skel {
  background: linear-gradient(90deg, var(--bg-2) 0%, var(--bg-3) 48%, var(--bg-2) 100%);
  background-size: 220% 100%;
  border-radius: var(--r-sm);
  animation: shimmer 1.35s linear infinite;
}
@keyframes shimmer { from { background-position: 130% 0; } to { background-position: -30% 0; } }

.spin { animation: spin 0.85s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.notice {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 12px 0 0; padding: 11px 13px;
  font-size: 13.5px; line-height: 1.45;
  border: 1px solid; border-radius: var(--r-md);
}
.notice svg { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 1px; }
.notice--warn { color: var(--amber); border-color: var(--amber); background: var(--amber-wash); }
.notice--bad  { color: var(--rose);  border-color: var(--rose);  background: var(--rose-wash); }
.notice--info { color: var(--sky);   border-color: var(--sky);   background: var(--sky-wash); }
.notice b { font-weight: 600; }
.notice .btn { margin-left: auto; }

/* ── 6. chronograph: the signature component ────────────────────────── */
/*
   One horizontal reading of a day: calendar blocks as bars, recordings as
   ticks under the axis, deadlines as pins above it, and "now" as a live
   signal line. It replaces three separate widgets in v1 and is the only
   place in the app that earns a coloured glow.
*/

/* Same widget, dropped at the top of Assistant/Todos: .chrono already carries
   its own background/border, so no wrapper is needed, only the gap below it
   and a way to collapse away when today has nothing recorded or booked. */
.todaychrono:empty { display: none; }
.todaychrono { margin-bottom: 18px; }

.chrono {
  position: relative;
  padding: 14px 16px 10px;
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  overflow: hidden;
}
.chrono__head {
  display: flex; align-items: baseline; gap: 10px; margin-bottom: 12px;
}
.chrono__head .overline { flex: 0 0 auto; }
.chrono__legend {
  margin-left: auto; display: flex; gap: 12px; flex-wrap: wrap;
  font: 400 11px/1 var(--sans); color: var(--fg-faint);
}
.chrono__legend i {
  display: inline-block; width: 8px; height: 8px; margin-right: 5px;
  border-radius: 2px; vertical-align: -1px;
}

.chrono__plot { position: relative; height: 74px; }

.chrono__grid { position: absolute; inset: 0; }
.chrono__hour {
  position: absolute; top: 22px; bottom: 16px; width: 1px;
  background: var(--line-soft);
}
.chrono__hour::after {
  content: attr(data-h);
  position: absolute; bottom: -15px; left: 0; transform: translateX(-50%);
  font: 500 9.5px/1 var(--mono); color: var(--fg-faint);
}
.chrono__hour--major { background: var(--line); }

/* calendar meeting bars sit on the axis band */
.chrono__band {
  position: absolute; left: 0; right: 0; top: 30px; height: 22px;
  background: var(--bg-1); border-radius: var(--r-xs);
  border: 1px solid var(--line-soft);
}
.chrono__mtg {
  position: absolute; top: 3px; height: 16px;
  background: var(--bg-4);
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  overflow: hidden;
  display: flex; align-items: center;
  padding: 0 4px;
  font: 500 9.5px/1 var(--sans); color: var(--fg-dim);
  white-space: nowrap;
  transition: background var(--t-fast);
}
.chrono__mtg:hover { background: var(--line-strong); color: var(--fg); }

/* recordings below the axis */
.chrono__rec {
  position: absolute; top: 55px; height: 7px; min-width: 3px;
  background: var(--signal-deep); border-radius: 2px;
  transition: background var(--t-fast), transform var(--t-fast);
}
.chrono__rec:hover { background: var(--signal); transform: scaleY(1.5); }

/* deadline pins above the axis */
.chrono__pin {
  position: absolute; top: 8px;
  width: 0; height: 0;
  transform: translateX(-50%);
}
.chrono__pin i {
  position: absolute; left: -4px; top: 0;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--bg-2); border: 2px solid var(--amber);
}
.chrono__pin--high i { border-color: var(--rose); }
.chrono__pin s {
  position: absolute; left: -0.5px; top: 7px; width: 1px; height: 15px;
  background: var(--line); text-decoration: none;
}

/* now */
.chrono__now { position: absolute; top: 4px; bottom: 14px; width: 1px;
  background: var(--signal); box-shadow: 0 0 10px var(--signal); }
.chrono__now::before {
  content: ""; position: absolute; top: -3px; left: -3px;
  width: 7px; height: 7px; border-radius: 50%; background: var(--signal);
  box-shadow: 0 0 0 0 var(--signal-line);
  animation: pulse 2.4s ease-out infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 var(--signal-line); }
  70%  { box-shadow: 0 0 0 9px oklch(0.855 0.19 124 / 0); }
  100% { box-shadow: 0 0 0 0 oklch(0.855 0.19 124 / 0); }
}

/* ── 6b. horizon: deadlines and load, 14 d to 6 m ───────────────────── */

.hz {
  padding: 13px 15px 11px;
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
}
.hz__head { display: flex; align-items: center; gap: 12px; margin-bottom: 11px; flex-wrap: wrap; }
.hz__head .overline { flex: 0 0 auto; }
.hz__sum {
  display: flex; gap: 12px; flex-wrap: wrap;
  font-size: 11.5px; color: var(--fg-mute);
}
.hz__scales { margin-left: auto; display: flex; gap: 4px; flex: 0 0 auto; }

.hz__body { display: flex; align-items: stretch; gap: 9px; height: 86px; }
.hz--compact .hz__body { height: 64px; }

/* overdue stack, left of the axis */
.hz__late { flex: 0 0 auto; display: flex; }
.hz__latebtn {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; width: 52px; height: 100%;
  background: var(--rose-wash);
  border: 1px solid var(--rose);
  border-radius: var(--r-sm);
  transition: background var(--t-fast);
}
.hz__latebtn:hover { background: color-mix(in oklab, var(--rose) 22%, transparent); }
.hz__laten { font-family: var(--serif); font-size: 23px; line-height: 1; color: var(--rose); }
.hz__latek {
  font: 500 9px/1 var(--mono); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--rose);
}

.hz__axis {
  flex: 1 1 auto; min-width: 0; display: flex;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--bg-1);
}
.hz__err {
  display: flex; align-items: center; gap: 8px; justify-content: center;
  width: 100%; font-size: 12.5px; color: var(--fg-faint);
}
.hz__err svg { width: 14px; height: 14px; }

.hz__cell {
  position: relative;
  flex: 1 1 0; min-width: 0; height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding-bottom: 13px;
}
.hz__cell--off { background: var(--recede); }
.hz__cell--mon { box-shadow: inset 1px 0 0 var(--line); }
.hz__cell--today { background: var(--signal-wash); }
.hz__cell--band { padding-bottom: 15px; }
.hz__cell--band + .hz__cell--band { box-shadow: inset 1px 0 0 var(--line); }

/* Meeting load reads as a column, so a wall of full-height columns is
   immediately a week you should not add anything to. */
.hz__load {
  width: 100%; min-height: 0;
  background: var(--signal-deep); opacity: 0.5;
  border-radius: 2px 2px 0 0;
}
.hz__cell--heavy .hz__load { opacity: 0.9; }
.hz__cell--today .hz__load { opacity: 0.95; background: var(--signal); }

.hz__tick {
  position: absolute; left: 0; right: 0; bottom: 2px;
  text-align: center; pointer-events: none;
  font: 500 9px/1 var(--mono); color: var(--fg-faint);
  overflow: hidden; white-space: nowrap;
}

.hz__pins {
  position: absolute; left: 1px; right: 1px; top: 4px;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
}
/* Colour is priority, the ring is authorship. Two channels so an
   Ashley-created high-priority task can show both at once. */
.hz__pin {
  width: 100%; max-width: 22px; height: 5px;
  border-radius: 2px;
  background: var(--fg-dim);
  transition: transform var(--t-fast), background var(--t-fast);
}
.hz__pin--high { background: var(--rose); }
.hz__pin--low { background: var(--fg-faint); }
.hz__pin--mine { box-shadow: 0 0 0 1.5px var(--signal); }
.hz__pin--muted { opacity: 0.4; }
.hz__pin:hover { transform: scaleY(1.9); background: var(--fg); }
.hz__more { font: 500 8.5px/1 var(--mono); color: var(--fg-faint); }

.hz__lateitem {
  display: grid; grid-template-columns: 1fr auto; gap: 9px; align-items: baseline;
  width: 100%; text-align: left;
  padding: 6px 7px; border-radius: var(--r-xs);
  font-size: 12.5px; line-height: 1.4; color: var(--fg-dim);
}
.hz__lateitem:hover { background: var(--bg-3); color: var(--fg); }
.hz__lateitem .mono { font-size: 10.5px; }

.hz__legend {
  display: flex; gap: 14px; flex-wrap: wrap; padding: 9px 0 0;
  font: 400 11px/1 var(--sans); color: var(--fg-faint);
}
.hz__legend i {
  display: inline-block; width: 14px; height: 4px; border-radius: 2px;
  margin-right: 6px; vertical-align: 1px;
}

@media (max-width: 700px) {
  .hz__head { gap: 8px; }
  .hz__sum { order: 3; width: 100%; }
  .hz__scales { margin-left: auto; }
  .hz__legend { display: none; }
}

/* week strip, used on the deadlines view */
.weekstrip { display: flex; gap: 5px; }
.weekstrip__d {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; gap: 6px;
  padding: 9px 8px 10px;
  background: var(--bg-1); border: 1px solid var(--line-soft);
  border-radius: var(--r-md); text-align: left;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.weekstrip__d:hover { border-color: var(--line-strong); background: var(--bg-3); }
.weekstrip__d--today { border-color: var(--signal-line); background: var(--signal-wash); }
.weekstrip__d--off { opacity: 0.55; }
.weekstrip__dow { font: 500 9.5px/1 var(--mono); letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--fg-faint); }
.weekstrip__num { font-family: var(--serif); font-size: 21px; line-height: 1; }
.weekstrip__load { height: 3px; border-radius: 2px; background: var(--bg-4); overflow: hidden; }
.weekstrip__load i { display: block; height: 100%; background: var(--fg-faint); }
.weekstrip__pins { display: flex; gap: 3px; flex-wrap: wrap; min-height: 7px; }
.weekstrip__pins i { width: 6px; height: 6px; border-radius: 50%; background: var(--amber); }
.weekstrip__pins i.high { background: var(--rose); }

/* ── 7. assistant view ──────────────────────────────────────────────── */

.asst {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--aside-w);
  height: 100%; min-height: 0;
}
.asst__main {
  display: flex; flex-direction: column;
  min-width: 0; min-height: 0;
  border-right: 1px solid var(--line-soft);
}
.asst__scroll {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 22px var(--pad) 8px;
  scroll-behavior: smooth;
}
.asst__inner { max-width: 900px; margin: 0 auto; }

.dayhead { display: flex; align-items: flex-end; gap: 16px; margin-bottom: 16px; }
.dayhead__t { min-width: 0; flex: 1 1 auto; }
.dayhead__t .overline { margin-bottom: 7px; }
.dayhead__state {
  margin: 8px 0 0; font-size: 13.5px; color: var(--fg-dim);
  display: flex; flex-wrap: wrap; gap: 4px 14px;
}
.dayhead__state span { display: inline-flex; align-items: center; gap: 6px; }
.dayhead__state i { width: 5px; height: 5px; border-radius: 50%; background: var(--fg-faint); }
.dayhead__nav { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; }

/* chat --------------------------------------------------------------- */

.thread { display: flex; flex-direction: column; gap: 22px; margin: 26px 0 0; }

.msg { display: flex; flex-direction: column; gap: 6px; }

/* Both sides get a bubble. Three things separate them, none of them an accent
   stripe: the tail corner is mirrored (Ashley bottom-left, Benjamin
   bottom-right), the surfaces are one step apart, and the text colour differs.
   Ashley's answer is the content you are reading, so it gets full-strength
   foreground; your own message is a reminder of what you asked, so it sits back
   at `--fg-dim`. */
.msg--a { max-width: var(--measure); }
.msg--a .msg__body {
  padding: 12px 16px;
  /* bg-1 for Ashley, bg-2 for Benjamin: in light mode bg-2 is pure white and
     bg-3 sat within half a percent of the page, so the two bubbles were only
     distinguishable in the dark theme. This pair separates in both, and puts
     the raised surface on the message you wrote. */
  background: var(--bg-1);
  color: var(--fg);
  border: 1px solid var(--line);
  border-radius: var(--r-lg) var(--r-lg) var(--r-lg) var(--r-xs);
  box-shadow: var(--sh-1);
}
.msg--a .msg__who { color: var(--signal-deep); padding-left: 2px; }
:root[data-theme="dark"] .msg--a .msg__who { color: var(--signal); }
/* Notes and errors hang under the bubble, not inside it. */
.msg--a > .msg__note { padding-left: 4px; }

.msg--u { align-self: flex-end; align-items: flex-end; max-width: min(100%, 60ch); }
.msg--u .msg__body {
  padding: 12px 16px;
  color: var(--fg-dim);
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--r-lg) var(--r-lg) var(--r-xs) var(--r-lg);
  box-shadow: var(--sh-1);
}

.msg__who {
  font: 500 10px/1 var(--mono); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--fg-faint);
  display: flex; align-items: center; gap: 8px;
}
.msg__who time { color: var(--fg-faint); letter-spacing: 0.04em; }
.msg__cost { color: var(--fg-faint); }
.msg__body { min-width: 0; }

.msg--stream .prose::after {
  content: ""; display: inline-block; vertical-align: -2px;
  width: 2px; height: 1.05em; margin-left: 3px;
  background: var(--signal); animation: blink 1s steps(2) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

.msg__note {
  display: flex; align-items: center; gap: 8px;
  font: 400 11.5px/1.4 var(--mono); color: var(--fg-faint);
}
.msg__note--bad { color: var(--rose); }
.msg__note::before {
  content: ""; width: 12px; height: 1px; background: currentColor; opacity: 0.5;
}

.thinking { display: flex; gap: 5px; padding: 4px 0; }
.thinking i {
  width: 5px; height: 5px; border-radius: 50%; background: var(--signal-deep);
  animation: bob 1.15s ease-in-out infinite;
}
.thinking i:nth-child(2) { animation-delay: 0.14s; }
.thinking i:nth-child(3) { animation-delay: 0.28s; }
@keyframes bob { 0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
                 30% { opacity: 1; transform: translateY(-3px); } }

/* composer ----------------------------------------------------------- */

.composer {
  position: sticky; bottom: 0; z-index: 5;
  padding: 12px var(--pad) 16px;
  background: var(--bg-0);
}
.composer__inner { max-width: 900px; margin: 0 auto; }
.composer__box {
  display: flex; align-items: flex-end; gap: 9px;
  padding: 9px 9px 9px 14px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-2);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.composer__box:focus-within {
  border-color: var(--signal-line);
  box-shadow: var(--sh-2), 0 0 0 3px var(--signal-wash);
}
.composer textarea {
  flex: 1 1 auto; min-width: 0;
  min-height: 24px; max-height: 210px;
  padding: 4px 0; margin: 0;
  background: none; border: 0; outline: none; resize: none;
  font-size: 15px; line-height: 1.5;
}
.composer textarea::placeholder { color: var(--fg-faint); }
.composer__send {
  flex: 0 0 auto; width: 32px; height: 32px;
  display: grid; place-items: center;
  color: var(--solid-fg); background: var(--solid);
  border-radius: 50%;
  transition: opacity var(--t-fast), transform var(--t-fast);
}
.composer__send:disabled { opacity: 0.3; cursor: default; }
.composer__send:not(:disabled):hover { transform: scale(1.06); }
.composer__send svg { width: 15px; height: 15px; }
.composer__foot {
  display: flex; align-items: center; gap: 12px;
  margin: 8px 4px 0; font-size: 11.5px; color: var(--fg-faint);
}
.composer__foot kbd {
  font: 500 10px/1 var(--mono);
  border: 1px solid var(--line-soft); border-radius: 4px; padding: 2px 4px;
}
.composer__hint { margin-left: auto; }

.suggest { display: flex; gap: 7px; flex-wrap: wrap; margin: 0 0 14px; }

/* proposals ---------------------------------------------------------- */

/* progress ----------------------------------------------------------- */

.pg {
  padding: 12px 14px;
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  box-shadow: var(--sh-1);
}
.pg__hd { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; font-size: 12.5px; }
.pg__what { color: var(--fg-dim); }
.pg__sp { flex: 1 1 auto; }
.pg__time { font-size: 11px; color: var(--fg-faint); }
.pg__bar { height: 4px; border-radius: 3px; background: var(--bg-4); overflow: hidden; }
.pg__bar i {
  display: block; height: 100%; width: 0;
  background: var(--signal-deep); border-radius: 3px;
  transition: width var(--t-slow);
}
.pg__step {
  margin-top: 7px; min-height: 1.3em;
  font-size: 11px; color: var(--fg-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pg--done .pg__bar i { background: var(--jade); }
.pg--done .pg__what { color: var(--jade); }
.pg--err .pg__bar i { background: var(--rose); }
.pg--err .pg__what { color: var(--rose); }

.props { margin: 30px 0 8px; }
.props__head {
  display: flex; align-items: center; gap: 11px; margin-bottom: 12px;
}
.props__head h2 { font-size: 15px; }
.props__head .overline { color: var(--signal-deep); }
.props__bulk { margin-left: auto; display: flex; align-items: center; gap: 6px; }

.prop {
  position: relative;
  display: grid; gap: 11px;
  padding: 15px 16px;
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  transition: border-color var(--t-fast), opacity var(--t-mid),
              transform var(--t-mid), box-shadow var(--t-fast);
}
.prop + .prop { margin-top: 9px; }
.prop:hover { border-color: var(--line); }
.prop--cursor { border-color: var(--signal-line); box-shadow: var(--sh-2), 0 0 0 1px var(--signal-line); }
.prop--busy { opacity: 0.55; pointer-events: none; }
.prop--gone { opacity: 0; transform: translateY(-6px) scale(0.985); }

.prop__hd { display: flex; align-items: flex-start; gap: 11px; }
.prop__hd input[type="checkbox"] { margin: 4px 0 0; accent-color: var(--signal-deep); }
.prop__ttl { flex: 1 1 auto; min-width: 0; font-size: 15px; font-weight: 600; line-height: 1.4; }
.prop__why { font-size: 13.5px; line-height: 1.5; color: var(--fg-dim); }
.prop__why a { border-bottom: 1px solid var(--signal-line); }

/* Evidence is the one quotation in the app, so it gets the serif. */
.prop__ev {
  padding: 2px 0 2px 13px;
  border-left: 2px solid var(--line);
  font-family: var(--serif); font-size: 14.5px; line-height: 1.45;
  color: var(--fg-dim);
}
.prop__meta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }

/* A mail draft in place of the date/priority row: this is the text that will
   sit in Drafts, so it is shown as the mail it is rather than as metadata.
   The body keeps its newlines: the paragraph breaks are what get turned into
   <p> tags server-side, so what you read here is what you will send. */
.prop__draft {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 7px;
  background: var(--bg-sunk, transparent);
}
.prop__draftmeta { font: 400 12px/1.45 var(--mono); color: var(--fg-mute); }
.prop__draftmeta b { color: var(--fg-faint); font-weight: 400; }
.prop__draftbody {
  white-space: pre-wrap;
  font-size: 13.5px; line-height: 1.55; color: var(--fg-dim);
}
.prop__src {
  display: flex; align-items: center; gap: 7px;
  font: 400 11.5px/1 var(--mono); color: var(--fg-faint);
}
.prop__src svg { width: 13px; height: 13px; }
.prop__src a { color: var(--fg-mute); border-bottom: 1px solid var(--line); }
.prop__src a:hover { color: var(--fg); border-bottom-color: var(--signal); }
.prop__act { display: flex; align-items: center; gap: 8px; }
/* The source sits left, the decision right: reading before deciding.
   Trailing 3 = chat/Nee/Ja, always the last three regardless of how many
   optional source/action links precede them. */
.prop__act > :nth-last-child(3) { margin-left: auto; }
.prop__nosrc {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--fg-faint);
}
.prop__nosrc svg { width: 13px; height: 13px; }
.prop__err { font-size: 12.5px; color: var(--rose); }

/* aside -------------------------------------------------------------- */

.aside {
  display: flex; flex-direction: column;
  min-height: 0; min-width: 0;
  background: var(--bg-1);
}
.aside__tabs {
  flex: 0 0 auto; display: flex; gap: 2px;
  padding: 9px 12px; border-bottom: 1px solid var(--line-soft);
}
.aside__tab {
  padding: 6px 11px; border-radius: var(--r-sm);
  font-size: 12.5px; font-weight: 500; color: var(--fg-mute);
  transition: color var(--t-fast), background var(--t-fast);
}
.aside__tab:hover { color: var(--fg-dim); background: var(--bg-3); }
.aside__tab[aria-selected="true"] { color: var(--fg); background: var(--bg-3); }
.aside__tab span { font: 500 10px/1 var(--mono); color: var(--fg-faint); margin-left: 5px; }
.aside__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 12px; }

.tgroup + .tgroup { margin-top: 14px; }
.tgroup__h {
  display: flex; align-items: center; gap: 8px;
  width: 100%; text-align: left;
  margin: 0 0 8px; padding: 5px 4px;
  border-radius: var(--r-sm);
  transition: background var(--t-fast);
}
button.tgroup__h:hover { background: var(--bg-3); }
.tgroup__h .overline { flex: 0 0 auto; }
.tgroup__h .n { font: 500 10px/1 var(--mono); color: var(--fg-faint); }
.tgroup__sp { flex: 1 1 auto; }
.tgroup--late .overline { color: var(--rose); }
.tgroup--today .overline { color: var(--amber); }

/* Collapsed groups keep a one-line trace of what is inside, so folding them
   away does not also hide that something is due on Friday. */
.tgroup__chev {
  display: grid; place-items: center; width: 14px; height: 14px;
  color: var(--fg-faint); flex: 0 0 auto;
  transition: transform var(--t-fast);
}
.tgroup__chev svg { width: 13px; height: 13px; }
.tgroup--closed .tgroup__chev { transform: rotate(-90deg); }
.tgroup--closed .tgroup__body { display: none; }
.tgroup__peek { font: 400 10.5px/1 var(--mono); color: var(--fg-faint); }
.tgroup:not(.tgroup--closed) .tgroup__peek { display: none; }

/* Two independent visual channels so they can co-occur: the left edge
   carries priority, the trailing dot carries authorship. In v1 an Ashley
   task could never show as high priority because both used the same slot. */
.task {
  position: relative;
  display: grid; gap: 5px;
  width: 100%; text-align: left;
  padding: 10px 11px 10px 12px;
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
  border-left: 2px solid var(--line);
  border-radius: var(--r-sm);
  transition: border-color var(--t-fast), background var(--t-fast);
}
.task + .task { margin-top: 6px; }
.task:hover { background: var(--bg-3); border-color: var(--line); }
.task--high { border-left-color: var(--rose); }
.task--low { border-left-color: transparent; }
.task--muted { opacity: 0.5; }
.task__top { display: flex; align-items: center; gap: 7px; }
.task__code {
  font: 500 10px/1 var(--mono); letter-spacing: 0.04em;
  color: var(--fg-mute); background: var(--bg-4);
  padding: 3px 5px; border-radius: 4px; flex: 0 0 auto;
}
.task__due { margin-left: auto; font: 500 10.5px/1 var(--mono); color: var(--fg-mute); flex: 0 0 auto; }
.task--late .task__due { color: var(--rose); }
.task__by {
  width: 5px; height: 5px; border-radius: 50%; background: var(--signal);
  flex: 0 0 auto;
}
.task__subj { font-size: 13px; line-height: 1.4; color: var(--fg); }
.task__body { font-size: 12px; line-height: 1.45; color: var(--fg-mute);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.task__nudge { font: 400 10.5px/1 var(--mono); color: var(--fg-faint); }

.actlog { display: grid; gap: 9px; }
.actlog__row {
  display: grid; grid-template-columns: 46px 1fr; gap: 10px;
  font-size: 12.5px; color: var(--fg-dim);
  padding-bottom: 9px; border-bottom: 1px solid var(--line-soft);
}
.actlog__row:last-child { border-bottom: 0; padding-bottom: 0; }
.actlog__t { font: 500 10.5px/1.5 var(--mono); color: var(--fg-faint); }

/* ── 8. meetings module ─────────────────────────────────────────────── */

.mtg { display: grid; grid-template-columns: 258px minmax(0, 1fr); height: 100%; min-height: 0; }

.mtg__list {
  display: flex; flex-direction: column; min-height: 0;
  background: var(--bg-1); border-right: 1px solid var(--line-soft);
}
.mtg__search { padding: 11px 12px; border-bottom: 1px solid var(--line-soft); }
.mtg__search .field { width: 100%; }
.mtg__searchmeta {
  display: flex; align-items: center; gap: 8px; margin-top: 8px;
  font: 400 11px/1 var(--mono); color: var(--fg-faint);
}
.mtg__days { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 8px; }

.dayrow {
  display: grid; grid-template-columns: 40px 1fr auto; align-items: center; gap: 10px;
  width: 100%; text-align: left;
  padding: 9px 10px; border-radius: var(--r-sm);
  border: 1px solid transparent;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.dayrow:hover { background: var(--bg-3); }
.dayrow--on { background: var(--bg-3); border-color: var(--line); }
.dayrow--on .dayrow__num { color: var(--fg); }
.dayrow__cal { text-align: center; }
.dayrow__dow { font: 500 9px/1 var(--mono); letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--fg-faint); }
.dayrow__num { font-family: var(--serif); font-size: 20px; line-height: 1.1; color: var(--fg-dim); }
.dayrow__meta { min-width: 0; }
.dayrow__mon { font-size: 12.5px; color: var(--fg-dim); }
.dayrow__strip { position: relative; margin-top: 5px; height: 4px; border-radius: 2px; background: var(--bg-4); }
.dayrow__strip i { position: absolute; top: 0; bottom: 0; border-radius: 1px; background: var(--signal-deep); }

.mtg__day { min-width: 0; min-height: 0; overflow-y: auto; overscroll-behavior-y: contain; padding: 22px var(--pad) 60px; }
.mtg__dayinner { max-width: 940px; margin: 0 auto; }

/* The spine: one vertical time axis the whole day hangs off. Chains are a
   thicker signal segment of the same spine rather than an SVG overlay. */
.spine { position: relative; margin-top: 24px; padding-left: 74px; }
.spine::before {
  content: ""; position: absolute; left: 55px; top: 6px; bottom: 6px;
  width: 1px; background: var(--line);
}

.seg { position: relative; }
.seg + .seg { margin-top: 14px; }
.seg__time {
  position: absolute; left: -74px; top: 15px; width: 44px; text-align: right;
  font: 500 11.5px/1.3 var(--mono); color: var(--fg-dim);
}
.seg__time small { display: block; font-size: 10px; color: var(--fg-faint); font-weight: 400; }
.seg__knot {
  position: absolute; left: -23px; top: 19px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--bg-0); border: 2px solid var(--line-strong);
  z-index: 1;
}
.seg--done .seg__knot { border-color: var(--signal-deep); }
.seg--chain .seg__knot { background: var(--signal-deep); border-color: var(--signal-deep); }

.chainmark {
  position: absolute; left: -20px; width: 3px; border-radius: 2px;
  background: var(--signal-line);
}

.card {
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  overflow: hidden;
  transition: border-color var(--t-fast);
}
.card:hover { border-color: var(--line); }

.seg__hd { display: flex; align-items: flex-start; gap: 11px; padding: 14px 16px 0; }
.seg__ttl { flex: 1 1 auto; min-width: 0; }
.seg__ttl h3 { font-size: 15.5px; line-height: 1.35; }
.seg__ttl .seg__loc {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 6px;
  font: 400 11.5px/1 var(--mono); color: var(--fg-faint);
}
.seg__body { padding: 12px 16px 14px; display: grid; gap: 13px; }
.seg__sum { font-size: 14px; line-height: 1.58; color: var(--fg-dim); }
.seg__row { display: flex; gap: 7px; flex-wrap: wrap; }

.kv { display: grid; gap: 7px; }
.kv__k { }

.person {
  display: grid; grid-template-columns: auto 1fr; gap: 9px; align-items: baseline;
  font-size: 13px; line-height: 1.45;
}
.person b { font-weight: 600; white-space: nowrap; }
.person span { color: var(--fg-mute); }

.insight {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 3px 0 3px 13px; border-left: 2px solid var(--signal-line);
  font-size: 14.5px; line-height: 1.5; color: var(--fg-dim);
}
.insight svg { flex: none; margin-top: 2px; color: var(--signal-deep); }
.insight + .insight { margin-top: 9px; }

/* Segment-control: alle tabs in één pill-container, compacter dan losse
   tekstlabels met onderstreep. De tabbladen schuiven; mailen en weggooien
   blijven staan. Zonder dit duwde een smal scherm die twee buiten beeld, en
   de prullenbak was de enige weg om een opname weg te gooien. */
.tabs {
  display: flex; gap: 2px; padding: 6px 16px;
  border-top: 1px solid var(--line-soft); background: var(--bg-1);
}
.tabs__scroll {
  display: flex; gap: 2px; min-width: 0;
  overflow-x: auto; overscroll-behavior-x: contain;
  scrollbar-width: none; -ms-overflow-style: none;
}
.tabs__scroll::-webkit-scrollbar { display: none; }
/* Fade aan de rechterrand zodra er tabbladen afgeknipt worden; de class zet
   segTabs in views/meetings.js op basis van scrollWidth. */
.tabs__scroll.tabs--cut {
  mask-image: linear-gradient(to right, black calc(100% - 28px), transparent);
  -webkit-mask-image: linear-gradient(to right, black calc(100% - 28px), transparent);
}
.tabs__t {
  position: relative; flex: none; padding: 5px 10px;
  font-size: 12px; font-weight: 500; color: var(--fg-mute);
  border-radius: var(--r-pill); white-space: nowrap;
  transition: color var(--t-fast), background var(--t-fast), box-shadow var(--t-fast);
}
.tabs__t:hover:not(:disabled) { color: var(--fg-dim); background: var(--bg-3); }
/* Mailing a recording is disabled until there is a verslag or a dialoog to
   mail; without this it looked identical to a live tab and read as broken. */
.tabs__t:disabled { opacity: 0.4; cursor: default; }
.tabs__t[aria-selected="true"] {
  color: var(--fg); background: var(--bg-3);
  box-shadow: inset 0 0 0 1px var(--line-soft);
}
.tabs__t span { font: 500 10px/1 var(--mono); color: var(--fg-faint); margin-left: 5px; }
/* Verslag staat er nog, maar het transcript is er sindsdien op veranderd
   (detail_stale/dialogue_stale). Zie staleNote in views/meetings.js. */
.tabs__t span.tabs__stale { color: var(--amber); font-weight: 700; }
.tabs__sp { flex: 1 1 auto; }
.tabpanel { padding: 16px; background: var(--bg-1); border-top: 1px solid var(--line-soft); }
.tabpanel--pad0 { padding: 0; }

.transcript {
  max-height: 62vh; overflow-y: auto;
  padding: 14px 16px;
  font: 400 13px/1.7 var(--mono);
  white-space: pre-wrap; overflow-wrap: anywhere;
  color: var(--fg-dim);
}
/* Hits, wherever they occur: transcript, report, dialogue, speakers, attachments.
   The active hit gets an outline, so that when jumping through them you can see
   which of the twelve highlighted words you are currently looking at. */
.mtg__day mark, .transcript mark {
  background: var(--signal-wash); color: var(--fg); border-radius: 3px; padding: 0 2px;
}
.mtg__day mark.mark--cur {
  background: var(--amber, #f5c451); color: #1a1a1a;
  box-shadow: 0 0 0 2px var(--amber, #f5c451);
}

/* Small search bar bottom-right: term, counter and arrows. */
.hitbar {
  position: fixed; right: 18px; bottom: 18px; z-index: 60;
  display: flex; align-items: center; gap: 8px;
  padding: 7px 9px 7px 12px;
  /* --bg-elev does not exist in this theme, so there was no background here and
     you read the text underneath straight through the bar. */
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: 999px; box-shadow: var(--sh-3);
  backdrop-filter: saturate(1.3) blur(18px);
}
.hitbar[hidden] { display: none; }
.hitbar__q { font-size: 13px; font-weight: 600; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hitbar__n { font: 400 12px/1 var(--mono); color: var(--fg-mute); font-variant-numeric: tabular-nums; }
.hitbar .iconbtn:disabled { opacity: .35; pointer-events: none; }

/* The text in which a speaker was found. */
.spk__match { font-size: 12px; color: var(--fg-mute); margin: 6px 0 2px; }

/* Utterance rows. `white-space: pre-wrap` from .transcript would turn the
   markup's own indentation into visible gaps, so rows opt out of it. */
.transcript--rows { white-space: normal; padding: 8px 16px 12px; }
.tx__row { display: grid; grid-template-columns: 122px 1fr; gap: 10px; padding: 2px 0; }

/* --- Teams-transcript paneel (officieel, met sprekersnamen) --- */
.teams-empty { padding: 18px 16px; display: grid; gap: 10px; justify-items: start; }
.teams-empty .muted { color: var(--fg-faint); font-size: 0.92em; max-width: 60ch; }
.teams-meta { padding: 8px 16px 2px; color: var(--fg-faint); font-size: 0.85em; }
.teams-list { max-height: 420px; overflow-y: auto; }
.tt-row { display: grid; grid-template-columns: 220px 1fr; gap: 10px; padding: 2px 0; }
.tt-spk { font-weight: 600; }
/* nowrap plus flex-shrink 0: the clock and the source pill each broke across
   two lines when a row was narrow, which made the gutter taller than its own
   line of text. */
.tx__meta { display: flex; align-items: baseline; gap: 5px; justify-content: flex-end;
  flex-wrap: nowrap; white-space: nowrap;
  font: 500 10.5px/1.7 var(--mono); color: var(--fg-faint); }
.tx__meta > * { flex: 0 0 auto; }
.tx__clock { letter-spacing: -0.01em; }
.tx__src { padding: 0 4px; border-radius: 3px; border: 1px solid var(--line-soft); }
.tx__src--mic { color: var(--signal-deep); border-color: var(--signal-line); }
.tx__spk { color: var(--fg-faint); }
.tx__txt { color: var(--fg-dim); }

/* The cut seam sits in the flow but takes no height until hovered, so a long
   transcript does not turn into a ladder of buttons. */
.tx__seam { position: relative; height: 5px; }
.tx__cut {
  position: absolute; left: 0; right: 0; top: -3px; height: 11px;
  display: flex; align-items: center; gap: 5px;
  opacity: 0; transition: opacity var(--t-fast);
  font: 500 10px/1 var(--mono); color: var(--fg-mute);
}
.tx__cut::after {
  content: ""; flex: 1 1 auto; height: 1px;
  background: repeating-linear-gradient(90deg, var(--line-strong) 0 4px, transparent 4px 8px);
}
.tx__seam:hover .tx__cut, .tx__cut:focus-visible { opacity: 1; }
.tx__cut:hover { color: var(--signal-deep); }
.tx__cut:disabled { cursor: progress; opacity: 0.5; }

/* The seam between two recordings: same idea, one level up. Quiet until you
   hover the boundary, because these are the destructive-ish controls. */
.seam { position: relative; height: 22px; }
.seam__acts {
  position: absolute; left: 0; top: 1px;
  display: flex; align-items: center; gap: 6px;
  opacity: 0; transition: opacity var(--t-fast);
}
.seam:hover .seam__acts, .seam:focus-within .seam__acts { opacity: 1; }
.seam__gap { font: 500 10px/1 var(--mono); color: var(--fg-faint); }
.seam .chip { padding: 3px 7px; font-size: 10.5px; }
/* No bar for .seam--linked: a seam inside a chain already sits on the
   .chainmark that spans the whole run. */

.actions { display: grid; gap: 7px; }
.action {
  display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center;
  padding: 9px 11px; border-radius: var(--r-sm);
  background: var(--bg-2); border: 1px solid var(--line-soft);
  font-size: 13.5px; line-height: 1.45;
}
.action__due { font: 500 10.5px/1 var(--mono); }
.action--done { opacity: 0.6; }

.spk { display: grid; gap: 6px; }
/* Four columns now: audio channel, editable name, talk-share bar, percentage.
   The channel stays visible because it, not the name, is what ties a speaker to
   lines in the transcript. The name column is `auto` capped at 220px rather
   than `1fr`: a one-word name stretching across the whole panel width looked
   broken, and the talk-share bar needs its own fixed room regardless of panel
   width. */
.spk__row { display: grid; grid-template-columns: 62px minmax(120px, 220px) 1fr 38px; gap: 10px;
  align-items: center; font-size: 12.5px; }
.spk__name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.spk__id { display: flex; align-items: center; gap: 4px;
  font: 500 10.5px/1.6 var(--mono); color: var(--fg-faint); }
.spk__input { width: 100%; max-width: 220px; padding: 4px 8px; font-size: 12.5px; }

/* One speaker's turns inside the surrounding transcript: their lines lit, the
   rest dim, so a fragment can be read in context. */
.spkctx { max-height: 260px; overflow-y: auto; margin-top: 6px;
  border-left: 2px solid var(--line-soft); padding-left: 9px; }
.spkctx__l { display: grid; grid-template-columns: 42px 1fr; gap: 9px;
  font-size: 12.5px; line-height: 1.5; padding: 2px 0; color: var(--fg-faint); }
.spkctx__l--on { color: var(--fg-dim); }
.spkctx__l--on .spkctx__t { color: var(--signal-deep); }
.spkctx__t { font: 500 10.5px/1.7 var(--mono); color: var(--fg-faint); }
.spk__bar { height: 5px; border-radius: 3px; background: var(--bg-4); overflow: hidden; }
.spk__bar i { display: block; height: 100%; background: var(--signal-deep); border-radius: 3px; }
.spk__pct { text-align: right; font: 500 11px/1 var(--mono); color: var(--fg-mute); }

.atts { display: flex; gap: 8px; flex-wrap: wrap; }
.att {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: var(--r-sm);
  background: var(--bg-2); border: 1px solid var(--line-soft);
  font-size: 12.5px; color: var(--fg-dim);
  transition: border-color var(--t-fast);
}
.att:hover { border-color: var(--line-strong); color: var(--fg); }
.att svg { width: 14px; height: 14px; color: var(--fg-faint); }
.att__sz { font: 400 10.5px/1 var(--mono); color: var(--fg-faint); }
.att img { width: 30px; height: 30px; object-fit: cover; border-radius: 5px; }

/* The cross sits on the chip rather than inside it: `.att` is a button, and a
   button inside a button is neither valid nor clickable. The wrapper carries
   the positioning so the chip itself keeps its own layout. */
.att__wrap { position: relative; display: inline-flex; }
.att__del {
  position: absolute; top: -6px; right: -6px;
  display: grid; place-items: center;
  width: 18px; height: 18px; padding: 0; border-radius: 50%;
  background: var(--bg-3); border: 1px solid var(--line);
  color: var(--fg-mute); cursor: pointer;
  opacity: 0; transition: opacity var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.att__wrap:hover .att__del, .att__del:focus-visible { opacity: 1; }
.att__del:hover { color: var(--rose); border-color: var(--rose); }
.att__del svg { width: 10px; height: 10px; color: inherit; }
/* No hover on touch, so there is nothing to reveal: show it always. */
@media (hover: none) { .att__del { opacity: 1; } }

.hit {
  display: grid; gap: 5px; width: 100%; text-align: left;
  padding: 10px 11px; border-radius: var(--r-sm);
  border: 1px solid transparent;
}
.hit:hover { background: var(--bg-3); border-color: var(--line-soft); }
.hit__d { font: 500 10.5px/1 var(--mono); color: var(--signal-deep); }
.hit__x { font-size: 12.5px; line-height: 1.5; color: var(--fg-mute); }
.hit__x mark { background: var(--signal-wash); color: var(--fg); }

/* ── 9. deadlines and costs ─────────────────────────────────────────── */

.board { padding: 22px var(--pad) 60px; overflow-y: auto; overscroll-behavior-y: contain; height: 100%; }
.board__inner { max-width: 1140px; margin: 0 auto; }

/* Flex, not grid: with zero-value tiles omitted (see deadlines.js) the number
   of cards varies, and `auto-fit` on a grid fills that gap by stretching the
   remaining tiles wider. Flex with a fixed minimum width lets each tile
   keep its own width and only wraps the row once they genuinely no longer
   fit, instead of wrapping by default after six. */
.stats { display: flex; flex-wrap: wrap; gap: 10px; }
.stat {
  flex: 1 1 140px; min-width: 140px; max-width: 220px;
  padding: 14px 15px;
  background: var(--bg-2); border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
}
.stat__n { font-family: var(--serif); font-size: 30px; line-height: 1; letter-spacing: -0.02em; }
.stat__k { margin-top: 7px; }
.stat--late .stat__n { color: var(--rose); }
.stat--today .stat__n { color: var(--amber); }
.stat__sub { margin-top: 4px; font-size: 11.5px; color: var(--fg-faint); }

.cols { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(292px, 1fr)); }

.bars { display: grid; gap: 7px; }
.bars__row { display: grid; grid-template-columns: minmax(0, 108px) 1fr 62px; gap: 10px;
  align-items: center; font-size: 12.5px; }
.bars__k { font: 500 11px/1 var(--mono); color: var(--fg-mute); }
.bars__t { height: 8px; border-radius: 4px; background: var(--bg-4); overflow: hidden; }
.bars__t i { display: block; height: 100%; border-radius: 4px; background: var(--signal-deep);
  transition: width var(--t-slow); }
.bars__v { text-align: right; font: 500 11.5px/1 var(--mono); color: var(--fg-dim); }

.table { width: 100%; border-collapse: collapse; font-size: 13px; }
.table th {
  text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--line);
  font: 500 10px/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--fg-mute); white-space: nowrap;
}
.table td { padding: 9px 10px; border-bottom: 1px solid var(--line-soft); }
.table tbody tr:hover { background: var(--bg-3); }
.table .num { text-align: right; font-family: var(--mono); font-size: 12px; }

.section { margin-top: 26px; }
.section__h { display: flex; align-items: center; gap: 11px; margin-bottom: 12px; }
.section__h h2 { flex: 1 1 auto; font-size: 15px; }

/* ── 9a2. onboarding (connectors + ingest tokens) ─────────────────────── */

.onboarding__banner:empty { display: none; }
.onboarding__banner .notice { margin-bottom: 18px; }

.onboarding__grid {
  display: grid; gap: 18px; margin-top: 18px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  /* Elke kaart krijgt zijn eigen hoogte. Standaard rekt een grid alle kaarten
     op een rij even hoog, en dan trok het uitklappen van "Verbinden via
     Chrome" de Gmail-kaart ernaast mee omhoog, met een groot leeg vlak tot
     gevolg (gezien 2026-08-30). Uitklappen hoort alleen de kaart te
     veranderen waarop geklikt is. */
  align-items: start;
}
/* De inhoud mag wel de hoogte van de kaart vullen: `start` hierboven geldt
   voor de kaart in het raster, niet voor wat erin staat. */
.onboarding__card { padding: 16px; display: grid; gap: 12px; align-content: start; }
/* min-width: 0 overrides the grid item default of min-width: auto (=
   max-content). Without it, this flex row refuses to shrink below its
   children's natural width when the card is narrow, so it overflows the
   card instead of wrapping - and .card's overflow: hidden then clips the
   status badge flush against the border (screenshot, Benjamin 2026-08-30). */
.onboarding__cardhd { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }
.onboarding__cardhd img, .onboarding__cardhd svg { flex: 0 0 auto; margin-top: 2px; }
.onboarding__cardhd > div { flex: 1 1 auto; min-width: 0; }
.onboarding__icon {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 26px; height: 26px; margin-top: 1px;
  color: var(--fg-dim);
}
.onboarding__steps {
  margin: 0; padding-left: 18px; display: grid; gap: 4px;
  font-size: 13px; color: var(--fg-dim); line-height: 1.5;
}
.onboarding__meta { font-size: 12.5px; color: var(--fg-mute); display: grid; gap: 4px; }
/* Granted OAuth scopes: reference detail rather than something to read on
   every visit, so smaller than the rest of the meta block. The scope string is
   one long unbroken run of dotted names, so it needs an explicit break rule to
   avoid pushing the card wider than its grid column. */
.onboarding__scopes { font-size: 11px; line-height: 1.45; overflow-wrap: anywhere; }
.onboarding__actions { display: flex; gap: 8px; flex-wrap: wrap; }
.onboarding__reveal:empty { display: none; }
.onboarding__tokenrow { display: flex; gap: 8px; align-items: center; }
.onboarding__tokenrow .field { flex: 1 1 auto; }

/* The Chrome-extension pairing is the FALLBACK for when corporate IT blocks
   the Microsoft OAuth consent (product decision Benjamin, 2026-08-30), so it
   is collapsed behind a disclosure inside the Microsoft 365 card instead of
   being a card of its own. No new design tokens: same --line-soft border,
   --fg-dim/--fg-mute text and 13px scale the rest of this block uses. */
.onboarding__fallback {
  border-top: 1px solid var(--line-soft);
  padding-top: 12px;
  display: grid; gap: 10px;
}
.onboarding__fallback > summary {
  cursor: pointer; font-size: 13px; color: var(--fg-dim);
  list-style: none; display: flex; align-items: center; gap: 6px;
}
.onboarding__fallback > summary::-webkit-details-marker { display: none; }
.onboarding__fallback > summary::before {
  content: '\203A'; display: inline-block; transition: transform .15s ease;
  color: var(--fg-mute);
}
.onboarding__fallback[open] > summary::before { transform: rotate(90deg); }
.onboarding__fallback > summary:hover { color: var(--fg); }
.onboarding__fallbackbody { display: grid; gap: 10px; }
.onboarding__fallbackbody .onboarding__steps { margin-top: 0; }

/* ── 9b. theme gallery ──────────────────────────────────────────────── */

.tp__grid {
  display: grid; gap: 18px; margin-top: 22px;
  grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
}
.tp__family {
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: 10px;
  margin: 12px 0 -4px; padding-bottom: 8px;
  border-bottom: 1px solid var(--line-soft);
}
.tp__family .mono { font-size: 10.5px; color: var(--fg-faint); }

.tp__card {
  display: block; width: 100%; text-align: left;
  padding: 0; overflow: hidden;
  background: var(--bg-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  transition: border-color var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
}
.tp__card:hover { border-color: var(--line-strong); transform: translateY(-2px); box-shadow: var(--sh-2); }
.tp__card--on { border-color: var(--signal); box-shadow: var(--sh-2), 0 0 0 1px var(--signal); }

/* The mock is a fixed 1200x760 and gets scaled by a transform, so the frame
   owns the clipping and the computed height. */
.tp__frame {
  position: relative; width: 100%; overflow: hidden;
  border-bottom: 1px solid var(--line-soft);
  background: var(--bg-0);
}
.tp__scale { transform-origin: top left; }
/* Inert: hovering a card must not light up controls inside the preview. */
.tp__skin { pointer-events: none; user-select: none; }

.tp__meta { padding: 13px 15px 15px; }
.tp__name {
  display: flex; align-items: center; gap: 8px;
  font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em;
}
.tp__note { margin-top: 5px; font-size: 12.5px; line-height: 1.45; color: var(--fg-mute); }
.tp__swatches {
  display: flex; align-items: center; gap: 5px; margin-top: 11px;
  padding-top: 11px; border-top: 1px solid var(--line-soft);
}
.tp__swatches i {
  width: 18px; height: 18px; border-radius: 5px;
  box-shadow: inset 0 0 0 1px oklch(0.5 0 0 / 0.22);
}
.tp__swatches .mono { margin-left: auto; font-size: 10.5px; color: var(--fg-faint); }

/* full-size hover preview */
/* Opened by a click, not a hover, so it is interactive: it carries the arrows
   and the apply button. */
.tp__stage {
  position: fixed; inset: 0; z-index: 86;
  display: grid; grid-template-rows: auto 1fr auto; gap: 12px;
  padding: 16px 22px 18px;
  background: color-mix(in oklab, var(--bg-0) 93%, transparent);
  backdrop-filter: blur(7px);
  animation: fade var(--t-fast) both;
}
.tp__stagebar {
  display: flex; align-items: center; gap: 10px;
  padding: 0 2px;
}
.tp__count { font-size: 12px; color: var(--fg-dim); min-width: 56px; text-align: center; }
.tp__hint {
  margin-left: auto; display: flex; align-items: center; gap: 5px;
  font-size: 11.5px; color: var(--fg-faint);
}
.tp__hint .mono {
  font-size: 10px; border: 1px solid var(--line-soft);
  border-radius: 4px; padding: 2px 5px;
}
.tp__stagenote { color: var(--fg-mute); }
@media (max-width: 820px) { .tp__hint { display: none; } }
.tp__stage[hidden] { display: none; }
.tp__stagelabel {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
  font-size: 13px; color: var(--fg-mute);
}
.tp__stagelabel b { font-size: 16px; color: var(--fg); font-weight: 600; }
.tp__stagelabel .mono { font-size: 11px; color: var(--signal-deep); }
.tp__stageframe {
  min-height: 0; min-width: 0;
  display: flex; align-items: flex-start; justify-content: center;
  overflow: hidden;
}
.tp__stageframe .tp__skin {
  border-radius: var(--r-lg); overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: var(--sh-3);
}
/* The preview stays inert; only the bar around it is clickable. */
.tp__stageframe { cursor: zoom-out; }

@media (max-width: 700px) {
  .tp__grid { grid-template-columns: 1fr; }
}

/* ── 9c. the mock itself ────────────────────────────────────────────── */
/* Only geometry. Every colour, font and radius comes from the skin tokens. */

.mk {
  display: grid; grid-template-columns: 66px 1fr;
  width: 1200px; height: 760px;
  background: var(--bg-0); color: var(--fg);
  font: 400 15px/1.55 var(--sans);
  font-variant-numeric: tabular-nums;
}
.mk__rail {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 0 14px;
  background: var(--bg-1); border-right: 1px solid var(--line-soft);
  color: var(--fg-mute);
}
.mk__rail svg { width: 18px; height: 18px; }
.mk__mark {
  width: 30px; height: 30px; margin-bottom: 10px;
  display: grid; place-items: center;
  font-family: var(--serif); font-size: 19px; line-height: 1;
  color: var(--solid-fg); background: var(--signal); border-radius: 9px;
}
.mk__railitem {
  width: 44px; height: 40px; display: grid; place-items: center; border-radius: var(--r-md);
}
.mk__railitem--on { color: var(--fg); background: var(--bg-3); }

.mk__surface { display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }
.mk__top {
  display: flex; align-items: center; gap: 10px;
  height: 56px; padding: 0 14px 0 18px; flex: 0 0 auto;
  border-bottom: 1px solid var(--line-soft);
}
.mk__crumb { display: flex; align-items: center; gap: 9px; font-size: 13.5px; color: var(--fg-dim); }
.mk__crumb b { font-weight: 600; color: var(--fg); }

/* `flex: 1 1 0`, not `1 1 auto`: with an auto basis the row takes its content
   height first and pushed the composer out of the fixed 760px preview. A zero
   basis makes it take exactly the space the topbar and composer leave. */
.mk__cols { display: grid; grid-template-columns: 1fr 336px; flex: 1 1 0;
  min-height: 0; overflow: hidden; }
.mk__main { padding: 20px 26px 0; overflow: hidden; min-width: 0; }
.mk__aside {
  display: flex; flex-direction: column; min-width: 0;
  background: var(--bg-1); border-left: 1px solid var(--line-soft);
}
.mk__asidebody { padding: 12px; overflow: hidden; }
.mk__composer { flex: 0 0 auto; padding: 10px 26px 16px; }
.mk .display { font-size: 34px; }
.mk .thread { gap: 18px; }
.mk .prop + .prop { margin-top: 0; }

/* ── 10. command palette ────────────────────────────────────────────── */

.pal {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: start center;
  padding: 11vh 18px 18px;
  background: oklch(0 0 0 / 0.42);
  backdrop-filter: blur(3px);
  animation: fade var(--t-fast) both;
}
@keyframes fade { from { opacity: 0; } }
.pal__box {
  width: min(720px, 100%);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-3);
  overflow: hidden;
  animation: rise var(--t-mid) both;
}
@keyframes rise { from { opacity: 0; transform: translateY(-8px) scale(0.985); } }
.pal__in {
  display: flex; align-items: center; gap: 11px;
  padding: 14px 16px; border-bottom: 1px solid var(--line-soft);
}
.pal__in svg { width: 16px; height: 16px; color: var(--fg-faint); }
.pal__in input {
  flex: 1 1 auto; min-width: 0;
  background: none; border: 0; outline: none; font-size: 15.5px;
}
.pal__in input::placeholder { color: var(--fg-faint); }
.pal__list { max-height: 46vh; overflow-y: auto; padding: 7px; }
.pal__grp { padding: 9px 10px 5px; }
.pal__row {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  padding: 9px 11px; border-radius: var(--r-sm); color: var(--fg-dim);
}
.pal__row[aria-selected="true"] { background: var(--bg-3); color: var(--fg); }
.pal__row svg { width: 15px; height: 15px; flex: 0 0 auto; color: var(--fg-faint); }
.pal__row[aria-selected="true"] svg { color: var(--signal); }
.pal__lbl { flex: 1 1 auto; min-width: 0; font-size: 13.5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pal__sub {
  flex: 0 1 auto; max-width: 150px; text-align: right;
  font: 400 11px/1 var(--mono); color: var(--fg-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pal__foot {
  display: flex; align-items: center; gap: 14px;
  padding: 9px 16px; border-top: 1px solid var(--line-soft);
  background: var(--bg-1);
  font-size: 11px; color: var(--fg-faint);
}
.pal__foot kbd { font: 500 10px/1 var(--mono);
  border: 1px solid var(--line-soft); border-radius: 4px; padding: 2px 4px; }

/* ── 11. dialogs and toasts ─────────────────────────────────────────── */

dialog {
  padding: 0; border: 0; color: var(--fg);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-3);
  max-width: min(520px, calc(100vw - 32px));
  width: 100%;
}
dialog::backdrop { background: oklch(0 0 0 / 0.45); backdrop-filter: blur(2px); }
dialog[open] { animation: rise var(--t-mid) both; }
.dlg__hd { padding: 17px 19px 0; }
.dlg__hd h2 { font-family: var(--serif); font-weight: 400; font-size: 21px; letter-spacing: -0.01em; }
.dlg__hd p { margin: 7px 0 0; font-size: 13.5px; color: var(--fg-dim); }
.dlg__bd { padding: 15px 19px; display: grid; gap: 12px; }
.dlg__ft {
  display: flex; align-items: center; gap: 8px;
  padding: 13px 19px; border-top: 1px solid var(--line-soft); background: var(--bg-1);
}
.dlg__ft .btn:last-child { margin-left: auto; }
.dlg__row { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.dlg__note { font-size: 12.5px; color: var(--fg-mute); min-height: 2.4em; }
.dlg label { font-size: 12.5px; color: var(--fg-mute); }
/* A textarea is not an input one line tall. This exception used to live only
   inside .dlg, which meant the first multi-line field outside a dialog (the
   memory page) collapsed to 33px and you couldn't see your own text. */
textarea.field { height: auto; min-height: 68px; padding: 9px 10px; resize: vertical;
  font-size: 13.5px; line-height: 1.5; width: 100%; }

/* recipient picker (mail a verslag) ----------------------------------- */
/* A field that looks like one input but holds chips plus a text input, with
   the directory suggestions hanging under it. The dropdown is absolutely
   positioned inside .rcpt__wrap rather than fixed: a <dialog> is in the top
   layer, so a fixed element positioned from a scroll offset lands in the wrong
   place as soon as the dialog itself scrolls. */
.dlg--mail { max-width: min(560px, calc(100vw - 32px)); }
.rcpt__wrap { position: relative; }
.rcpt {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
  /* Capped and scrollable: a meeting can legitimately have twenty people, and
     an uncapped chip box pushed the subject, the language row and the buttons
     off the screen (measured with a 211-recipient invite before the server
     stopped suggesting those at all). */
  min-height: 34px; max-height: 132px; overflow-y: auto; padding: 4px 6px;
  background: var(--bg-1); border: 1px solid var(--line);
  border-radius: var(--r-md); cursor: text;
}
.rcpt:focus-within { border-color: var(--signal-line); }
.rcpt__chips { display: contents; }
.rcpt__chip {
  display: inline-flex; align-items: center; gap: 4px;
  height: 22px; padding: 0 4px 0 9px;
  font-size: 12px; color: var(--fg);
  background: var(--bg-3); border: 1px solid var(--line-soft);
  border-radius: var(--r-pill); max-width: 100%;
}
.rcpt__chip > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rcpt__x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%; color: var(--fg-faint);
}
.rcpt__x:hover { color: var(--fg); background: var(--bg-2); }
.rcpt__in {
  flex: 1 1 130px; min-width: 130px; height: 24px;
  background: none; border: 0; color: var(--fg); font-size: 13.5px;
}
.rcpt__in:focus { outline: none; }
.rcpt__list {
  position: absolute; z-index: 5; left: 0; right: 0; top: calc(100% + 4px);
  max-height: 240px; overflow-y: auto;
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--sh-3);
}
.rcpt__opt {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 10px;
  padding: 7px 11px; cursor: pointer;
}
.rcpt__opt--on { background: var(--bg-3); }
.rcpt__optname { font-size: 13px; color: var(--fg); }
.rcpt__optmail { font: 500 11px/1.4 var(--mono); color: var(--fg-mute); }
.rcpt__optsub { grid-column: 1 / -1; font-size: 11.5px; color: var(--fg-faint); }
.rcpt__note { padding: 8px 11px; font-size: 12px; color: var(--fg-mute); }
.mail__lookup {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  max-height: 96px; overflow-y: auto;
}
.mail__check { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.mail__check input { accent-color: var(--signal-deep); }
.mail__lang { display: flex; align-items: center; gap: 10px; }
.mail__lang .field { width: auto; min-width: 160px; }

/* hover cards -------------------------------------------------------- */
/* Fixed, because segment cards and the aside clip with overflow: hidden.
   pointer-events stay on so the links inside are actually reachable. */
.hovercard {
  /* Above the command palette (z-index 90): a hover card opened on a palette
     row used to render, positioned correctly, right behind the palette's own
     backdrop -- invisible even though it existed in the DOM. Still below the
     lightbox/toast layers, which should stay on top of everything. */
  position: fixed; z-index: 91;
  width: min(430px, calc(100vw - 24px));
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--sh-3);
  animation: hcin 120ms cubic-bezier(0.32, 0.72, 0, 1) both;
}
@keyframes hcin { from { opacity: 0; transform: translateY(-3px); } }

.hovercard__hd { padding: 11px 13px 0; }
.hovercard__ttl { font-size: 13.5px; font-weight: 600; line-height: 1.4; }
.hovercard__meta {
  display: flex; gap: 10px; flex-wrap: wrap;
  margin-top: 6px; font-size: 11px; color: var(--fg-mute);
}
.hovercard__bd {
  padding: 10px 13px 12px;
  font-size: 12.5px; line-height: 1.55; color: var(--fg-dim);
  overflow-wrap: anywhere;
}
.hovercard__bd:empty { display: none; }
.hovercard__bd a, .hovercard__link {
  color: var(--fg); border-bottom: 1px solid var(--signal-line);
}
.hovercard__bd a:hover, .hovercard__link:hover { border-bottom-color: var(--signal); }
.hovercard__row { display: grid; grid-template-columns: 74px 1fr; gap: 9px; padding: 2px 0; }
.hovercard__k { font: 500 10px/1.6 var(--mono); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--fg-faint); }
.hovercard__ft {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 13px; border-top: 1px solid var(--line-soft);
  background: var(--bg-1); border-radius: 0 0 var(--r-md) var(--r-md);
  font-size: 12px;
}
.hovercard__quote {
  margin: 7px 0 0; padding: 2px 0 2px 11px;
  border-left: 2px solid var(--line);
  font-family: var(--serif); font-size: 13.5px; color: var(--fg-dim);
}

/* A trigger that has a card gets a hint, so you know to hover it. */
[data-hascard] { cursor: default; }
button[data-hascard], a[data-hascard] { cursor: pointer; }

.toasts {
  position: fixed; z-index: 95; bottom: 18px; left: 50%; transform: translateX(-50%);
  display: grid; gap: 8px; justify-items: center; pointer-events: none;
}
.toast {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 15px;
  background: var(--bg-3); border: 1px solid var(--line);
  border-radius: var(--r-pill); box-shadow: var(--sh-3);
  font-size: 13.5px; pointer-events: auto;
  animation: toastin var(--t-mid) both;
}
@keyframes toastin { from { opacity: 0; transform: translateY(10px); } }
.toast--out { animation: toastout var(--t-mid) both; }
@keyframes toastout { to { opacity: 0; transform: translateY(6px) scale(0.97); } }
.toast svg { width: 15px; height: 15px; }
.toast--ok svg { color: var(--jade); }
.toast--bad svg { color: var(--rose); }
.toast .btn { margin-left: 4px; }
.toast__dismiss {
  width: 22px; height: 22px; margin-left: 2px; flex: none;
  display: grid; place-items: center; border-radius: 50%;
  color: var(--fg-faint);
}
.toast__dismiss svg { width: 12px; height: 12px; }
.toast__dismiss:hover { background: var(--bg-4); color: var(--fg); }

.scrim {
  position: fixed; inset: 0; z-index: 35;
  background: oklch(0 0 0 / 0.4);
  animation: fade var(--t-fast) both;
}

.lightbox {
  position: fixed; inset: 0; z-index: 92;
  display: grid; place-items: center; padding: 24px;
  background: oklch(0 0 0 / 0.82);
  animation: fade var(--t-fast) both;
}
.lightbox img, .lightbox iframe {
  max-width: 100%; max-height: 100%;
  border-radius: var(--r-md); box-shadow: var(--sh-3);
  background: var(--bg-2); border: 0;
}
.lightbox iframe { width: min(980px, 100%); height: 90vh; }

/* ── 12. responsive ─────────────────────────────────────────────────── */

@media (max-width: 1180px) {
  :root { --aside-w: 296px; }
}

/* Declared before the media queries below: an unconditional rule placed after
   them would win at equal specificity and the toggles would never appear. */
.asideToggle, .listToggle { display: none; }

@media (max-width: 1040px) {
  .asst { grid-template-columns: minmax(0, 1fr); }
  .asst__main { border-right: 0; }
  /* The aside becomes a sheet from the right, opened from the topbar. */
  .aside {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 45;
    width: min(360px, 92vw);
    border-left: 1px solid var(--line);
    box-shadow: var(--sh-3);
    transform: translateX(100%);
    transition: transform var(--t-mid);
  }
  .aside--open { transform: none; }
  .asideToggle { display: inline-grid; }
}

@media (max-width: 900px) {
  :root { --rail-w: 0px; --topbar-h: 52px; }
  .view { --pad: 16px; }
  .shell { grid-template-columns: 1fr; }
  .rail {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 50;
    width: var(--rail-open);
    transform: translateX(-100%);
    transition: transform var(--t-mid);
    box-shadow: var(--sh-3);
    /* The drawer sits at the screen edge: respect the notch side. */
    padding-left: max(9px, env(safe-area-inset-left, 0px));
  }
  .rail--open { transform: none; }
  .rail__label, .rail__wordmark, .rail__count { opacity: 1 !important; }
  .rail__pip { opacity: 0; }
  /* Pinning only has a job on desktop: the mobile drawer always shows labels. */
  #pinBtn { display: none; }
  .surface { grid-column: 1; }
  .topbar .topbar__menu { display: inline-grid; }
  .omni { min-width: 0; }
  .omni__text, .omni__kbd { display: none; }
  /* flex-shrink would take this below its width and collapse it onto the
     icon, so the collapsed search button gets a fixed basis. */
  .omni { flex: 0 0 33px; width: 33px; padding: 0; justify-content: center;
    border-radius: var(--r-sm); }

  .mtg { grid-template-columns: 1fr; }
  .mtg__list {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 44;
    width: min(320px, 90vw); border-right: 1px solid var(--line);
    transform: translateX(-100%); transition: transform var(--t-mid);
    box-shadow: var(--sh-3);
  }
  .mtg__list--open { transform: none; }
  .listToggle { display: inline-grid; }

  .spine { padding-left: 0; }
  .spine::before { display: none; }
  .seg__time { position: static; width: auto; text-align: left; margin-bottom: 6px; display: flex; gap: 9px; }
  .seg__time small { display: inline; }
  .seg__knot, .chainmark { display: none; }
  .seg--chain > .card { border-left: 2px solid var(--signal-line); }

  .msg--u { max-width: 92%; }
  .chrono__legend { display: none; }
  .dayhead { flex-direction: column; align-items: stretch; gap: 12px; }
  .dayhead__nav { justify-content: space-between; }
  .composer { padding-bottom: max(16px, env(safe-area-inset-bottom)); }
}

/* Inside the iPhone app (see index.html's .is-ios-app): the app draws its own
   bottom bar for Assistant / Meetings / Todos and owns signing out, so the rail
   keeps only what the bar does NOT carry. Two ways to reach one screen that
   behave slightly differently is worse than one. */
html.is-ios-app .rail__item[data-nav="/v2"],
html.is-ios-app .rail__item[data-nav="/v2/meetings"],
html.is-ios-app .rail__item[data-nav="/v2/deadlines"],
html.is-ios-app #logoutBtn { display: none; }

/* One list, not two. On the desktop the rail is full height and the bottom
   group belongs at the bottom; in the app the drawer holds only what the bar
   does not carry, so pushing three of those to the far edge leaves a hole in
   the middle and makes them look like a different kind of thing. */
html.is-ios-app .rail__foot { margin-top: 2px; }

/* De app zet haar eigen balk over deze pagina heen, dus een melding onderaan
   landt eronder. Dezelfde maat die de rest van de pagina al krijgt. */
html.is-ios-app .toasts { bottom: calc(18px + var(--app-bottom-inset, 0px)); }

/* De vier voorbeeldvragen zijn er om een leeg scherm op een desktop op gang te
   helpen. Op een telefoon vullen ze het halve scherm met tekst die je niet
   gevraagd hebt, terwijl het veld eronder al zegt wat je kan doen. */
html.is-ios-app .suggest { display: none; }

/* The app floats its own bar over this page and tells us how tall it is
   (--app-bottom-inset, from WebShellModel.setInsets). Padding on the elements
   that actually reach the bottom, not on .surface: the message field is
   `position: sticky` inside the scrolling view, so it anchors to that view and
   sails straight under a shorter surface. Padding rather than a shorter page,
   so the bar keeps something to look through - that is the whole point of the
   glass. */
html.is-ios-app .composer { padding-bottom: calc(16px + var(--app-bottom-inset, 0px)); }
html.is-ios-app .board,
html.is-ios-app .mtg__day { padding-bottom: calc(60px + var(--app-bottom-inset, 0px)); }

/* The keyboard does not shrink the layout viewport in a web view, so a bottom
   sticky element stays where it is and disappears behind the keys. The app
   measures the overlap (visualViewport) and we move the anchor up by it. While
   the keyboard is up the app's own bar is behind it too, so its inset goes
   away for as long as that lasts. */
html.is-ios-app .composer { bottom: var(--app-keyboard, 0px); }
html.is-ios-app.is-keyboard .composer { padding-bottom: 12px; }

/* iOS zooms the whole page in the moment you focus a field whose text is
   smaller than 16px, and it never zooms back out. Everything then sits too
   wide - the horizon card is simply the first thing you notice, because it
   runs the full width. Sixteen pixels is the documented threshold, so this is
   the fix rather than locking the page with maximum-scale, which would also
   take pinch-to-zoom away from someone who needs it. App only: the desktop
   keeps its denser type. */
html.is-ios-app input,
html.is-ios-app textarea,
html.is-ios-app select { font-size: 16px; }

/* Touch: 44pt is the smallest target a thumb hits reliably (Apple HIG). Only
   for coarse pointers, so a narrow desktop or Electron window keeps its dense
   33px controls. min-height wins over the fixed height set above. */
@media (pointer: coarse) and (max-width: 900px) {
  .btn, .btn--sm { min-height: 44px; }
  .iconbtn { min-width: 44px; min-height: 44px; }

  /* Verticale ruimte is schaars op een telefoon. Een leeg gesprek stond met
     44px lucht boven en onder, wat op een desktop rustig oogt en hier een
     tiende van het scherm kost voor een zin die zegt dat er niets is. */
  .empty { padding: 18px 16px; gap: 9px; }
  .empty p { font-size: 13px; }

  /* De marges begrenzen de melding, ze vullen hem niet. Volle breedte met de
     tekst links maakte van een korte melding een lege balk; nu groeit de pil
     mee met wat erin staat en wordt hij pas breed als dat nodig is. Een lange
     zin loopt binnen die grens over twee regels. */
  .toasts { left: 12px; right: 12px; transform: none; }
  .toast {
    font-size: 12.5px; padding: 9px 13px;
    max-width: 100%; justify-content: center;
  }
  /* Ongedaan IS een knop, dus die hoort er ook een te zijn. De ghost-variant
     heeft geen vlak en is op een zwevende pil niet van gewone tekst te
     onderscheiden, en juist dit is het ding waarvan je moet zien dat je erop
     kan drukken. */
  .toast .btn--ghost {
    background: var(--bg-2); border-color: var(--line); color: var(--fg-dim);
    /* Pilvorm, net als de melding eromheen. Een rechthoek met ronde hoekjes in
       een capsule leest als een vreemd element dat er is ingeplakt. */
    border-radius: var(--r-pill);
    padding: 0 12px;
  }
}

@media (max-width: 700px) {
  /* Only the section name survives: the date is already in the page heading,
     and the two together pushed the crumb under the topbar actions. */
  .topbar__crumb > *:nth-child(n+2) { display: none; }
  /* Topbar actions go icon-only. "Opnieuw verwerken" plus a crumb plus three
     icon buttons does not fit 393px, and the crumb was what lost. */
  .topbar__actions .btn__t { display: none; }
  .topbar__actions .btn { padding: 0 8px; }
  .topbar__crumb { min-width: 5.5em; }
}

@media (max-width: 560px) {
  .stat { flex-basis: 132px; min-width: 132px; }
  .prop__act { flex-wrap: wrap; }
  /* No fixed name cap on a narrow phone screen: 220px would eat the whole row. */
  .spk__row { grid-template-columns: 44px minmax(0, 1fr) 60px 30px; gap: 6px; }
  .spk__input { max-width: none; }
  .bars__row { grid-template-columns: 60px 1fr 54px; }
}

/* closed tasks, with a way back ---------------------------------------- */

.closed {
  display: flex; align-items: center; gap: 10px; padding: 7px 2px;
  border-bottom: 1px solid var(--line-soft);
}
.closed:last-child { border-bottom: 0; }
.closed__t { min-width: 0; flex: 1 1 auto; display: grid; gap: 2px; }
/* Struck through: this is done, and it needs to keep reading that way even
   though there is now a button next to it to undo it. */
.closed__subj {
  font-size: 13.5px; color: var(--fg-mute); text-decoration: line-through;
  text-decoration-color: var(--line-strong);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.closed .mono { font-size: 11px; }
.closed .btn { flex: 0 0 auto; opacity: 0.65; transition: opacity 0.12s; }
.closed:hover .btn, .closed:focus-within .btn { opacity: 1; }

/* The + next to the aside's tabs, not among them: it is not a third tab. */
.aside__add { margin-left: auto; align-self: center; }

/* A person is not a topic. Same shape, a bit more emphasis, and the dotted
   line signals that there is context behind it. */
.chip--person { color: var(--fg-dim); border-color: var(--line); }
.chip--person[data-hascard] {
  border-bottom-style: dashed; border-bottom-color: var(--line-strong);
}
.chip--person[data-hascard]:hover { color: var(--fg); border-color: var(--signal-line); }

/* number of people in the speakers tab --------------------------------- */

.spk__head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: 4px; font-size: 11.5px;
}
.spk__cnt { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; }
.spk__cntval {
  width: 52px; height: 27px; padding: 0 4px; text-align: center;
  font: 500 12.5px/1 var(--mono);
}
/* The arrows of a number input are too small to aim at and differ per
   browser; the steppers next to it are the real controls. */
.spk__cntval::-webkit-outer-spin-button,
.spk__cntval::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.spk__cntval { -moz-appearance: textfield; appearance: textfield; }
.spk__step { width: 24px; height: 24px; font: 500 14px/1 var(--sans); }

/* What the number is going to do, spelled out: otherwise it is a field where
   you don't know whether anyone is looking at it. */
.spk__hint {
  margin: 0 0 11px; font-size: 12px; line-height: 1.45; color: var(--fg-mute);
}
.spk__hint:empty { display: none; }

/* ── 12b. memory ────────────────────────────────────────────────────── */

/* One column with a readable line length: these are sentences, not data. Wider
   produces a 90-character line that you have to read twice. */
.mem__add, .mem__sect { max-width: 76ch; }

.mem__add {
  margin: 0 0 26px; padding: 12px; border: 1px solid var(--line);
  border-radius: var(--r-md); background: var(--bg-2);
  display: flex; flex-direction: column; gap: 9px;
}

.mem__sect { margin: 0 0 22px; }
.mem__head { display: flex; align-items: center; gap: 8px; margin-bottom: 3px; }
.mem__head .n { font: 500 10px/1 var(--mono); color: var(--fg-faint); }
.mem__help { margin: 0 0 10px; font-size: 12.5px; color: var(--fg-mute); }
.mem__list { display: flex; flex-direction: column; gap: 8px; }

.mem__item {
  padding: 10px 12px; border: 1px solid var(--line-soft);
  border-radius: var(--r-md); background: var(--bg-2);
}
/* Turned off is not gone: lighter, but still readable, because you need to be
   able to decide whether it can go back on. */
.mem__item--off { opacity: 0.55; }
.mem__item--off .mem__txt { text-decoration: line-through; text-decoration-color: var(--line-strong); }
.mem__item--edit { border-color: var(--signal-line); background: var(--bg-1); }

.mem__txt { font-size: 14px; line-height: 1.5; white-space: pre-wrap; }
.mem__meta {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 9px;
}
.mem__sp { flex: 1 1 auto; }
/* Only make the buttons stand out on hover: a list with three buttons per line
   reads like a form instead of like a list of sentences. */
.mem__item .btn, .mem__item .iconbtn { opacity: 0.6; transition: opacity 0.12s; }
.mem__item:hover .btn, .mem__item:hover .iconbtn,
.mem__item:focus-within .btn, .mem__item:focus-within .iconbtn { opacity: 1; }

.field--sm { height: 27px; padding: 0 7px; font-size: 12.5px; width: auto; }

.mem__toggle {
  display: flex; align-items: center; gap: 8px; width: 100%;
  background: none; border: 0; padding: 6px 0; cursor: pointer;
  color: var(--fg-dim); font: inherit; font-size: 13px; text-align: left;
}
.mem__toggle:hover { color: var(--fg); }
.mem__toggle svg { width: 13px; height: 13px; transition: transform 0.15s; }
.mem__toggle[aria-expanded="true"] svg { transform: rotate(-180deg); }
.mem__toggle .mono { margin-left: auto; }

.mem__prompt {
  margin: 6px 0 0; padding: 12px; border: 1px solid var(--line-soft);
  border-radius: var(--r-md); background: var(--bg-3);
  font: 12px/1.6 var(--mono); color: var(--fg-dim);
  white-space: pre-wrap; overflow-x: auto;
}

/* ── 13. motion preference ──────────────────────────────────────────── */

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

/* print is not a target, but a printed report should at least be legible */
@media print {
  .rail, .topbar, .aside, .composer, .tabs, .mtg__list { display: none !important; }
  body { background: #fff; color: #000; }
  .card, .panel { box-shadow: none; border-color: #ccc; }
}

/* ── 14. right-click corrections ───────────────────────────────────────
   The popout on right-click inside a card, and the verkeerd→juist dialog. */

.ctxmenu {
  position: fixed;
  z-index: 1000;
  min-width: 200px;
  padding: 4px;
  background: var(--bg-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  box-shadow: 0 10px 30px rgb(0 0 0 / 0.18);
  display: flex;
  flex-direction: column;
}

.ctxmenu__item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border: 0;
  background: none;
  text-align: left;
  font: 500 13px/1.3 var(--sans);
  color: var(--fg);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.ctxmenu__item:hover { background: var(--signal-wash); }
.ctxmenu__item svg { flex: 0 0 auto; color: var(--fg-mute); }

.fieldrow { display: flex; align-items: center; gap: 10px; margin: 8px 0; }
.fieldrow > span { flex: 0 0 68px; font: 500 11px/1 var(--mono); color: var(--fg-mute); text-transform: uppercase; letter-spacing: 0.04em; }
.fieldrow .field { flex: 1; }

.corradio { display: flex; align-items: baseline; gap: 8px; padding: 5px 0; cursor: pointer; }
.corradio input { accent-color: var(--signal-deep); }
.corradio span { font: 500 13.5px/1.4 var(--sans); }
.corradio small { display: block; font-weight: 400; font-size: 11.5px; color: var(--fg-mute); }
.corradio--off { opacity: 0.45; cursor: not-allowed; }
.corradio--off input { cursor: not-allowed; }

/* ── instellingen (/v2/settings) ─────────────────────────────────────── */

.settings__row { display: flex; align-items: center; gap: 8px; margin-top: 12px; font-size: 13.5px; }
/* De weekdagen liggen op een rij en mogen op een smal scherm afbreken, want
   zeven vakjes naast elkaar passen niet altijd. */
.settings__days { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
.settings__day {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; color: var(--fg-dim);
  padding: 5px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.settings__day:hover { border-color: var(--line-strong); }

/* Een blok per gekoppeld account (meerdere accounts per bron). De knop staat
   rechts naast het adres in plaats van eronder, zodat drie accounts geen drie
   losse knoprijen worden. */
.onboarding__account {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  min-width: 0; /* same grid-item min-width:auto trap as .onboarding__cardhd above */
  padding: 9px 0;
  border-top: 1px solid var(--line-soft);
  font-size: 13px;
}
/* min-width: 0 alone lets the box shrink, but an email address is one
   unbreakable word with no space to wrap at - the text then overflows this
   box and visually bleeds into the Disconnect button next to it instead of
   wrapping. overflow-wrap lets it break mid-address as a last resort. */
.onboarding__account > div { min-width: 0; overflow-wrap: anywhere; }

/* ── learning (/v2/leren) ────────────────────────────────────────────── */

.learn__sect { margin-bottom: 28px; min-width: 0; }

.learn__toggles {
  display: flex; flex-direction: column; gap: 8px;
  margin: 4px 0 20px; min-width: 0;
}
.learn__toggle {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; max-width: 420px; min-width: 0;
  background: var(--bg-2); border: 1px solid var(--line-soft); border-radius: var(--r-md);
  padding: 10px 14px; cursor: pointer; text-align: left;
  font: 13.5px/1.4 var(--sans); color: var(--fg);
}
.learn__toggle:hover { border-color: var(--line); }
.learn__toggle span:first-child { min-width: 0; overflow-wrap: anywhere; }

.learn__head {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin-bottom: 10px; min-width: 0;
}
.learn__head .overline { flex: 1; min-width: 0; }
.learn__head .n {
  font-weight: 500; font-size: 11px; color: var(--fg-dim);
  text-transform: uppercase; letter-spacing: 0.04em;
}

.learn__help { font: 13px/1.5 var(--sans); color: var(--fg-dim); margin: 8px 0 12px; }

.learn__list { display: flex; flex-direction: column; gap: 10px; min-width: 0; }

.learn__item {
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
  padding: 12px; border: 1px solid var(--line-soft); border-radius: var(--r-md);
  background: var(--bg-2);
}
.learn__item--off { opacity: 0.6; }
.learn__item--inactive { opacity: 0.7; }
.learn__item--edit { gap: 12px; padding: 14px; background: var(--bg-3); }
.learn__item--prompt { padding: 14px; }

.learn__txt {
  font: 13.5px/1.6 var(--sans); color: var(--fg);
  word-break: break-word; overflow-wrap: anywhere;
}
.learn__item--prompt .learn__txt { font-weight: 500; }

.learn__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font: 11px/1 var(--mono); color: var(--fg-mute);
  min-width: 0;
}
/* Long evidence labels (urls, filenames) must break inside their own chip
   rather than force the whole meta row wider than the viewport (seen at
   393px/595px widths: .chip's global white-space: nowrap holds here). */
.learn__meta .chip, .learn__meta .tag {
  max-width: 100%; white-space: normal; overflow-wrap: anywhere;
}
.learn__meta > span { min-width: 0; }

.learn__sp { flex: 1; }

.learn__note { margin-top: 8px; }
.learn__summary { margin: 8px 0 0; font-size: 13px; color: var(--fg-dim); overflow-wrap: anywhere; }

.learn__facts { margin: 8px 0 0; display: flex; flex-direction: column; gap: 6px; }
.learn__fact { padding: 8px; background: var(--bg-4); border-radius: var(--r-sm); min-width: 0; }
.learn__fact p { font: 12px/1.5 var(--sans); margin: 0; overflow-wrap: anywhere; }
.learn__factSource { font-size: 11px !important; margin-top: 4px; overflow-wrap: anywhere; }

.learn__rationale {
  margin: 8px 0 0; font: 13px/1.5 var(--sans); color: var(--fg-dim);
  overflow-wrap: anywhere;
}

.learn__details { margin-top: 8px; min-width: 0; }
.learn__details summary {
  cursor: pointer; font: 12px/1.4 var(--sans); color: var(--fg-dim);
}
.learn__details summary:hover { color: var(--fg); }

.learn__guidance {
  margin: 8px 0 0; padding: 10px; background: var(--bg-4);
  border-radius: var(--r-sm); font: 12px/1.5 var(--mono);
  color: var(--fg-dim); white-space: pre-wrap; overflow-wrap: anywhere;
  max-width: 100%; overflow-x: auto;
}

.learn__eval {
  margin: 6px 0 0; font: 11px/1.4 var(--mono); color: var(--fg-mute);
  overflow-wrap: anywhere;
}

.learn__diff {
  margin: 8px 0 0; display: flex; flex-direction: column;
  gap: 1px; font: 11px/1.4 var(--mono); min-width: 0;
}
.learn__diffLine {
  padding: 4px 8px; background: var(--bg-4); margin: 0;
  white-space: pre-wrap; overflow-wrap: anywhere; max-width: 100%; overflow-x: auto;
}
.learn__diff--add { background: var(--jade-wash); color: var(--jade); }
.learn__diff--remove { background: var(--rose-wash); color: var(--rose); }
.learn__diff--ctx { color: var(--fg-mute); }
.learn__diff--skip { color: var(--fg-mute); opacity: 0.6; background: none; }

.learn__actions {
  display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap;
}
.learn__actions .btn { margin-top: 8px; }

.learn__stats { display: flex; flex-direction: column; gap: 16px; margin: 12px 0; min-width: 0; }

.learn__stat { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.learn__stat .overline { margin-bottom: 4px; }

.learn__chart {
  display: flex; align-items: flex-end; gap: 3px;
  height: 60px; padding: 4px 0; overflow-x: auto; max-width: 100%;
}
.learn__bar {
  flex: 1; min-width: 12px; border-radius: 2px;
  transition: opacity 0.15s;
}
.learn__bar:hover { opacity: 0.75; }
.learn__bar--empty { background: var(--fg-faint); opacity: 0.5; }

.learn__table {
  width: 100%; border-collapse: collapse; table-layout: fixed;
  font: 12px/1.4 var(--mono); color: var(--fg-dim);
}
.learn__table th, .learn__table td {
  padding: 6px 8px; border-bottom: 1px solid var(--line-soft);
  text-align: left; overflow-wrap: anywhere;
}
.learn__table th { font-weight: 500; }
.learn__table tr:hover { background: var(--bg-4); }

.learn__cost { margin: 12px 0; font: 13px/1.5 var(--sans); }
.learn__cost .overline { display: block; margin-bottom: 4px; }
.learn__cost span:last-child { font-weight: 500; }

.learn__lastRuns { margin: 12px 0; min-width: 0; }
.learn__lastRuns .overline { display: block; margin-bottom: 8px; }
.learn__lastRuns ul { list-style: none; padding: 0; margin: 0; }
.learn__lastRuns li {
  padding: 6px 0; font: 12px/1.4 var(--sans);
  border-bottom: 1px solid var(--line-soft);
  overflow-wrap: anywhere;
}
.learn__lastRuns li .tag { margin-right: 6px; }

.learn__evidence--link {
  display: inline-block; max-width: 100%;
  padding: 3px 6px; border-radius: 2px;
  background: var(--signal-wash); color: var(--signal);
  overflow-wrap: anywhere;
}
.learn__evidence--link a {
  color: inherit; text-decoration: none;
  border-bottom: 1px solid currentColor;
}
.learn__evidence--link a:hover { opacity: 0.75; }

.tag--jade { background: var(--jade-wash); color: var(--jade); }
.tag--amber { background: var(--amber-wash); color: var(--amber); }
.tag--rose { background: var(--rose-wash); color: var(--rose); }
.tag--sky { background: var(--sky-wash); color: var(--sky); }
.tag--mute { background: var(--bg-4); color: var(--fg-mute); }
