/* SpaceCamp design system tokens — extracted from docs/design/styles.css */

:root {
  /* Light mode neutrals — warm-ish near-whites */
  --sc-bg: oklch(0.995 0.001 90);
  --sc-bg-alt: oklch(0.978 0.001 90);
  --sc-bg-sunken: oklch(0.965 0.002 90);
  --sc-surface: #ffffff;
  --sc-surface-hover: oklch(0.975 0.002 90);
  --sc-border: oklch(0.92 0.002 90);
  --sc-border-strong: oklch(0.86 0.002 90);
  --sc-divider: oklch(0.95 0.002 90);

  --sc-fg: oklch(0.20 0.005 90);
  --sc-fg-muted: oklch(0.45 0.004 90);
  --sc-fg-subtle: oklch(0.62 0.003 90);
  --sc-fg-faint: oklch(0.78 0.002 90);

  /* Accent — overridden per variant */
  --sc-accent: oklch(0.20 0.005 90);
  --sc-accent-fg: #ffffff;
  --sc-accent-soft: oklch(0.96 0.003 90);
  --sc-accent-line: oklch(0.20 0.005 90);

  /* Status — restrained, used only for state */
  --sc-success: oklch(0.62 0.13 150);
  --sc-warn: oklch(0.72 0.14 75);
  --sc-danger: oklch(0.58 0.18 25);
  --sc-info: oklch(0.60 0.12 240);

  /* Long Resource Grid — the fill of a marked day. One colour for every row on
     purpose (the sheet this replaced was all cyan); "states" are sibling tokens
     below, not per-client colours. */
  --sc-lgrid-mark: oklch(0.86 0.10 215);

  /* …and the first of those states: a Deadline — the job's go-live or drop-dead
     date. Loud on purpose, because the point of it is to be findable across a
     three-month range. Not --sc-danger itself: that is the outline a mark wears
     when leave lands on it, and a state and a clash must not be one colour. */
  --sc-lgrid-deadline: oklch(0.60 0.20 25);
  --sc-lgrid-deadline-line: oklch(0.48 0.19 25);

  /* Long Resource Grid — a day the person is away for. Warm, so it never reads
     as another shade of the (cool) mark, and deliberately not --sc-danger: being
     on leave is a fact about the plan, not a fault in it. */
  --sc-lgrid-leave: oklch(0.93 0.045 70);
  --sc-lgrid-leave-line: oklch(0.78 0.10 70);

  /* ToDo lane pitch — card height and the gap below it. Cards, spacers and the
     cell padding all key off these, so lanes line up across day columns. */
  --sc-todo-lane-h: 58px;
  --sc-todo-lane-gap: 4px;

  /* Backlog drawer width. Two things have to agree on it: the drawer itself, and the
     inset the page takes so the panel never sits over a column you might drag a card
     onto. */
  --sc-todo-backlog-w: 320px;

  /* Type */
  --sc-font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --sc-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Sizing */
  --sc-row-h: 32px;
  --sc-row-h-tight: 28px;
  --sc-radius: 6px;
  --sc-radius-sm: 4px;

  /* Shadows — barely there */
  --sc-shadow-1: 0 1px 0 oklch(0.92 0.002 90);
  --sc-shadow-2: 0 1px 2px oklch(0.20 0.005 90 / 0.06), 0 0 0 1px var(--sc-border);
  --sc-shadow-pop: 0 8px 24px oklch(0.20 0.005 90 / 0.10), 0 0 0 1px var(--sc-border);
}

[data-bs-theme="dark"] {
  --sc-bg: oklch(0.16 0.003 270);
  --sc-bg-alt: oklch(0.185 0.003 270);
  --sc-bg-sunken: oklch(0.14 0.003 270);
  --sc-surface: oklch(0.20 0.003 270);
  --sc-surface-hover: oklch(0.23 0.003 270);
  --sc-border: oklch(0.27 0.004 270);
  --sc-border-strong: oklch(0.34 0.004 270);
  --sc-divider: oklch(0.23 0.003 270);

  --sc-fg: oklch(0.96 0.002 270);
  --sc-fg-muted: oklch(0.70 0.003 270);
  --sc-fg-subtle: oklch(0.55 0.004 270);
  --sc-fg-faint: oklch(0.40 0.004 270);

  --sc-accent-soft: oklch(0.24 0.005 270);
  --sc-lgrid-mark: oklch(0.62 0.11 215);
  --sc-lgrid-deadline: oklch(0.55 0.19 25);
  --sc-lgrid-deadline-line: oklch(0.68 0.17 25);
  --sc-lgrid-leave: oklch(0.36 0.045 70);
  --sc-lgrid-leave-line: oklch(0.55 0.08 70);
  --sc-shadow-1: 0 1px 0 oklch(0.10 0.003 270);
  --sc-shadow-2: 0 1px 2px black, 0 0 0 1px var(--sc-border);
  --sc-shadow-pop: 0 12px 32px black, 0 0 0 1px var(--sc-border);
}

[data-accent="indigo"] {
  --sc-accent: oklch(0.55 0.18 265);
  --sc-accent-fg: #ffffff;
  --sc-accent-soft: oklch(0.96 0.025 265);
  --sc-accent-line: oklch(0.55 0.18 265);
}
[data-bs-theme="dark"][data-accent="indigo"] {
  --sc-accent-soft: oklch(0.30 0.08 265);
}

[data-density="compact"] {
  --sc-row-h: 28px;
  --sc-row-h-tight: 24px;
}

/* Page layout */
.sc-page-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 22px 28px 40px;
}
.sc-page-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 20px;
  gap: 16px;
}
.sc-page-title {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--sc-fg);
}
.sc-page-sub {
  font-size: 12.5px;
  color: var(--sc-fg-subtle);
  margin-top: 2px;
}

/* KPI tiles */
.sc-kpi {
  padding: 14px 16px;
  background: var(--sc-surface);
  border: 1px solid var(--sc-border);
  border-radius: var(--sc-radius);
  display: flex; flex-direction: column; gap: 4px;
  min-height: 84px;
}
.sc-kpi-label {
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 500;
  color: var(--sc-fg-subtle);
}
.sc-kpi-value {
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--sc-fg);
  font-variant-numeric: tabular-nums;
  display: flex; align-items: baseline; gap: 4px;
}
.sc-kpi-unit { font-size: 13px; color: var(--sc-fg-muted); font-weight: 500; }
.sc-kpi-delta {
  font-size: 11.5px;
  color: var(--sc-fg-muted);
  display: flex; align-items: center; gap: 4px;
  font-variant-numeric: tabular-nums;
}
.sc-kpi-delta.up { color: var(--sc-success); }
.sc-kpi-delta.down { color: var(--sc-danger); }

/* Buttons */
.sc-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 10px;
  border-radius: var(--sc-radius-sm);
  border: 1px solid var(--sc-border);
  background: var(--sc-surface);
  color: var(--sc-fg);
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  font-family: inherit;
  /* A fixed-height button can't wrap its label without spilling out of itself. */
  white-space: nowrap;
  transition: background .1s, border-color .1s;
}
.sc-btn:hover { background: var(--sc-surface-hover); border-color: var(--sc-border-strong); }
.sc-btn.primary {
  background: var(--sc-accent);
  color: var(--sc-accent-fg);
  border-color: var(--sc-accent);
}
.sc-btn.primary:hover { filter: brightness(1.08); }
.sc-btn.ghost { border-color: transparent; background: transparent; color: var(--sc-fg-muted); }
.sc-btn.ghost:hover { background: var(--sc-surface-hover); color: var(--sc-fg); }
.sc-btn.sm { height: 24px; padding: 0 8px; font-size: 12px; }

/* Icon button */
.sc-iconbtn {
  width: 28px; height: 28px;
  display: inline-flex;
  align-items: center; justify-content: center;
  border-radius: var(--sc-radius-sm);
  color: var(--sc-fg-muted);
  cursor: pointer;
  border: none; background: transparent;
  transition: background .1s, color .1s;
}
.sc-iconbtn:hover { background: var(--sc-surface-hover); color: var(--sc-fg); }

/* Avatar */
.sc-avatar {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: linear-gradient(135deg, oklch(0.75 0.08 50), oklch(0.55 0.10 30));
  display: inline-flex; align-items: center; justify-content: center;
  color: white; font-size: 11px; font-weight: 600;
  flex-shrink: 0;
}

/* Keyboard shortcut */
.sc-kbd {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 5px;
  border-radius: 4px;
  background: var(--sc-bg-sunken);
  border: 1px solid var(--sc-border);
  border-bottom-width: 1.5px;
  font-family: var(--sc-font-mono);
  font-size: 10.5px;
  color: var(--sc-fg-muted);
  font-weight: 500;
}

/* Filter chips */
.sc-filter-row {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--sc-divider);
  background: var(--sc-bg-alt);
}
.sc-chip {
  display: inline-flex; align-items: center; gap: 4px;
  height: 26px; padding: 0 9px;
  border-radius: var(--sc-radius-sm);
  border: 1px dashed var(--sc-border-strong);
  color: var(--sc-fg-muted);
  font-size: 12px;
  background: transparent;
  cursor: pointer;
  font-family: inherit;
  /* Fixed height, so a wrapped label would spill out of the chip. */
  white-space: nowrap;
  transition: all .1s;
}
.sc-chip:hover { color: var(--sc-fg); border-color: var(--sc-fg-subtle); }
.sc-chip.active {
  background: var(--sc-surface);
  border-style: solid;
  border-color: var(--sc-border-strong);
  color: var(--sc-fg);
}

/* Inputs */
.sc-input {
  height: 28px;
  padding: 0 10px;
  border-radius: var(--sc-radius-sm);
  border: 1px solid var(--sc-border);
  background: var(--sc-surface);
  color: var(--sc-fg);
  font-size: 13px;
  font-family: inherit;
  outline: none;
  width: 100%;
  transition: border-color .1s, box-shadow .1s;
}
.sc-input:focus {
  border-color: var(--sc-accent-line);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--sc-accent) 15%, transparent);
}
.sc-input::placeholder { color: var(--sc-fg-faint); }
.sc-input.is-invalid {
  border-color: var(--sc-danger);
}
.sc-input.is-invalid:focus {
  border-color: var(--sc-danger);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--sc-danger) 18%, transparent);
}

/* ─── Grid (resourcing) ─────────────────────────────────────── */
/* overflow:visible so the wrapper isn't a scroll container — lets the head row
   (position:sticky) anchor to the page and stay pinned while scrolling down.
   Horizontal scroll is restored on narrow screens below. */
.sc-grid-wrap { background: var(--sc-surface); border: 1px solid var(--sc-border); border-radius: var(--sc-radius); overflow: visible; }
@media (max-width: 767.98px) {
  .sc-grid-wrap { overflow-x: auto; }
}
.sc-grid {
  display: grid;
  width: 100%;
  font-size: 12.5px;
  /* user col + 5 weekday cols */
  grid-template-columns: 180px repeat(5, minmax(0, 1fr));
}
[data-density="compact"] .sc-grid { grid-template-columns: 160px repeat(5, minmax(0, 1fr)); }

.sc-grid-head {
  display: contents;
}
.sc-grid-head > div {
  background: var(--sc-bg-alt);
  border-bottom: 1px solid var(--sc-border);
  padding: 8px 12px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--sc-fg-subtle);
  position: sticky; top: 0; z-index: 3;
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
}
.sc-grid-head .day-meta { font-weight: 500; text-transform: none; letter-spacing: 0; color: var(--sc-fg-faint); font-size: 10.5px; }
.sc-grid-head .holiday { color: var(--sc-warn); }
.sc-grid-head > div:first-child { z-index: 4; }
.sc-grid-head > div.today { color: var(--sc-fg); background: var(--sc-accent-soft); box-shadow: inset 0 -2px 0 var(--sc-accent); }

.sc-grid-group-h {
  grid-column: 1 / -1;
  padding: 6px 12px;
  background: var(--sc-bg-sunken);
  border-bottom: 1px solid var(--sc-border);
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--sc-fg-subtle);
  display: flex; align-items: center; gap: 8px;
  cursor: pointer;
  user-select: none;
}
.sc-grid-group-h .count {
  margin-left: auto;
  font-family: var(--sc-font-mono);
  font-feature-settings: "tnum";
  color: var(--sc-fg-faint);
  letter-spacing: 0;
}

.sc-grid-row { display: contents; }
.sc-grid-row > div {
  border-bottom: 2px solid var(--sc-border-strong);
  border-right: 1px solid var(--sc-divider);
  min-height: 64px;
  padding: 5px 6px;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.sc-grid-row > div:last-child { border-right: none; }
.sc-grid-user {
  background: var(--sc-bg-alt);
  border-right: 1px solid var(--sc-border);
  padding: 8px 12px !important;
  flex-direction: row !important;
  align-items: center !important;
  gap: 8px !important;
  position: sticky; left: 0; z-index: 1;
}
.sc-grid-user .name { font-weight: 500; color: var(--sc-fg); font-size: 13px; }
.sc-grid-user .role { font-size: 11px; color: var(--sc-fg-subtle); }
.sc-grid-cell.holiday { background: repeating-linear-gradient(135deg, var(--sc-bg-sunken) 0 6px, transparent 6px 12px); }
.sc-grid-cell.non-working { background: repeating-linear-gradient(135deg, color-mix(in oklch, var(--sc-bg-sunken) 70%, transparent) 0 6px, transparent 6px 12px); opacity: 0.6; cursor: default; }
.sc-grid-cell.weekend { background: var(--sc-bg-sunken); }
.sc-grid-cell.today-col { background: color-mix(in oklch, var(--sc-accent-soft) 60%, transparent); }
/* background-color, not the shorthand — the hatching and half-day leave tints below
   are background-images on the same element and must survive a hover. */
.sc-grid-cell:hover { background-color: var(--sc-surface-hover); }
/* Half-day leave: tint the half of the cell the person is away for. */
.sc-grid-cell.leave-am {
  background-image: linear-gradient(to bottom, color-mix(in oklch, var(--sc-warn) 12%, transparent) 0 50%, transparent 50%);
}
.sc-grid-cell.leave-pm {
  background-image: linear-gradient(to top, color-mix(in oklch, var(--sc-warn) 12%, transparent) 0 50%, transparent 50%);
}
.sc-grid-cell.over { box-shadow: inset 0 0 0 1.5px var(--sc-danger); }
/* The cell a chip dragged in from another day (or another person) would land in.
   The hover background alone reads as "the mouse is here", not "drop it here",
   so the destination is outlined as well. */
.sc-grid-cell.drop-into {
  background-color: var(--sc-accent-soft);
  box-shadow: inset 0 0 0 1.5px var(--sc-accent);
}
/* A Ctrl/Option drag copies rather than moves: the same cell, a dashed edge. */
.sc-grid-cell.drop-into.drop-copy {
  box-shadow: none;
  outline: 1.5px dashed var(--sc-accent);
  outline-offset: -1.5px;
}

/* Day status (Office/WFH) — small top label */
.sc-day-status {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10.5px;
  color: var(--sc-fg-subtle);
  text-transform: none;
  font-weight: 500;
  padding: 1px 4px;
  border-radius: 3px;
  align-self: flex-start;
}
.sc-day-status.wfh { color: var(--sc-info); background: color-mix(in oklch, var(--sc-info) 12%, transparent); }
.sc-day-status.offsite { color: var(--sc-success); background: color-mix(in oklch, var(--sc-success) 12%, transparent); }
.sc-day-status.leave { color: var(--sc-warn); background: color-mix(in oklch, var(--sc-warn) 14%, transparent); font-weight: 600; }
.sc-day-status.leave.half { font-weight: 500; }
/* Row of chips for a day that is part leave, part worked */
.sc-day-statuses { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }

/* Booking pill */
.sc-booking {
  display: flex; align-items: center; gap: 6px;
  padding: 3px 6px;
  border-radius: 4px;
  font-size: 12.5px;
  background: var(--sc-bg-sunken);
  border: 1px solid var(--sc-border);
  color: var(--sc-fg);
  cursor: grab;
  line-height: 1.25;
  min-height: 22px;
  position: relative;
}
.sc-booking:hover { background: var(--sc-surface); border-color: var(--sc-border-strong); }
.sc-booking .swatch {
  width: 3px; height: 14px; border-radius: 2px; flex-shrink: 0; background: var(--bk, var(--sc-fg));
}
.sc-booking .name { flex: 1; min-width: 0; white-space: normal; word-break: break-word; }
.sc-booking .name .primary { display: block; }
.sc-booking .name .meta { display: block; font-size: 10px; color: var(--sc-fg-muted); }
/* Booking note — "here's what you're actually on today".
   Clamped to one line so a chatty note can't push a grid row twice as tall;
   the full text is in the chip's title tooltip and the note dialog. */
.sc-booking .name .note {
  display: block;
  margin-top: 1px;
  font-size: 10.5px;
  font-style: italic;
  color: var(--sc-fg-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sc-booking .name .note::before { content: "\201C"; }
.sc-booking .name .note::after { content: "\201D"; }
/* A noted booking is worth spotting from across the grid, so the accent runs the
   full height of the chip rather than sitting in the text. */
.sc-booking.has-note { border-left: 2px solid var(--sc-info); }
.sc-booking .hrs { font-family: var(--sc-font-mono); font-size: 12px; color: var(--sc-fg-muted); font-variant-numeric: tabular-nums; }
.sc-booking.allday .hrs::before { content: ""; }
.sc-booking.partial { background: var(--sc-surface); }
.sc-booking.over { color: var(--sc-danger); border-color: var(--sc-danger); }
/* Dragging a chip: to reorder within an AM/PM/all-day group, or to another cell */
.sc-booking[draggable="true"]:active { cursor: grabbing; }
.sc-booking:not([draggable="true"]) { cursor: pointer; }
.sc-booking.dragging { opacity: 0.4; }
.sc-booking.drop-before::before,
.sc-booking.drop-after::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--sc-accent);
}
.sc-booking.drop-before::before { top: -2px; }
.sc-booking.drop-after::after { bottom: -2px; }

/* Add cell button — appears at bottom */
.sc-grid-add {
  margin-top: auto;
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  height: 20px;
  border-radius: 3px;
  border: 1px dashed var(--sc-border-strong);
  color: var(--sc-fg-faint);
  background: transparent;
  font-size: 11.5px;
  cursor: pointer;
  opacity: 0;
  transition: all .1s, opacity 0.15s;
  font-family: inherit;
}
.sc-grid-cell:hover .sc-grid-add { opacity: 1; color: var(--sc-fg-muted); border-color: var(--sc-fg-subtle); }
.sc-grid-add:hover { background: var(--sc-surface); color: var(--sc-fg) !important; border-color: var(--sc-fg-subtle) !important; }

/* Cell totals shown bottom-right when bookings exist */
.sc-cell-total {
  position: absolute; bottom: 2px; right: 4px;
  font-family: var(--sc-font-mono);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  color: var(--sc-fg-subtle);
  pointer-events: none;
}
.sc-cell-total.over { color: var(--sc-danger); font-weight: 600; }

/* Department row totals (right gutter) */
.sc-grid-dept-totals {
  font-family: var(--sc-font-mono);
  font-size: 11px;
  color: var(--sc-fg-muted);
  font-variant-numeric: tabular-nums;
}

/* Legend */
.sc-grid-legend {
  display: flex; gap: 14px; align-items: center;
  font-size: 11.5px; color: var(--sc-fg-subtle);
}
.sc-grid-legend span { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }

/* Grid header. People open the Grid and the Long Grid side by side, half a
   screen each, so the header has to survive ~600px. The toolbar drops below the
   heading as a whole rather than squeezing it into a column three words wide;
   within the toolbar the legend may wrap, the week navigator never does. */
.sc-grid-header { flex-wrap: wrap; row-gap: 10px; }
.sc-grid-heading { min-width: 0; }
/* The heading and the Week | Long range switch share a line; the switch drops
   under the heading rather than squeezing it. Shared with the Long Grid. */
.sc-grid-title-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 14px; }
.sc-grid-views { display: flex; gap: 4px; }
.sc-grid-views .sc-chip { text-decoration: none; }
.sc-grid-toolbar {
  display: flex; align-items: center; justify-content: flex-end;
  flex-wrap: wrap; gap: 8px 6px; min-width: 0;
}
.sc-grid-toolbar-legend { flex-wrap: wrap; row-gap: 5px; margin-right: 8px; }
.sc-grid-toolbar-sep { width: 1px; height: 22px; background: var(--sc-border); flex-shrink: 0; }
/* Below md the container is too narrow for legend and navigator on one line, and a
   divider left at the end of the legend row divides nothing. */
@media (max-width: 767.98px) { .sc-grid-toolbar-sep { display: none; } }
.sc-grid-controls { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }

/* The KPI strip wraps whole cards rather than squeezing five into a half screen,
   where each label broke over two lines; a short second row stretches to fill. */
.sc-grid-kpis { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.sc-grid-kpis > .sc-kpi { flex: 1 1 150px; min-width: 0; }

/* The filter row wraps whole chips, as the ToDo board's does, and the shortcut
   hint goes onto a line of its own rather than breaking mid-phrase. */
.sc-grid-filter-row { flex-wrap: wrap; row-gap: 8px; }
.sc-grid-filter-box { position: relative; flex: 0 1 200px; min-width: 140px; display: flex; align-items: center; }
.sc-grid-filter-hint {
  margin-left: auto; display: flex; align-items: center; gap: 4px;
  font-size: 11px; color: var(--sc-fg-subtle); white-space: nowrap;
}
.sc-grid-legend i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }

/* Modal — reused for Bookings dialog */
.sc-modal-overlay {
  position: fixed; inset: 0;
  background: oklch(0.20 0.005 90 / 0.45);
  backdrop-filter: blur(2px);
  z-index: 1060;
  display: flex; justify-content: center; align-items: flex-start;
  padding-top: 8vh;
}
[data-bs-theme="dark"] .sc-modal-overlay {
  background: oklch(0.05 0 0 / 0.65);
}
.sc-modal {
  width: 720px; max-width: 92vw; max-height: 84vh;
  background: var(--sc-surface);
  border: 1px solid var(--sc-border);
  border-radius: 10px;
  box-shadow: 0 24px 60px oklch(0 0 0 / 0.30);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.sc-modal-h {
  padding: 14px 16px;
  border-bottom: 1px solid var(--sc-divider);
  display: flex; align-items: center; gap: 12px;
}
.sc-modal-h .title { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; }
.sc-modal-h .sub { font-size: 12px; color: var(--sc-fg-subtle); }
.sc-modal-toolbar {
  padding: 10px 16px;
  border-bottom: 1px solid var(--sc-divider);
  background: var(--sc-bg-alt);
  display: flex; align-items: center; gap: 10px;
}
.sc-modal-body { flex: 1; overflow: auto; }
.sc-modal-foot { padding: 10px 16px; border-top: 1px solid var(--sc-divider); display: flex; align-items: center; gap: 8px; }

/* Quick-assign job picker in the booking modal footer.
   The list opens upward: .sc-modal is overflow:hidden and this sits on the
   bottom edge, so a downward list would be clipped out of existence. */
.sc-quick-assign { position: relative; flex: 1; min-width: 0; }
.sc-quick-assign-list {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0; right: 0;
  max-height: 260px;
  overflow-y: auto;
  z-index: 5;
  background: var(--sc-surface);
  border: 1px solid var(--sc-border);
  border-radius: 8px;
  box-shadow: 0 12px 32px oklch(0 0 0 / 0.22);
}
.sc-quick-assign-item { padding: 6px 10px; cursor: pointer; border-bottom: 1px solid var(--sc-divider); }
.sc-quick-assign-item:last-child { border-bottom: none; }
.sc-quick-assign-item.is-active { background: var(--sc-surface-hover); }
.sc-quick-assign-item .nm {
  font-size: 13px; font-weight: 500;
  display: flex; align-items: center; gap: 6px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sc-quick-assign-item .nm .id {
  font-family: var(--sc-font-mono); font-size: 11px; font-weight: 400;
  color: var(--sc-fg-subtle); padding: 1px 5px;
  background: var(--sc-bg-sunken); border-radius: 3px; flex: none;
}
.sc-quick-assign-item .meta {
  font-size: 11.5px; color: var(--sc-fg-subtle);
  display: flex; align-items: center; gap: 8px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sc-quick-assign-item .meta .st { color: var(--sc-fg-faint); }
.sc-quick-assign-empty { padding: 10px; font-size: 12px; color: var(--sc-fg-subtle); text-align: center; }

.sc-modal-row {
  display: grid;
  grid-template-columns: 1fr 110px 110px 70px 60px;
  gap: 10px;
  align-items: center;
  padding: 7px 16px;
  border-bottom: 1px solid var(--sc-divider);
}
.sc-modal-row:last-child { border-bottom: none; }
.sc-modal-row:hover { background: var(--sc-surface-hover); }
.sc-modal-row .nm { font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sc-modal-row .id { font-family: var(--sc-font-mono); font-size: 11px; color: var(--sc-fg-subtle); padding: 1px 5px; background: var(--sc-bg-sunken); border-radius: 3px; margin-left: 6px; }

/* Eyebrow label */
.sc-eyebrow {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--sc-fg-subtle);
  white-space: nowrap;
}

/* A dialog opened from inside another modal (the ToDo repeat scope choice). The base
   overlay is 1060, so this has to clear it or the question renders behind the form
   it is asking about. */
.sc-modal-overlay.is-stacked {
  z-index: 1075;
  padding-top: 16vh;
}

/* Repeat scope options — radio rows big enough to click anywhere on, so the label and
   its explanation are both part of the target. */
.sc-scope-option {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--sc-border);
  border-radius: 6px;
  cursor: pointer;
}
.sc-scope-option:hover { background: var(--sc-surface-hover); }
.sc-scope-option.is-checked {
  border-color: var(--sc-accent);
  background: var(--sc-accent-soft);
}
.sc-scope-option input { margin-top: 2px; flex-shrink: 0; }
.sc-scope-text { display: flex; flex-direction: column; gap: 2px; }
.sc-scope-label { font-size: 13px; font-weight: 600; color: var(--sc-fg); }
.sc-scope-hint { font-size: 12px; color: var(--sc-fg-muted); line-height: 1.35; }
.sc-scope-note {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  margin-top: 2px;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--sc-bg-alt);
  font-size: 12px;
  line-height: 1.35;
  color: var(--sc-fg-muted);
}
.sc-scope-note i { color: var(--sc-fg-subtle); margin-top: 1px; }

/* Modal hint (keyboard shortcuts shown in toolbar) */
.sc-modal-hint {
  margin-left: auto;
  font-size: 11px;
  color: var(--sc-fg-subtle);
  display: flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}

/* Utility */
.mono { font-family: var(--sc-font-mono); font-feature-settings: "tnum"; }
.tnum { font-variant-numeric: tabular-nums; }

/* Finance report value-column text colours (matches legacy SpaceCamp).
   !important needed to beat Bootstrap's .table cell colour (--bs-table-color). */
.fin-inc-tbc { color: #8f8a4d !important; }   /* Income TBC — muted olive/gold */
.fin-exp-tbc { color: #7a1f1f !important; }   /* Expenses TBC — dark maroon */
.fin-income  { color: #2f7d32 !important; }   /* Actual Income — green */
.fin-expense { color: #d32f2f !important; }   /* Actual Expenses — bright red */
[data-bs-theme="dark"] .fin-inc-tbc { color: #c2bd7a !important; }
[data-bs-theme="dark"] .fin-exp-tbc { color: #d98080 !important; }
[data-bs-theme="dark"] .fin-income  { color: #5cc46a !important; }
[data-bs-theme="dark"] .fin-expense { color: #f06a6a !important; }

/* ============================================================
   ToDo board
   ============================================================ */

.sc-todo-wrap {
  background: var(--sc-surface);
  border: 1px solid var(--sc-border);
  border-radius: var(--sc-radius);
  overflow-x: auto;
  margin-top: 8px;
}

.sc-todo-matrix {
  display: table;
  width: 100%;
  border-collapse: collapse;
  min-width: 900px;
  table-layout: fixed;
}

/* Header row */
.sc-todo-header {
  display: table-row;
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--sc-bg-alt);
}

/* Every row */
.sc-todo-row {
  display: table-row;
}

/* User column (sticky left) */
.sc-todo-user-col {
  display: table-cell;
  width: 150px;
  min-width: 150px;
  max-width: 150px;
  padding: 8px 10px;
  vertical-align: top;
  border-right: 1px solid var(--sc-border-strong);
  border-bottom: 1px solid var(--sc-border);
  background: var(--sc-bg-alt);
  position: sticky;
  left: 0;
  z-index: 2;
  font-size: 13px;
  font-weight: 500;
  color: var(--sc-fg);
}

.sc-todo-header .sc-todo-user-col {
  border-bottom: 1px solid var(--sc-border);
}

/* Flex lives on an inner wrapper — a flex box directly in a table-row would be
   wrapped in an anonymous, unstyled table cell and leave gaps around it. */
.sc-todo-user-col-inner {
  display: flex;
  align-items: center;
  gap: 7px;
}

.sc-todo-user-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 13px;
  font-weight: 500;
}

/* "PERSON" label in header first column */
.sc-todo-col-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--sc-fg-subtle);
}

/* Day header cells */
.sc-todo-day-head {
  display: table-cell;
  padding: 8px 12px;
  text-align: left;
  border-right: 1px solid var(--sc-border);
  border-bottom: 1px solid var(--sc-border);
  min-width: 120px;
}

.sc-todo-day-head.weekend {
  background: var(--sc-bg-sunken);
  color: var(--sc-fg-muted);
}

.sc-todo-day-head.weekend:not(.has-tasks) {
  width: 52px;
  min-width: 52px;
  padding: 6px 4px;
  overflow: hidden;
}

.sc-todo-day-head.weekend:not(.has-tasks) .sc-todo-day-meta {
  display: none;
}

.sc-todo-day-head.today {
  background: var(--sc-accent-soft);
  color: var(--sc-accent);
  box-shadow: inset 0 -2px 0 var(--sc-accent);
}

.sc-todo-day-head-inner {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.sc-todo-day-name {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: inherit;
}

.sc-todo-day-meta {
  font-weight: 500;
  font-size: 10.5px;
  color: var(--sc-fg-faint);
  text-transform: none;
  letter-spacing: 0;
}

.sc-todo-day-head.today .sc-todo-day-meta {
  color: var(--sc-accent);
}

/* Per-day estimate total, on its own line under the day name — a row across the
   sticky header rather than a row of its own beneath it, so it stays pinned with
   the day names it belongs to. Rendered only when something on the board carries
   an estimate, so a board with none looks exactly as it did. */
.sc-todo-day-total {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 3px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--sc-fg-muted);
  white-space: nowrap;
  overflow: hidden;
}

.sc-todo-day-total i {
  font-size: 9.5px;
  flex-shrink: 0;
}

/* A day nobody has estimated gets a dash rather than "0h": nothing estimated and
   nothing planned print differently, the same distinction a null estimate draws
   from a zero. */
.sc-todo-day-total.is-empty {
  color: var(--sc-fg-faint);
  font-weight: 500;
}

/* The Person column's label for the line, matching .sc-todo-col-label above it. */
.sc-todo-day-total.is-label {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--sc-fg-subtle);
}

.sc-todo-day-head.today .sc-todo-day-total {
  color: var(--sc-accent);
}

/* A weekend with nothing on it is 52px wide, which is not enough for the icon. */
.sc-todo-day-head.weekend:not(.has-tasks) .sc-todo-day-total i {
  display: none;
}

/* Task cells */
.sc-todo-cell {
  display: table-cell;
  vertical-align: top;
  padding: 6px 6px 4px;
  border-right: 1px solid var(--sc-border);
  border-bottom: 1px solid var(--sc-border);
  min-height: 60px;
  cursor: default;
  /* Visible so a multi-day bar can run out of its start cell across the columns
     it covers. Cards clip their own text, so nothing else escapes. */
  overflow: visible;
}

.sc-todo-cell.weekend {
  background: var(--sc-bg-sunken);
}

/* Narrow, but the top padding has to match every other cell or the lanes in this
   column sit a couple of pixels high. */
.sc-todo-cell.weekend:not(.has-tasks) {
  padding: 6px 2px 4px;
}

.sc-todo-cell.today {
  background: color-mix(in oklch, var(--sc-accent-soft) 40%, transparent);
}

.sc-todo-cell:hover {
  background: var(--sc-surface-hover);
}

.sc-todo-cell.today:hover {
  background: color-mix(in oklch, var(--sc-accent-soft) 60%, transparent);
}

/* Task cards */
/* Fixed height: cards and spacers share one lane pitch, which is the only thing
   keeping lanes aligned across day columns. Three lines of content fit in 58px —
   title, the client/job + times row, and the due date on a line of its own. Cards
   with no due date leave that third line blank rather than shrinking, because the
   pitch is shared and every title has to sit at the same height to be scannable. */
.sc-todo-card {
  height: var(--sc-todo-lane-h);
  margin-bottom: var(--sc-todo-lane-gap);
}

/* Holds a lane's slot open in a column that doesn't start a card there — either
   the day sits under a bar that began earlier, or the lane is simply empty here. */
.sc-todo-lane-spacer {
  height: var(--sc-todo-lane-h);
  margin-bottom: var(--sc-todo-lane-gap);
  pointer-events: none;
}

/* Multi-day bar. Its pixel width is measured and set by TodoMatrix; the stacking
   context lifts it over the backgrounds of the columns it runs across. */
.sc-todo-card.is-span {
  position: relative;
  z-index: 1;
  max-width: none;
}

/* Squared off where the run continues past the edge of the visible window. */
.sc-todo-card.clip-start {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

.sc-todo-card.clip-end {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.sc-todo-card:last-of-type {
  margin-bottom: 2px;
}

/* Add button */
.sc-todo-add-btn {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 3px 5px;
  font-size: 11.5px;
  color: var(--sc-fg-faint);
  background: transparent;
  border: 1px dashed transparent;
  border-radius: var(--sc-radius-sm);
  cursor: pointer;
  width: 100%;
  margin-top: 2px;
  opacity: 0;
  transition: color 0.1s, border-color 0.1s, opacity 0.15s;
}

.sc-todo-cell:hover .sc-todo-add-btn {
  opacity: 1;
}

.sc-todo-add-btn:hover {
  color: var(--sc-fg-muted);
  border-color: var(--sc-fg-subtle);
}

/* SortableJS states */
.sc-todo-ghost {
  opacity: 0.35;
}

.sc-todo-chosen {
  outline: 2px solid var(--sc-accent);
  outline-offset: 1px;
}

/* Task card hover popover */
.sc-todo-card-popover {
  background: var(--sc-surface);
  border: 1px solid var(--sc-border);
  border-radius: var(--sc-radius);
  box-shadow: var(--sc-shadow-pop);
  padding: 10px 12px 10px 15px;
  width: 256px;
  position: relative;
  overflow: hidden;
  animation: sc-popover-in 0.1s ease;
}

@keyframes sc-popover-in {
  from { opacity: 0; transform: translateX(-4px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* ============================================================
   ToDo backlog drawer
   ============================================================ */

/* `.sc-filter-row` is a single row everywhere else in the app; this one carries two
   filter boxes — people, and client/job — as well as the chips, so it is allowed to
   wrap rather than clip the last one off. Same licence the leave calendar's row takes. */
.sc-todo-filter-row { flex-wrap: wrap; row-gap: 8px; }

/* The board is pushed in rather than covered. A fixed panel with no backdrop is the
   only shape that works: the drag out of the drawer and onto a day is the feature,
   and an overlay would eat the drop. */
.sc-todo-page {
  transition: padding-right 0.18s ease;
}

.sc-todo-page.backlog-open {
  padding-right: var(--sc-todo-backlog-w);
}

.sc-todo-backlog {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--sc-todo-backlog-w);
  display: flex;
  flex-direction: column;
  background: var(--sc-bg-alt);
  border-left: 1px solid var(--sc-border-strong);
  box-shadow: -4px 0 16px oklch(0.20 0.005 90 / 0.06);
  /* Under the task modal (1060) — opening a card's editor from the drawer should
     cover the drawer, not fight it — and well over the board's sticky header (3). */
  z-index: 1040;
  animation: sc-backlog-in 0.18s ease;
}

@keyframes sc-backlog-in {
  from { transform: translateX(12px); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}

.sc-todo-backlog-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 10px 10px 14px;
  border-bottom: 1px solid var(--sc-border);
  background: var(--sc-surface);
}

.sc-todo-backlog-title {
  display: flex;
  align-items: center;
  gap: 7px;
  flex: 1;
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--sc-fg);
}

.sc-todo-backlog-tools {
  padding: 10px 12px;
  border-bottom: 1px solid var(--sc-border);
}

.sc-todo-backlog-hint {
  margin: 7px 0 0;
  font-size: 11px;
  line-height: 1.45;
  color: var(--sc-fg-subtle);
}

/* The drop target. It has to hold a height while empty — there is nothing to drop
   beside until the first item is in — so it takes the remaining space rather than
   sizing to its content. */
.sc-todo-backlog-list {
  flex: 1;
  min-height: 120px;
  overflow-y: auto;
  padding: 10px 12px 24px;
}

/* Cards here are laid out one per row rather than in lanes, so the shared lane
   pitch's fixed height still applies but the multi-day bar's pixel width does not —
   a parked task has no span. */
.sc-todo-backlog-list .sc-todo-card {
  width: auto;
  max-width: none;
  margin-bottom: 6px;
}

.sc-todo-backlog-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 32px 12px;
  text-align: center;
  font-size: 12px;
  color: var(--sc-fg-subtle);
}

/* The header-row link that opens it, and the count badge it shares with the
   drawer's own header. */
.sc-todo-backlog-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  padding: 3px 7px;
  font-size: 13px;
  color: var(--sc-fg-muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--sc-radius-sm);
  cursor: pointer;
}

.sc-todo-backlog-toggle:hover {
  color: var(--sc-fg);
  background: var(--sc-surface-hover);
  border-color: var(--sc-border);
}

.sc-todo-backlog-toggle.active {
  color: var(--sc-accent);
  background: var(--sc-accent-soft);
  border-color: var(--sc-border);
  font-weight: 600;
}

.sc-todo-backlog-count {
  flex-shrink: 0;
  min-width: 18px;
  padding: 0 5px;
  font-size: 11px;
  font-weight: 700;
  line-height: 17px;
  text-align: center;
  color: var(--sc-accent-fg);
  background: var(--sc-accent);
  border-radius: 9px;
}

/* Narrow viewports have no room to give up 320px, so the drawer takes the screen
   and the board is left where it was — you close the drawer to get back to it.
   Dragging onto a day isn't available at this width either way. */
@media (max-width: 700px) {
  .sc-todo-page.backlog-open {
    padding-right: 0;
  }

  .sc-todo-backlog {
    width: min(var(--sc-todo-backlog-w), 100vw);
  }
}

/* The chip colour override's swatch, beside the Private checkbox in the task modal.
   A native colour input, sized down to sit on the same line as the .sc-btn.sm next
   to it — the browser's own padding around the swatch is what the inset trims. */
.sc-colour-input {
  width: 34px;
  height: 24px;
  padding: 1px;
  border: 1px solid var(--sc-border);
  border-radius: var(--sc-radius-sm);
  background: var(--sc-surface);
  cursor: pointer;
  flex-shrink: 0;
}
.sc-colour-input::-webkit-color-swatch-wrapper { padding: 0; }
.sc-colour-input::-webkit-color-swatch { border: none; border-radius: 2px; }
.sc-colour-input::-moz-color-swatch { border: none; border-radius: 2px; }

/* Time estimate field — the Time Tracking page's control, rebuilt for the ToDo
   modal: an HH:MM box with a stacked pair of chevrons stepping it 15 minutes at a
   time. The two halves share one border so it reads as a single field, which is why
   the input's own right-hand corners are squared off. */
.sc-estimate {
  display: flex;
  align-items: stretch;
}

.sc-estimate .sc-input {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-right: none;
}

.sc-estimate-steps {
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  width: 22px;
}

.sc-estimate-step {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--sc-border);
  background: var(--sc-surface);
  color: var(--sc-fg-muted);
  cursor: pointer;
  font-size: 9px;
  line-height: 1;
  transition: background .1s, color .1s;
}

.sc-estimate-step:first-child {
  border-top-right-radius: var(--sc-radius-sm);
  border-bottom: none;
}

.sc-estimate-step:last-child {
  border-bottom-right-radius: var(--sc-radius-sm);
}

.sc-estimate-step:hover {
  background: var(--sc-surface-hover);
  color: var(--sc-fg);
}

/* Help text under a modal field — the backlog item's optional date says what
   leaving it blank means, which is not something a label can carry. */
.sc-modal-help {
  margin-top: 4px;
  font-size: 11px;
  line-height: 1.45;
  color: var(--sc-fg-subtle);
}

/* Context menu */
.sc-ctx-menu {
  background: var(--sc-surface);
  border: 1px solid var(--sc-border);
  border-radius: var(--sc-radius);
  box-shadow: var(--sc-shadow-pop);
  min-width: 170px;
  padding: 4px 0;
  z-index: 9999;
}

.sc-ctx-header {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--sc-fg-subtle);
  padding: 5px 12px 3px;
}

.sc-ctx-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 12px;
  font-size: 13px;
  color: var(--sc-fg);
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  /* The menu is shrink-to-fit and positioned at the cursor, so a long label
     near the right edge would otherwise wrap onto two lines and make the
     height estimate that keeps the menu on-screen wrong. */
  white-space: nowrap;
}

.sc-ctx-item:hover {
  background: var(--sc-surface-hover);
}

.sc-ctx-item.danger {
  color: var(--sc-danger);
}

/* The status the task already has: bold plus a trailing tick, so the list doubles as
   a read-out of where the task is rather than only a set of things to pick. */
.sc-ctx-item.active {
  font-weight: 600;
}

.sc-ctx-check {
  margin-left: auto;
  font-size: 11px;
  color: var(--sc-accent);
}

/* Emoji stand in for the bi icons on the status rows; a fixed width keeps every
   label in the menu on the same left edge. */
.sc-ctx-emoji {
  display: inline-block;
  width: 16px;
  text-align: center;
  font-size: 12px;
  line-height: 1;
  flex-shrink: 0;
}

.sc-ctx-divider {
  height: 1px;
  background: var(--sc-divider);
  margin: 3px 0;
}

/* Modal fields */
.sc-modal-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.sc-modal-label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--sc-fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* Required marker — the label text is muted, so the asterisk needs its own
   colour to read as a marker rather than punctuation. */
.sc-required {
  color: var(--sc-danger);
  font-weight: 700;
  margin-left: 3px;
}

.sc-field-error {
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--sc-danger);
}

/* ─── Long Resource Grid ───────────────────────────────────── */
/* Unlike .sc-grid-wrap this wrapper IS the scroll container, on both axes: the
   day range is wider than any viewport, and sticky-left columns need the element
   that scrolls horizontally to be their container. The header therefore sticks
   to the wrapper, which is capped in height so it scrolls vertically as well. */
.sc-lgrid-wrap {
  background: var(--sc-surface);
  border: 1px solid var(--sc-border);
  border-radius: var(--sc-radius);
  overflow: auto;
  max-height: calc(100vh - 190px);
  position: relative;
}
.sc-lgrid {
  --lg-label-w: 240px;   /* keep in step with LABEL_W / PM_W / DAY_W in LongGridPage.js */
  --lg-pm-w: 110px;
  --lg-day-w: 30px;
  --lg-row-h: 28px;
  --lg-month-h: 20px;
  --lg-head-h: 36px;
  display: grid;
  grid-template-columns: var(--lg-label-w) var(--lg-pm-w) repeat(var(--lg-days), var(--lg-day-w));
  width: max-content;
  min-width: 100%;
  font-size: 12px;
}
/* Row wrappers contribute no box; every cell is a direct child of the grid. */
.sc-lgrid > * { display: contents; }
.sc-lgrid.is-painting, .sc-lgrid.is-painting * { user-select: none; cursor: crosshair; }

/* Month row */
.sc-lgrid-month {
  position: sticky; top: 0; z-index: 4;
  height: var(--lg-month-h);
  background: var(--sc-bg-alt);
  border-bottom: 1px solid var(--sc-divider);
  border-left: 1px solid var(--sc-border-strong);
  padding: 0 6px;
  display: flex; align-items: center;
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--sc-fg-subtle);
  white-space: nowrap; overflow: hidden;
}
.sc-lgrid-month.sc-lgrid-corner { grid-column: 1 / span 2; left: 0; z-index: 6; border-left: none; border-right: 1px solid var(--sc-border-strong); }

/* Day head */
.sc-lgrid-head {
  position: sticky; top: var(--lg-month-h); z-index: 4;
  height: var(--lg-head-h);
  background: var(--sc-bg-alt);
  border-bottom: 1px solid var(--sc-border);
  border-right: 1px solid var(--sc-divider);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  line-height: 1.1;
  font-size: 9.5px; color: var(--sc-fg-subtle);
  font-variant-numeric: tabular-nums;
}
.sc-lgrid-head .dn { font-weight: 600; font-size: 11.5px; color: var(--sc-fg); }
.sc-lgrid-head.week-start { border-left: 1px solid var(--sc-border-strong); }
.sc-lgrid-head.weekend, .sc-lgrid-head.holiday { background: var(--sc-bg-sunken); color: var(--sc-fg-faint); }
.sc-lgrid-head.weekend .dn { color: var(--sc-fg-subtle); }
.sc-lgrid-head.holiday .dn { color: var(--sc-warn); }
.sc-lgrid-head.today { background: var(--sc-accent-soft); box-shadow: inset 0 -2px 0 var(--sc-accent); }
.sc-lgrid-head.today .dn { color: var(--sc-fg); }
.sc-lgrid-head.sc-lgrid-corner {
  left: 0; z-index: 6;
  align-items: flex-start; justify-content: center;
  padding: 0 12px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  border-right: 1px solid var(--sc-border);
}
.sc-lgrid-head.sc-lgrid-corner.pm { left: var(--lg-label-w); padding: 0 8px; border-right: 1px solid var(--sc-border-strong); }

/* Department group header — the label sticks left; the filler carries the band
   across the day columns, because a single 1 / -1 cell would scroll its text away. */
.sc-lgrid-group-h {
  grid-column: 1 / span 2;
  position: sticky; left: 0; z-index: 3;
  padding: 5px 12px;
  background: var(--sc-bg-sunken);
  border-bottom: 1px solid var(--sc-border);
  border-right: 1px solid var(--sc-border-strong);
  font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--sc-fg-subtle);
  display: flex; align-items: center; gap: 8px;
  cursor: pointer; user-select: none;
}
.sc-lgrid-group-h .count { margin-left: auto; font-family: var(--sc-font-mono); color: var(--sc-fg-faint); letter-spacing: 0; }
.sc-lgrid-group-fill { grid-column: 3 / -1; background: var(--sc-bg-sunken); border-bottom: 1px solid var(--sc-border); }

/* Person header */
.sc-lgrid-person-h {
  grid-column: 1 / span 2;
  position: sticky; left: 0; z-index: 3;
  height: 34px;
  padding: 0 8px 0 12px;
  background: var(--sc-bg-alt);
  border-bottom: 1px solid var(--sc-border);
  border-right: 1px solid var(--sc-border-strong);
  display: flex; align-items: center; gap: 8px;
}
.sc-lgrid-person-h .name { font-weight: 600; font-size: 13px; color: var(--sc-fg); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sc-lgrid-person-h .count { font-family: var(--sc-font-mono); font-size: 11px; color: var(--sc-fg-faint); }
.sc-lgrid-person-h .leave {
  flex: none;
  display: inline-flex; align-items: center; gap: 3px;
  padding: 0 5px; height: 16px; border-radius: 8px;
  background: var(--sc-lgrid-leave);
  box-shadow: inset 0 0 0 1px var(--sc-lgrid-leave-line);
  font-family: var(--sc-font-mono); font-size: 10px; color: var(--sc-fg-muted);
}
.sc-lgrid-person-h .leave i { font-size: 8px; }
/* The band across the day columns is now a run of cells rather than one 3 / -1
   filler: a leave stretch has to line up with the days it covers. Each element
   spans its own run, so a person header is a handful of boxes, not 84. */
.sc-lgrid-person-fill { background: var(--sc-bg-alt); border-bottom: 1px solid var(--sc-border); }
.sc-lgrid-person-leave {
  background: var(--sc-lgrid-leave);
  border-bottom: 1px solid var(--sc-border);
  box-shadow: inset 0 0 0 1px var(--sc-lgrid-leave-line);
  display: flex; align-items: center; justify-content: center; gap: 3px;
  overflow: hidden; white-space: nowrap;
  font-size: 10px; font-weight: 600; letter-spacing: 0.02em;
  color: var(--sc-fg-muted);
}
.sc-lgrid-person-leave.is-half { background: repeating-linear-gradient(-45deg, var(--sc-lgrid-leave) 0 4px, var(--sc-bg-alt) 4px 8px); }
.sc-lgrid-person-leave i { font-size: 9px; }

/* Rows — label and PM cells stick left, at 0 and at the label column's width. */
.sc-lgrid-label, .sc-lgrid-pm {
  position: sticky; z-index: 2;
  height: var(--lg-row-h);
  background: var(--sc-surface);
  border-bottom: 1px solid var(--sc-divider);
  display: flex; align-items: center; gap: 6px;
  overflow: hidden;
}
.sc-lgrid-label { left: 0; padding: 0 6px 0 12px; border-right: 1px solid var(--sc-border); color: var(--sc-fg); }
.sc-lgrid-pm { left: var(--lg-label-w); padding: 0 8px; border-right: 1px solid var(--sc-border-strong); color: var(--sc-fg-muted); font-size: 11.5px; }
.sc-lgrid-label .lbl, .sc-lgrid-pm .pm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sc-lgrid-label .num { font-family: var(--sc-font-mono); font-size: 10px; color: var(--sc-fg-faint); flex: none; }
.sc-lgrid-label .editable, .sc-lgrid-pm.editable { cursor: text; }
.sc-lgrid-pm .empty { color: var(--sc-fg-faint); font-style: italic; }
.sc-lgrid-rm {
  flex: none; width: 18px; height: 18px;
  border: none; background: transparent; border-radius: 3px;
  color: var(--sc-fg-faint); font-size: 15px; line-height: 1;
  cursor: pointer; opacity: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.sc-lgrid-label:hover .sc-lgrid-rm, .sc-lgrid-rm:focus-visible { opacity: 1; }
.sc-lgrid-rm:hover { background: var(--sc-surface-hover); color: var(--sc-danger); }
.sc-lgrid-inline { height: 22px; font-size: 12px; padding: 0 6px; }
/* A row just added, or the existing row a duplicate add pointed at. */
.sc-lgrid-label.is-highlight { animation: sc-lgrid-flash 1.6s ease-out; }
@keyframes sc-lgrid-flash {
  0%, 40% { background: var(--sc-lgrid-mark); }
  100% { background: var(--sc-surface); }
}

/* Day cells. Rule order carries the precedence: hover < weekend/holiday < marked
   < preview, all at the same specificity. */
.sc-lgrid-cell {
  height: var(--lg-row-h);
  border-right: 1px solid var(--sc-divider);
  border-bottom: 1px solid var(--sc-divider);
  cursor: pointer;
}
.sc-lgrid-cell.week-start { border-left: 1px solid var(--sc-border-strong); }
.sc-lgrid-cell:hover { background: var(--sc-surface-hover); }
.sc-lgrid-cell.today { box-shadow: inset 1px 0 0 var(--sc-accent), inset -1px 0 0 var(--sc-accent); }
.sc-lgrid-cell.weekend, .sc-lgrid-cell.holiday { background: var(--sc-bg-sunken); cursor: default; }
.sc-lgrid-cell.marked { background: var(--sc-lgrid-mark); }
.sc-lgrid-cell.marked:hover { background: color-mix(in oklch, var(--sc-lgrid-mark) 88%, var(--sc-fg)); }
.sc-lgrid-cell.preview-mark { background: color-mix(in oklch, var(--sc-lgrid-mark) 55%, transparent); }
.sc-lgrid-cell.preview-unmark { background: color-mix(in oklch, var(--sc-lgrid-mark) 25%, transparent); }
/* Leave. A full day cannot be marked, so it loses the pointer like a weekend; a
   half day still has half a day in it and stays paintable, so it keeps one. */
.sc-lgrid-cell.on-leave { background: var(--sc-lgrid-leave); cursor: default; }
.sc-lgrid-cell.on-leave:hover { background: var(--sc-lgrid-leave); }
.sc-lgrid-cell.on-leave-half { background: repeating-linear-gradient(-45deg, var(--sc-lgrid-leave) 0 4px, transparent 4px 8px); }
/* A day this person does not work at all — a four-day week. Nothing can be
   planned on it, so it reads like a weekend, and the hatch is the weekly Grid's
   own `.sc-grid-cell.non-working` so the same fact looks the same on both pages.
   It sits after the leave rules because it wins over them: leave on a day off is
   a fact about a day nobody was working anyway. */
.sc-lgrid-cell.non-working {
  background: repeating-linear-gradient(135deg, color-mix(in oklch, var(--sc-bg-sunken) 70%, transparent) 0 6px, transparent 6px 12px);
  opacity: 0.6;
  cursor: default;
}
.sc-lgrid-cell.non-working:hover { background: repeating-linear-gradient(135deg, color-mix(in oklch, var(--sc-bg-sunken) 70%, transparent) 0 6px, transparent 6px 12px); }
/* A mark that leave — or a change to someone's working days — has since landed
   on. It keeps the mark's colour, because the work really is planned there, and
   is outlined so the clash is what you see. The cell stays clickable, because
   clearing it is the whole point. */
.sc-lgrid-cell.marked.on-leave,
.sc-lgrid-cell.marked.non-working {
  background: var(--sc-lgrid-mark);
  box-shadow: inset 0 0 0 2px var(--sc-danger);
  opacity: 1;
  cursor: pointer;
}
.sc-lgrid-cell.marked.on-leave.preview-unmark,
.sc-lgrid-cell.marked.non-working.preview-unmark { background: color-mix(in oklch, var(--sc-lgrid-mark) 25%, transparent); }

/* A Deadline (right-click a cell). Still a marked day — the state is only what
   the day is painted in — so every selector here carries `.marked` as well:
   `.marked.on-leave` above is two classes deep and would otherwise repaint a
   deadline blue. Rule order carries the rest of the precedence, as above. */
.sc-lgrid-cell.marked.deadline {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--sc-lgrid-deadline);
  /* White on both themes: the fill is dark enough for it either way. */
  color: #fff;
}
.sc-lgrid-cell.marked.deadline i { font-size: 9px; }
.sc-lgrid-cell.marked.deadline:hover { background: color-mix(in oklch, var(--sc-lgrid-deadline) 88%, var(--sc-fg)); }
.sc-lgrid-cell.marked.deadline.preview-unmark { background: color-mix(in oklch, var(--sc-lgrid-deadline) 30%, transparent); }
.sc-lgrid-cell.marked.deadline.preview-unmark i { opacity: 0.45; }
/* Leave landed on a deadline. The blue mark's clash ring is --sc-danger, which
   is invisible on red — so this one is the leave colour, which is the half of
   the clash that is news anyway. */
.sc-lgrid-cell.marked.deadline.on-leave,
.sc-lgrid-cell.marked.deadline.non-working { box-shadow: inset 0 0 0 2px var(--sc-lgrid-leave-line); }

/* Header toolbar. The legend and the controls are two stacked rows rather than
   one wrapping row: every legend entry added pushed the week chips along, and a
   single wrapping row broke the navigator apart — the right arrow ended up on a
   line of its own, away from Today and the left arrow it belongs with. */
.sc-lgrid-header { flex-wrap: wrap; }
.sc-lgrid-heading { min-width: 0; }
.sc-lgrid-toolbar {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 8px; min-width: 0;
}
/* The legend is the row that may wrap; the controls never do. */
.sc-lgrid-legend { flex-wrap: wrap; justify-content: flex-end; row-gap: 5px; }
.sc-lgrid-controls { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }
.sc-lgrid-weeks { display: flex; gap: 4px; }

/* The client/job filter. The icon and the clear button are positioned over the
   input rather than beside it, so the box keeps its full width in a row that is
   already carrying the week chips and the navigator — the same shape the ToDo
   board's keyword box takes. A plain text input, not `type=search`: the browser's
   own cancel widget would sit right next to the clear button below. */
.sc-lgrid-filter {
  position: relative; display: flex; align-items: center;
  width: 210px; flex-shrink: 0;
}
.sc-lgrid-filter > i {
  position: absolute; left: 8px; z-index: 1;
  color: var(--sc-fg-subtle); font-size: 12px; pointer-events: none;
}
.sc-lgrid-filter .sc-input { padding-left: 28px; padding-right: 28px; }
.sc-lgrid-filter .sc-iconbtn.clear {
  position: absolute; right: 1px; z-index: 1;
  width: 24px; height: 24px; font-size: 11px;
}

.sc-lgrid-controls-sep {
  width: 1px; height: 22px; background: var(--sc-border); flex-shrink: 0;
  margin: 0 2px;
}

/* Legend swatches (layout comes from .sc-grid-legend) */
.sc-lgrid-legend i.mark { background: var(--sc-lgrid-mark); }
.sc-lgrid-legend i.deadline { background: var(--sc-lgrid-deadline); border: 1px solid var(--sc-lgrid-deadline-line); }
.sc-lgrid-legend i.weekend { background: var(--sc-bg-sunken); border: 1px solid var(--sc-border); }
.sc-lgrid-legend i.today { background: var(--sc-accent-soft); box-shadow: inset 0 -2px 0 var(--sc-accent); }
.sc-lgrid-legend i.leave { background: var(--sc-lgrid-leave); border: 1px solid var(--sc-lgrid-leave-line); }
.sc-lgrid-legend i.non-working {
  background: repeating-linear-gradient(135deg, var(--sc-bg-sunken) 0 3px, transparent 3px 6px);
  border: 1px solid var(--sc-border);
}

.sc-lgrid-empty {
  padding: 40px; text-align: center;
  color: var(--sc-fg-subtle); font-size: 13px;
  background: var(--sc-surface); border: 1px solid var(--sc-border); border-radius: var(--sc-radius);
}

/* Add-row dialog */
.sc-lgrid-add-modal { width: 560px; }
.sc-lgrid-add-modes { display: flex; gap: 4px; }
.sc-lgrid-add-pane { display: flex; flex-direction: column; gap: 10px; }
.sc-lgrid-add-results {
  max-height: 300px; overflow-y: auto;
  border: 1px solid var(--sc-border); border-radius: 8px;
}
.sc-lgrid-add-results .sc-quick-assign-item.is-taken { opacity: 0.55; }
.sc-lgrid-add-field { display: flex; flex-direction: column; gap: 4px; font-size: 11.5px; color: var(--sc-fg-subtle); }

/* ============================================================
   Rendered Markdown — ToDo descriptions
   ============================================================
   Server-rendered by App\Markdown\MarkdownRenderer, which is the only place
   this HTML comes from. Note there is deliberately no `white-space: pre-wrap`
   anywhere in here: that renderer turns a single newline into <br>, so pre-wrap
   would double every line break in every description written before Markdown
   existed. */

.sc-markdown { font-size: 12.5px; line-height: 1.5; color: var(--sc-fg); word-break: break-word; }
.sc-markdown > :first-child { margin-top: 0; }
.sc-markdown > :last-child { margin-bottom: 0; }

.sc-markdown p,
.sc-markdown ul,
.sc-markdown ol,
.sc-markdown blockquote,
.sc-markdown pre { margin: 0 0 6px; }

.sc-markdown h1,
.sc-markdown h2,
.sc-markdown h3,
.sc-markdown h4,
.sc-markdown h5,
.sc-markdown h6 {
  font-size: 13px; font-weight: 650; line-height: 1.35; margin: 8px 0 3px;
}
.sc-markdown h1, .sc-markdown h2 { font-size: 14px; }

.sc-markdown ul, .sc-markdown ol { padding-left: 18px; }
.sc-markdown li > ul, .sc-markdown li > ol { margin-bottom: 0; }

/* A task-list item: the checkbox stands in for the bullet. league puts no class
   on the <li>, hence :has(). */
.sc-markdown li:has(> input[type="checkbox"]) { list-style: none; margin-left: -18px; }
.sc-markdown li > input[type="checkbox"] {
  margin-right: 5px; vertical-align: -0.1em; cursor: pointer; accent-color: var(--sc-accent);
}
.sc-markdown li > input[type="checkbox"]:disabled { cursor: default; }

.sc-markdown code {
  font-size: 0.88em; background: var(--sc-surface-hover); color: inherit;
  border-radius: var(--sc-radius-sm); padding: 1px 4px;
}
.sc-markdown pre {
  background: var(--sc-surface-hover); border-radius: var(--sc-radius-sm);
  padding: 6px 9px; font-size: 0.88em; overflow-wrap: anywhere;
}
.sc-markdown pre code { background: none; padding: 0; font-size: inherit; }

.sc-markdown blockquote {
  border-left: 3px solid var(--sc-border-strong); padding-left: 8px; color: var(--sc-fg-muted);
}
.sc-markdown hr { margin: 8px 0; border: 0; border-top: 1px solid var(--sc-border); }
/* A pasted URL has nothing to break at and would push the column wide. */
.sc-markdown a { overflow-wrap: anywhere; }

/* The read view in the task modal: click it to edit, click a box to tick it. */
.sc-desc-read {
  min-height: 64px; padding: 6px 9px; cursor: text;
  border: 1px solid var(--sc-border); border-radius: var(--sc-radius-sm);
  background: var(--sc-surface);
}
.sc-desc-read:hover { border-color: var(--sc-border-strong); }
.sc-desc-read:focus-visible {
  outline: none; border-color: var(--sc-accent-line);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--sc-accent) 15%, transparent);
}
.sc-desc-read.is-busy { opacity: 0.7; }

/* The chip's hover popover. Its boxes are not controls — the popover is gone the
   moment the pointer leaves the chip — hence pointer-events: none.

   The height cap is new with Markdown. The popover grows to fit and never
   scrolls, and its placement maths assumes about 220px; a plain-text description
   was one block of text, but a twenty-item checklist is not, and would run off
   the bottom of the window. Cut off mid-line reads as "there is more", and the
   task modal is one click away for the whole of it. */
.sc-todo-pop-desc {
  color: var(--sc-fg-muted); margin-bottom: 8px;
  max-height: 200px; overflow: hidden; pointer-events: none;
}

/* ------------------------------------------------------------
   The Markdown editor's toolbar (assets/vue/Todo/MarkdownEditor.js)
   ------------------------------------------------------------ */

.sc-md-textarea { height: auto; min-height: 64px; padding: 6px 9px; resize: vertical; }
.sc-md-textarea-sm { min-height: 44px; font-size: 12px; }

.sc-md-toolbar { display: flex; align-items: center; gap: 1px; margin-top: 3px; padding: 0 2px; }
.sc-md-btn {
  width: 24px; height: 24px; border: 0; border-radius: var(--sc-radius-sm);
  background: transparent; color: var(--sc-fg-subtle); font-size: 12px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  /* A glyph with a space in it would otherwise wrap inside 24px. */
  white-space: nowrap;
}
.sc-md-btn:hover, .sc-md-btn:focus-visible, .sc-md-btn-on {
  background: var(--sc-surface-hover); color: var(--sc-fg);
}
.sc-md-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10.5px; }
.sc-md-sep { width: 1px; height: 15px; background: var(--sc-border); margin: 0 4px; }

.sc-md-help {
  display: grid; grid-template-columns: max-content 1fr; gap: 2px 10px;
  margin: 4px 0 0; padding: 7px 9px; font-size: 11px; color: var(--sc-fg-muted);
  background: var(--sc-surface-hover); border-radius: var(--sc-radius-sm);
}
.sc-md-help dt, .sc-md-help dd { margin: 0; font-weight: 400; }
.sc-md-help dt > code { color: var(--sc-fg); background: none; padding: 0; }
