/* ═══════════════════════════════════════════════════════════════
   Scheduler — styled to match the duct-canvas editor (app.html)
   Same product family: dark slate surfaces, brand-blue accent, floating
   glass panels (blur + soft shadow + inset top-light edge), a light-dotted
   work-surface backdrop with a faint blue vignette, and the editor's
   button feel (hover lift, active scale). The markup keeps its .sched-*
   hooks; component internals come from dashboard.css, recoloured via the
   token overrides below.
   ═══════════════════════════════════════════════════════════════ */

/* ── Airflow palette (dark-default) ──
   The dispatch board now shares the neuralduct "Airflow"/plenum identity used by
   the hub + dashboard: warm near-black paper, the signature ice-blue supply accent
   (with a red return accent for urgent/exhaust states), Sora type, and FLAT
   ink-tinted chrome instead of the old heavy editor-glass blur. Kept dark by
   default — dispatchers live on this screen all day. Light variant below. */
body.sched-app {
  /* Surface/text/accent/border colours flow from the shared --app-* palette in
     tokens.css (identical values, both themes; see "Shared APP surface" there).
     The accent-HOVER shade, the accent/hot tint rgbas and the glass tokens stay
     dispatch-local. --nd-* (nav) is intentionally not merged (differs on
     hairlines + danger). */
  --bg:            var(--app-bg);
  --bg-secondary:  var(--app-sunken);
  --surface:       var(--app-card);
  --card:          var(--app-card);
  --bg-card:       var(--app-card);
  --bg-card-hover: var(--app-card-hover);
  --bg-sidebar:    var(--app-surface);
  --bg-modal:      var(--app-card);
  --border:        var(--app-border);
  --border-strong: var(--app-border-2);
  --text:          var(--app-text);
  --text-primary:  var(--app-text);
  --text-secondary:var(--app-text-2);
  --text-muted:    var(--app-muted);
  /* Airflow-dark ice-blue (supply) accent. accent-hover stays local (brighter
     than the shared accent so it reads on warm near-black). */
  --accent:        var(--app-accent);
  --accent-fg:     var(--app-accent-fg);
  --accent-hover:  #5cc0ff;
  --accent-soft:   rgba(51,177,255,0.14);
  --accent-edge:   rgba(51,177,255,0.45);
  --accent-glow:   rgba(51,177,255,0.28);
  /* Red return accent — urgent / overdue / exhaust states. */
  --hot:           var(--app-danger);
  --hot-soft:      rgba(255,92,92,0.12);

  /* Semantic job-status colours (--st-scheduled … --st-invoiced) are defined
     once in tokens.css and consumed here via the [data-status] map below.
     They MUST stay in sync with JOB_STATUS in js/scheduler/state.js. */
  --st: var(--st-scheduled);   /* per-chip fallback; set by [data-status] below */

  /* Flat Airflow surfaces (glass tokens retuned: near-solid panels, gentle
     ink-tinted shadow, light blur — the old heavy blur/black-drop is gone). */
  --glass-bg:     rgba(24, 27, 33, 0.96);
  --glass-bg-2:   rgba(29, 32, 40, 0.97);
  --glass-border: rgba(255, 255, 255, 0.07);
  --glass-shadow: 0 1px 2px rgba(0,0,0,.28), 0 12px 30px -14px rgba(0,0,0,.55);
  --glass-blur:   blur(8px) saturate(115%);
  --topbar-h:     50px;
  --float-gap:    14px;

  background-color: var(--bg);
  color: var(--text);
  /* style.css (the editor shell) locks body to `height:100vh; overflow:hidden`.
     The scheduler is a normal scrolling document, so undo that here. */
  height: auto;
  min-height: 100vh;
  overflow-x: hidden;
  overflow-y: auto;
  /* Calm Airflow backdrop — a single soft ice-blue vignette, no CAD dot-grid. */
  background-image:
    radial-gradient(120% 80% at 50% -10%, rgba(51,177,255,0.07), transparent 62%);
  background-attachment: fixed;
}

/* Map each job status onto --st so a single set of chip/badge rules colours by
   status with no per-status duplication. Driven by the data-status attribute
   that viewhtml.js already stamps on every chip/event/card. */
.sched-app [data-status="scheduled"]   { --st: var(--st-scheduled); }
.sched-app [data-status="en_route"]    { --st: var(--st-en_route); }
.sched-app [data-status="in_progress"] { --st: var(--st-in_progress); }
.sched-app [data-status="complete"]    { --st: var(--st-complete); }
.sched-app [data-status="no_show"]     { --st: var(--st-no_show); }
.sched-app [data-status="cancelled"]   { --st: var(--st-cancelled); }
.sched-app [data-status="invoiced"]    { --st: var(--st-invoiced); }

html, body {
  height: 100%;
  margin: 0;
  font-family: 'Sora', system-ui, sans-serif;
}

/* ── Page shell ── */
.sched-page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* clear the fixed floating topbar */
  padding-top: calc(var(--topbar-h) + var(--float-gap) * 2);
}

/* ── Floating glass topbar (like the editor's immersive topbar) ── */
.sched-topbar {
  position: fixed;
  top: var(--float-gap);
  left: var(--float-gap);
  right: var(--float-gap);
  height: var(--topbar-h);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 0 var(--sp-3_5);
  border-radius: 16px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
}
.sched-back.btn-icon {
  width: 30px; height: 30px;
  color: var(--text-secondary);
  text-decoration: none;
}
.sched-brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}
.sched-brand-mark { border-radius: 6px; display: block; }
.sched-brand-name { font-weight: 700; font-size: 14px; color: var(--text-primary); letter-spacing: -0.01em; }
.sched-brand-name b, .sched-app .auth-gate-name b { font-weight: 800; color: var(--accent); }
.sched-brand-sep  { color: var(--text-muted); font-weight: 400; }
.sched-brand-page { font-weight: 600; font-size: 14px; color: var(--text-secondary); }
.sched-topbar-spacer { flex: 1; }
.sched-clock {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-muted);
  letter-spacing: .04em;
  padding: 4px 9px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(255,255,255,0.02);
}

/* ── Page body ── */
.sched-page-body {
  flex: 1;
  padding: var(--sp-1) var(--sp-5) var(--sp-10);
  width: 100%;
  max-width: 1720px;
  margin: 0 auto;
  box-sizing: border-box;
}
/* Section switching driven by the topbar tabs — only the active section shows. */
.sched-sections { width: 100%; min-width: 0; }
.sched-sections > section.dash-section { display: none; }
.sched-sections[data-section="board"]     #sec-scheduler { display: block; }
.sched-sections[data-section="customers"] #sec-customers { display: block; }
.sched-sections[data-section="equipment"] #sec-equipment { display: block; }
.sched-sections[data-section="reports"]   #sec-reports   { display: block; }

/* ── Topbar section tabs (Board / Customers / Equipment / Reports) ── */
.sched-tabs {
  display: flex;
  align-items: center;
  gap: var(--sp-0_5);
  padding: 3px;
  border-radius: 11px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
}
.sched-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1_5);
  padding: var(--sp-1_5) var(--sp-2_5);
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: background .12s, color .12s;
}
.sched-tab i { font-size: 16px; }
.sched-tab:hover { color: var(--text-primary); }
.sched-tab.active {
  background: var(--accent-soft, rgba(59,130,246,0.16));
  color: var(--accent);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}
html[data-theme="light"] .sched-tabs { background: rgba(15,23,42,0.04); }

/* ── Glass panel recipe applied to the toolbar + calendar surface ──
   The rail columns are NOT panels any more — they're transparent containers for
   a stack of individual rail cards (see the rail-cards block below), so the
   calendar reads as the hero. */
.sched-app .sched-toolbar,
.sched-app .sched-main {
  background: var(--glass-bg-2);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
}

/* ── Editor button feel (hover lift, active scale, blue active) ── */
.sched-app .btn {
  /* The editor's style.css makes .btn / .btn-primary width:100% (meant for its
     sidebar). On the scheduler, buttons live in toolbars/footers/rows and must
     size to content — otherwise they stretch full-width and crush their row
     (this is what broke the History "Report" button's card). */
  width: auto;
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.02);
  color: var(--text-secondary);
  border-radius: 8px;
  transition: background .15s, color .15s, border-color .15s, transform .12s ease;
}
.sched-app .btn-primary { width: auto; }
/* …except the sign-in button in the auth gate, which is meant to fill its card. */
.sched-app .auth-gate-btn { width: 100%; }
.sched-app .btn:hover {
  background: rgba(255,255,255,0.08);
  color: var(--text-primary);
  border-color: rgba(255,255,255,0.14);
  transform: translateY(-1px);
}
.sched-app .btn:active { transform: scale(0.96); }
.sched-app .btn.active {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: var(--accent-edge);
}
.sched-app .btn-primary,
.sched-app .sched-toolbar .btn-primary {
  background: var(--accent);
  color: var(--accent-fg);
  border: none;
}
.sched-app .btn-primary:hover {
  background: var(--accent-hover);
  box-shadow: 0 4px 12px var(--accent-glow);
  transform: translateY(-1px);
}

/* ── Section toolbar → command bar (own the layout; buttons stay compact) ── */
.sched-app .sched-toolbar {
  padding: var(--sp-3) var(--sp-3_5);
  margin-bottom: 14px;
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-3);
}
.sched-app .sched-toolbar-controls {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}
.sched-app .sched-toolbar-controls > * { flex: 0 0 auto !important; width: auto !important; }
.sched-app .sched-toolbar-controls .btn,
.sched-app .sched-toolbar-controls a.btn {
  width: auto !important;
  flex: 0 0 auto !important;
  min-height: 34px;
  justify-content: center;
}
.sched-app .sched-nav { display: flex; gap: var(--sp-1_5); }
.sched-app .sched-nav .btn { width: auto !important; }
.sched-app .sched-toolbar-controls .sched-label {
  min-width: 140px;
  text-align: center;
  margin-right: auto;
  padding: 0 var(--sp-1_5);
  font-weight: 700;
  color: var(--text-primary);
}
/* Board-tools cluster: the utilities (density/stats/map/requests/settings) sit
   together as a plain button row — each button already carries its own border,
   so no wrapping box (it read as a box-around-boxes). Add Job stays isolated at
   the far right. */
.sched-app .sched-util-cluster {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}
/* Keep the primary action clearly separated from the tool cluster. */
.sched-app .sched-add-job { margin-left: var(--sp-1_5); }
@media (max-width: 900px) {
  /* On narrow widths the cluster wraps as a unit rather than scattering. */
  .sched-app .sched-util-cluster { flex-wrap: wrap; }
}

/* ── P2 · Command-row consolidation (flag feature_sched_toolbar_v2) ──
   Scoped under html.sched-toolbar-v2 so flag-OFF is byte-identical. js/scheduler/
   toolbar.js moves the five utility buttons into a "⋯ Tools" dropdown and turns
   the date label into a month-picker popover; the rules below style the new
   wrapper, dropdown panel, badge and popover. */
/* Lift the toolbar's stacking context above the board so its dropdowns (Tools
   panel, date popover) aren't trapped below the dock by the toolbar's own
   backdrop-filter context. */
html.sched-toolbar-v2 .sched-app .sched-toolbar { position: relative; z-index: 30; }
/* Drop the big "Dispatch board" title/subtitle block — the NDNav/topbar already
   names the app, and the reclaimed height goes to the grid. The command row
   becomes the board's header. */
html.sched-toolbar-v2 .sched-app .sched-toolbar-head { display: none; }
html.sched-toolbar-v2 .sched-app .sched-toolbar { padding-top: var(--sp-2); padding-bottom: var(--sp-2); gap: 0; }
/* Pre-fold: hide the raw cluster before toolbar.js moves it, to avoid a flash of
   all five buttons collapsing. Once moved it carries data-folded and lives inside
   the (hidden) panel, so this rule no longer applies to it. */
html.sched-toolbar-v2 .sched-app .sched-util-cluster:not([data-folded]) { visibility: hidden; }
html.sched-toolbar-v2 .sched-app .sched-tools { position: relative; display: inline-flex; }
/* Inside the dropdown the moved buttons become full-width menu rows. */
html.sched-toolbar-v2 .sched-app .sched-tools-panel {
  position: absolute; top: calc(100% + var(--sp-1_5)); right: 0; z-index: 70;
  min-width: 210px;
  display: flex; flex-direction: column; gap: var(--sp-1);
  padding: var(--sp-2);
  background: var(--glass-bg-2);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  box-shadow: var(--glass-shadow);
}
html.sched-toolbar-v2 .sched-app .sched-tools-panel[hidden] { display: none; }
html.sched-toolbar-v2 .sched-app .sched-tools-panel .sched-util-cluster {
  display: flex; flex-direction: column; align-items: stretch; gap: var(--sp-1);
}
html.sched-toolbar-v2 .sched-app .sched-tools-panel .btn {
  justify-content: flex-start; min-height: 38px;
}
html.sched-toolbar-v2 .sched-app .sched-tools-panel .sched-req-badge {
  position: static; margin-left: auto; box-shadow: none;
}
/* Count mirror on the trigger (pending booking requests, while folded). */
html.sched-toolbar-v2 .sched-app .sched-tools-trigger { position: relative; }
html.sched-toolbar-v2 .sched-app .sched-tools-badge {
  position: absolute; top: calc(var(--sp-1_5) * -1); right: calc(var(--sp-1_5) * -1);
  min-width: 17px; height: 17px; padding: 0 var(--sp-1);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--hot); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 1;
  font-family: var(--num, 'Inter', system-ui, sans-serif); font-variant-numeric: tabular-nums;
  border-radius: 999px; box-shadow: 0 0 0 2px var(--bg);
}
/* The display:inline-flex above out-specifies the UA [hidden] rule; restore it. */
html.sched-toolbar-v2 .sched-app .sched-tools-badge[hidden] { display: none; }
/* Date label as a button. */
html.sched-toolbar-v2 .sched-app .sched-label-btn {
  cursor: pointer; border-radius: 8px; border: 1px solid transparent;
  transition: background .14s, border-color .14s;
}
html.sched-toolbar-v2 .sched-app .sched-label-btn:hover { background: var(--bg-card-hover); border-color: var(--border); }
/* Month-picker popover, anchored beneath the date label. */
html.sched-toolbar-v2 .sched-app .sched-label-wrap { position: relative; display: inline-flex; margin-right: auto; }
html.sched-toolbar-v2 .sched-app .sched-label-wrap .sched-label { margin-right: 0; }
html.sched-toolbar-v2 .sched-app .sched-datepop {
  position: absolute; top: calc(100% + var(--sp-1_5)); left: 0; z-index: 70;
  width: 268px; padding: var(--sp-2_5);
  background: var(--glass-bg-2); border: 1px solid var(--glass-border);
  border-radius: 14px; box-shadow: var(--glass-shadow);
}
.sched-app .sched-dp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-2); }
.sched-app .sched-dp-title { font-weight: 700; font-size: 13px; }
.sched-app .sched-dp-nav {
  width: 26px; height: 26px; border-radius: 7px; border: 1px solid var(--border);
  background: var(--card); color: var(--text-secondary); cursor: pointer; font-size: 15px; line-height: 1;
}
.sched-app .sched-dp-nav:hover { background: var(--bg-card-hover); color: var(--text-primary); }
.sched-app .sched-dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-0_5); }
.sched-app .sched-dp-dow span { text-align: center; font-size: 10px; font-weight: 700; color: var(--text-muted); padding-bottom: var(--sp-1); }
.sched-app .sched-dp-blank { aspect-ratio: 1; }
.sched-app .sched-dp-day {
  aspect-ratio: 1; display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: transparent; color: var(--text-secondary);
  border-radius: 7px; font: inherit; font-size: 12px; cursor: pointer;
  font-family: var(--num, 'Inter', system-ui, sans-serif);
}
.sched-app .sched-dp-day:hover { background: var(--bg-card-hover); color: var(--text-primary); }
.sched-app .sched-dp-day.today { color: var(--accent); font-weight: 700; }
.sched-app .sched-dp-day.sel { background: var(--accent); color: var(--accent-fg, #04121d); font-weight: 700; }
.sched-app .sched-dp-day.has { position: relative; }
.sched-app .sched-dp-day.has::after { content: ""; position: absolute; bottom: var(--sp-1); width: 3px; height: 3px; border-radius: 50%; background: var(--accent); }
.sched-app .sched-dp-day.sel.has::after { background: var(--accent-fg, #04121d); }
.sched-app .sched-dp-today {
  width: 100%; margin-top: var(--sp-2); padding: var(--sp-1_5);
  border: 1px solid var(--border); background: var(--card); color: var(--text-secondary);
  border-radius: 8px; font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
}
.sched-app .sched-dp-today:hover { background: var(--bg-card-hover); color: var(--text-primary); }

/* Section title: keep the editor's understated header weight */
.sched-app .section-title { font-weight: 700; }
.sched-app .section-subtitle { color: var(--text-muted); }

/* View switch — segmented control with a sliding active pill. The pill is a
   .sched-view-ind element positioned by views.js (_positionViewIndicator);
   the buttons themselves stay transparent and sit above it. */
.sched-app .sched-viewswitch {
  position: relative;
  background: rgba(0,0,0,.25);
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: var(--sp-1);
}
.sched-app .sched-view-ind {
  position: absolute;
  top: var(--sp-1); bottom: var(--sp-1); left: 0;
  border-radius: 6px;
  background: var(--accent);
  box-shadow: 0 2px 10px -3px var(--accent-glow);
  transition: transform .22s cubic-bezier(.4, 0, .2, 1), width .22s cubic-bezier(.4, 0, .2, 1), opacity .15s;
  pointer-events: none;
}
.sched-app .sched-viewbtn {
  position: relative;
  z-index: 1;
  color: var(--text-secondary);
  font-weight: 600;
  font-size: 12px;
  border-radius: 6px;
  padding: var(--sp-1_5) var(--sp-3);
  transition: color .15s;
}
.sched-app .sched-viewbtn:hover { color: var(--text-primary); }
.sched-app .sched-viewbtn.active { color: #fff; }

/* ── 3-pane operations layout ── */
.sched-app .sched-layout {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr) 300px;
  gap: var(--sp-3_5);
  align-items: start;
}
.sched-railcol {
  padding: 0;
  position: sticky;
  top: calc(var(--topbar-h) + var(--float-gap) * 2 + var(--sp-1));
}
.sched-railcol-title {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: var(--sp-0_5) var(--sp-1) var(--sp-2_5);
  border-bottom: 1px solid var(--border);
  margin-bottom: 10px;
}
.sched-railcol-title i { color: var(--accent); font-size: 14px; }

.sched-app .sched-main {
  padding: var(--sp-3);
  min-height: 60vh;
  overflow-x: auto;
}

/* ── P1 · Full-height board (flag feature_sched_fullheight) ──
   Scoped under html.sched-fullheight so flag-OFF is byte-identical: none of the
   rules below apply, the dashboard.css 560px cap on .sched-tg-body stays, and the
   document scrolls as before. When ON, the board becomes a fixed, viewport-tall
   pane: .sched-layout gets a measured height (--sched-board-h, set by
   js/scheduler/fullheight.js), its three columns stretch to fill it, and each
   view-root owns the ONE vertical scroll — the time grid finally uses the screen.

   Only the board section is bounded; Customers/Equipment/Reports are untouched. */
html.sched-fullheight .sched-app .sched-sections[data-section="board"] .sched-layout {
  height: var(--sched-board-h, calc(100dvh - 210px));
  min-height: 440px;
  align-items: stretch;   /* columns fill the fixed height instead of top-aligning */
}
/* Rails: fixed-height columns that scroll their own overflow (drop the sticky
   offset — the whole board no longer scrolls with the document). */
html.sched-fullheight .sched-app .sched-sections[data-section="board"] .sched-railcol {
  position: static;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: var(--sp-1);   /* keep cards clear of the scrollbar */
}
/* Main is a flex column that clips; the view-root inside is the single scroller. */
html.sched-fullheight .sched-app .sched-sections[data-section="board"] .sched-main {
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
/* Week/day: keep .sched-tg-body as the scroller (scroll-restore JS targets it),
   just uncap it and let it flex to fill. */
html.sched-fullheight .sched-main > .sched-tg { flex: 1; min-height: 0; }
html.sched-fullheight .sched-main .sched-tg-body { max-height: none; flex: 1; min-height: 0; }
/* Month / list / history / swimlane roots each become the single scroller. */
html.sched-fullheight .sched-main > .sched-month,
html.sched-fullheight .sched-main > .sched-list,
html.sched-fullheight .sched-main > .sched-history { flex: 1; min-height: 0; overflow-y: auto; }
html.sched-fullheight .sched-main > .sched-swim { flex: 1; min-height: 0; overflow: auto; }
html.sched-fullheight .sched-main > .sched-empty { flex: 1; min-height: 0; }

/* ── P3 · Context dock + inspector (flag feature_sched_dock) ──
   Scoped under html.sched-dock so flag-OFF is byte-identical: js/scheduler/dock.js
   only moves the trays + wires the chip→inspector interceptor when the flag is on,
   and the rules below (tab bar, tray show/hide, inspector) apply only then. */
html.sched-dock .sched-app .sched-railcol-right {
  display: flex; flex-direction: column; gap: 0;
  background: var(--glass-bg-2);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  box-shadow: var(--glass-shadow);
  overflow: hidden;
}
/* The dock is the card — neutralise the base `.sched-railcol > *` card chrome on
   the dock's own direct children (tab bar / body / inspector), which otherwise
   double-cards them into stacked ghost panels. */
html.sched-dock .sched-app .sched-railcol-right > * {
  background: transparent; border: 0; box-shadow: none; border-radius: 0;
  margin: 0; padding: 0;
}
/* Trays live inside the body — give them their own padding. */
html.sched-dock .sched-app .sched-dock-tray {
  background: transparent; border: 0; box-shadow: none; border-radius: 0;
  margin: 0; padding: var(--sp-3);
}
html.sched-dock .sched-app .sched-dock-tabs {
  display: flex; gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-2) 0;
  border-bottom: 1px solid var(--glass-border);
}
/* Compact icon tabs; the active one expands to reveal its label. */
html.sched-dock .sched-app .sched-dtab {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-2); position: relative;
  background: transparent; border: 0; border-bottom: 2px solid transparent;
  color: var(--text-muted); font: inherit; font-size: 12px; font-weight: 600;
  cursor: pointer; white-space: nowrap;
  transition: color .14s, border-color .14s, background .14s;
}
html.sched-dock .sched-app .sched-dtab i { font-size: 16px; }
html.sched-dock .sched-app .sched-dtab .sched-dtab-lbl { display: none; }
html.sched-dock .sched-app .sched-dtab:hover { color: var(--text-secondary); }
html.sched-dock .sched-app .sched-dtab.active {
  color: var(--text-primary); border-bottom-color: var(--accent);
}
html.sched-dock .sched-app .sched-dtab.active .sched-dtab-lbl { display: inline; }
/* Count: an inline pill on the active tab, a small dot on inactive tabs. */
html.sched-dock .sched-app .sched-dtab-ct {
  background: var(--accent); color: var(--accent-fg, #04121d);
  font-size: 9.5px; font-weight: 700; border-radius: 8px; padding: 0 var(--sp-1); min-width: 15px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--num, 'Inter', system-ui, sans-serif); font-variant-numeric: tabular-nums;
}
html.sched-dock .sched-app .sched-dtab:not(.active) .sched-dtab-ct {
  position: absolute; top: var(--sp-1); right: var(--sp-0_5);
  min-width: 0; width: 6px; height: 6px; padding: 0; font-size: 0; border-radius: 50%;
}
html.sched-dock .sched-app .sched-dtab-ct[hidden] { display: none; }

/* ── Unified shell (layout-v3 look) — matches _sched-layout-v3-mockup ──
   The mockup's depth hierarchy: darkest page canvas < calendar well (--app-bg) <
   lifted chrome (command row + filter + rails + dock, --app-surface) < rail cards
   (--app-card). Uses the --app-* tokens directly — the scheduler's --surface alias
   maps to --app-card, so it can't reach the mockup's distinct #15171c chrome tone. */
/* Full-bleed: the board stretches the whole viewport width — no inset margin, no
   framing borders around it. Depth comes from the internal surface hierarchy. */
html.sched-toolbar-v2 .sched-app .sched-page-body {
  max-width: none; padding-left: 0; padding-right: 0;
}
/* Board container = the calendar-canvas level; zero the section's own padding so
   the panes reach the viewport edges (content keeps its own insets). */
html.sched-toolbar-v2 .sched-app #sec-scheduler { background: var(--app-bg); border: 0; border-radius: 0; padding: 0; }
/* Command row + filter: one lifted surface chrome bar. */
html.sched-toolbar-v2 .sched-app #sec-scheduler > .sched-toolbar {
  background: var(--app-surface); border: 0; border-radius: 0; box-shadow: none;
  -webkit-backdrop-filter: none; backdrop-filter: none; margin: 0;
}
html.sched-toolbar-v2 .sched-app #schedulerLegend:not(:empty) {
  background: var(--app-surface); padding: var(--sp-2) var(--sp-3_5); margin: 0;
}
html.sched-toolbar-v2 .sched-app #schedAttention { margin: 0; }
/* Board: no gaps; one hairline splits the lifted chrome from the calendar well. */
html.sched-toolbar-v2 .sched-app .sched-layout { gap: 0; margin-top: 0; border-top: 1px solid var(--border); }
html.sched-toolbar-v2 .sched-app .sched-main {
  background: transparent; border: 0; border-radius: 0; box-shadow: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
/* Rails + dock: lifted surface chrome flanking the darker calendar, hairline dividers. */
html.sched-toolbar-v2 .sched-app .sched-railcol-left {
  background: var(--app-surface); border-right: 1px solid var(--border);
  padding: var(--sp-3) var(--sp-3);
}
html.sched-toolbar-v2.sched-dock .sched-app .sched-railcol-right {
  background: var(--app-surface); border: 0; border-left: 1px solid var(--border);
  border-radius: 0; box-shadow: none;
}
/* Rail widgets: small cards on the surface (like the mockup's rcard). */
html.sched-toolbar-v2 .sched-app .sched-railcol-left > * {
  background: var(--app-card); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: none; padding: var(--sp-3); margin: 0;
}
html.sched-toolbar-v2 .sched-app .sched-railcol-left > * + * { margin-top: var(--sp-2_5); }
html.sched-dock .sched-app .sched-dock-body { flex: 1; min-height: 0; overflow-y: auto; }
/* One tray visible at a time; the active-class overrides each tray's own
   empty-hide (display:none) so tab selection — not emptiness — controls it. */
html.sched-dock .sched-app .sched-dock-tray { display: none !important; }
html.sched-dock .sched-app .sched-dock-tray.active { display: block !important; }
html.sched-dock .sched-app .sched-dock-tray.active:empty::after {
  content: "Nothing here right now."; display: block;
  padding: var(--sp-8) var(--sp-2); text-align: center;
  color: var(--text-muted); font-size: 12.5px;
}
/* Inside the dock, tray headers are redundant with the tab — soften them. */
html.sched-dock .sched-app .sched-dock-tray .sched-rail-head { margin-top: 0; }

/* Inspector */
html.sched-dock .sched-app .sched-dock-insp { flex: 1; min-height: 0; display: flex; flex-direction: column; }
html.sched-dock .sched-app .sched-dock-insp[hidden] { display: none; }
.sched-app .sched-insp-head { padding: var(--sp-3) var(--sp-3) var(--sp-2_5); border-bottom: 1px solid var(--glass-border); position: relative; }
.sched-app .sched-insp-close {
  position: absolute; top: var(--sp-2_5); right: var(--sp-2_5);
  width: 26px; height: 26px; border-radius: 7px; border: 0; background: transparent;
  color: var(--text-muted); cursor: pointer; font-size: 15px;
}
.sched-app .sched-insp-close:hover { background: var(--bg-card-hover); color: var(--text-primary); }
.sched-app .sched-insp-title {
  font-size: 15px; font-weight: 700; letter-spacing: -.01em; padding-right: 30px;
  border-left: 3px solid var(--jc, var(--accent)); padding-left: var(--sp-2); margin-bottom: var(--sp-2);
}
.sched-app .sched-insp-status-row { display: flex; align-items: center; gap: var(--sp-1_5); }
.sched-app .sched-insp-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.sched-app .sched-insp-status {
  flex: 1; background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  padding: var(--sp-1_5) var(--sp-2); color: var(--text-primary); font: inherit; font-size: 12.5px; cursor: pointer;
}
.sched-app .sched-insp-body { flex: 1; min-height: 0; overflow-y: auto; padding: var(--sp-3); }
.sched-app .sched-insp-field { margin-bottom: var(--sp-3); }
.sched-app .sched-insp-field > label {
  display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-muted); font-weight: 700; margin-bottom: var(--sp-1_5);
}
.sched-app .sched-insp-time { display: flex; align-items: center; gap: var(--sp-2); }
.sched-app .sched-insp-nudge {
  width: 30px; height: 34px; flex: 0 0 auto;
  border: 1px solid var(--border); background: var(--card); color: var(--text-secondary);
  border-radius: 8px; font-size: 15px; cursor: pointer;
}
.sched-app .sched-insp-nudge:hover:not(:disabled) { background: var(--bg-card-hover); color: var(--text-primary); }
.sched-app .sched-insp-nudge:disabled { opacity: .4; cursor: default; }
.sched-app .sched-insp-timeval {
  flex: 1; text-align: center; background: var(--card); border: 1px solid var(--border);
  border-radius: 8px; padding: var(--sp-2); font-size: 13px; font-weight: 600;
  font-family: var(--num, 'Inter', system-ui, sans-serif);
}
.sched-app .sched-insp-tech {
  width: 100%; background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  padding: var(--sp-2); color: var(--text-primary); font: inherit; font-size: 13px; cursor: pointer;
}
.sched-app .sched-insp-val {
  display: block; background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  padding: var(--sp-2); font-size: 13px; color: var(--text-primary);
}
a.sched-insp-site { text-decoration: none; color: var(--accent); }
a.sched-insp-site:hover { text-decoration: underline; }
.sched-app .sched-insp-notes {
  background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  padding: var(--sp-2); font-size: 12.5px; color: var(--text-secondary); line-height: 1.5;
  white-space: pre-wrap; word-break: break-word;
}
/* Attached quote/invoice rows */
.sched-app .sched-insp-docs { display: flex; flex-direction: column; gap: var(--sp-1_5); }
.sched-app .sched-insp-doc {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2_5); background: var(--card);
  border: 1px solid var(--border); border-radius: 8px;
  color: var(--text-primary); text-decoration: none; font-size: 13px;
  transition: border-color .14s, background .14s;
}
.sched-app .sched-insp-doc:hover { border-color: var(--accent-edge); background: var(--bg-card-hover); }
.sched-app .sched-insp-doc > i:first-child { color: var(--text-muted); font-size: 15px; flex: 0 0 auto; }
.sched-app .sched-insp-doc-main { flex: 1; min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-app .sched-insp-doc-status { font-size: 11px; font-weight: 600; color: var(--text-muted); flex: 0 0 auto; }
.sched-app .sched-insp-doc-status.is-good { color: var(--st-complete); }
.sched-app .sched-insp-doc-status.is-bad { color: var(--hot); }
.sched-app .sched-insp-doc-go { color: var(--text-muted); font-size: 14px; flex: 0 0 auto; }
.sched-app .sched-insp-bar { height: 6px; border-radius: 3px; background: var(--bg-secondary); overflow: hidden; }
.sched-app .sched-insp-bar i { display: block; height: 100%; background: var(--accent); }
.sched-app .sched-insp-foot {
  display: flex; gap: var(--sp-2); align-items: center;
  padding: var(--sp-2_5) var(--sp-3); border-top: 1px solid var(--glass-border);
}
.sched-app .sched-insp-btn {
  border: 1px solid var(--border-strong); background: var(--card); color: var(--text-primary);
  border-radius: 8px; padding: var(--sp-2) var(--sp-2_5); font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--sp-1);
}
.sched-app .sched-insp-btn:hover { background: var(--bg-card-hover); }
.sched-app .sched-insp-complete { background: var(--st-complete); border-color: var(--st-complete); color: #04140a; }
.sched-app .sched-insp-edit { margin-left: auto; background: transparent; border: 0; color: var(--accent); text-decoration: underline; }

/* ── P4 · Quick-create popover (flag feature_sched_quickcreate) ──
   The popover element is appended to <body> and only created when the flag is on
   (js/scheduler/quickcreate.js), so these rules are inert with the flag off. */
.sched-app .sched-qc-pop, .sched-qc-pop {
  position: fixed; z-index: 1000; width: 300px;
  background: var(--glass-bg, #1b1e25); border: 1px solid var(--glass-border, #2c313b);
  border-radius: var(--r-lg, 15px); box-shadow: 0 18px 48px rgba(0,0,0,.5);
  color: var(--text-primary, #f2f4f8); font-family: 'Sora', system-ui, sans-serif;
  overflow: hidden;
}
.sched-qc-pop[hidden] { display: none; }
.sched-qc-pop .sched-qc-head {
  padding: var(--sp-3) var(--sp-3_5); border-bottom: 1px solid var(--border, #2c313b);
  font-size: 12px; color: var(--accent, #33b1ff); font-weight: 700;
  display: flex; align-items: center; gap: var(--sp-1_5);
}
.sched-qc-pop .sched-qc-body { padding: var(--sp-3) var(--sp-3_5); display: flex; flex-direction: column; gap: var(--sp-2_5); }
.sched-qc-pop .sched-qc-f > label {
  display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-muted, #727b8b); font-weight: 700; margin-bottom: var(--sp-1_5);
}
.sched-qc-pop .sched-qc-cust,
.sched-qc-pop .sched-qc-type,
.sched-qc-pop .sched-qc-tech {
  width: 100%; background: var(--card, #1b1e25); border: 1px solid var(--border, #2c313b);
  border-radius: var(--r-xs, 7px); padding: var(--sp-2) var(--sp-2_5);
  color: var(--text-primary, #f2f4f8); font: inherit; font-size: 13px;
}
.sched-qc-pop .sched-qc-cust:focus,
.sched-qc-pop .sched-qc-type:focus,
.sched-qc-pop .sched-qc-tech:focus { outline: none; border-color: var(--accent-edge, rgba(51,177,255,.45)); }
.sched-qc-pop .sched-qc-durs { display: flex; gap: var(--sp-1_5); }
.sched-qc-pop .sched-qc-dchip {
  flex: 1; border: 1px solid var(--border, #2c313b); background: var(--card, #1b1e25);
  color: var(--text-secondary, #aeb6c4); border-radius: var(--r-xs, 7px);
  padding: var(--sp-1_5) 0; font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
  transition: background .14s, border-color .14s, color .14s;
}
.sched-qc-pop .sched-qc-dchip.on { border-color: var(--accent-edge, rgba(51,177,255,.45)); background: var(--accent-soft, rgba(51,177,255,.14)); color: var(--text-primary, #f2f4f8); }
.sched-qc-pop .sched-qc-more {
  background: transparent; border: 0; color: var(--accent, #33b1ff);
  font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer; text-align: left; padding: 0;
}
.sched-qc-pop .sched-qc-foot { display: flex; gap: var(--sp-2); padding: 0 var(--sp-3_5) var(--sp-3_5); }
.sched-qc-pop .sched-qc-cancel {
  flex: 0 0 auto; padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border-strong, #3a404c);
  background: var(--card, #1b1e25); color: var(--text-secondary, #aeb6c4);
  border-radius: var(--r-xs, 7px); font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.sched-qc-pop .sched-qc-go {
  flex: 1; padding: var(--sp-2) var(--sp-3); border: 0;
  background: var(--accent, #33b1ff); color: var(--accent-fg, #04121d);
  border-radius: var(--r-xs, 7px); font: inherit; font-size: 12.5px; font-weight: 700; cursor: pointer;
  box-shadow: 0 2px 10px var(--accent-glow, rgba(51,177,255,.28));
}
.sched-qc-pop .sched-qc-go:hover { background: var(--accent-hover, #5cc0ff); }

/* ── P7 · View cross-fade ──
   A subtle fade-in of the calendar canvas when the view or date genuinely
   changes (views.js gates it on the grid key, so soft re-renders from a drag /
   save / auto-refresh don't flicker). Opacity-only — no transform — so it never
   disturbs the sticky day headers or the scroll position. */
@media (prefers-reduced-motion: no-preference) {
  .sched-app .sched-view-enter { animation: schedViewEnter .19s var(--ease-standard, cubic-bezier(.4,0,.2,1)); }
}
@keyframes schedViewEnter { from { opacity: 0; } to { opacity: 1; } }

/* ── P5 · Touch long-press drag (flag feature_sched_dnd_v2) ──
   .sched-lift is applied to a job when a touch long-press grabs it — a clear
   "picked up" cue (ring + raise) before the drag begins. Only ever added on
   touch under the flag, so it's inert otherwise. */
.sched-app .sched-lift {
  box-shadow: 0 0 0 2px var(--accent), 0 8px 22px rgba(0,0,0,.45);
  transform: scale(1.03);
  transition: transform .12s var(--spring, cubic-bezier(.34,1.56,.64,1));
  z-index: 6;
}
@media (prefers-reduced-motion: reduce) {
  .sched-app .sched-lift { transform: none; }
}


/* ── Rail cards ──
   Every direct child of a rail column is now its own card: a flat Airflow
   surface with the shared shadow, stacked with a gap. This replaces the old
   "flatten everything into one panel" approach and gives the rail a clear,
   scannable, card-per-widget rhythm. */
.sched-app .sched-railcol > * {
  background: var(--glass-bg-2);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  box-shadow: var(--glass-shadow);
  padding: var(--sp-3);
  margin: 0;
}
.sched-app .sched-railcol > * + * { margin-top: var(--sp-2_5); }
/* The old dashboard .sched-rail chrome is superseded by the card rule above. */
.sched-app .sched-railcol .sched-rail {
  background: var(--glass-bg-2);
  border: 1px solid var(--glass-border);
}

/* ── Collapsible rail cards ──
   Any rail card with a .sched-rail-head can collapse to just its header (state
   persisted in extras.js). A caret on the right shows/rotates for affordance;
   the header stays clickable except over its inner controls (add-tech button,
   counts). Lets a dispatcher tuck away lower-priority cards so the calendar
   stays the focus. */
.sched-app .sched-railcol .sched-rail-head {
  cursor: pointer;
  user-select: none;
  position: relative;
  padding-right: var(--sp-5);
  transition: margin-bottom .15s ease;
}
.sched-app .sched-railcol .sched-rail-head::after {
  content: "";
  position: absolute; right: var(--sp-0_5); top: 50%;
  width: 6px; height: 6px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-60%) rotate(45deg);   /* ⌄ expanded */
  opacity: .5;
  transition: transform .18s ease, opacity .15s ease;
}
.sched-app .sched-railcol .sched-rail-head:hover::after { opacity: 1; }
.sched-app .sched-rail-collapsed > .sched-rail-head::after { transform: translateY(-30%) rotate(-135deg); }  /* ⌃ collapsed */
.sched-app .sched-rail-collapsed > .sched-rail-head { margin-bottom: 0; }
/* High specificity (id-free) so it beats component display rules without !important. */
.sched-app .sched-railcol .sched-rail-collapsed > :not(.sched-rail-head) { display: none; }

/* ── Job chips — dual-encoded (status + technician) ──
   DUAL ENCODING so a dispatcher can triage the whole board at a glance:
     · the LEFT EDGE is the job STATUS colour (--st, set by [data-status]) — the
       single most important read, so it owns the strongest, boldest edge;
     · the BODY TINT + text accent stay the TECHNICIAN colour (--jc, inline from
       viewhtml.js) so you still see who owns the job.
   Where the chip has room (day/week/swimlane events) a status dot reinforces the
   edge. Times are bold tabular numerals. */
.sched-app .sched-chip,
.sched-app .sched-event,
.sched-app .sched-swim-event,
.sched-app .sched-swim-chip {
  background: color-mix(in srgb, var(--jc, var(--accent)) 15%, var(--card));
  border-left: 4px solid var(--st);
  color: var(--text-primary);
  border-radius: 6px;
  box-shadow: 0 1px 2px rgba(0,0,0,.28);
  transition: background .12s, transform .12s, box-shadow .12s;
}
.sched-app .sched-chip:hover,
.sched-app .sched-event:hover,
.sched-app .sched-swim-event:hover,
.sched-app .sched-swim-chip:hover {
  background: color-mix(in srgb, var(--jc, var(--accent)) 26%, var(--card));
  transform: translateY(-1px);
  box-shadow: 0 4px 12px -2px rgba(0,0,0,.42);
}
.sched-app .sched-chip b,
.sched-app .sched-event-time,
.sched-app .sched-swim-event b {
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--jc, var(--accent)) 55%, var(--text-primary));
}
/* Reserve room on the right so the tech-initials avatar clears the status
   dot (::after) that sits top-right of the event. */
.sched-app .sched-event-time { display: flex; align-items: center; gap: var(--sp-1); padding-right: var(--sp-3_5); }
.sched-app .sched-swim-sub { opacity: .7; font-weight: 400; }
.sched-app .sched-event:hover .sched-event-resize { background: color-mix(in srgb, var(--st) 55%, transparent); }

/* Status dot — reinforces the status edge where the chip is wide enough to
   carry it (day/week timed events + swimlane bars). Pure CSS via --st.
   NB: the events are already position:absolute (dashboard.css) which anchors
   the ::after dot — do NOT set position:relative here or timed jobs fall out
   of the absolutely-positioned time grid and stack at the bottom. */
.sched-app .sched-event > .sched-event-title,
.sched-app .sched-swim-event { padding-right: var(--sp-3_5); }
.sched-app .sched-event::after,
.sched-app .sched-swim-event::after {
  content: ""; position: absolute; top: var(--sp-1_5); right: var(--sp-1_5);
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--st);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--st) 26%, transparent);
}
/* In-progress + no-show are time-critical — give their dot a gentle pulse. */
@media (prefers-reduced-motion: no-preference) {
  .sched-app .sched-event[data-status="in_progress"]::after,
  .sched-app .sched-event[data-status="no_show"]::after,
  .sched-app .sched-swim-event[data-status="in_progress"]::after,
  .sched-app .sched-swim-event[data-status="no_show"]::after { animation: schedStatusPulse 2s ease-out infinite; }
}
@keyframes schedStatusPulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--st) 60%, transparent); }
  70%  { box-shadow: 0 0 0 6px color-mix(in srgb, var(--st) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--st) 0%, transparent); }
}

/* Completed jobs — softer than the old opacity:.5 + line-through (which hurt
   legibility). Keep them clearly "done" via a muted body + the green status
   rail/dot, but readable and un-struck. Overrides the dashboard.css default. */
.sched-app .sched-chip.is-complete,
.sched-app .sched-event.is-complete,
.sched-app .sched-swim-event.is-complete,
.sched-app .sched-list-card.is-complete {
  opacity: .74;
  text-decoration: none;
}
.sched-app .sched-chip.is-complete:hover,
.sched-app .sched-event.is-complete:hover,
.sched-app .sched-swim-event.is-complete:hover,
.sched-app .sched-list-card.is-complete:hover { opacity: 1; }

/* Technician on leave — diagonal-stripe shaded lane + label */
.sched-app .sched-swim-track .sched-swim-leave {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  display: flex; align-items: center; justify-content: center; gap: var(--sp-1);
  font-size: 12px; font-weight: 600; color: var(--text-muted);
  background: repeating-linear-gradient(45deg,
    color-mix(in srgb, var(--text-muted) 9%, transparent) 0, color-mix(in srgb, var(--text-muted) 9%, transparent) 8px,
    transparent 8px, transparent 16px);
}
.sched-app .sched-swim-row.is-onleave .sched-swim-tech { opacity: .6; }
.sched-app .sched-leave-tag {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  color: var(--text-muted); background: color-mix(in srgb, var(--text-muted) 14%, transparent);
  padding: 1px 6px; border-radius: 5px; margin-left: var(--sp-1);
}

/* Technician time-off list inside the tech modal */
.sched-app .sched-timeoff-list { display: flex; flex-direction: column; gap: var(--sp-1); margin: var(--sp-2) 0; }
.sched-app .sched-timeoff-empty { font-size: 13px; color: var(--text-muted); }
.sched-app .sched-timeoff-item {
  display: flex; align-items: center; gap: var(--sp-2); font-size: 13px;
  padding: var(--sp-1) var(--sp-2); background: var(--surface-2, rgba(127,127,127,.06)); border-radius: 7px;
}
.sched-app .sched-timeoff-dates { font-weight: 600; color: var(--text-primary); }
.sched-app .sched-timeoff-reason { color: var(--text-muted); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-app .sched-timeoff-del { margin-left: auto; border: 0; background: none; color: var(--text-muted); font-size: 18px; line-height: 1; cursor: pointer; padding: 0 var(--sp-1); }
.sched-app .sched-timeoff-del:hover { color: #ef4444; }
.sched-app .sched-timeoff-add { display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
.sched-app .sched-timeoff-add input[type="text"] { flex: 1; min-width: 120px; }
.sched-app .sched-timeoff-sep { color: var(--text-muted); }

/* Timesheets section in the stats modal */
.sched-app .sched-timesheet-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-2); }
.sched-app .sched-timesheet-controls { display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }

/* Tiny technician initials on timed events */
.sched-ev-av {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--jc, var(--accent));
  color: #fff;
  font-size: 8px; font-weight: 800; letter-spacing: .02em;
  margin-left: auto;
  flex-shrink: 0;
}
/* Tech rail: initials avatars replace the plain dots */
.sched-tech-av {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  border-radius: 50%;
  color: #fff;
  font-size: 9px; font-weight: 800;
  flex-shrink: 0;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14);
}

/* ── Live now line — accent, pulsing dot, time pill ── */
.sched-app .sched-nowline {
  background: var(--accent);
  box-shadow: 0 0 6px var(--accent-edge);
}
.sched-app .sched-nowline::before {
  background: var(--accent);
  box-shadow: 0 0 0 0 rgba(51,177,255,.55);
}
.sched-nowline-lbl {
  position: absolute;
  left: var(--sp-3);
  top: calc(var(--sp-2_5) * -1);
  background: var(--accent);
  color: #0b1020;
  font-size: 9px; font-weight: 800;
  font-variant-numeric: tabular-nums;
  padding: var(--sp-0_5) var(--sp-1_5);
  border-radius: 999px;
  pointer-events: none;
}

/* ── Working-hours texture: off days get a subtle diagonal hatch, today's
      column a faint accent wash ── */
.sched-app .sched-tg-col.is-offday,
.sched-app .sched-month-cell.is-offday {
  background:
    repeating-linear-gradient(-45deg, rgba(120,135,170,0.055) 0 5px, transparent 5px 11px),
    rgba(0,0,0,0.22);
}
.sched-app .sched-tg-col.is-today { background: rgba(51,177,255,0.05); }
.sched-app .sched-tg-headcell.is-today { box-shadow: inset 0 -2px 0 var(--accent); }

/* ═══════════════════════════════════════════════════════════════
   Modals — job + settings overhaul (editor glass cards)
   ═══════════════════════════════════════════════════════════════ */
.sched-app .modal-box {
  background: var(--card);
  border: 1px solid var(--border-strong);
  border-radius: 16px;
  box-shadow: 0 24px 60px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,0.06);
}

/* Structured modal: sticky head + scrolling body + sticky footer */
.sched-app .sched-modal {
  display: flex;
  flex-direction: column;
  max-height: 90vh;
  padding: 0;
  overflow: hidden;
  width: 100%;
}
.sched-modal-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, rgba(255,255,255,0.03), transparent);
  flex-shrink: 0;
}
.sched-modal-head h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: var(--sp-2_5);
  color: var(--text-primary);
}
.sched-modal-ico {
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 9px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-edge);
  color: var(--accent);
  font-size: 17px;
}
.sched-modal-x {
  margin-left: auto;
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.02);
  color: var(--text-muted);
  cursor: pointer;
  font-size: 16px;
  transition: background .15s, color .15s, transform .12s;
}
.sched-modal-x:hover { background: rgba(255,255,255,0.08); color: var(--text-primary); }
.sched-modal-x:active { transform: scale(0.94); }
.sched-modal-ico-green {
  background: rgba(34,197,94,0.14);
  border-color: rgba(34,197,94,0.40);
  color: #22c55e;
}
.sched-modal-sub {
  font-size: 11px;
  font-weight: 500;
  color: var(--text-muted);
  padding: var(--sp-0_5) var(--sp-2);
  border: 1px solid var(--border);
  border-radius: 999px;
}
.sched-modal-status { font-size: 12px; color: var(--text-muted); margin-bottom: 10px; }
.sched-color-input {
  width: 100%; height: 40px;
  padding: 3px;
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: 9px;
  cursor: pointer;
}
.sched-modal-body {
  padding: 16px 18px;
  overflow-y: auto;
  flex: 1;
}
.sched-app .sched-modal .sched-modal-footer {
  flex-direction: row;
  align-items: center;
  gap: var(--sp-2_5);
  flex-wrap: wrap;
  margin: 0;
  padding: 13px 18px;
  border-top: 1px solid var(--border);
  background: linear-gradient(0deg, rgba(0,0,0,0.18), transparent);
  flex-shrink: 0;
}
.sched-app .sched-modal .sched-primaryactions { margin-left: auto; }

/* Sections inside the job modal */
.sset-sec + .sset-sec { margin-top: 18px; }
.sset-sec-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--text-muted);
  margin-bottom: 11px;
  padding-bottom: 7px;
  border-bottom: 1px solid var(--border);
}
.sset-sec-head i { color: var(--accent); font-size: 14px; }

/* Field grid */
.sset-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
}
.sset-grid .span2 { grid-column: 1 / -1; }
.sset-grid .form-group { margin: 0; }

/* Inputs & selects — crisp canvas styling with an accent focus ring */
.sched-app .form-group label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 6px;
}
.sched-app .sched-modal-body input[type="text"],
.sched-app .sched-modal-body input[type="email"],
.sched-app .sched-modal-body input[type="tel"],
.sched-app .sched-modal-body input[type="time"],
.sched-app .sched-modal-body input[type="date"],
.sched-app .sched-modal-body input[type="number"],
.sched-app .sset-tabbody input[type="text"],
.sched-app .sset-tabbody input[type="email"],
.sched-app .sset-tabbody input[type="tel"],
.sched-app .sset-tabbody input[type="time"],
.sched-app .sset-tabbody input[type="date"],
.sched-app .sset-tabbody input[type="number"],
.sched-app .sched-modal .filter-select {
  width: 100%;
  box-sizing: border-box;
  padding: 9px 12px;
  font-size: 13px;
  font-family: inherit;
  color: var(--text-primary);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: 9px;
  transition: border-color .15s, box-shadow .15s;
}
.sched-app .sched-modal input:focus,
.sched-app .sched-modal .filter-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.sched-app .hint { color: var(--text-muted); font-weight: 400; font-size: 11px; }
.sched-app .hint-block { display: block; margin-top: 6px; line-height: 1.45; }

/* Checklist + copy rows */
.sched-checklist-add, .sched-checklist-tpl, .sset-copyrow {
  display: flex; gap: var(--sp-2); align-items: center; margin-top: 8px; flex-wrap: wrap;
}
.sset-copyrow { margin-top: 0; }
.sset-copyrow input { flex: 1; min-width: 0; }
.sched-checklist-add input { flex: 1; }

/* ── Toggle switches (settings) ── */
.sset-toggle {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 11px 0;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
}
.sset-toggle:last-child { border-bottom: none; }
/* A toggle placed inside a .form-group (the job modal's "Notify customer" pair)
   was losing its flex row to `.sched-app .form-group label { display:block }`
   below, which outranks the class. An inline <span> ignores width/height, so the
   38×22 track collapsed to nothing and only the absolutely-positioned knob
   painted — over the label text. Re-assert the row, and drop the settings-list
   divider/padding since these sit side by side rather than stacked. */
.sched-app .form-group label.sset-toggle {
  display: flex;
  padding: 0;
  margin-bottom: 0;
  border-bottom: none;
}
.sset-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.sset-switch {
  flex-shrink: 0;
  width: 38px; height: 22px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid var(--border-strong);
  position: relative;
  transition: background .18s, border-color .18s;
}
.sset-switch::after {
  content: "";
  position: absolute;
  top: var(--sp-0_5); left: var(--sp-0_5);
  width: 16px; height: 16px;
  border-radius: 50%;
  background: #cfd6e4;
  transition: transform .18s, background .18s;
}
.sset-toggle input:checked + .sset-switch {
  background: var(--accent);
  border-color: var(--accent);
}
.sset-toggle input:checked + .sset-switch::after { transform: translateX(16px); background: #fff; }
.sset-toggle input:focus-visible + .sset-switch { box-shadow: 0 0 0 3px var(--accent-soft); }
.sset-toggle-label { font-size: 13px; color: var(--text-primary); }

/* ── Settings: tabbed layout ── */
.sset-tabwrap { display: flex; flex: 1; min-height: 0; }
.sset-tabs {
  flex-shrink: 0;
  width: 176px;
  padding: var(--sp-3) var(--sp-2_5);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 3px;
  background: rgba(0,0,0,0.14);
  overflow-y: auto;
}
.sset-tab {
  display: flex;
  align-items: center;
  gap: var(--sp-2_5);
  padding: 9px 11px;
  border: none;
  background: transparent;
  color: var(--text-secondary);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  text-align: left;
  border-radius: 8px;
  cursor: pointer;
  transition: background .15s, color .15s;
}
.sset-tab i { font-size: 16px; color: var(--text-muted); transition: color .15s; }
.sset-tab:hover { background: rgba(255,255,255,0.05); color: var(--text-primary); }
.sset-tab.active { background: var(--accent-soft); color: var(--accent); }
.sset-tab.active i { color: var(--accent); }
.sset-tabbody { flex: 1; padding: 18px 20px; overflow-y: auto; }
.sset-panel { display: none; animation: ssetFade .18s ease; }
.sset-panel.active { display: block; }
@keyframes ssetFade { from { opacity: 0; transform: translateY(4px); } }
.sset-panel-lead {
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.5;
  margin-bottom: 16px;
}

/* Weekday pills */
.sched-app .sched-weekdays { display: flex; gap: var(--sp-1_5); flex-wrap: wrap; }
.sched-app .sched-wd {
  width: 34px; height: 34px;
  border-radius: 8px;
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--text-secondary);
  font-weight: 700;
  font-size: 12px;
  cursor: pointer;
  transition: all .14s;
}
.sched-app .sched-wd:hover { border-color: var(--accent-edge); color: var(--text-primary); }
.sched-app .sched-wd.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* ═══════════════════════════════════════════════════════════════
   Rail widgets — mini-cal, weather, unscheduled tray, attention strip
   ═══════════════════════════════════════════════════════════════ */
/* Rail cards are separated by the gap from the rail-cards block above — no
   hairline needed now that each widget is its own card. */

/* ── Mini-month navigator ── */
.sched-mc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.sched-mc-title { font-size: 12.5px; font-weight: 700; color: var(--text-primary); }
.sched-mc-nav {
  width: 24px; height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 7px;
  background: rgba(255,255,255,0.02); color: var(--text-secondary);
  cursor: pointer; font-size: 14px;
  transition: background .15s, color .15s;
}
.sched-mc-nav:hover { background: var(--accent-soft); color: var(--accent); }
.sched-mc-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--sp-0_5);
}
.sched-mc-dow { margin-bottom: 3px; }
.sched-mc-wd {
  text-align: center;
  font-size: 9.5px;
  font-weight: 700;
  color: var(--text-muted);
  padding: var(--sp-0_5) 0;
}
.sched-mc-day {
  aspect-ratio: 1 / 1;
  min-height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent;
  color: var(--text-secondary);
  font-family: inherit; font-size: 11.5px; font-weight: 500;
  border-radius: 7px; cursor: pointer;
  position: relative;
  transition: background .12s, color .12s;
}
.sched-mc-day:hover { background: rgba(255,255,255,0.07); color: var(--text-primary); }
.sched-mc-blank { pointer-events: none; }
.sched-mc-day.has::after {
  content: ""; position: absolute; bottom: 3px; left: 50%; transform: translateX(-50%);
  width: 4px; height: 4px; border-radius: 50%; background: var(--accent);
}
.sched-mc-day.today { color: var(--accent); font-weight: 700; }
.sched-mc-day.sel {
  background: var(--accent); color: #fff; font-weight: 700;
}
.sched-mc-day.sel.has::after { background: #fff; }

/* ── Weather forecast ── */
.sched-wx-place { display: inline-flex; align-items: center; gap: 3px; font-size: 10.5px; color: var(--text-muted); font-weight: 500; }
.sched-wx-place i { font-size: 12px; }
.sched-wx-list { display: flex; flex-direction: column; gap: 1px; }
.sched-wx-row {
  display: flex; align-items: center; gap: var(--sp-2);
  width: 100%;
  padding: 5px 6px;
  border: none; background: transparent;
  border-radius: 7px; cursor: pointer;
  font-family: inherit;
  transition: background .12s;
}
.sched-wx-row:hover { background: rgba(255,255,255,0.06); }
.sched-wx-day { flex: 1; text-align: left; font-size: 12px; font-weight: 600; color: var(--text-secondary); }
.sched-wx-ico { font-size: 16px; color: var(--accent); }
.sched-wx-temp { font-size: 12px; font-weight: 600; color: var(--text-primary); min-width: 52px; text-align: right; }
.sched-wx-lo { color: var(--text-muted); font-weight: 400; margin-left: 3px; }

/* ── Today at a glance ── */
.sched-today-date { margin-left: auto; font-size: 10.5px; color: var(--text-muted); font-weight: 600; }
.sched-today-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
  margin-top: 4px;
}
.sched-today-stat {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 9px 4px;
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--border);
  border-radius: 9px;
}
.sched-today-stat .n { font-size: 18px; font-weight: 800; color: var(--text-primary); line-height: 1; }
.sched-today-stat .n.warn { color: #fbbf24; }
.sched-today-stat .l { font-size: 9.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); font-weight: 600; }
.sched-today-next {
  display: block; width: 100%; text-align: left;
  margin-top: 8px;
  padding: var(--sp-2) var(--sp-2_5);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 9px;
  background: rgba(255,255,255,0.02);
  color: var(--text-secondary);
  font-family: inherit; font-size: 12px;
  cursor: pointer;
  transition: background .14s;
}
.sched-today-next:hover { background: rgba(255,255,255,0.06); }
.sched-today-next .lbl { color: var(--text-muted); font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; margin-right: 6px; }
.sched-today-next b { color: var(--text-primary); }

/* ── Per-tech capacity chip (Crew rail) ── */
.sched-app .sched-tech-hrs {
  margin-left: auto;
  font-size: 10.5px; font-weight: 700;
  color: var(--text-secondary);
  background: rgba(255,255,255,0.06);
  border-radius: 999px;
  padding: 1px 7px;
}
.sched-app .sched-tech-item.active .sched-tech-hrs { color: var(--accent); background: var(--accent-soft); }
/* the edit pencil should sit after the hours chip without pushing it */
.sched-app .sched-tech-hrs + .sched-tech-edit { margin-left: 8px; }

/* ── Keyboard shortcuts button + help popover ── */
.sched-kbd-btn {
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 8px;
  background: rgba(255,255,255,0.02); color: var(--text-secondary);
  cursor: pointer; font-size: 16px;
  transition: background .15s, color .15s;
}
.sched-kbd-btn:hover { background: var(--accent-soft); color: var(--accent); }
.sched-signout-btn:hover { background: rgba(239,68,68,0.12); color: #ef4444; border-color: rgba(239,68,68,0.3); }
.sched-kbd-help {
  position: absolute;
  top: calc(100% + var(--sp-2));
  right: var(--sp-3);
  width: 300px;
  padding: var(--sp-3_5) var(--sp-4);
  border-radius: 14px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  z-index: 70;
}
.sched-kbd-help-title { font-size: 12px; font-weight: 700; color: var(--text-primary); margin-bottom: 10px; }
.sched-kbd-row {
  display: flex; align-items: center; gap: var(--sp-1_5);
  font-size: 12px; color: var(--text-secondary);
  padding: var(--sp-1) 0;
}
.sched-kbd-row span { margin-left: 6px; }
.sched-kbd-help kbd {
  min-width: 20px; height: 20px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 5px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px; font-weight: 600;
  color: var(--text-primary);
  background: rgba(255,255,255,0.07);
  border: 1px solid var(--border-strong);
  border-bottom-width: 2px;
  border-radius: 5px;
}

/* ── "Needs assigning" tray ── */
.sched-rail-count {
  margin-left: auto;
  font-size: 10.5px; font-weight: 700;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid var(--accent-edge);
  border-radius: 999px;
  padding: 1px 7px;
}
.sched-unsched-card {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: var(--sp-2) var(--sp-2_5);
  border-radius: 9px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  background: rgba(255,255,255,0.02);
  margin-top: 8px;
  transition: background .14s, transform .12s;
}
.sched-unsched-card:hover { background: rgba(255,255,255,0.06); transform: translateX(2px); }
.sched-unsched-main { flex: 1 1 auto; min-width: 0; cursor: pointer; }

/* Quick-assign trigger (tray card) + popover */
.sched-qa-btn {
  flex: 0 0 auto;
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: transparent;
  color: var(--text-2, #94a3b8);
  cursor: pointer;
  font-size: 15px;
  transition: background .14s, color .14s, border-color .14s;
}
.sched-qa-btn:hover { background: var(--accent); border-color: var(--accent); color: #fff; }

.sched-qa-pop {
  position: fixed;
  z-index: var(--z-modal, 1000);
  min-width: 180px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 5px;
  border-radius: 11px;
  background: var(--panel, #1b1e25);
  border: 1px solid var(--border);
  box-shadow: 0 14px 34px -10px rgba(0,0,0,.6);
}
.sched-qa-row {
  display: flex; align-items: center; gap: 9px;
  width: 100%;
  padding: 8px 10px;
  border: 0; border-radius: 8px;
  background: transparent;
  color: var(--text, #e5e7eb);
  font: inherit; font-size: 13px;
  text-align: left; cursor: pointer;
}
.sched-qa-row:hover { background: rgba(255,255,255,0.07); }
.sched-qa-dot { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; }
.sched-qa-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-qa-hrs { flex: 0 0 auto; font-size: 11px; color: var(--text-2, #94a3b8); font-variant-numeric: tabular-nums; }
html[data-theme="light"] .sched-qa-pop { background: #fff; }
html[data-theme="light"] .sched-qa-row { color: #1e293b; }
html[data-theme="light"] .sched-qa-row:hover { background: rgba(15,23,42,0.05); }

/* ── Callback staging tray ("To book", flag feature_callback_staging) ─────── */
.sched-stage-overdue {
  font-size: 10px; font-weight: 700;
  color: #f59e0b;
  background: rgba(245,158,11,0.12);
  border: 1px solid rgba(245,158,11,0.4);
  border-radius: 999px;
  padding: var(--sp-px) var(--sp-1_5);
  margin-left: auto;
}
.sched-stage-overdue + .sched-rail-count { margin-left: 6px; }
.sched-stage-card {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2_5);
  border-radius: 9px;
  border: 1px solid var(--border);
  border-left: 3px solid #0ea5e9;
  background: rgba(14,165,233,0.05);
  margin-top: 8px;
  cursor: grab;
  touch-action: none;                 /* let the pointer-drag own vertical moves */
  transition: background .14s, transform .12s, box-shadow .12s;
}
.sched-stage-card:hover { background: rgba(14,165,233,0.1); transform: translateX(2px); }
.sched-stage-card.is-overdue { border-left-color: #f59e0b; background: rgba(245,158,11,0.06); }
.sched-stage-card.sched-dragging { opacity: .4; }
.sched-stage-main { flex: 1 1 auto; min-width: 0; cursor: pointer; }
.sched-stage-cb { color: var(--accent); font-weight: 600; }                       /* callback flag — theme-aware ice-blue (was hard-coded #38bdf8, no light variant) */
.sched-stage-card.is-overdue .sched-stage-cb { color: var(--st-in_progress); }    /* #f59e0b amber, tokenized */
.sched-stage-grip {
  flex: 0 0 auto;
  display: inline-flex; align-items: center;
  color: var(--text-2, #94a3b8);
  font-size: 16px;
  opacity: .5;
}
.sched-stage-card:hover .sched-stage-grip { opacity: .85; }
/* The whole tray is a drop target for un-booking a scheduled job. */
.sched-stage-rail.sched-drop-active {
  outline: 2px dashed #0ea5e9;
  outline-offset: 2px;
  border-radius: 11px;
  background: rgba(14,165,233,0.06);
}

/* Capture popover — quick "log a callback" without the full job modal. */
.sched-stage-pop {
  position: fixed;
  z-index: var(--z-modal, 1000);
  width: 268px; max-width: calc(100vw - 16px);
  padding: var(--sp-3);
  border-radius: 12px;
  background: var(--panel, #1b1e25);
  border: 1px solid var(--border);
  box-shadow: 0 14px 34px -10px rgba(0,0,0,.6);
}
.sched-stage-pop-head { font-weight: 700; font-size: 13px; margin-bottom: 8px; }
.sched-stage-pop-lbl {
  display: block;
  font-size: 11.5px; font-weight: 600;
  color: var(--text-2, #94a3b8);
  margin-bottom: 9px;
}
.sched-stage-pop-lbl .input {
  margin-top: var(--sp-1);
  width: 100%;
  padding: var(--sp-1_5) var(--sp-2);
  font: inherit; font-size: 13px; font-weight: 400;
  color: var(--text, #e5e7eb);
  background: var(--bg-elevated, rgba(255,255,255,0.04));
  border: 1px solid var(--border);
  border-radius: 8px;
  box-sizing: border-box;
}
.sched-stage-pop-lbl textarea.input { resize: vertical; min-height: 40px; }
.sched-stage-pop-lbl .input:focus { outline: none; border-color: var(--accent); }
html[data-theme="light"] .sched-stage-pop-lbl .input { color: #1e293b; background: #fff; }
.sched-stage-pop-opt { font-weight: 400; opacity: .7; }
.sched-stage-pop-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); margin-top: var(--sp-0_5); }
.sched-stage-pop-actions .btn { width: auto; flex: 0 0 auto; }   /* editor base .btn is width:100% outside .sched-app */
html[data-theme="light"] .sched-stage-pop { background: #fff; }
html[data-theme="light"] .sched-stage-card { background: rgba(14,165,233,0.06); }
html[data-theme="light"] .sched-stage-card:hover { background: rgba(14,165,233,0.11); }

/* Service-due tray cards */
.sched-servicedue-card {
  padding: var(--sp-2) var(--sp-2_5);
  border-radius: 9px;
  border: 1px solid var(--border);
  border-left: 3px solid #f59e0b;
  background: rgba(255,255,255,0.02);
  margin-top: 8px;
}
.sched-servicedue-card.is-overdue { border-left-color: #ef4444; }
.sched-servicedue-when { text-transform: capitalize; color: var(--text-muted); }
.sched-servicedue-card.is-overdue .sched-servicedue-when { color: #ef4444; }
.sched-servicedue-book { margin-top: var(--sp-1_5); width: 100%; justify-content: center; }

/* ── Overdue attention strip ── */
.sched-attention {
  border: 1px solid rgba(239,68,68,0.35);
  background: rgba(239,68,68,0.08);
  border-radius: 12px;
  padding: var(--sp-3) var(--sp-3_5);
  margin-bottom: 14px;
}
.sched-att-head {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: 13px; font-weight: 700; color: #f87171;
  margin-bottom: 9px;
}
.sched-att-list { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
.sched-att-chip {
  display: inline-flex; align-items: center; gap: var(--sp-1_5);
  padding: 5px 10px;
  border: 1px solid rgba(239,68,68,0.3);
  background: rgba(255,255,255,0.03);
  color: var(--text-primary);
  border-radius: 999px;
  font-family: inherit; font-size: 12px; font-weight: 500;
  cursor: pointer;
  transition: background .14s, border-color .14s;
}
.sched-att-chip:hover { background: rgba(239,68,68,0.14); border-color: rgba(239,68,68,0.5); }
.sched-att-date { color: var(--text-muted); font-size: 11px; }
.sched-att-more { font-size: 11px; color: var(--text-muted); align-self: center; }
.sched-att-x {
  margin-left: auto;
  width: 24px; height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent;
  color: #f87171; cursor: pointer; border-radius: 7px; font-size: 15px;
  transition: background .14s;
}
.sched-att-x:hover { background: rgba(239,68,68,0.18); }

/* ═══════════════════════════════════════════════════════════════
   History view — full-width report list
   ═══════════════════════════════════════════════════════════════ */
/* History spans the whole board (rails hidden) — it's a list, not a calendar. */
.sched-layout.sched-history-mode { grid-template-columns: 1fr; }
.sched-layout.sched-history-mode .sched-railcol { display: none; }

.sched-history-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-3_5);
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.sched-history-title {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: 15px; font-weight: 700; color: var(--text-primary);
}
.sched-history-title i { color: var(--accent); }
.sched-history-searchwrap {
  position: relative;
  margin-left: auto;
  flex: 1;
  max-width: 380px;
  min-width: 200px;
}
.sched-history-searchwrap > i {
  position: absolute; left: var(--sp-3); top: 50%; transform: translateY(-50%);
  color: var(--text-muted); font-size: 15px; pointer-events: none;
}
.sched-app input.sched-history-search {
  width: 100%;
  box-sizing: border-box;
  padding: 9px 12px 9px 34px;
  font-size: 13px; font-family: inherit;
  color: var(--text-primary);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  transition: border-color .15s, box-shadow .15s;
}
.sched-app input.sched-history-search:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.sched-hist-count {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .08em;
  color: var(--text-muted);
  margin-bottom: 12px;
}
.shist-group { margin-bottom: 22px; }
.sched-hist-more { display: flex; justify-content: center; padding: 8px 0 20px; }
.shist-date {
  font-size: 12px; font-weight: 700; color: var(--text-secondary);
  text-transform: uppercase; letter-spacing: .04em;
  padding-bottom: 7px; margin-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.shist-card {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-3_5) var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: 11px;
  background: rgba(255,255,255,0.02);
  margin-bottom: 8px;
  position: relative;
  overflow: hidden;
  transition: background .14s, border-color .14s;
}
.shist-card:hover { background: rgba(255,255,255,0.055); border-color: var(--border-strong); }
.shist-stripe { position: absolute; left: 0; top: 0; bottom: 0; width: 4px; }
.shist-body { flex: 1; min-width: 0; cursor: pointer; }
.shist-top { display: flex; align-items: center; gap: var(--sp-2_5); flex-wrap: wrap; }
.shist-name { font-size: 14px; font-weight: 700; color: var(--text-primary); }
.shist-badge {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  padding: var(--sp-0_5) var(--sp-2); border: 1px solid; border-radius: 999px;
}
.shist-time {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: 12px; color: var(--text-muted);
}
.shist-time i { font-size: 13px; }
/* Report meta on history cards: "needs attention" flag count + SR number */
.shist-flags {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: 11px; font-weight: 700;
  padding: var(--sp-0_5) var(--sp-2); border-radius: 999px;
  background: rgba(245,158,11,.14); color: #d97706;
}
.shist-flags i { font-size: 12px; }
/* "Already asked for a review" on a history card — quiet by design: it answers a
   question the owner asks while scanning, it isn't the card's headline. The
   hand-picked ask reads solid, the cron's reads outlined, so a glance down the
   list separates "I chose this customer" from "the daily sweep got them". */
.shist-review {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: 11px; font-weight: 700;
  padding: var(--sp-0_5) var(--sp-2); border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--accent) 38%, transparent);
  color: var(--accent); background: transparent;
}
.shist-review.manual { background: color-mix(in srgb, var(--accent) 14%, transparent); }
.shist-review i { font-size: 12px; }
html[data-theme="light"] .shist-review { color: #0f76bf; }
.shist-repnum { color: var(--text-muted); font-family: ui-monospace, monospace; font-size: 11.5px; text-transform: none; }
.shist-meta {
  font-size: 12.5px; color: var(--text-secondary);
  margin-top: 4px;
  text-transform: capitalize;
}
.shist-sep { color: var(--text-muted); margin: 0 7px; }
.shist-type { color: var(--text-primary); font-weight: 600; }
.shist-addr {
  display: flex; align-items: center; gap: 5px;
  font-size: 12px; color: var(--text-muted);
  margin-top: 4px;
}
.shist-addr i { font-size: 13px; }
.shist-thumbs { margin-top: 8px; }
.shist-report { flex-shrink: 0; align-self: center; }

/* ═══════════════════════════════════════════════════════════════
   Clickable legend (status filters) + global job search
   ═══════════════════════════════════════════════════════════════ */
/* Leading label so the strip reads as a filter control, not a passive key. */
.sched-app .sched-legend-label {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  color: var(--text-muted); font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  margin-right: var(--sp-0_5);
}
.sched-app .sched-legend-item {
  display: inline-flex; align-items: center; gap: var(--sp-1_5);
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.03);
  color: var(--text-secondary);
  font-family: inherit; font-size: 12px;
  padding: var(--sp-0_5) var(--sp-2); border-radius: 999px;
  cursor: pointer;
  transition: background .14s, color .14s, opacity .14s, border-color .14s;
}
.sched-app .sched-legend-item:hover { background: rgba(255,255,255,0.08); color: var(--text-primary); border-color: var(--border-strong); }
/* Active (shown) chip reads as "on" — accent ring; off chip dims + strikes. */
.sched-app .sched-legend-item[aria-pressed="true"] { border-color: var(--accent-edge); }
.sched-app .sched-legend-item.off { opacity: .45; text-decoration: line-through; background: transparent; }
.sched-app .sched-legend-item.off .sched-legend-dot { box-shadow: inset 0 0 0 2px var(--surface); }

/* Booking-requests count badge — a red pill on the "Requests" toolbar button.
   (Previously unstyled: it rendered as a bare number with no pill/position.)
   The host button carries position:relative; JS toggles display none/inline-flex. */
.sched-app .sched-req-badge {
  position: absolute; top: calc(var(--sp-1_5) * -1); right: calc(var(--sp-1_5) * -1);
  min-width: 17px; height: 17px; padding: 0 var(--sp-1);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--hot); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 1;
  font-family: var(--num, 'Inter', system-ui, sans-serif); font-variant-numeric: tabular-nums;
  border-radius: 999px;
  box-shadow: 0 0 0 2px var(--bg);
  pointer-events: none;
}

/* Topbar search */
.sched-topbar-search {
  position: relative;
  flex: 1;
  max-width: 460px;
  margin: 0 auto 0 var(--sp-2);
}
.sched-topbar-search > i {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  color: var(--text-muted); font-size: 15px; pointer-events: none;
}
.sched-app .sched-topbar-search input {
  width: 100%;
  box-sizing: border-box;
  height: 34px;
  padding: 0 46px 0 34px;
  font-size: 13px; font-family: inherit;
  color: var(--text-primary);
  background: rgba(0,0,0,0.25);
  border: 1px solid var(--border);
  border-radius: 9px;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.sched-app .sched-topbar-search input::placeholder { color: var(--text-muted); }
.sched-app .sched-topbar-search input:focus {
  outline: none;
  background: var(--bg);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* ⌘K hint badge inside the search field — opens the command palette. */
.sched-cmdk {
  position: absolute; right: var(--sp-1_5); top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center;
  border: none; background: transparent; cursor: pointer; padding: 0;
}
.sched-cmdk kbd {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10.5px; font-weight: 600; color: var(--text-muted);
  background: rgba(255,255,255,0.06); border: 1px solid var(--border-strong);
  border-radius: 5px; padding: var(--sp-0_5) var(--sp-1_5);
}
.sched-cmdk:hover kbd { color: var(--accent); border-color: var(--accent-edge); background: var(--accent-soft); }

/* Mobile-only search trigger — opens the command palette (which already does
   job search). Hidden on desktop where the full topbar input is shown. */
.sched-search-mob { display: none; }

/* Day-map technician filter (modal header) */
.sched-daymap-tech {
  margin-left: auto;
  max-width: 170px;
  font-size: 13px;
  padding: 6px 10px;
}
/* "Optimise" — reorder the day's stops for the shortest drive (OSRM). */
.sched-daymap-optimize {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1_5);
  font-size: 13px;
  font-weight: 600;
  padding: var(--sp-1_5) var(--sp-3);
  border-radius: var(--sp-2);
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.04);
  color: var(--text-primary);
  cursor: pointer;
  white-space: nowrap;
  transition: background .12s, border-color .12s, opacity .12s;
}
.sched-daymap-optimize:hover { background: rgba(255,255,255,0.08); border-color: var(--accent); }
.sched-daymap-optimize:active { transform: scale(0.97); }
.sched-daymap-optimize:disabled { opacity: 0.55; cursor: progress; }
/* In the promoted Map view the controls sit in the top bar, not a modal head. */
.sched-mapview-bar .sched-daymap-optimize { margin-left: var(--sp-1); }
/* ── Day map promoted to a first-class split view ──
   The dispatch map is core, so it gets a large map pane + a taller route list
   side-by-side rather than the cramped default. Scheduler-scoped so the shared
   dashboard.css defaults are untouched. */
.sched-app .sched-map-modal .sched-modal-body { padding: var(--sp-2) var(--sp-3) var(--sp-3); }
.sched-app .sched-map-modal .day-map-body {
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: var(--sp-3);
}
.sched-app .sched-map-modal #dayMap {
  height: 74vh;
  min-height: 440px;
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--glass-shadow);
}
.sched-app .sched-map-modal #dayMapList {
  max-height: 74vh;
  padding-right: var(--sp-1);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1_5);
}
@media (max-width: 820px) {
  .sched-app .sched-map-modal .day-map-body { grid-template-columns: 1fr; }
  .sched-app .sched-map-modal #dayMap { height: 52vh; min-height: 300px; }
  .sched-app .sched-map-modal #dayMapList { max-height: none; }
}
.sched-search-results {
  position: absolute;
  top: calc(100% + var(--sp-2));
  left: 0; right: 0;
  max-height: 60vh;
  overflow-y: auto;
  padding: var(--sp-1_5);
  border-radius: 14px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  z-index: 70;
}
.sched-search-item {
  display: flex; align-items: center; gap: var(--sp-2_5);
  width: 100%;
  padding: 9px 10px;
  border: none; background: transparent;
  border-radius: 9px; cursor: pointer;
  text-align: left;
  transition: background .12s;
}
.sched-search-item:hover { background: rgba(255,255,255,0.07); }
.sched-search-item .ss-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.sched-search-item .ss-body { display: flex; flex-direction: column; gap: var(--sp-0_5); min-width: 0; }
.sched-search-item .ss-cust { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.sched-search-item .ss-meta { font-size: 11.5px; color: var(--text-muted); }
.sched-search-empty { padding: var(--sp-3_5); text-align: center; font-size: 12.5px; color: var(--text-muted); }

/* ── AI daily briefing card ── */
.sched-brief-cta {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-1_5);
  width: 100%; padding: var(--sp-2_5);
  border: 1px solid var(--accent-edge);
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 10px; cursor: pointer;
  font-family: inherit; font-size: 13px; font-weight: 600;
  transition: background .15s;
}
.sched-brief-cta:hover { background: rgba(51,177,255,0.18); }
.sched-brief-cta i { font-size: 15px; }
.sched-brief-body {
  font-size: 12.5px; line-height: 1.55; color: var(--text-secondary);
  padding: var(--sp-0_5) var(--sp-1);
}
.sched-brief-refresh {
  margin-left: auto; width: 24px; height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--text-muted);
  cursor: pointer; border-radius: 7px; font-size: 14px;
}
.sched-brief-refresh:hover { background: rgba(255,255,255,0.08); color: var(--accent); }
.sched-cmd-item.ai i { color: var(--accent); }
.sched-cmd-item.ai .sched-cmd-hint { color: var(--accent); border: 1px solid var(--accent-edge); border-radius: 999px; padding: var(--sp-0_5) var(--sp-1_5); font-size: 10px; font-weight: 700; }

/* ── Command palette (⌘K) ── */
.sched-cmd-overlay {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: flex-start; justify-content: center;
  padding-top: 12vh;
  background: rgba(0,0,0,.45);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.sched-cmd {
  width: 560px; max-width: 92vw;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  border-radius: 16px; box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  overflow: hidden;
}
.sched-cmd-inp { display: flex; align-items: center; gap: var(--sp-2_5); padding: var(--sp-3_5) var(--sp-4); border-bottom: 1px solid var(--border); }
.sched-cmd-inp i { color: var(--text-muted); font-size: 18px; }
.sched-cmd-inp input { flex: 1; background: transparent; border: none; outline: none; color: var(--text-primary); font-family: inherit; font-size: 15px; }
.sched-cmd-list { max-height: 52vh; overflow-y: auto; padding: var(--sp-1_5); }
.sched-cmd-item { display: flex; align-items: center; gap: var(--sp-2_5); padding: var(--sp-2_5) var(--sp-3); border-radius: 9px; cursor: pointer; font-size: 14px; color: var(--text-secondary); }
.sched-cmd-item i { font-size: 17px; color: var(--text-muted); width: 20px; text-align: center; }
.sched-cmd-item.sel { background: var(--accent-soft); color: var(--accent); }
.sched-cmd-item.sel i { color: var(--accent); }
.sched-cmd-label { flex: 1; }
.sched-cmd-hint { font-size: 12px; color: var(--text-muted); }
.sched-cmd-empty { padding: var(--sp-5); text-align: center; color: var(--text-muted); font-size: 13px; }

/* ── Job-chip context menu ── */
.sched-ctx {
  position: fixed; z-index: 210; min-width: 176px; padding: var(--sp-1_5);
  border-radius: 12px; background: var(--glass-bg); border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow); -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
}
.sched-ctx-item {
  display: flex; align-items: center; gap: var(--sp-2_5); width: 100%;
  padding: var(--sp-2) var(--sp-2_5); border: none; background: transparent;
  color: var(--text-secondary); font-family: inherit; font-size: 13px; text-align: left;
  border-radius: 8px; cursor: pointer;
}
.sched-ctx-item i { font-size: 16px; }
.sched-ctx-item:hover { background: rgba(255,255,255,0.07); color: var(--text-primary); }
.sched-ctx-item.danger { color: #f87171; }
.sched-ctx-item.danger:hover { background: rgba(239,68,68,0.14); }

/* ── Drag-to-create selection on the time grid ── */
.sched-create-sel {
  position: absolute; left: var(--sp-0_5); right: var(--sp-0_5);
  background: var(--accent-soft); border: 1px dashed var(--accent);
  border-radius: 6px; pointer-events: none; z-index: 5;
}

/* ── Accessibility: visible keyboard focus ── */
.sched-app :focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 5px;
}
/* form controls already show an accent box-shadow ring on focus — no double ring */
.sched-app input:focus-visible,
.sched-app select:focus-visible,
.sched-app textarea:focus-visible { outline: none; }

/* ── Loading skeleton ── */
.sched-skel { padding: var(--sp-1); }
.sched-skel-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-2); margin-top: var(--sp-3_5); }
@media (max-width: 860px) { .sched-skel-grid { grid-template-columns: repeat(4, 1fr); } }

/* ── Responsive ── */
@media (max-width: 1200px) {
  .sched-app .sched-layout { grid-template-columns: 200px minmax(0,1fr); }
  .sched-railcol-right { display: none; }
}
@media (max-width: 860px) {
  .sched-app .sched-layout { grid-template-columns: 1fr; }
  .sched-railcol { position: static; }
  .sched-railcol-left { display: none; }
  .sched-page-body { padding: var(--sp-1) var(--sp-3) var(--sp-8); }
  .sched-brand-name { display: none; }
  /* Tabs collapse to icons only to fit the narrow topbar. */
  .sched-tab span { display: none; }
  .sched-tab { padding: var(--sp-1_5); }
  .cust-drawer { width: 100%; max-width: 100%; }
  /* The full search input doesn't fit — swap it for an icon button that opens
     the command palette (job search lives there too). */
  .sched-topbar-search { display: none; }
  .sched-search-mob { display: inline-flex; }
}
@media (max-width: 620px) {
  /* Settings tabs collapse to a horizontal scroll strip above the panels. */
  .sset-tabwrap { flex-direction: column; }
  .sset-tabs {
    width: auto;
    flex-direction: row;
    border-right: none;
    border-bottom: 1px solid var(--border);
    overflow-x: auto;
    padding: var(--sp-2);
  }
  .sset-tab { flex-shrink: 0; }
  .sset-tab span { display: none; }
  .sset-tab i { font-size: 18px; }
  .sset-tab.active span { display: inline; }
  .sset-grid { grid-template-columns: 1fr; }

  /* ── Mobile: modals become bottom sheets, bigger touch targets ── */
  .sched-app .modal-overlay { align-items: flex-end; padding: 0; }
  .sched-app .modal-box,
  .sched-app .sched-modal {
    width: 100% !important;
    max-width: 100% !important;
    max-height: 92vh;
    border-radius: 18px 18px 0 0;
    animation: schedSheetUp .22s ease;
  }
  .sched-app .btn { min-height: 40px; }
  .sched-app .sched-viewbtn { padding: var(--sp-2_5) var(--sp-3_5); }
  .sched-app .sched-modal-x { width: 36px; height: 36px; }
  /* 16px prevents iOS Safari from zooming the sheet on input focus. */
  .sched-app .sched-modal-body input,
  .sched-app .sched-modal-body select,
  .sched-app .sched-modal-body textarea,
  .sched-app .sset-tabbody input,
  .sched-app .sset-tabbody select,
  .sched-app .sset-tabbody textarea,
  .sched-app .sched-modal .filter-select { font-size: 16px; }
  /* Keep the sheet's Save/Cancel row clear of the iOS home indicator. */
  .sched-app .sched-modal .sched-modal-footer {
    padding-bottom: calc(13px + env(safe-area-inset-bottom));
  }
}
@keyframes schedSheetUp { from { transform: translateY(100%); opacity: .6; } }
@media (prefers-reduced-motion: reduce) {
  .sched-app .sched-modal, .sched-app .modal-box { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════
   Lifecycle extras — attention sections, confirmation flags,
   day-map travel legs, AI slot suggestions
   ═══════════════════════════════════════════════════════════════ */

/* Attention strip now stacks sections (reschedule asks / overdue / tight
   transfers) — space the follow-on headings off the previous list. */
.sched-att-list + .sched-att-head { margin-top: var(--sp-3); }
.sched-att-chip.resched { border-color: rgba(245,158,11,0.35); }
.sched-att-chip.resched:hover { background: rgba(245,158,11,0.14); border-color: rgba(245,158,11,0.55); }
.sched-att-chip.resched i, .sched-att-chip.tight i { font-size: 13px; }
.sched-att-chip.tight { border-color: rgba(51,177,255,0.35); }
.sched-att-chip.tight:hover { background: rgba(51,177,255,0.14); border-color: rgba(51,177,255,0.55); }

/* Customer confirmation state inside the job modal */
.sched-confirm-flag {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: 12px; font-weight: 600;
  padding: var(--sp-1_5) var(--sp-2_5);
  border-radius: 8px;
}
.sched-confirm-flag.ok { color: var(--st-complete); background: color-mix(in srgb, var(--st-complete) 10%, transparent); border: 1px solid color-mix(in srgb, var(--st-complete) 30%, transparent); }
.sched-confirm-flag.warn { color: var(--st-in_progress); background: color-mix(in srgb, var(--st-in_progress) 10%, transparent); border: 1px solid color-mix(in srgb, var(--st-in_progress) 30%, transparent); }
/* "A review has been asked for" — a done fact, not a good/bad one, so it takes
   the accent rather than the green reserved for customer confirmation. */
.sched-confirm-flag.info { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent); }

/* Day-map travel legs between stops */
.day-map-total {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: 12px; font-weight: 600; color: var(--text-secondary);
  padding: var(--sp-1_5) var(--sp-2);
}
.day-map-leg {
  display: flex; align-items: center; gap: var(--sp-1_5);
  font-size: 11px; color: var(--text-muted);
  padding: var(--sp-0_5) var(--sp-2) var(--sp-0_5) var(--sp-6);
}
.day-map-leg.tight { color: #fbbf24; }
/* Google-Maps "Directions" links: per-route (in the total/header) + per-stop. */
.day-map-stop { position: relative; }
.day-map-stop > div:not(.day-map-num) { flex: 1 1 auto; min-width: 0; }
.day-map-open {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  margin-left: auto; flex: 0 0 auto;
  font-size: 11px; font-weight: 600; color: var(--accent);
  text-decoration: none; white-space: nowrap;
  padding: var(--sp-0_5) var(--sp-1_5); border-radius: 6px;
}
.day-map-open:hover { background: var(--accent-soft); text-decoration: underline; }
.day-map-stop .day-map-open { opacity: 0; transition: opacity .12s; }
.day-map-stop:hover .day-map-open, .day-map-stop:focus-within .day-map-open { opacity: 1; }
.day-map-total .day-map-open { opacity: 1; }
/* Geocode-miss triage: clickable "fix the address" rows. */
.day-map-unlocated { margin-top: var(--sp-2); border-top: 1px solid var(--border); padding-top: var(--sp-1_5); }
.day-map-unlocated-h {
  display: flex; align-items: center; gap: var(--sp-1_5);
  font-size: 11px; font-weight: 600; color: #fbbf24;
  padding: var(--sp-1) var(--sp-2);
}
.day-map-num-warn { background: rgba(251,191,36,0.18) !important; color: #fbbf24; }
/* Start/finish of the day (technicians.home_address). A row that reads like a
   stop but isn't one — no number, no hover affordance, nothing to open. The
   dimming is what says "context, not a job" without a second explanation. */
.day-map-home { cursor: default; opacity: .82; }
.day-map-home:hover { background: transparent; }
/* Squared off so a house never reads as one of the round numbered stops. */
.day-map-pin-home span { border-radius: var(--radius-sm); }
html[data-theme="light"] .day-map-unlocated-h,
html[data-theme="light"] .day-map-num-warn { color: #92400e; }
/* Tight-transfer count badge in the route total + its red map connector. */
.day-map-tight-badge {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: 10px; font-weight: 700; color: #ef4444;
  background: rgba(239,68,68,0.14); border-radius: 999px;
  padding: 1px var(--sp-1_5); margin-left: var(--sp-1);
}
.day-map-tight-leg { pointer-events: stroke; }
/* Day/Week range toggle (segmented). */
.sched-daymap-span {
  display: inline-flex; flex: 0 0 auto;
  border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
}
.sched-daymap-span button {
  font: inherit; font-size: 12px; font-weight: 600;
  padding: var(--sp-1) var(--sp-3);
  background: transparent; border: 0; color: var(--text-muted); cursor: pointer;
}
.sched-daymap-span button + button { border-left: 1px solid var(--border); }
.sched-daymap-span button.is-on { background: var(--accent-soft); color: var(--accent); }
/* Week-map weekday markers + list day dots. */
.day-map-weekpin span {
  display: block; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid #fff; box-shadow: 0 1px 3px rgba(0,0,0,.4);
}
.day-map-daydot {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  margin-right: var(--sp-1_5); flex: 0 0 auto;
}
/* Live en-route ETA pill (permanent Leaflet tooltip on the tech dot). */
.leaflet-tooltip.day-map-eta-tip {
  background: rgba(17,24,39,0.96); color: rgba(255,255,255,0.96);
  border: 1px solid rgba(255,255,255,0.18); border-radius: 999px;
  padding: var(--sp-px) var(--sp-1_5); font-size: 11px; font-weight: 700;
  box-shadow: 0 var(--sp-0_5) var(--sp-1_5) rgba(0,0,0,.45);
}
.leaflet-tooltip.day-map-eta-tip::before { display: none; }   /* drop the caret */

/* AI slot suggestions in the job modal */
.sched-slot-btn {
  display: inline-flex; align-items: center; gap: var(--sp-1_5);
  padding: var(--sp-1_5) var(--sp-3);
  border: 1px dashed rgba(51,177,255,0.45);
  background: rgba(51,177,255,0.06);
  color: #93c5fd;
  border-radius: 8px;
  font-family: inherit; font-size: 12px; font-weight: 600;
  cursor: pointer;
  transition: background .14s, border-color .14s;
}
.sched-slot-btn:hover { background: rgba(51,177,255,0.14); border-color: rgba(51,177,255,0.7); }
.sched-slot-list { display: flex; flex-direction: column; gap: var(--sp-1_5); margin-top: var(--sp-2); }
.sched-slot-busy { font-size: 12px; color: var(--text-muted); display: flex; align-items: center; gap: var(--sp-1_5); }
.sched-slot-opt {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-1_5) var(--sp-2);
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.03);
  color: var(--text-primary);
  border-radius: 10px;
  font-family: inherit; font-size: 12px;
  transition: background .14s, border-color .14s;
}
.sched-slot-opt:hover { border-color: rgba(51,177,255,0.5); }
/* Left region: fills the form for review. Transparent button, wraps its rows. */
.sched-slot-fill {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-1_5);
  padding: var(--sp-1) var(--sp-1_5);
  background: transparent; border: 0; border-radius: 8px;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
  transition: background .14s;
}
.sched-slot-fill:hover { background: rgba(51,177,255,0.1); }
/* Right action: fill + save in one tap. */
.sched-slot-book {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1_5) var(--sp-2_5);
  background: var(--accent); color: var(--accent-fg, #04121d);
  border: 0; border-radius: 8px;
  font: inherit; font-size: 11.5px; font-weight: 700; cursor: pointer;
  transition: background .14s, transform .12s;
}
.sched-slot-book:hover { background: var(--accent-hover); }
.sched-slot-book:active { transform: translateY(1px); }
.sched-slot-when { font-weight: 700; }
.sched-slot-tech {
  font-size: 11px; font-weight: 600; color: #93c5fd;
  background: rgba(51,177,255,0.12);
  padding: var(--sp-0_5) var(--sp-2);
  border-radius: 999px;
}
.sched-slot-why { font-size: 11px; color: var(--text-muted); flex-basis: 100%; }

/* ═══════════════════════════════════════════════════════════════
   Look & feel pass — hover previews, micro-motion, light theme
   ═══════════════════════════════════════════════════════════════ */

/* ── Hover preview card (power.js builds + positions it) ── */
.sched-preview {
  position: fixed;
  z-index: 90;
  width: 264px;
  padding: var(--sp-3) var(--sp-3_5);
  border-radius: 12px;
  background: var(--glass-bg-2);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  pointer-events: none;
  font-size: 12px;
  color: var(--text-primary);
}
.sched-pv-head { display: flex; align-items: baseline; gap: var(--sp-2); margin-bottom: var(--sp-1_5); }
.sched-pv-cust { font-weight: 700; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-pv-status { margin-left: auto; font-size: 11px; font-weight: 700; flex-shrink: 0; }
.sched-pv-row {
  display: flex; align-items: center; gap: var(--sp-2);
  color: var(--text-secondary);
  padding: var(--sp-0_5) 0;
  font-variant-numeric: tabular-nums;
}
.sched-pv-row i { color: var(--accent); font-size: 13px; width: 14px; text-align: center; flex-shrink: 0; }
.sched-pv-notes {
  margin-top: var(--sp-1_5);
  padding-top: var(--sp-1_5);
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 11px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ── Micro-motion (skipped entirely under reduced-motion) ── */
@keyframes schedPulse { 0% { box-shadow: 0 0 0 0 rgba(51,177,255,.55); } 70% { box-shadow: 0 0 0 7px rgba(51,177,255,0); } 100% { box-shadow: 0 0 0 0 rgba(51,177,255,0); } }
@keyframes schedRise  { from { transform: translateY(8px); opacity: 0; } }
@keyframes schedFade  { from { opacity: .55; } }
@keyframes schedModalPop { from { transform: scale(.97) translateY(6px); opacity: .6; } }
/* In-flight spinner (Save button). */
@keyframes schedSpin { to { transform: rotate(360deg); } }
.sched-spin { display: inline-block; animation: schedSpin .7s linear infinite; }

/* Chip context menu extras (power.js) — assign section + current-tick. */
.sched-ctx { max-height: min(70vh, 420px); overflow-y: auto; }
.sched-ctx-label {
  padding: var(--sp-1_5) var(--sp-2_5) var(--sp-1); font-size: 11px; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-muted); pointer-events: none;
}
.sched-ctx-item .sched-ctx-check { margin-left: auto; font-size: 15px; color: var(--accent); }
@media (prefers-reduced-motion: no-preference) {
  .sched-app .sched-nowline::before { animation: schedPulse 2.4s ease-out infinite; }
  /* Rail widgets rise in once on page load (containers persist across re-renders) */
  .sched-railcol > div { animation: schedRise .35s cubic-bezier(.22, 1, .36, 1) backwards; }
  .sched-railcol > div:nth-child(2) { animation-delay: .05s; }
  .sched-railcol > div:nth-child(3) { animation-delay: .1s; }
  .sched-railcol > div:nth-child(4) { animation-delay: .15s; }
  .sched-railcol > div:nth-child(5) { animation-delay: .2s; }
  /* Gentle crossfade when the board re-renders */
  #schedulerCalendar > * { animation: schedFade .16s ease; }
}
/* Desktop modal pop (mobile keeps its bottom-sheet slide from the ≤620px block) */
@media (prefers-reduced-motion: no-preference) and (min-width: 621px) {
  .sched-app .modal-overlay .modal-box { animation: schedModalPop .18s cubic-bezier(.34, 1.4, .64, 1); }
}

/* ── Light theme (device-level: localStorage sched_theme → html[data-theme="light"],
      applied pre-paint). Re-derives the palette tokens; component rules that
      mix against var(--card)/var(--border) adapt automatically. ── */
html[data-theme="light"] body.sched-app {
  /* Surface/text/accent/border/hot auto-flip via the shared --app-* light
     values in tokens.css (the dark block above references them). Only the
     dispatch-local hover, tint rgbas and glass surfaces need light overrides. */
  --accent-hover:  #0f76bf;
  --accent-soft:   rgba(20,147,230,0.10);
  --accent-edge:   rgba(20,147,230,0.35);
  --accent-glow:   rgba(20,147,230,0.22);
  --hot-soft:      rgba(226,59,59,0.10);
  /* Flat Airflow-light surfaces — near-solid panels, soft ink-tinted shadow. */
  --glass-bg:     rgba(255,255,255,0.94);
  --glass-bg-2:   rgba(255,255,255,0.97);
  --glass-border: rgba(15,23,42,0.08);
  --glass-shadow: 0 1px 2px rgba(28,26,22,.05), 0 12px 28px -16px rgba(28,26,22,.18);
  /* Calm single vignette — no CAD dot-grid (matches the dark backdrop). */
  background-image:
    radial-gradient(120% 80% at 50% -10%, rgba(20,147,230,0.05), transparent 62%);
}
/* Dark-tuned literals that need a light counterpart */
html[data-theme="light"] .sched-app .sched-viewswitch { background: rgba(15,23,42,0.05); }
/* Toggle switches: the dark track is a 10%-white wash on a dark card, which goes
   invisible on the light theme's white one. Flip to an ink wash + a white knob
   so an "off" switch still reads as a switch. Scoped to :not(:checked) so it
   can't outrank the accent-filled "on" track. */
html[data-theme="light"] .sched-app .sset-toggle input:not(:checked) + .sset-switch {
  background: rgba(15,23,42,0.09);
}
html[data-theme="light"] .sched-app .sset-switch::after {
  background: #fff;
  box-shadow: 0 1px 2px rgba(15,23,42,.3);
}
html[data-theme="light"] .sched-app .sched-chip,
html[data-theme="light"] .sched-app .sched-event,
html[data-theme="light"] .sched-app .sched-swim-event,
html[data-theme="light"] .sched-app .sched-swim-chip { box-shadow: 0 1px 2px rgba(15,23,42,.12); }
html[data-theme="light"] .sched-app .sched-chip:hover,
html[data-theme="light"] .sched-app .sched-event:hover,
html[data-theme="light"] .sched-app .sched-swim-event:hover,
html[data-theme="light"] .sched-app .sched-swim-chip:hover { box-shadow: 0 3px 8px rgba(15,23,42,.16); }
html[data-theme="light"] .sched-app .sched-tg-col.is-offday,
html[data-theme="light"] .sched-app .sched-month-cell.is-offday {
  background:
    repeating-linear-gradient(-45deg, rgba(15,23,42,0.045) 0 5px, transparent 5px 11px),
    rgba(15,23,42,0.02);
}
html[data-theme="light"] .sched-app .sched-tg-col.is-today { background: rgba(20,147,230,0.045); }
html[data-theme="light"] .sched-att-head { color: #dc2626; }
html[data-theme="light"] .sched-att-chip { background: rgba(15,23,42,0.02); }
html[data-theme="light"] .sched-confirm-flag.ok { color: #15803d; }
html[data-theme="light"] .sched-confirm-flag.warn { color: #92400e; }
html[data-theme="light"] .sched-confirm-flag.info { color: #0f76bf; }
html[data-theme="light"] .day-map-leg.tight { color: #92400e; }
html[data-theme="light"] .sched-slot-btn { color: #0f76bf; background: rgba(20,147,230,0.05); }
html[data-theme="light"] .sched-slot-btn:hover { background: rgba(20,147,230,0.1); }
html[data-theme="light"] .sched-slot-tech { color: #0f76bf; }
html[data-theme="light"] .sched-slot-opt { background: rgba(15,23,42,0.02); }
html[data-theme="light"] .sched-nowline-lbl { color: #fff; background: var(--accent); }
html[data-theme="light"] .sched-app .sched-nowline,
html[data-theme="light"] .sched-app .sched-nowline::before { background: var(--accent); }
html[data-theme="light"] .sched-unsched-card:hover { background: rgba(15,23,42,0.04); }

.sched-warr-ico { color:#f59e0b; }

/* ── Equipment on site (job modal) ── */
.equip-list { display:flex; flex-direction:column; gap:var(--sp-2); margin-bottom:var(--sp-2_5); }
.equip-empty { font-size:12px; color:var(--text-muted); }
.equip-row { display:flex; align-items:flex-start; gap:var(--sp-2); padding:var(--sp-2) var(--sp-2_5); border:1px solid var(--border); border-radius:10px; background:var(--bg-card-hover); }
.equip-row-main { flex:1; min-width:0; display:flex; flex-direction:column; gap:var(--sp-0_5); }
.equip-row-actions { display:flex; gap:var(--sp-0_5); flex-shrink:0; }
.equip-title { font-size:13px; font-weight:600; color:var(--text); }
.equip-meta { font-size:12px; color:var(--text-muted); }
.equip-warr { display:inline-block; align-self:flex-start; margin-top:var(--sp-0_5); font-size:11px; font-weight:600; padding:var(--sp-0_5) var(--sp-2); border-radius:999px; }
.equip-warr.in { background:color-mix(in srgb, var(--st-complete) 14%, transparent); color:var(--st-complete); }
.equip-warr.expired { background:color-mix(in srgb, var(--st-no_show) 14%, transparent); color:var(--st-no_show); }
.equip-warr.unknown { background:color-mix(in srgb, var(--text-muted) 10%, transparent); color:var(--text-muted); }
.equip-thumbs { display:flex; flex-wrap:wrap; gap:var(--sp-1); margin-top:var(--sp-1); }
.equip-thumb { width:52px; height:52px; object-fit:cover; border-radius:8px; border:1px solid var(--border); display:block; cursor:zoom-in; }
/* Read-only equipment detail view (shown before Edit). */
.eqv-hero { display:flex; align-items:center; gap:var(--sp-3); margin-bottom:var(--sp-3); }
.eqv-hero-ico {
  flex-shrink:0; width:48px; height:48px; border-radius:12px; display:grid; place-items:center;
  background:var(--accent-soft, rgba(59,130,246,0.14)); color:var(--accent); font-size:24px;
}
.eqv-hero-main { flex:1; min-width:0; }
.eqv-hero-title { font-size:17px; font-weight:700; color:var(--text-primary); line-height:1.2; }
.eqv-hero-sub { font-size:12px; color:var(--text-muted); margin-top:2px; }
.eqv-specs {
  display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:1px;
  background:var(--border); border:1px solid var(--border); border-radius:12px; overflow:hidden; margin-bottom:var(--sp-3);
}
.eqv-spec { display:flex; flex-direction:column; gap:2px; padding:var(--sp-2) var(--sp-2_5); background:var(--surface, rgba(255,255,255,0.02)); }
.eqv-k { font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.03em; color:var(--text-muted); }
.eqv-v { font-size:14px; color:var(--text-primary); font-variant-numeric:tabular-nums; word-break:break-word; }
.eqv-block { margin-bottom:var(--sp-3); }
.eqv-block-h { display:flex; align-items:center; gap:var(--sp-1); font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.03em; color:var(--text-muted); margin-bottom:var(--sp-1_5); }
.eqv-notes { font-size:13px; color:var(--text-secondary); line-height:1.5; white-space:pre-wrap; }
.equip-addrow { display:flex; gap:var(--sp-2); flex-wrap:wrap; }
.equip-form { margin-top:var(--sp-3); padding:var(--sp-3); border:1px solid var(--border); border-radius:12px; background:var(--bg-card-hover); }
.equip-form-actions { display:flex; justify-content:flex-end; gap:var(--sp-2); margin-top:var(--sp-2_5); }
/* --bg-card-hover is theme-aware (#23272f dark / #eef2f7 light), so equipment
   rows/forms now read as raised cards above the modal surface in both themes —
   no separate light override needed (was rgba(15,23,42,.02), near-invisible). */

/* ═══════════════════════════════════════════════════════════════
   Records sections — Customers / Equipment / Reports list views
   + the customer profile drawer. Left-rail nav switches between
   these and the dispatch board.
   ═══════════════════════════════════════════════════════════════ */

.rec-section { padding-top: var(--sp-1); }
.rec-toolbar {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-4);
}
.rec-toolbar-controls { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.rec-search {
  position: relative; display: inline-flex; align-items: center;
  min-width: 240px;
}
.rec-search > i {
  position: absolute; left: 11px; color: var(--text-muted); font-size: 15px; pointer-events: none;
}
.rec-search input {
  width: 100%; padding: var(--sp-2) var(--sp-3) var(--sp-2) 32px;
  border: 1px solid var(--border); border-radius: 10px;
  background: rgba(255,255,255,0.03); color: var(--text-primary);
  font-size: 13px;
}
.rec-search input::placeholder { color: var(--text-muted); }
.rec-search input:focus { outline: none; border-color: var(--accent); }

.rec-list { display: flex; flex-direction: column; gap: var(--sp-2); }
.rec-count { font-size: 12px; color: var(--text-muted); margin-bottom: var(--sp-2); }

/* Generic record card (customer / equipment / report row) */
.rec-card {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-3_5);
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--glass-bg, rgba(255,255,255,0.02));
  cursor: pointer; text-align: left; width: 100%;
  transition: border-color .12s, background .12s, transform .06s;
}
.rec-card:hover { border-color: var(--accent-border, rgba(59,130,246,0.4)); background: rgba(255,255,255,0.04); }
.rec-card:active { transform: translateY(1px); }
/* Item a finder pointed at (opened from the Equipment / Reports tab). */
.rec-card--hl { border-color: var(--accent); animation: recPulse 1.3s ease 1; }
@keyframes recPulse {
  0% { box-shadow: 0 0 0 0 rgba(59,130,246,0.0); }
  30% { box-shadow: 0 0 0 3px rgba(59,130,246,0.32); }
  100% { box-shadow: 0 0 0 0 rgba(59,130,246,0.0); }
}
@media (prefers-reduced-motion: reduce) { .rec-card--hl { animation: none; } }
.rec-avatar {
  flex-shrink: 0; width: 38px; height: 38px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--accent-soft, rgba(59,130,246,0.14)); color: var(--accent);
  font-size: 15px; font-weight: 700;
}
.rec-avatar i { font-size: 18px; }
.rec-main { flex: 1; min-width: 0; }
.rec-title { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.rec-sub { font-size: 12px; color: var(--text-muted); margin-top: var(--sp-0_5); display: flex; gap: var(--sp-2_5); flex-wrap: wrap; }
.rec-sub span { display: inline-flex; align-items: center; gap: var(--sp-1); }
.rec-side { display: flex; align-items: center; gap: var(--sp-2); flex-shrink: 0; }
.rec-chip {
  font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 20px;
  border: 1px solid var(--border); color: var(--text-secondary); white-space: nowrap;
}
/* Status/warranty chips share the one semantic --st-* family (see the token
   block) so every status reads the same colour everywhere. --_t is the chip's
   tone; the shared rule below tints border + background from it. */
.rec-chip.warr-in,
.rec-chip.st-signed     { --_t: var(--st-complete); }
.rec-chip.warr-expired  { --_t: var(--st-no_show); }
.rec-chip.st-completed  { --_t: var(--accent); }
.rec-chip.st-sent       { --_t: var(--st-invoiced); }
.rec-chip.st-attention  { --_t: var(--st-in_progress); }
.rec-chip.st-draft,
.rec-chip.warr-unknown  { --_t: var(--st-cancelled); }
.rec-chip.warr-in, .rec-chip.warr-expired,
.rec-chip.st-completed, .rec-chip.st-signed,
.rec-chip.st-sent, .rec-chip.st-attention, .rec-chip.st-draft {
  color: var(--_t);
  border-color: color-mix(in srgb, var(--_t) 35%, transparent);
  background: color-mix(in srgb, var(--_t) 9%, transparent);
}
.rec-chip.warr-unknown { color: var(--text-muted); }
.rec-empty { padding: var(--sp-12) var(--sp-4); text-align: center; color: var(--text-muted); }
.rec-empty i { font-size: 34px; display: block; margin-bottom: var(--sp-2_5); opacity: .5; }

/* ── Customer profile drawer ── */
.cust-drawer-backdrop {
  position: fixed; inset: 0; z-index: 58;   /* below the floating topbar (z 60) */
  background: rgba(2,6,23,0.5);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.cust-drawer {
  /* Sits behind the floating heading bar: starts below it and stacks under it
     (z 59 < topbar z 60), so the heading stays visible and undimmed. */
  position: fixed; top: calc(var(--topbar-h) + var(--float-gap) * 2); right: 0; bottom: 0; z-index: 59;
  width: 440px; max-width: 94vw;
  display: flex; flex-direction: column;
  background: var(--bg-elevated, var(--bg));
  border-left: 1px solid var(--border);
  box-shadow: -18px 0 48px rgba(0,0,0,0.35);
  animation: custDrawerIn .22s cubic-bezier(.22,1,.36,1);
}
@keyframes custDrawerIn { from { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .cust-drawer { animation: none; } }
.cust-drawer-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: 16px 16px 12px;
}
.cust-drawer-id { display: flex; align-items: center; gap: 12px; min-width: 0; }
.cust-drawer-avatar {
  width: 42px; height: 42px; border-radius: 12px; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--accent-soft, rgba(59,130,246,0.16)); color: var(--accent);
  font-size: 17px; font-weight: 700;
}
.cust-drawer-name { font-size: 16px; font-weight: 700; color: var(--text-primary); }
.cust-drawer-sub { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.cust-drawer-actions { display: flex; gap: var(--sp-2); padding: 0 16px 12px; flex-wrap: wrap; }
.cust-drawer-tabs {
  display: flex; gap: 2px; padding: 0 12px;
  border-bottom: 1px solid var(--border);
}
.cust-tab {
  padding: 9px 12px; border: none; background: transparent;
  color: var(--text-secondary); font-size: 13px; font-weight: 500;
  cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.cust-tab:hover { color: var(--text-primary); }
.cust-tab.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
.cust-tab-n {
  font-size: 10px; font-weight: 700; padding: 1px 5px; border-radius: 8px;
  background: rgba(255,255,255,0.07); color: var(--text-muted);
}
.cust-tab.active .cust-tab-n { background: var(--accent-soft, rgba(59,130,246,0.16)); color: var(--accent); }
.cust-drawer-body { flex: 1; overflow-y: auto; padding: 16px; }

/* Overview tab detail rows */
.cust-detail { display: flex; flex-direction: column; gap: 2px; margin-bottom: 14px; }
.cust-detail-label { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); font-weight: 600; }
.cust-detail-val { font-size: 14px; color: var(--text-primary); }
.cust-detail-val a { color: var(--accent); text-decoration: none; }
.cust-detail-val a:hover { text-decoration: underline; }
.cust-drawer-body .rec-card { margin-bottom: 8px; }
.cust-mini-empty { padding: 30px 12px; text-align: center; color: var(--text-muted); font-size: 13px; }

/* NDIS plan-status banner (top of a participant's Overview). Tone comes from
   the shared --st-* family — green active, amber expiring, red expired. */
.cust-plan-banner {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 10px 12px; border-radius: 10px; margin-bottom: var(--sp-4);
  font-size: 13px; font-weight: 600;
  color: var(--_t, var(--text-secondary));
  border: 1px solid color-mix(in srgb, var(--_t, var(--border)) 35%, transparent);
  background: color-mix(in srgb, var(--_t, var(--border)) 9%, transparent);
}
.cust-plan-banner i { font-size: 17px; flex-shrink: 0; }
.cust-plan-banner.ok   { --_t: var(--st-complete); }
.cust-plan-banner.warn { --_t: var(--st-in_progress); }
.cust-plan-banner.over { --_t: var(--st-no_show); }

/* White cards + drawer in light mode. The drawer especially needs an OPAQUE
   surface — it floats over its own dark backdrop, so a translucent fill would
   let the backdrop bleed through and dim all the drawer content. */
html[data-theme="light"] .rec-card,
html[data-theme="light"] .cust-drawer { background: var(--surface, #fff); }
html[data-theme="light"] .rec-card:hover { background: var(--bg-card-hover, #eef2f7); }

/* ── Quick-job modal (Phase 1 — flag feature_sched_quickjob) ──────────────────
   All rules scoped under #jobModal.qj-on, so the flag-off modal is untouched.
   The quick-job UI is purely presentational: see js/scheduler/quickjob.js. */

/* 1.1 — Collapsible detail sections (On-site, Equipment) */
#jobModal.qj-on .qj-acc-head { cursor: pointer; user-select: none; }
#jobModal.qj-on .qj-acc-head:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
#jobModal.qj-on .qj-acc-cue {
  margin-left: auto; display: inline-flex; align-items: center; gap: var(--sp-2);
  text-transform: none; letter-spacing: 0;
}
#jobModal.qj-on .qj-acc-summary {
  display: none; font-size: 11px; font-weight: 500; color: var(--text-muted);
}
#jobModal.qj-on .qj-collapsed .qj-acc-summary { display: inline; }
#jobModal.qj-on .qj-acc-caret {
  color: var(--text-muted); font-size: 15px; transition: transform .18s var(--out, ease);
}
#jobModal.qj-on .qj-collapsed .qj-acc-caret { transform: rotate(-90deg); }
#jobModal.qj-on .qj-collapsed .sset-grid { display: none; }
#jobModal.qj-on .qj-collapsed .sset-sec-head { margin-bottom: 0; border-bottom-color: transparent; }

/* 1.2 — Customer search-or-create combobox */
#jobModal.qj-on #jobCustLinkGroup,
#jobModal.qj-on #jobCustNameGroup { display: none; }
.qj-combo-field { position: relative; }
.qj-combo-ico {
  position: absolute; left: var(--sp-3); top: 50%; transform: translateY(-50%);
  color: var(--text-muted); font-size: 15px; pointer-events: none;
}
.sched-app .sched-modal-body .qj-combo-field input[type="text"] { padding-left: 34px; padding-right: 34px; }
.qj-combo-clear {
  position: absolute; right: var(--sp-2); top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border: 0; border-radius: 6px; cursor: pointer;
  background: transparent; color: var(--text-muted);
}
.qj-combo-clear:hover { background: var(--accent-soft); color: var(--accent); }
.qj-combo-menu {
  position: absolute; top: calc(100% + var(--sp-1)); left: 0; right: 0; z-index: 40;
  max-height: 240px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,0.32); padding: var(--sp-1);
}
.qj-combo-opt {
  width: 100%; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2_5); border: 0; border-radius: 7px; cursor: pointer;
  background: transparent; color: var(--text-primary); font: inherit; text-align: left;
}
.qj-combo-opt:hover, .qj-combo-opt:focus-visible { background: var(--accent-soft); outline: none; }
.qj-combo-opt i { color: var(--text-muted); font-size: 15px; flex: none; }
.qj-combo-opt-main { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.qj-combo-opt-main { font-size: 13px; }
.qj-combo-opt-sub { font-size: 11px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.qj-combo-create { color: var(--accent); }
.qj-combo-create i { color: var(--accent); }
.qj-combo-empty { padding: var(--sp-2_5); font-size: 12px; color: var(--text-muted); }
.qj-combo-linked {
  display: flex; align-items: center; gap: var(--sp-1_5); margin-top: 7px;
  font-size: 12px; color: var(--st-complete);
  padding: var(--sp-1_5) var(--sp-2); border-radius: 7px;
  background: color-mix(in srgb, var(--st-complete) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--st-complete) 26%, transparent);
}
.qj-combo-linked strong { font-weight: 600; }
/* [hidden] must win over the display:flex above — otherwise the bar shows even
   when nothing is linked, and (sitting under the field) it hides the dropdown's
   "Create …" row. */
.qj-combo-linked[hidden] { display: none; }

/* 1.4 — Recurrence presets (raw controls hidden unless "Custom…") */
#jobModal.qj-on:not(.qj-recur-custom) #jobRecurGroup,
#jobModal.qj-on:not(.qj-recur-custom) #jobRecurOpts { display: none !important; }

/* ── Reports home (Phase 3 — flag feature_sched_reports_home) ─────────────────
   Segments the Reports section into Service reports + Analytics & timesheets.
   Injected by js/scheduler/reportshome.js; inert when the flag is off. */
.rh-seg { display: flex; gap: var(--sp-1); margin-bottom: var(--sp-3); }
.rh-seg-btn {
  display: inline-flex; align-items: center; gap: var(--sp-1_5);
  padding: var(--sp-2) var(--sp-3_5); border: 1px solid var(--border-strong); border-radius: 9px;
  background: var(--bg); color: var(--text-secondary); font: inherit; font-size: 13px;
  font-weight: 600; cursor: pointer; transition: color .15s, border-color .15s, background .15s;
}
.rh-seg-btn i { font-size: 15px; }
.rh-seg-btn:hover { color: var(--text-primary); }
.rh-seg-btn.active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }

.rh-analytics { display: none; }
#sec-reports.rh-analytics-on .rh-analytics { display: block; }
#sec-reports.rh-analytics-on #reportsList { display: none; }
#sec-reports.rh-analytics-on .rec-toolbar-controls { display: none; }

.rh-a-head { font-size: 15px; font-weight: 700; color: var(--text-primary); margin-bottom: var(--sp-3); }
.rh-a-sub { font-size: 12px; font-weight: 500; color: var(--text-muted); margin-left: var(--sp-2); }

/* 2.2 — clickable KPI cards */
.rh-kpi-link { cursor: pointer; transition: border-color .15s, transform .05s; }
.rh-kpi-link:hover { border-color: var(--accent); }
.rh-kpi-link:active { transform: translateY(1px); }
.rh-kpi-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rh-kpi-sublink { cursor: pointer; text-decoration: underline dotted; text-underline-offset: 2px; }
.rh-kpi-sublink:hover { color: var(--bad, #ef4444); }

/* Bulk-bar danger button (the edit-actions rule is scoped elsewhere) */
.sched-bulkbar .sched-btn-danger { color: var(--bad, #ef4444); }

/* Timesheet date pickers stay compact — the generic modal input width:100% rule
   was stretching them full-width and breaking the Timesheets header row (both in
   the Stats modal and the Reports-home analytics segment). */
.sched-app .sched-modal-body .sched-timesheet-controls input[type="date"],
.sched-app #sec-reports .sched-timesheet-controls input[type="date"] { width: auto; min-width: 148px; }
.sched-timesheet-head { row-gap: var(--sp-2); }

/* Analytics section headings (Stats modal + Reports-home) — the per-tech table
   and Timesheets read as peer sections with matching uppercase labels + divider
   rules, instead of one labelled and one floating. */
.sched-a-subhead,
.sched-app .sched-timesheet-head { border-top: 1px solid var(--border); padding-top: var(--sp-3); }
.sched-a-subhead {
  display: flex; align-items: center; gap: var(--sp-1_5);
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: var(--text-muted); margin: 0 0 var(--sp-2);
}
.sched-a-subhead i,
.sched-app .sched-timesheet-head h4 i { color: var(--accent); font-size: 14px; }
.sched-app .sched-timesheet-head h4 {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: var(--text-muted); display: flex; align-items: center; gap: var(--sp-1_5);
}

/* Analytics cards: no resting shadow and no hover lift/glow in the scheduler
   (dashboard.css applies those globally; scope the removal to .sched-app so the
   main dashboard keeps its treatment). */
.sched-app .stat-card,
.sched-app .chart-card,
.sched-app .table-card { box-shadow: none; }
.sched-app .stat-card { transition: none; }
.sched-app .stat-card:hover { transform: none; box-shadow: none; }
.sched-app .stat-card:hover .si-blue,
.sched-app .stat-card:hover .si-purple,
.sched-app .stat-card:hover .si-green,
.sched-app .stat-card:hover .si-amber,
.sched-app .stat-card:hover .si-red { box-shadow: none; }

/* ── Board flow (Phase 2 — flag feature_sched_boardflow) ──────────────────────
   §1.5 loud conflict banner + §1.7 per-job status button/popover. */
.sched-conflict-banner {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-2_5) var(--sp-3); border-radius: 9px; font-size: 13px; line-height: 1.35;
}
.sched-conflict-banner strong { font-weight: 700; }
.sched-conflict-banner .scb-msg { flex: 1 1 auto; min-width: 150px; }
.sched-conflict-banner.is-warn  { color: var(--st-in_progress); background: color-mix(in srgb, var(--st-in_progress) 12%, transparent); border: 1px solid color-mix(in srgb, var(--st-in_progress) 34%, transparent); }
.sched-conflict-banner.is-block { color: var(--bad, #ef4444);     background: color-mix(in srgb, var(--bad, #ef4444) 12%, transparent);     border: 1px solid color-mix(in srgb, var(--bad, #ef4444) 36%, transparent); }
.sched-conflict-banner.is-ack   { color: var(--text-secondary);   background: var(--bg); border: 1px solid var(--border-strong); }
.scb-actions { display: flex; gap: var(--sp-1_5); flex: 0 0 auto; flex-wrap: wrap; }
.scb-btn {
  display: inline-flex; align-items: center; gap: var(--sp-1); padding: var(--sp-1_5) var(--sp-2_5);
  border-radius: 7px; border: 1px solid currentColor; background: transparent;
  color: inherit; font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
}
.scb-btn:hover { background: color-mix(in srgb, currentColor 14%, transparent); }
.scb-btn.scb-ghost { border-color: var(--border-strong); color: var(--text-secondary); }
.scb-btn.scb-ghost:hover { color: var(--text-primary); background: color-mix(in srgb, var(--text-primary) 8%, transparent); }

/* §1.7 — status trigger on list cards + popover (reuses .sched-qa-pop look) */
.sched-list-card .sched-st-btn { margin-left: auto; }
.sched-st-btn {
  flex: 0 0 auto; width: 30px; height: 30px; display: inline-flex; align-items: center;
  justify-content: center; border: 1px solid var(--border-strong); border-radius: 8px;
  background: var(--bg); color: var(--text-secondary); cursor: pointer;
}
.sched-st-btn:hover { border-color: var(--accent); color: var(--accent); }
.sched-st-btn i { font-size: 16px; }
.sched-st-pop .sched-st-row i { flex: 0 0 auto; width: 18px; text-align: center; font-size: 15px; }

/* ── Board notes/reports: glyph on chips+events (flag feature_board_notes) ── */
.sched-app .sched-nr-glyph {
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; line-height: 1;
  color: color-mix(in srgb, var(--text-primary) 62%, transparent);
  transition: color .12s, transform .12s;
}
.sched-app .sched-nr-glyph:hover { color: var(--accent); transform: scale(1.12); }
.sched-app .sched-nr-glyph.is-report { color: color-mix(in srgb, var(--accent) 78%, var(--text-primary)); }
/* Report status at a glance (flags still win the colour below). */
.sched-app .sched-nr-glyph.is-signed { color: var(--st-complete); }
.sched-app .sched-nr-glyph.is-sent { color: var(--accent); }
.sched-app .sched-nr-glyph.has-flags { color: var(--warn, #f59e0b); }
/* Chips (month / all-day / list): glyph rides at the end of the label. */
.sched-app .sched-chip > .sched-nr-glyph { margin-left: var(--sp-1); vertical-align: middle; }
/* Timed events are position:absolute — pin the glyph bottom-right, clear of the
   status dot that already sits top-right (::after). */
.sched-app .sched-event > .sched-nr-glyph,
.sched-app .sched-swim-event > .sched-nr-glyph {
  position: absolute; bottom: var(--sp-0_5); right: var(--sp-1);
  background: color-mix(in srgb, var(--card) 72%, transparent);
  border-radius: 4px; padding: 0 var(--sp-0_5);
}
.sched-app .sched-swim-chip > .sched-nr-glyph,
.sched-app .sched-list-card > .sched-nr-glyph { margin-left: var(--sp-1); vertical-align: middle; }
.sched-app .sched-nr-flagdot {
  margin-left: var(--sp-0_5); font-size: 9px; font-weight: 800;
  color: var(--warn, #f59e0b);
}

/* Read popover — anchored, read-only, no modal. */
.sched-nr-pop {
  position: fixed; z-index: 1200; width: min(320px, 92vw);
  background: var(--card); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 12px 34px -8px rgba(0,0,0,.5);
  padding: var(--sp-3) var(--sp-3_5); font-size: 13px;
  animation: schedNrPop .12s ease-out;
}
@keyframes schedNrPop { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.sched-nr-pop-head {
  display: flex; align-items: center; gap: var(--sp-2);
  font-weight: 700; font-size: 13.5px; margin-bottom: var(--sp-2);
}
.sched-nr-live, .sched-nrf-live {
  font-size: 9.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ok, #16a34a);
  background: color-mix(in srgb, var(--ok, #16a34a) 14%, transparent);
  border-radius: 999px; padding: var(--sp-0_5) var(--sp-1_5);
}
.sched-nr-note {
  white-space: pre-wrap; line-height: 1.5;
  max-height: 220px; overflow: auto;
  color: color-mix(in srgb, var(--text-primary) 92%, transparent);
}
.sched-nr-empty { color: var(--text-muted); font-style: italic; }
.sched-nr-flags { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-top: var(--sp-2); }
.sched-nr-flag {
  display: inline-flex; align-items: center; gap: var(--sp-0_5);
  font-size: 11px; font-weight: 600;
  color: var(--warn, #f59e0b);
  background: color-mix(in srgb, var(--warn, #f59e0b) 12%, transparent);
  border-radius: 6px; padding: var(--sp-0_5) var(--sp-2);
}
.sched-nr-flag.more { color: var(--text-muted); background: var(--bg-soft, rgba(0,0,0,.05)); }
.sched-nr-pop-actions { margin-top: var(--sp-3); display: flex; }
.sched-nr-pop-actions .btn { flex: 1; justify-content: center; }

/* "Notes & reports" rail card. */
.sched-app .sched-nrf-card {
  cursor: pointer;
  border: 1px solid var(--border); border-radius: 8px;
  padding: var(--sp-2) var(--sp-2_5); margin-top: var(--sp-2);
  background: var(--card);
  transition: border-color .12s, transform .12s, box-shadow .12s;
}
.sched-app .sched-nrf-card:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px -4px rgba(0,0,0,.35);
}
.sched-nrf-top { display: flex; align-items: center; gap: var(--sp-1_5); }
.sched-nrf-cust { font-weight: 700; font-size: 13px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-nrf-flag {
  display: inline-flex; align-items: center; gap: var(--sp-0_5); flex: 0 0 auto;
  font-size: 10.5px; font-weight: 700; color: var(--warn, #f59e0b);
}
.sched-nrf-meta { font-size: 11px; color: var(--text-muted); margin-top: var(--sp-0_5); }
.sched-nrf-rep { font-weight: 700; color: color-mix(in srgb, var(--accent) 80%, var(--text-primary)); }
.sched-nrf-snip {
  font-size: 12px; line-height: 1.4; margin-top: var(--sp-1);
  color: color-mix(in srgb, var(--text-primary) 82%, transparent);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.sched-nrf-snip.is-muted { color: var(--text-muted); font-style: italic; }

/* ═══════════════════════════════════════════════════════════════
   Dispatch fields — travel, priority, crew, parts
   (db/add-dispatch-fields.sql · js/scheduler/jobfields.js)

   Board rules follow the dual-encoding rule already set above: the left edge
   stays STATUS and the body tint stays TECHNICIAN, so priority gets an OUTLINE
   and an ICON rather than another fill — nothing here is colour-only.
   ═══════════════════════════════════════════════════════════════ */

/* Drive-to-site block. Hatched and translucent so it reads as "this time is
   spent, but not on the job" — never mistakable for a second booking. */
.sched-app .sched-travel,
.sched-app .sched-swim-travel {
  position: absolute; box-sizing: border-box;
  border-radius: 5px 5px 0 0;
  background: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, var(--jc, var(--accent)) 22%, transparent) 0 4px,
    transparent 4px 9px
  );
  border: 1px dashed color-mix(in srgb, var(--jc, var(--accent)) 45%, transparent);
  border-bottom: 0;
  pointer-events: none;
  overflow: hidden;
}
.sched-app .sched-swim-travel { border-radius: 5px 0 0 5px; border-bottom: 1px dashed color-mix(in srgb, var(--jc, var(--accent)) 45%, transparent); border-right: 0; }
.sched-app .sched-travel span {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-0_5);
  height: 100%; font-size: 9px; font-weight: 600;
  color: color-mix(in srgb, var(--text-primary) 62%, transparent);
}

/* Priority. Emergency and high get an outline ring; low and normal get nothing
   at all, so the board only shouts when something actually is urgent. */
.sched-app .sched-chip[data-priority="emergency"],
.sched-app .sched-event[data-priority="emergency"],
.sched-app .sched-swim-event[data-priority="emergency"] {
  outline: 2px solid color-mix(in srgb, #ef4444 78%, transparent);
  outline-offset: -2px;
}
.sched-app .sched-chip[data-priority="high"],
.sched-app .sched-event[data-priority="high"],
.sched-app .sched-swim-event[data-priority="high"] {
  outline: 1.5px solid color-mix(in srgb, #f59e0b 62%, transparent);
  outline-offset: -2px;
}
.sched-prio-ico, .sched-parts-ico { font-size: 11px; vertical-align: -1px; }
.sched-crew-ico {
  display: inline-flex; align-items: center; gap: var(--sp-px);
  font-size: 9.5px; font-weight: 700;
  color: color-mix(in srgb, var(--text-primary) 70%, transparent);
}
.sched-crew-ico i { font-size: 11px; }
/* The window the customer was promised, alongside the real start time. */
.sched-app .sched-event-win {
  font-weight: 500; font-size: 9px; opacity: .72;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}

/* ── Job modal ── */
.job-travel-row { display: flex; gap: var(--sp-1_5); align-items: center; }
.job-travel-row input { flex: 1; min-width: 0; }
.job-travel-row button { flex: 0 0 auto; }
.job-travel-hint { font-size: 11px; line-height: 1.35; margin-top: var(--sp-1); color: var(--text-muted); }
.job-travel-hint.ok   { color: color-mix(in srgb, #22c55e 78%, var(--text-primary)); }
.job-travel-hint.warn { color: color-mix(in srgb, #f59e0b 78%, var(--text-primary)); }
.job-window-row { display: flex; gap: var(--sp-1_5); align-items: center; }
.job-window-row input { flex: 1; min-width: 0; }
.job-window-row span { font-size: 12px; color: var(--text-muted); flex: 0 0 auto; }

.job-crew-chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: 12px; font-weight: 600;
  border: 1px solid var(--border); border-radius: 999px;
  padding: var(--sp-0_5) var(--sp-1) var(--sp-0_5) var(--sp-2);
  margin: var(--sp-1) var(--sp-1) 0 0;
  background: var(--card);
}
.job-crew-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.job-crew-chip button {
  background: none; border: 0; cursor: pointer; padding: 0 var(--sp-0_5);
  color: var(--text-muted); display: inline-flex; line-height: 1;
}
.job-crew-chip button:hover { color: var(--danger, #ef4444); }

.job-parts-add { display: flex; gap: var(--sp-1_5); align-items: center; }
.job-parts-add input[type="number"] { width: 68px; flex: 0 0 auto; }
.job-parts-add input[type="text"] { flex: 1; min-width: 0; }
.job-parts-list { margin-top: var(--sp-1_5); display: flex; flex-direction: column; gap: var(--sp-1); }
.job-parts-empty { font-size: 12px; color: var(--text-muted); }
.job-parts-item { display: flex; align-items: center; gap: var(--sp-2); font-size: 13px; }
.job-parts-item > span:nth-child(2) { flex: 1; min-width: 0; }
.job-parts-qty {
  font-variant-numeric: tabular-nums; font-weight: 700; font-size: 12px;
  min-width: 28px; color: color-mix(in srgb, var(--accent) 70%, var(--text-primary));
}
.job-parts-x {
  background: none; border: 0; cursor: pointer; color: var(--text-muted);
  display: inline-flex; line-height: 1; padding: var(--sp-0_5);
}
.job-parts-x:hover { color: var(--danger, #ef4444); }

/* ── Materials list (flag feature_job_materials · js/scheduler/materials.js) ──
   The same rows as .job-parts-item plus a status per line. Reuses
   .job-parts-list / -add / -empty / -x so the two editors sit identically in
   the modal and only the row internals differ. */
.job-mat-bar { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-2); }
.job-mat-bar .hint { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.job-mat-sum {
  display: inline-flex; align-items: center; gap: var(--sp-1); margin-left: auto;
  font-size: 11.5px; font-weight: 700; white-space: nowrap;
  color: var(--_t, var(--text-muted));
}
.job-mat-sum.is-needed  { --_t: #ef4444; }
.job-mat-sum.is-ordered { --_t: #f59e0b; }
.job-mat-sum.is-picked  { --_t: #22c55e; }
.job-mat-changed {
  display: flex; align-items: flex-start; gap: var(--sp-2); font-size: 12px;
  padding: var(--sp-2) var(--sp-2_5); margin-bottom: var(--sp-2); border-radius: 9px;
  color: var(--text-secondary, var(--text-primary));
  background: color-mix(in srgb, #f59e0b 10%, transparent);
  border: 1px solid color-mix(in srgb, #f59e0b 32%, transparent);
}
.job-mat-changed i { color: #f59e0b; flex: none; }
.job-mat-item { display: flex; align-items: center; gap: var(--sp-2); font-size: 13px; }
.job-mat-item.is-na { opacity: .5; }
.job-mat-item.is-na .nm { text-decoration: line-through; }
.job-mat-qty {
  font-variant-numeric: tabular-nums; font-weight: 700; font-size: 11.5px; flex: none;
  min-width: 42px; text-align: center; padding: var(--sp-0_5) var(--sp-1); border-radius: 6px;
  background: var(--bg-secondary, transparent); border: 1px solid var(--border-color, transparent);
  color: color-mix(in srgb, var(--accent) 70%, var(--text-primary));
}
.job-mat-name { flex: 1; min-width: 0; }
.job-mat-name .nm { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.job-mat-name .src { display: block; font-size: 10.5px; color: var(--text-muted); }
.job-mat-seg { display: inline-flex; flex: none; border-radius: 8px; padding: var(--sp-0_5); background: var(--bg-secondary, transparent); }
.job-mat-seg button {
  border: 0; background: none; cursor: pointer; font: inherit; font-size: 10.5px; font-weight: 700;
  color: var(--text-muted); padding: var(--sp-1) var(--sp-1_5); border-radius: 6px; min-height: 26px;
}
.job-mat-seg button:hover { color: var(--text-primary); }
.job-mat-seg button[aria-pressed="true"] { background: var(--bg-primary, transparent); color: var(--_t, var(--text-primary)); }
.job-mat-seg button.s-needed  { --_t: #ef4444; }
.job-mat-seg button.s-ordered { --_t: #f59e0b; }
.job-mat-seg button.s-picked  { --_t: #22c55e; }

/* ── Supplier orders raised for a job (flag feature_purchase_orders ·
   js/scheduler/jobpos.js) ─────────────────────────────────────────────────
   Read-only rows under the materials list: what's on order, from whom, and
   what it costs. Reuses .job-parts-list / -empty so it sits flush with the
   list above it and only the row internals differ. */
.job-po-bar { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-2); }
.job-po-sum {
  display: inline-flex; align-items: center; gap: var(--sp-1); margin-left: auto;
  font-size: 11.5px; font-weight: 700; white-space: nowrap; color: var(--text-muted);
}
.job-po-sum.is-warn { color: #f59e0b; }
.job-po-item {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%; text-align: left;
  font: inherit; font-size: 13px; color: var(--text-primary); cursor: pointer;
  background: none; border: 0; border-radius: 8px; padding: var(--sp-1) var(--sp-1_5); min-height: 40px;
}
.job-po-item:hover { background: var(--bg-secondary); }
.job-po-name { flex: 1; min-width: 0; }
.job-po-name .nm { display: block; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.job-po-name .src { display: block; font-size: 10.5px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.job-po-st {
  flex: none; font-size: 10.5px; font-weight: 700; white-space: nowrap;
  padding: var(--sp-0_5) var(--sp-1_5); border-radius: 6px;
  background: var(--bg-secondary); color: var(--text-muted);
}
/* The same three the materials segments and the PO list use, so "on order"
   means one colour across the app rather than one per surface. */
.job-po-st.is-open { color: #3b82f6; }
.job-po-st.is-part { color: #f59e0b; }
.job-po-st.is-done { color: #22c55e; }
.job-po-amt { flex: none; font-variant-numeric: tabular-nums; font-size: 12.5px; font-weight: 600; }
/* Bucket headings in the "Link a purchase order" picker (JobPOs.openPicker).
   Same rows as the panel list, grouped — unattached orders, then ones a link
   would take off another job. */
.job-po-sec {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-muted); padding: var(--sp-2_5) var(--sp-1_5) var(--sp-1);
}
#linkPoBody .job-po-item { min-height: 44px; }

/* Generate-from-document picker (SchedMaterials.openGenerate) */
.matgen-chips { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-2); }
.matgen-chip {
  border: 1px solid var(--border-color); background: var(--bg-secondary); color: var(--text-secondary);
  border-radius: 99px; padding: var(--sp-1_5) var(--sp-3); font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
}
.matgen-chip[aria-pressed="true"] {
  border-color: var(--accent); color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.matgen-list { max-height: 46vh; overflow-y: auto; }
.matgen-h {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-muted); padding: var(--sp-2_5) var(--sp-1) var(--sp-1);
}
.matgen-row {
  display: flex; align-items: center; gap: var(--sp-2_5); padding: var(--sp-2) var(--sp-1);
  border-radius: 8px; cursor: pointer; min-height: 44px;
}
.matgen-row:hover { background: var(--bg-secondary); }
.matgen-row.is-dim { opacity: .55; }
.matgen-row input { width: 17px; height: 17px; flex: none; accent-color: var(--accent); }
.matgen-row .q {
  flex: none; width: 58px; font-size: 12px; font-variant-numeric: tabular-nums; color: var(--text-secondary);
}
.matgen-row .d { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }
.matgen-tag {
  flex: none; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-muted); border: 1px solid var(--border-color); border-radius: 5px; padding: var(--sp-0_5) var(--sp-1_5);
}

/* ── Inspector ── */
.sched-insp-prio {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-weight: 700; color: var(--p, var(--text-primary));
}
.sched-insp-parts-st {
  display: flex; align-items: center; gap: var(--sp-1_5);
  font-size: 12px; font-weight: 600; color: var(--p, var(--text-primary));
  margin-bottom: var(--sp-1_5);
}
.sched-insp-part { display: flex; gap: var(--sp-2); font-size: 12.5px; padding: var(--sp-0_5) 0; }
.sched-insp-part .q {
  font-variant-numeric: tabular-nums; font-weight: 700;
  color: var(--text-muted); min-width: 26px;
}
/* Per-line detail (flag feature_job_materials) — swapped in over the plain
   list by _inspLoadMaterials once the rows arrive. */
.sched-insp-matbar {
  height: 4px; border-radius: 99px; overflow: hidden; margin-bottom: var(--sp-1_5);
  background: var(--bg-secondary, transparent);
}
.sched-insp-matbar i { display: block; height: 100%; border-radius: 99px; background: #22c55e; }
.sched-insp-matcount { font-size: 11px; font-weight: 600; color: var(--text-muted); margin-bottom: var(--sp-1); }
.sched-insp-mat { align-items: center; }
.sched-insp-mat .tick {
  flex: none; width: 15px; height: 15px; border-radius: 5px; display: grid; place-items: center;
  border: 1.5px solid var(--border-color); font-size: 10px; color: transparent;
}
.sched-insp-mat .nm { flex: 1; min-width: 0; }
.sched-insp-mat .st { flex: none; font-size: 10px; font-weight: 700; color: #f59e0b; }
.sched-insp-mat.on { color: var(--text-muted); }
.sched-insp-mat.on .tick { background: #22c55e; border-color: #22c55e; color: #fff; }
.sched-insp-mat.on .nm { text-decoration: line-through; }
.sched-insp-mat.is-na { opacity: .5; }
.sched-insp-mat.is-na .nm { text-decoration: line-through; }

/* ═══════════════════════════════════════════════════════════════
   Calendar notes (db/add-calendar-notes.sql · js/scheduler/notes.js)

   A note must never be mistaken for a job, so it deliberately breaks the job
   language: no status edge, no technician tint, no square card. It reads as a
   torn-off sticky — soft fill, dashed edge, its own swatch colour.
   ═══════════════════════════════════════════════════════════════ */
.sched-app .sched-note {
  --nc: var(--sched-note-amber);
  position: relative;
  display: flex; align-items: center; gap: var(--sp-1);
  box-sizing: border-box; overflow: hidden;
  font-size: 10px; font-weight: 600; line-height: 1.25;
  padding: var(--sp-0_5) var(--sp-1_5);
  margin-top: var(--sp-0_5);
  border-radius: 4px;
  border: 1px dashed color-mix(in srgb, var(--nc) 62%, transparent);
  background: color-mix(in srgb, var(--nc) 17%, var(--card));
  color: color-mix(in srgb, var(--nc) 42%, var(--text-primary));
  cursor: pointer; touch-action: none;
  transition: background .12s, transform .12s, box-shadow .12s;
}
.sched-app .sched-note:hover {
  background: color-mix(in srgb, var(--nc) 30%, var(--card));
  transform: translateY(-1px);
  box-shadow: 0 4px 12px -4px rgba(0,0,0,.4);
}
.sched-app .sched-note i { flex: 0 0 auto; font-size: 11px; opacity: .8; }
/* A note placed but not yet typed into still has to be findable + grabbable. */
.sched-app .sched-note.is-empty { font-style: italic; opacity: .72; }
/* Timed notes are absolutely positioned into the grid/track by notes.js. */
.sched-app .sched-tg-col > .sched-note,
.sched-app .sched-swim-track > .sched-note { position: absolute; margin-top: 0; }
.sched-app .sched-note[data-note-color="amber"] { --nc: var(--sched-note-amber); }
.sched-app .sched-note[data-note-color="blue"]  { --nc: var(--sched-note-blue); }
.sched-app .sched-note[data-note-color="green"] { --nc: var(--sched-note-green); }
.sched-app .sched-note[data-note-color="red"]   { --nc: var(--sched-note-red); }
.sched-app .sched-note[data-note-color="grey"]  { --nc: var(--sched-note-grey); }

/* Placement mode: the whole board becomes a target, so say so with the cursor
   and a soft outline rather than a modal that blocks seeing where to drop. */
body.sched-note-arm .sched-main { cursor: copy; }
body.sched-note-arm .sched-tg-cell:hover,
body.sched-note-arm .sched-month-cell:hover,
body.sched-note-arm .sched-allday-cell:hover,
body.sched-note-arm .sched-swim-track:hover {
  outline: 2px dashed color-mix(in srgb, var(--sched-note-amber) 70%, transparent);
  outline-offset: -2px;
}
#schedNoteBtn[aria-pressed="true"] {
  border-color: var(--sched-note-amber);
  color: var(--sched-note-amber);
}

/* Editor popover — fixed so it can anchor to a note inside a scrolled grid. */
.sched-note-pop {
  position: fixed; z-index: 60; width: 260px;
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-2_5);
  background: var(--card); border: 1px solid var(--border);
  border-radius: 10px; box-shadow: 0 12px 32px -8px rgba(0,0,0,.55);
}
.sched-note-pop[hidden] { display: none; }
.sched-note-pop textarea {
  width: 100%; resize: vertical; font: inherit; font-size: 13px;
  padding: var(--sp-2); border-radius: 6px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text-primary);
}
.sched-note-sws { display: flex; gap: var(--sp-1_5); }
.sched-note-sw {
  width: 20px; height: 20px; border-radius: 50%; cursor: pointer; padding: 0;
  border: 2px solid transparent; background: var(--nc, var(--sched-note-amber));
}
.sched-note-sw[data-color="amber"] { --nc: var(--sched-note-amber); }
.sched-note-sw[data-color="blue"]  { --nc: var(--sched-note-blue); }
.sched-note-sw[data-color="green"] { --nc: var(--sched-note-green); }
.sched-note-sw[data-color="red"]   { --nc: var(--sched-note-red); }
.sched-note-sw[data-color="grey"]  { --nc: var(--sched-note-grey); }
.sched-note-sw.on { border-color: var(--text-primary); }
.sched-note-acts { display: flex; gap: var(--sp-2); justify-content: space-between; }

/* ═══════════════════════════════════════════════════════════════════════════
   Job editor v2 — flag feature_job_editor_v2
   ---------------------------------------------------------------------------
   The dispatch job editor used to be one 600px column: six sections open at
   once, ~40 fields, and thirteen same-weight buttons in the footer. v2 turns
   the sections into rail destinations, promotes status and the job's identity
   into a sticky header, and collapses the footer to one primary action plus a
   menu.

   Every rule here is scoped to #jobModal.jm2, a class jobeditor2.js only stamps
   when the flag resolves true. With the flag off nothing below applies and the
   modal renders exactly as it always has — the markup carries both, and CSS
   picks. Elements the v2 layout supersedes carry .jm2-legacy (hidden, never
   removed: saveJob still reads their values). New chrome carries .jm2-only.
   ═══════════════════════════════════════════════════════════════════════════ */

#jobModal .jm2-only { display: none; }
#jobModal.jm2 .jm2-only { display: block; }
#jobModal.jm2 .jm2-only.jm2-f { display: flex; }
#jobModal.jm2 .jm2-legacy { display: none; }

#jobModal .sched-modal { max-width: 600px; }
#jobModal.jm2 .sched-modal { max-width: 1060px; }

/* ── Context header ──────────────────────────────────────────────────────── */
#jobModal.jm2 .sched-modal-head { flex-wrap: wrap; padding-bottom: var(--sp-3); }
.jm2-jobno {
  font-size: 11px; font-weight: 700; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  background: var(--bg); border: 1px solid var(--border);
  padding: var(--sp-0_5) var(--sp-2); border-radius: 6px;
}
#jobModal.jm2 .sched-modal-head h3 { min-width: 0; }
#jobModal.jm2 .sched-modal-head h3 > span[data-term] {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.jm2-meta {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  width: 100%; margin-top: var(--sp-0_5);
  font-size: 12px; color: var(--text-secondary);
}
.jm2-meta i { color: var(--text-muted); font-size: 13px; margin-right: var(--sp-0_5); }
.jm2-meta .jm2-sep { color: var(--border-strong); }
.jm2-meta span:empty { display: none; }
.jm2-save {
  display: inline-flex; align-items: center; gap: var(--sp-1_5);
  font-size: 12px; font-weight: 500; color: var(--text-muted); white-space: nowrap;
}
.jm2-save i { font-size: 14px; }
.jm2-save.is-dirty { color: var(--st-in_progress); }
.jm2-save.is-saved i { color: var(--st-complete); }

/* ── Status stepper ──────────────────────────────────────────────────────── */
.jm2-stepper {
  display: flex; gap: var(--sp-1); width: 100%; margin-top: var(--sp-2_5);
  background: var(--bg); border: 1px solid var(--border);
  padding: var(--sp-1); border-radius: 10px; overflow-x: auto;
}
.jm2-step {
  flex: 1; min-width: 86px;
  display: flex; align-items: center; justify-content: center; gap: var(--sp-1_5);
  padding: var(--sp-2) var(--sp-2); border: 0; background: transparent; border-radius: 7px;
  font-size: 12px; font-weight: 500; color: var(--text-muted);
  white-space: nowrap; cursor: pointer;
  transition: background .15s, color .15s;
}
.jm2-step:hover { background: var(--surface-hover); color: var(--text-secondary); }
.jm2-step i { font-size: 14px; }
.jm2-step.is-done { color: var(--st-complete); }
.jm2-step.is-cur { background: var(--accent-soft); color: var(--accent); font-weight: 700; }

/* ── Body: rail + pane ───────────────────────────────────────────────────── */
#jobModal.jm2 .sched-modal-body {
  padding: 0; display: grid; grid-template-columns: 206px minmax(0, 1fr);
  overflow: hidden; min-height: 0;
}
.jm2-rail {
  border-right: 1px solid var(--border);
  background: var(--bg);
  padding: var(--sp-2_5) var(--sp-2); display: flex; flex-direction: column; gap: var(--sp-0_5);
  overflow-y: auto;
}
.jm2-railitem {
  display: flex; align-items: center; gap: var(--sp-2_5);
  width: 100%; padding: var(--sp-2) var(--sp-3); border: 0; background: transparent;
  border-radius: 9px; font-size: 13px; font-weight: 500;
  color: var(--text-secondary); text-align: left; cursor: pointer;
  transition: background .15s, color .15s;
}
.jm2-railitem:hover { background: var(--surface-hover); color: var(--text-primary); }
.jm2-railitem.is-active { background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.jm2-railitem > i:first-child { font-size: 16px; flex: 0 0 auto; }
.jm2-railitem .jm2-cnt {
  margin-left: auto; font-size: 10px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  min-width: 18px; height: 18px; padding: 0 var(--sp-1_5);
  display: none; place-items: center; border-radius: 999px;
  background: var(--elev-3, var(--surface-hover)); color: var(--text-muted);
}
.jm2-railitem .jm2-cnt.on { display: grid; }
.jm2-railitem.is-active .jm2-cnt { background: var(--accent); color: var(--app-accent-fg, #fff); }
.jm2-railitem .jm2-tick {
  margin-left: auto; color: var(--st-complete);
  font-size: 15px; display: none;
}
.jm2-railitem .jm2-tick.on { display: block; }
.jm2-railitem .jm2-cnt.on ~ .jm2-tick { display: none; }

/* The pane wrapper is in the markup unconditionally. With the flag off it must
   not exist as far as layout is concerned, or its padding would stack on top of
   .sched-modal-body's — display:contents makes the box vanish and its children
   lay out against the body exactly as they did before v2. */
.jm2-pane { display: contents; }
#jobModal.jm2 .jm2-pane {
  display: block; padding: var(--sp-5) var(--sp-6); overflow-y: auto; min-height: 0;
}
#jobModal.jm2 .jm2-panel { display: none; }
#jobModal.jm2 .jm2-panel.is-show { display: block; animation: jm2fade .2s ease-out; }
#jobModal.jm2 .jm2-panel + .jm2-panel.is-show { margin-top: var(--sp-4); }
#jobModal.jm2 .sset-sec-head { display: none; }
@keyframes jm2fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  #jobModal.jm2 .jm2-panel.is-show { animation: none; }
}
.jm2-panelhead { margin-bottom: var(--sp-4); }
.jm2-panelhead h4 { margin: 0; font-size: 15px; font-weight: 700; color: var(--text-primary); }
.jm2-panelhead p { margin: var(--sp-1) 0 0; font-size: 12px; color: var(--text-muted); line-height: 1.5; }

/* ── Segmented mirrors (job type, priority) ──────────────────────────────── */
.jm2-seg {
  display: flex; gap: var(--sp-1);
  background: var(--bg); border: 1px solid var(--border);
  padding: var(--sp-1); border-radius: 10px;
}
.jm2-seg button {
  flex: 1; padding: var(--sp-2) var(--sp-1_5); border: 0; background: transparent; border-radius: 7px;
  font-size: 12px; font-weight: 500; color: var(--text-secondary);
  white-space: nowrap; cursor: pointer;
  transition: background .15s, color .15s;
}
.jm2-seg button:hover { background: var(--surface-hover); color: var(--text-primary); }
.jm2-seg button.on {
  background: var(--surface); color: var(--text-primary); font-weight: 700;
  box-shadow: var(--shadow-1, none);
}
.jm2-seg button.on[data-v="emergency"] {
  background: color-mix(in srgb, var(--st-no_show) 15%, transparent);
  color: var(--st-no_show);
}
.jm2-seg button.on[data-v="high"] {
  background: color-mix(in srgb, var(--st-in_progress) 15%, transparent);
  color: var(--st-in_progress);
}

/* ── Duration chips ──────────────────────────────────────────────────────── */
.jm2-chips { display: flex; gap: var(--sp-1_5); flex-wrap: wrap; }
.jm2-chip {
  padding: var(--sp-2) var(--sp-3); background: var(--surface);
  border: 1px solid var(--border); border-radius: 999px;
  font-size: 12px; font-weight: 500; color: var(--text-secondary);
  font-variant-numeric: tabular-nums; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.jm2-chip:hover { border-color: var(--border-strong); color: var(--text-primary); }
.jm2-chip.on {
  background: var(--accent-soft); border-color: var(--accent-edge);
  color: var(--accent); font-weight: 700;
}

/* ── Progressive disclosure ──────────────────────────────────────────────── */
.jm2-more { margin-top: var(--sp-4); border-top: 1px dashed var(--border); padding-top: var(--sp-3); }
.jm2-more-btn {
  display: flex; align-items: center; gap: var(--sp-2);
  background: transparent; border: 0; padding: var(--sp-1) 0; cursor: pointer;
  font-size: 13px; font-weight: 700; color: var(--accent);
}
.jm2-more-btn i.jm2-caret { transition: transform .18s ease; }
.jm2-more.is-open .jm2-more-btn i.jm2-caret { transform: rotate(90deg); }
.jm2-more-btn .jm2-more-sum { font-weight: 500; color: var(--text-muted); font-size: 11px; }
#jobModal.jm2 .jm2-more .jm2-more-body { display: none; padding-top: var(--sp-3_5); }
#jobModal.jm2 .jm2-more.is-open .jm2-more-body { display: grid; }

/* ── Footer: one primary action, the rest in a menu ──────────────────────── */
#jobModal.jm2 .sched-editactions { display: none; }
.jm2-menuwrap { position: relative; }
.jm2-menu {
  position: absolute; bottom: calc(100% + var(--sp-2)); left: 0; width: 258px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: 12px; box-shadow: var(--card-shadow-hover);
  padding: var(--sp-1_5); display: none; z-index: 40; max-height: 60vh; overflow-y: auto;
}
.jm2-menu.is-open { display: block; }
.jm2-menu-lbl {
  padding: var(--sp-2) var(--sp-2_5) var(--sp-1_5); font-size: 10px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted);
}
.jm2-menu button {
  display: flex; align-items: center; gap: var(--sp-2_5); width: 100%;
  padding: var(--sp-2) var(--sp-2_5); border: 0; background: transparent; border-radius: 8px;
  font-size: 13px; text-align: left; color: var(--text-primary); cursor: pointer;
}
.jm2-menu button:hover { background: var(--surface-hover); }
.jm2-menu button i { font-size: 16px; color: var(--text-muted); }
.jm2-menu button.jm2-danger { color: var(--danger); }
.jm2-menu button.jm2-danger:hover { background: color-mix(in srgb, var(--st-no_show) 13%, transparent); }
.jm2-menu button.jm2-danger i { color: var(--danger); }
.jm2-menu-sep { height: 1px; background: var(--border); margin: var(--sp-1_5) var(--sp-1_5); }

/* ── Small screens: the rail folds to a chip scroller ────────────────────── */
@media (max-width: 860px) {
  #jobModal.jm2 .sched-modal-body { grid-template-columns: minmax(0, 1fr); }
  .jm2-rail {
    flex-direction: row; overflow-x: auto; border-right: 0;
    border-bottom: 1px solid var(--border); padding: var(--sp-2) var(--sp-2_5); gap: var(--sp-1_5);
  }
  .jm2-railitem { width: auto; flex: 0 0 auto; white-space: nowrap; }
  .jm2-railitem .jm2-cnt.on, .jm2-railitem .jm2-tick.on { margin-left: var(--sp-1); }
  #jobModal.jm2 .jm2-pane { padding: var(--sp-4) var(--sp-3_5); }
  #jobModal.jm2 .sset-grid { grid-template-columns: minmax(0, 1fr); }
  .jm2-stepper { margin-top: var(--sp-2); }
  /* Touch targets: 44px minimum on the controls a dispatcher taps in the van. */
  #jobModal.jm2 .sched-modal-body input[type="text"],
  #jobModal.jm2 .sched-modal-body input[type="email"],
  #jobModal.jm2 .sched-modal-body input[type="tel"],
  #jobModal.jm2 .sched-modal-body input[type="time"],
  #jobModal.jm2 .sched-modal-body input[type="date"],
  #jobModal.jm2 .sched-modal-body input[type="number"],
  #jobModal.jm2 .sched-modal .filter-select { min-height: 44px; }
  .jm2-chip { padding: var(--sp-2_5) var(--sp-3_5); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Subcontract mode — flag feature_subcontract_mode (public/js/scheduler/subcontract.js)
   ---------------------------------------------------------------------------
   On a subcontract job the same fields describe different people: the linked
   customer is the principal contractor you invoice, and the site contact is
   their client. Both readings are authored into the markup and CSS picks —
   the direct label is a [data-term] node the industry registry sweeps, so
   rewriting its text in JS would be undone on the next sweep.

   Default (no .sc-sub) is the direct reading, which is what every account that
   never turns the flag on sees.
   ═══════════════════════════════════════════════════════════════════════════ */

#jobModal .sc-sub-only { display: none; }
#jobModal.sc-sub .sc-sub-only { display: inline; }
#jobModal.sc-sub .sc-dir-only { display: none; }
/* Whole fields that only exist on subcontract work need the grid cell back, not
   an inline box — the label swaps above are spans, this one is a .form-group. */
#jobModal.sc-sub .form-group.sc-sub-only { display: block; }

/* The one-line explanation under the choice — only ever shown in subcontract
   mode, so it needs the block display the inline rule above doesn't give it. */
#jobModal.sc-sub .sc-note {
  display: block;
  margin-top: var(--sp-1_5);
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--text-muted);
}
#jobModal.sc-sub .sc-note i { color: var(--accent); margin-right: var(--sp-1); }

/* ═══════════════════════════════════════════════════════════════════════════
   "Charge as" — what this job bills as (feature_job_price_item)
   A chip carrying the item and the price it will bill at, with the two actions
   beside it. The price is the point of the control, so it is the part that
   reads as data; the buttons stay ghost-weight because picking one is rarer
   than reading the number. The hint wraps to its own line at any width.
   ═══════════════════════════════════════════════════════════════════════════ */
.jpi-pick { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.jpi-chip {
  display: inline-flex; align-items: center; gap: var(--sp-1_5);
  padding: var(--sp-1) var(--sp-2);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2, rgba(127, 127, 127, 0.06)); min-width: 0;
}
.jpi-chip b { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jpi-chip i { color: var(--accent); }
.jpi-chip.is-missing { color: var(--text-muted); }
.jpi-chip.is-missing i { color: var(--warn); }
.jpi-price { font-size: 0.78rem; color: var(--text-muted); white-space: nowrap; }
.jpi-hint { flex-basis: 100%; font-size: 0.78rem; line-height: 1.45; color: var(--text-muted); }

/* Bill-to is the field most likely to be read past on a subcontract job — it's
   the one that changed meaning — so it gets a rule beside it. */
#jobModal.sc-sub #jobCustLinkGroup,
#jobModal.sc-sub #jobCustNameGroup { border-left: 2px solid var(--accent); padding-left: var(--sp-2_5); }

/* Board / inspector tag naming the principal behind a subcontract job. */
.sched-sub-tag {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: 0 var(--sp-1); border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--text-muted);
  font-size: 0.68rem; font-weight: 600; letter-spacing: 0.01em;
}

/* ══════════════════════════════════════════════════════════════════════════
   Quick-create popover — flag feature_sched_quickcreate (quickcreate.js)
   The six answers a booking actually has, anchored to the gesture that
   started it. Positioned by JS (inline left/top); everything else lives here.
   ══════════════════════════════════════════════════════════════════════════ */
.sched-qc {
  position: fixed;
  z-index: var(--z-modal, 1000);
  width: 392px; max-width: calc(100vw - 16px);
  max-height: calc(100vh - 24px);
  display: flex; flex-direction: column;
  border-radius: 13px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  box-shadow: 0 18px 40px -10px rgba(0,0,0,.55), 0 40px 70px -30px rgba(0,0,0,.6);
  color: var(--text-primary);
  font-size: 13px;
}
.sched-qc-head {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-3) var(--sp-2);
}
.sched-qc-head h3 { margin: 0; font-size: 13.5px; font-weight: 600; }
.sched-qc-x {
  margin-left: auto;
  width: 28px; height: 28px; display: grid; place-items: center;
  border: 0; border-radius: 8px; background: transparent; cursor: pointer;
  color: var(--text-muted); font-size: 16px;
}
.sched-qc-x:hover { background: var(--surface-hover, rgba(255,255,255,.06)); color: var(--text-primary); }

/* The line the gesture already answered. */
.sched-qc-slot {
  display: flex; align-items: center; gap: var(--sp-1_5);
  margin: 0 var(--sp-3) var(--sp-2);
  padding: var(--sp-1_5) var(--sp-2);
  border-radius: 8px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  font-size: 11.5px; font-weight: 500;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.sched-qc-slot i { color: var(--accent); font-size: 14px; }
.sched-qc-slot span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-qc-edit {
  margin-left: auto; padding: 0; border: 0; background: transparent; cursor: pointer;
  color: var(--accent); font: inherit; font-size: 11.5px; font-weight: 600;
}

.sched-qc-body {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: 0 var(--sp-3);
  display: flex; flex-direction: column; gap: var(--sp-3);
}
.sched-qc-f { display: flex; flex-direction: column; gap: var(--sp-1_5); position: relative; }
.sched-qc-f > label {
  font-size: 11.5px; font-weight: 600;
  color: var(--text-secondary);
}
.sched-qc-hint { font-weight: 400; color: var(--text-muted); }
.sched-qc-f input[type="text"] {
  width: 100%; box-sizing: border-box;
  padding: var(--sp-2) var(--sp-2_5);
  font: inherit; font-size: 13px;
  color: var(--text-primary); background: var(--bg-secondary);
  border: 1px solid var(--border); border-radius: 9px;
}
.sched-qc-f input[type="text"]:focus { outline: none; border-color: var(--accent); }
.sched-qc-f input.is-bad { border-color: var(--hot, #ef4444); }
html[data-theme="light"] .sched-qc-f input[type="text"] { background: #fff; }

/* Natural language — the same prompt the palette uses, on the create path. */
.sched-qc-nl {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2_5);
  border: 1px solid var(--accent); border-radius: 10px;
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.sched-qc-nl > i { flex: none; color: var(--accent); font-size: 16px; }
.sched-qc-nl input {
  flex: 1; min-width: 0; padding: 0; border: 0; background: transparent;
  font: inherit; font-size: 13px; color: var(--text-primary);
}
.sched-qc-nl input:focus { outline: none; }
.sched-qc-nl.is-busy { opacity: .6; pointer-events: none; }
.sched-qc-nlgo {
  flex: none; padding: var(--sp-0_5) var(--sp-1_5);
  border: 1px solid var(--border-strong); border-radius: 5px;
  background: transparent; cursor: pointer;
  color: var(--text-muted); font: inherit; font-size: 10px; font-weight: 600;
}
.sched-qc-nlgo:hover { color: var(--accent); border-color: var(--accent); }

/* Customer — one field that always ends up with a customer_id or a name. */
.sched-qc-combo {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 0 var(--sp-2_5);
  border: 1px solid var(--border); border-radius: 9px;
  background: var(--bg-secondary);
}
html[data-theme="light"] .sched-qc-combo { background: #fff; }
.sched-qc-combo > i { flex: none; color: var(--text-muted); font-size: 15px; }
.sched-qc-combo input {
  flex: 1; min-width: 0;
  padding: var(--sp-2) 0;
  border: 0; background: transparent;
  font: inherit; font-size: 13px; color: var(--text-primary);
}
.sched-qc-combo input:focus { outline: none; }
.sched-qc-combo.is-linked { border-color: var(--st-complete); }
.sched-qc-combo.is-linked > i { color: var(--st-complete); }
.sched-qc-clear {
  flex: none; padding: 0; border: 0; background: transparent; cursor: pointer;
  color: var(--text-muted); font-size: 15px; display: grid; place-items: center;
}
.sched-qc-linked {
  display: flex; align-items: center; gap: var(--sp-1);
  font-size: 11.5px; font-weight: 500; color: var(--st-complete);
}
.sched-qc-linked i { font-size: 13px; }

/* Shared dropdown (customers, technicians). */
/* Fixed, not absolute: the popover body scrolls, and a menu inside a scrolling
   container is clipped by it — which hid the bottom of the technician list
   (Leave unassigned / No date yet) exactly when it mattered. Placed by JS
   against the trigger's rect, and re-placed on scroll and resize. */
.sched-qc-menu {
  position: fixed; z-index: calc(var(--z-modal, 1000) + 2);
  max-height: 260px; overflow-y: auto;
  padding: var(--sp-1);
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  box-shadow: 0 12px 32px rgba(0,0,0,.32);
}
.sched-qc-menu-tech { max-height: 340px; }
.sched-qc-pickwrap { position: relative; }
.sched-qc-opt {
  width: 100%; box-sizing: border-box;
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2);
  border: 0; border-radius: 8px; cursor: pointer;
  background: transparent; color: var(--text-primary);
  font: inherit; text-align: left;
}
.sched-qc-opt:hover, .sched-qc-opt:focus-visible, .sched-qc-opt.is-hi { background: var(--accent-soft); outline: none; }
.sched-qc-opt > i { flex: none; color: var(--text-muted); font-size: 16px; }
.sched-qc-opt.is-off { opacity: .55; }
.sched-qc-opt-main { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
.sched-qc-opt-main b { font-size: 12.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-qc-opt-main small { font-size: 11px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-qc-opt-new b { color: var(--accent); }
.sched-qc-opt-new > i { color: var(--accent); }
.sched-qc-empty { padding: var(--sp-2_5); font-size: 12px; color: var(--text-muted); }
.sched-qc-menu-lbl {
  padding: var(--sp-1_5) var(--sp-2) var(--sp-1);
  font-size: 10.5px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-muted);
}
.sched-qc-menu-sep { height: 1px; margin: var(--sp-1) var(--sp-0_5); background: var(--border); }

/* Chips — job type and duration. */
.sched-qc-chips { display: flex; flex-wrap: wrap; gap: var(--sp-1_5); }
.sched-qc-chip {
  padding: var(--sp-1_5) var(--sp-2_5);
  border: 1px solid var(--border); border-radius: 8px; cursor: pointer;
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font: inherit; font-size: 12px; font-weight: 500; white-space: nowrap;
}
.sched-qc-chip:hover { border-color: var(--border-strong); color: var(--text-primary); }
.sched-qc-chip.is-on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }

/* Technician — load, availability and leave, in the picker. */
.sched-qc-pick {
  width: 100%; box-sizing: border-box;
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2);
  border: 1px solid var(--border); border-radius: 9px; cursor: pointer;
  background: var(--bg-secondary);
  color: var(--text-primary); font: inherit; text-align: left;
}
.sched-qc-pick:hover { border-color: var(--border-strong); }
.sched-qc-pick.is-busy { border-color: var(--st-in_progress, #f59e0b); }
.sched-qc-pick-main { display: flex; flex-direction: column; min-width: 0; flex: 1; line-height: 1.3; }
.sched-qc-pick-main b { font-size: 12.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-qc-pick-main small { font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-qc-chg { flex: none; color: var(--accent); font-size: 12px; font-weight: 600; }
.sched-qc-av {
  flex: none; width: 24px; height: 24px; border-radius: 7px;
  display: grid; place-items: center;
  font-size: 10px; font-weight: 700; color: #0e0f12;
}
.sched-qc-av-none { background: #565f6e; color: #fff; font-size: 12px; }
.sched-qc-load { margin-left: auto; flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-0_5); }
.sched-qc-load small { font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.sched-qc-bar { display: block; width: 52px; height: 4px; border-radius: 3px; overflow: hidden; background: var(--border); }
.sched-qc-bar i { display: block; height: 100%; background: var(--st-complete); }
.sched-qc-bar.is-high i { background: var(--st-in_progress, #f59e0b); }
.sched-qc-bar.is-over i { background: var(--hot, #ef4444); }

/* The clash, with its two ways out attached. */
.sched-qc-clash {
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2_5);
  border-radius: 10px;
  background: color-mix(in srgb, var(--st-in_progress, #f59e0b) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--st-in_progress, #f59e0b) 45%, transparent);
  font-size: 12px; line-height: 1.45;
}
.sched-qc-clash.is-ack {
  flex-direction: row; align-items: center; gap: var(--sp-1_5);
  background: var(--accent-soft); border-color: var(--accent);
  color: var(--text-secondary);
}
.sched-qc-clash-msg { display: flex; gap: var(--sp-2); }
.sched-qc-clash-msg i { flex: none; color: var(--st-in_progress, #f59e0b); font-size: 15px; }
.sched-qc-clash-acts { display: flex; flex-wrap: wrap; gap: var(--sp-1_5); padding-left: var(--sp-4); }
.sched-qc-cbtn {
  padding: var(--sp-1) var(--sp-2_5);
  border: 1px solid var(--border-strong); border-radius: 7px; cursor: pointer;
  background: var(--surface); color: var(--text-primary);
  font: inherit; font-size: 11.5px; font-weight: 600;
}
.sched-qc-cbtn:hover { border-color: var(--accent); color: var(--accent); }
.sched-qc-cbtn.is-ghost { background: transparent; border-color: transparent; color: var(--text-muted); }
.sched-qc-cbtn.is-ghost:hover { color: var(--text-primary); border-color: var(--border); }

.sched-qc-foot {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-3);
  padding: var(--sp-2_5) var(--sp-3);
  border-top: 1px solid var(--border);
}
.sched-qc-more {
  display: inline-flex; align-items: center; gap: var(--sp-1_5);
  padding: var(--sp-1_5) 0;
  border: 0; background: transparent; cursor: pointer;
  color: var(--text-secondary); font: inherit; font-size: 12.5px; font-weight: 600;
}
.sched-qc-more:hover { color: var(--accent); }
.sched-qc-book {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: var(--sp-1_5);
  padding: var(--sp-2) var(--sp-3);
  border: 0; border-radius: 9px; cursor: pointer;
  background: var(--accent); color: #fff;
  font: inherit; font-size: 13px; font-weight: 600;
}
.sched-qc-book:hover { background: var(--accent-hover, var(--accent)); }
.sched-qc-book:disabled { opacity: .7; cursor: default; }

@media (max-width: 480px) {
  .sched-qc { width: calc(100vw - 16px); }
}

/* Light theme. The scheduler flips its palette on `html[data-theme="light"]
   body.sched-app`, so everything above that mixes against --surface / --border /
   --text-* adapts on its own. These three do not: a saturated green or amber as
   TEXT on a pale tint is unreadable, which is why .sched-confirm-flag already
   carries the same two inks. */
html[data-theme="light"] .sched-qc-f input[type="text"],
html[data-theme="light"] .sched-qc-combo input { color: #1e293b; }
html[data-theme="light"] .sched-qc-linked,
html[data-theme="light"] .sched-qc-combo.is-linked > i { color: #15803d; }
html[data-theme="light"] .sched-qc-clash-msg i { color: #92400e; }

/* ── ServiceM8 import panel (Scheduling Settings → Import) ────────────────
   Rendered by js/scheduler/sm8-import.js. The panel is a small three-act
   surface — connect, preview, import — and the preview table is the part
   that has to be readable, because it is what the contractor checks their
   real customer names against before anything is written to the board. */
.sched-app .sm8-lead {
  font-size: 13px; line-height: 1.55; color: var(--text-secondary);
  margin-bottom: var(--sp-4); max-width: 58ch;
}
.sched-app .sm8-connect { padding: var(--sp-2) 0; }

/* Connected-account header: status dot, who, and the account actions. */
.sched-app .sm8-acct {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-3_5); margin-bottom: var(--sp-4);
  background: var(--sunken); border: 1px solid var(--border); border-radius: 10px;
}
.sched-app .sm8-acct-l { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.sched-app .sm8-acct-r { display: flex; align-items: center; gap: var(--sp-2); flex-shrink: 0; }
.sched-app .sm8-acct-name { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.sched-app .sm8-acct-sub  { font-size: 11px; color: var(--text-muted); margin-top: 2px; line-height: 1.45; }
.sched-app .sm8-dot {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
  background: var(--text-muted);
}
.sched-app .sm8-dot.ok   { background: var(--success, #10b981); }
.sched-app .sm8-dot.warn { background: var(--warn, #f59e0b); }

/* Date window + Preview, on one line where there's room. */
.sched-app .sm8-window {
  display: flex; align-items: flex-end; gap: var(--sp-3); flex-wrap: wrap;
}
.sched-app .sm8-window .form-group { flex: 1 1 150px; min-width: 0; margin: 0; }

/* The counts. Three numbers is the whole summary — new, already-here, total. */
.sched-app .sm8-summary {
  display: flex; gap: var(--sp-3); flex-wrap: wrap; margin: var(--sp-4) 0 var(--sp-3);
}
.sched-app .sm8-stat {
  flex: 1 1 90px; padding: var(--sp-2_5) var(--sp-3);
  background: var(--sunken); border: 1px solid var(--border); border-radius: 10px;
}
.sched-app .sm8-stat b {
  display: block; font-size: 20px; font-weight: 650; color: var(--text-primary);
  line-height: 1.1; font-variant-numeric: tabular-nums;
}
.sched-app .sm8-stat span { display: block; font-size: 11px; color: var(--text-muted); margin-top: 3px; }

.sched-app .sm8-caveat {
  display: flex; gap: var(--sp-2); align-items: flex-start;
  padding: var(--sp-2_5) var(--sp-3); margin-bottom: var(--sp-3);
  font-size: 11.5px; line-height: 1.5; color: var(--text-secondary);
  background: var(--warn-soft, rgba(245, 158, 11, .08));
  border: 1px solid var(--warn-border, rgba(245, 158, 11, .25));
  border-radius: 9px;
}
.sched-app .sm8-caveat i { color: var(--warn, #f59e0b); flex-shrink: 0; margin-top: 1px; }
.sched-app .sm8-caveat > div > div + div { margin-top: 4px; }

/* The table scrolls inside itself: a long address must never push the
   settings modal sideways. */
.sched-app .sm8-tablewrap {
  overflow-x: auto; border: 1px solid var(--border); border-radius: 10px;
  max-height: 300px; overflow-y: auto;
}
.sched-app .sm8-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.sched-app .sm8-table th {
  position: sticky; top: 0; z-index: 1;
  text-align: left; padding: var(--sp-2) var(--sp-2_5); white-space: nowrap;
  font-size: 10.5px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted); background: var(--sunken);
  border-bottom: 1px solid var(--border);
}
.sched-app .sm8-table td {
  padding: var(--sp-2) var(--sp-2_5); border-bottom: 1px solid var(--border);
  color: var(--text-secondary); vertical-align: top;
}
.sched-app .sm8-table tr:last-child td { border-bottom: none; }
.sched-app .sm8-t { color: var(--text-muted); }

.sched-app .sm8-tag {
  display: inline-block; padding: var(--sp-0_5) var(--sp-1_5); border-radius: 999px;
  font-size: 10px; font-weight: 600; white-space: nowrap;
}
.sched-app .sm8-tag.new { color: var(--success, #10b981); background: rgba(16, 185, 129, .12); }
.sched-app .sm8-tag.upd { color: var(--text-muted);      background: var(--sunken); }

.sched-app .sm8-actions { margin-top: var(--sp-4); }
.sched-app .sm8-empty, .sched-app .sm8-err {
  padding: var(--sp-3_5); margin-top: var(--sp-3); border-radius: 10px;
  font-size: 12.5px; line-height: 1.5;
  background: var(--sunken); border: 1px solid var(--border); color: var(--text-secondary);
}
.sched-app .sm8-err { color: var(--danger, #ef4444); }
.sched-app .sm8-err i { margin-right: 6px; }

@keyframes sm8-spin { to { transform: rotate(360deg); } }
.sched-app .sm8-spin { display: inline-block; animation: sm8-spin 1s linear infinite; }
@media (prefers-reduced-motion: reduce) {
  .sched-app .sm8-spin { animation: none; }
}

/* ── Pending technician updates ("Send update") ──────────────────────────────
   Moves and edits queue instead of buzzing the assigned tech on every drag
   (js/scheduler/techupdates.js); this chip is the queue made visible and is the
   only way those changes reach a phone. Amber rather than accent on purpose: it
   sits beside the board's one primary button ("Add Job") and has to read as
   unfinished business, not as a second thing to click by default. Hidden at
   zero — the toolbar is not the place for an empty affordance. */
.sched-app .sched-sendupd { display: inline-flex; align-items: center; gap: var(--sp-1); }
.sched-app .sched-sendupd[hidden] { display: none; }
.sched-app .sched-sendupd-go,
.sched-app .sched-sendupd-x {
  color: var(--app-warn, #f59e0b);
  background: color-mix(in srgb, var(--app-warn, #f59e0b) 13%, transparent);
  border: 1px solid color-mix(in srgb, var(--app-warn, #f59e0b) 38%, transparent);
}
.sched-app .sched-sendupd-go:hover,
.sched-app .sched-sendupd-x:hover {
  background: color-mix(in srgb, var(--app-warn, #f59e0b) 22%, transparent);
  border-color: color-mix(in srgb, var(--app-warn, #f59e0b) 55%, transparent);
}
.sched-app .sched-sendupd-go[disabled] { opacity: .6; pointer-events: none; }
/* Count pill: tinted, never solid — a solid amber fill needs a different ink in
   each theme (--app-warn is #f59e0b dark, #b45309 light) and one of the two
   always lost contrast. Inheriting the chip's amber keeps both legible. */
.sched-app .sched-sendupd-n {
  min-width: 17px; padding: 0 var(--sp-1);
  display: inline-flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--app-warn, #f59e0b) 26%, transparent);
  border-radius: 999px;
  font-size: var(--text-2xs, 10px); font-weight: 700; line-height: 17px;
  font-variant-numeric: tabular-nums;
}

/* ── Variations panel (feature_variations) ────────────────────────
   Extra work agreed after the job was priced, listed under the materials it
   sits beside. Each row leads with what the work is and follows with what has
   actually happened to it — sent, opened, answered — because "the customer has
   not opened it yet" and "the customer said no" call for completely different
   next moves and both otherwise look like silence. */
.jv-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-2); }
.jv-head b { display: block; font-size: var(--t-sm); }
.jv-head .hint { display: block; margin-top: var(--sp-1); max-width: 60ch; }
.jv-empty { padding: var(--sp-3) 0; font-size: var(--t-sm); color: var(--text-muted); }
.jv-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; border-top: 1px solid var(--border); }
.jv-main { flex: 1; min-width: 0; }
.jv-title { font-size: var(--t-sm); }
.jv-trail { font-size: var(--t-xs); color: var(--text-muted); margin-top: var(--sp-1); }
/* State is named in the text as well as coloured — the row still reads
   correctly in greyscale and to a colour-blind reader (ui_ux_audit.md §1). */
.jv-trail.jv-ok { color: var(--ok); }
.jv-trail.jv-bad { color: var(--danger); }
.jv-amt { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
.jv-acts { display: flex; gap: var(--sp-1); flex-shrink: 0; }

/* The editor's shell.

   The editor is appended to <body> rather than into the job modal, so it sits
   outside .sched-modal-body and inherits none of that modal's field styling.
   It was written against books.css's .bk-overlay/.bk-modal, which scheduler.html
   does not load — so the overlay opened with no position and no ground, laid
   itself out below the fold, and read as the button doing nothing at all.
   Everything it needs is therefore declared here, against this page's tokens. */
#jvModal {
  position: fixed; inset: 0;
  z-index: calc(var(--z-modal, 1000) + 4);   /* above the job modal that opens it */
  display: none;                             /* the script sets flex to show it */
  align-items: center; justify-content: center;
  padding: var(--sp-4);
  background: rgba(0,0,0,.5);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
#jvModal .bk-modal {
  width: 100%; max-height: 88vh; overflow-y: auto;
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg, 14px);
  box-shadow: var(--glass-shadow);
  color: var(--text-primary);
}
#jvModal h3 { margin: 0 0 var(--sp-4); font-size: var(--t-lg); display: flex; align-items: center; gap: var(--sp-2); }
#jvModal h3 i { color: var(--accent); }
#jvModal .lbl { display: block; margin: var(--sp-3) 0 var(--sp-1); font-size: var(--t-sm); font-weight: 600; }
#jvModal .lbl .hint { font-weight: 400; color: var(--text-muted); }
#jvModal input,
#jvModal textarea {
  width: 100%; box-sizing: border-box;
  padding: var(--sp-2) var(--sp-3);
  font-family: inherit; font-size: var(--t-sm);
  color: var(--text-primary);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: 9px;
}
#jvModal textarea { resize: vertical; }
#jvModal input:focus,
#jvModal textarea:focus { outline: none; border-color: var(--accent); }
#jvModal .link {
  display: inline-block; margin-top: var(--sp-2);
  padding: 0; background: none; border: 0;
  font-family: inherit; font-size: var(--t-sm); color: var(--accent);
  cursor: pointer;
}
#jvModal .link:hover { text-decoration: underline; }
#jvModal .bk-modal-actions { display: flex; margin-top: var(--sp-4); }
#jvModal .bk-right { display: flex; gap: var(--sp-2); margin-left: auto; }

/* The editor. Five columns collapsing to a stack on a phone, because this gets
   filled in on one as often as at a desk. */
.jv-modal { max-width: 40rem; }
.jv-ehead, .jv-erow { display: grid; grid-template-columns: 1fr 4.5rem 4.5rem 6rem 2rem; gap: var(--sp-1); align-items: center; }
.jv-ehead { margin-top: var(--sp-3); font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); }
.jv-erow { margin-top: var(--sp-1); }
.jv-erow input { min-width: 0; }
.jv-etotal { display: flex; justify-content: space-between; align-items: baseline; margin-top: var(--sp-3); padding-top: var(--sp-2); border-top: 1px solid var(--border); font-size: var(--t-sm); }
.jv-etotal b { font-size: var(--t-lg); font-variant-numeric: tabular-nums; }
@media (max-width: 560px) {
  .jv-ehead { display: none; }
  .jv-erow { grid-template-columns: 1fr 1fr; }
  .jv-erow .jv-desc { grid-column: 1 / -1; }
  .jv-row { flex-wrap: wrap; }
  .jv-main { flex: 1 1 100%; }
}

/* ── Board signals (feature_sched_board_signals, signals.js) ──
   Comms state and the no-technician marker ride in the chip's glyph strip next
   to priority / crew / parts. Each is icon + title text, never colour alone. */
.sched-app .sched-sig-comms,
.sched-app .sched-sig-unassigned { font-size: 11px; vertical-align: -1px; }
.sched-app .sched-sig-comms.is-ok   { color: var(--st-complete); }
.sched-app .sched-sig-comms.is-wait { color: color-mix(in srgb, var(--text-primary) 55%, transparent); }
.sched-app .sched-sig-comms.is-ask  { color: var(--st-in_progress); }
.sched-app .sched-sig-unassigned    { color: var(--sc-unassigned, var(--st-in_progress)); }
.sched-app .sched-sig-comms-row { display: inline-flex; align-items: center; gap: var(--sp-1); }
.sched-app .sched-sig-comms-row.is-ok   { color: var(--st-complete); }
.sched-app .sched-sig-comms-row.is-wait { color: color-mix(in srgb, var(--text-primary) 70%, transparent); }
.sched-app .sched-sig-comms-row.is-ask  { color: var(--st-in_progress); }
/* Days a tray card has waited for a technician. */
.sched-app .sched-unsched-age {
  margin-left: auto;
  font-size: 10px; font-weight: 700; line-height: 1.4;
  padding: 0 var(--sp-1_5); border-radius: 999px;
  background: color-mix(in srgb, var(--sc-unassigned, var(--st-in_progress)) 18%, transparent);
  color: var(--sc-unassigned, var(--st-in_progress));
  font-variant-numeric: tabular-nums;
}
.sched-app .sched-att-chip.parts i { color: var(--st-in_progress); }

/* ── Day flow (feature_sched_dayflow, dayflow.js) ──
   The exceptions rail replaces the needs-attention strip in the same slot above
   the board: one row per problem, a count, and a click that filters the board
   to it. Rows are buttons, so the whole row is the target — the dismiss X is a
   separate control at the end and never swallows the click. */
.sched-app .sched-attention.sched-dayflow {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sp-2) var(--sp-3);
}
.sched-app .sched-df-rows { display: flex; flex-wrap: wrap; gap: var(--sp-1_5); align-items: center; }
.sched-app .sched-df-row {
  display: inline-flex; align-items: stretch;
  border: 1px solid var(--border); border-radius: var(--radius-sm, 6px);
  background: var(--card); overflow: hidden;
}
.sched-app .sched-df-row.is-on { border-color: var(--app-accent); box-shadow: 0 0 0 1px var(--app-accent); }
.sched-app .sched-df-main {
  display: inline-flex; align-items: center; gap: var(--sp-1_5);
  padding: var(--sp-1) var(--sp-2); border: 0; background: transparent;
  color: var(--text-primary); font-size: 12.5px; cursor: pointer;
}
.sched-app .sched-df-main:hover { background: color-mix(in srgb, var(--app-accent) 10%, transparent); }
.sched-app .sched-df-main i { font-size: 14px; color: var(--app-danger); }
.sched-app .sched-df-n { font-weight: 700; font-variant-numeric: tabular-nums; }
.sched-app .sched-df-lbl { color: var(--text-secondary); }
.sched-app .sched-df-x {
  display: inline-flex; align-items: center; padding: 0 var(--sp-1_5);
  border: 0; border-left: 1px solid var(--border); background: transparent;
  color: var(--text-muted); cursor: pointer; font-size: 12px;
}
.sched-app .sched-df-x:hover { background: color-mix(in srgb, var(--app-danger) 14%, transparent); color: var(--text-primary); }
.sched-app .sched-df-more {
  border: 1px dashed var(--border); border-radius: var(--radius-sm, 6px);
  background: transparent; color: var(--text-muted);
  padding: var(--sp-1) var(--sp-2); font-size: 12px; cursor: pointer;
}
.sched-app .sched-df-clear { display: flex; align-items: center; gap: var(--sp-1_5); font-size: 12.5px; color: var(--text-secondary); }
.sched-app .sched-df-clear i { color: var(--st-complete); font-size: 15px; }
.sched-app .sched-attention.sched-dayflow.is-clear { border-color: var(--border); }
.sched-app .sched-df-acts { display: flex; gap: var(--sp-1_5); margin-left: auto; }
.sched-app .sched-df-act {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  border: 1px solid var(--app-accent); border-radius: var(--radius-sm, 6px);
  background: color-mix(in srgb, var(--app-accent) 12%, transparent);
  color: var(--text-primary); padding: var(--sp-1) var(--sp-2_5, 10px);
  font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.sched-app .sched-df-act:hover { background: color-mix(in srgb, var(--app-accent) 22%, transparent); }
.sched-app .sched-df-act.is-done { border-color: var(--st-complete); background: color-mix(in srgb, var(--st-complete) 12%, transparent); }
.sched-app .sched-df-act.is-done i { color: var(--st-complete); }

/* The publish / close sheet. */
.sched-df-body { display: flex; flex-direction: column; gap: var(--sp-3); }
.sched-df-lead { margin: 0; color: var(--text-secondary); font-size: 13.5px; }
.sched-df-check { display: flex; flex-direction: column; gap: var(--sp-1); }
.sched-df-check-row {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2); border-radius: var(--radius-sm, 6px);
  background: var(--card); font-size: 13px; color: var(--text-secondary);
}
.sched-df-check-row i { font-size: 15px; color: var(--text-muted); }
.sched-df-check-row.is-warn i { color: var(--app-danger); }
.sched-df-check-row.is-ok i { color: var(--st-complete); }
.sched-df-sec { display: flex; flex-direction: column; gap: var(--sp-1); }
.sched-df-sec-t {
  display: flex; align-items: center; gap: var(--sp-1_5);
  font-size: 12px; font-weight: 700; letter-spacing: .02em;
  text-transform: uppercase; color: var(--text-muted);
}
.sched-df-job {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-2); border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px); background: var(--card); flex-wrap: wrap;
}
.sched-df-job-name {
  border: 0; background: transparent; padding: 0; cursor: pointer;
  color: var(--text-primary); font-size: 13.5px; font-weight: 600; text-align: left;
}
.sched-df-job-name:hover { color: var(--app-accent); }
.sched-df-job-acts { display: flex; gap: var(--sp-1); }
.sched-df-foot { display: flex; justify-content: flex-end; gap: var(--sp-2); }

/* ── Day by technician + colour-by (feature_sched_techday, techday.js) ──
   The toolbar segments. Same segmented-control language as the view switch, one
   step quieter — these change how the board reads, not what it shows. */
/* The day-layout and colour segments live in hub/css/dispatch.css, beside the
   view switch and date stepper they have to match to the pixel. Keeping them
   here meant copying .sviews's geometry across two files, which is how the
   three controls drifted into three different heights in the first place. */

/* Column heads: a technician, not a date. */
.sched-app .sched-tg-bytech .sched-td-head {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-px);
  padding: var(--sp-1_5) var(--sp-1);
}
.sched-app .sched-td-av {
  width: 24px; height: 24px; border-radius: 50%; display: inline-grid; place-items: center;
  font-size: 10px; font-weight: 700; color: #fff;
}
.sched-app .sched-td-name {
  font-size: 11.5px; font-weight: 600; color: var(--text-primary);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sched-app .sched-td-load { font-size: 10px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.sched-app .sched-tg-bytech .sched-td-head.is-unassigned .sched-td-name { color: var(--sc-unassigned, var(--text-primary)); }
.sched-app .sched-tg-bytech .sched-td-head.is-onleave { opacity: .7; }
/* A column whose technician is off, striped like the Timeline lane so the two
   views say "unavailable" the same way. */
.sched-app .sched-tg-bytech .sched-tg-col.is-onleave {
  background-image: repeating-linear-gradient(45deg, transparent 0 10px,
    color-mix(in srgb, var(--text-muted) 12%, transparent) 10px 12px);
}
.sched-app .sched-td-leave {
  position: absolute; top: var(--sp-2); left: 50%; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: 11px; font-weight: 600; color: var(--text-muted);
  background: var(--card); border: 1px solid var(--border);
  border-radius: 999px; padding: var(--sp-px) var(--sp-2); pointer-events: none; z-index: 3;
}

/* ── Capacity (feature_sched_capacity, capacity.js) ──
   One meter, used by the Timeline lane label and the day-by-technician column
   head. The reserve is drawn as a marked-off tail of the bar so "what is left
   to plan with" is a length, not a subtraction. State is carried by the fill
   colour AND by an icon in the label, never by colour alone. */
.sched-app .sched-cap-bar {
  position: relative; display: block; height: 3px; width: 70px;
  background: var(--border); border-radius: 2px; overflow: hidden;
}
.sched-app .sched-cap-fill { position: absolute; inset: 0 auto 0 0; background: var(--app-accent); }
.sched-app .sched-cap-reserve {
  position: absolute; top: 0; right: 0; bottom: 0;
  background: repeating-linear-gradient(45deg, transparent 0 2px,
    color-mix(in srgb, var(--text-muted) 45%, transparent) 2px 4px);
}
.sched-app .sched-cap.is-high  .sched-cap-fill { background: var(--st-in_progress); }
.sched-app .sched-cap.is-reserve .sched-cap-fill { background: var(--st-in_progress); }
.sched-app .sched-cap.is-reserve .sched-swim-pct { color: var(--st-in_progress); }
.sched-app .sched-cap.is-over  .sched-cap-fill { background: var(--app-danger); }
.sched-app .sched-cap.is-over  .sched-swim-pct { color: var(--app-danger); }
/* Column-head variant: the number leads, the bar sits under it. */
.sched-app .sched-tg-bytech .sched-cap {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-px);
}
.sched-app .sched-tg-bytech .sched-cap .sched-swim-pct { font-size: 10px; }
.sched-app .sched-tg-bytech .sched-cap-bar { width: 54px; }
/* Hours outside a technician's shift, in their own column. */
.sched-app .sched-cap-offshift {
  position: absolute; left: 0; right: 0; pointer-events: none; z-index: 1;
  background: color-mix(in srgb, var(--text-muted) 9%, transparent);
}

/* ── Selection & keyboard (feature_sched_power, selection.js) ──
   A picked chip carries a ring, not a fill: the fill is already saying which
   technician owns the job, and the status stripe is already saying where it is
   up to. The ring is the only channel left that is not spoken for. */
.sched-app #schedulerCalendar [data-job-id].is-picked {
  outline: 2px solid var(--app-accent);
  outline-offset: 1px;
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--app-accent) 22%, transparent);
}
/* The action bar for a selection made outside the List view. Floats clear of
   the board rather than pushing it, so picking a job never moves the chip you
   were about to pick next. */
.sched-app .sched-selbar {
  position: fixed; left: 50%; bottom: var(--sp-4); transform: translateX(-50%);
  z-index: 60; display: flex; flex-direction: column; gap: var(--sp-1_5);
  padding: var(--sp-2) var(--sp-3);
  background: var(--elev-3, var(--card)); border: 1px solid var(--border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-3, 0 18px 46px -12px rgba(0,0,0,.66));
  max-width: min(94vw, 940px);
}
.sched-app .sched-selbar .sched-bulkbar {
  margin: 0; padding: 0; border: 0; background: transparent;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1_5);
}
.sched-app .sched-selbar-keys {
  font-size: 10.5px; color: var(--text-muted); text-align: center;
}
.sched-app .sched-selbar-keys kbd {
  font-size: 9.5px; padding: 0 var(--sp-1); border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--card);
}
@media (max-width: 720px) {
  .sched-app .sched-selbar { left: var(--sp-2); right: var(--sp-2); transform: none; max-width: none; }
  .sched-app .sched-selbar-keys { display: none; }
}

/* ── Ranked assignment (feature_sched_smart_assign, assign.js) ──
   The popover becomes two lines per row: who, and why they are where they are.
   The reason is the whole point — a ranking nobody can check is a ranking
   nobody trusts — so it gets real space rather than a tooltip. */
.sched-app .sched-qa-pop-ranked { min-width: 250px; max-width: 320px; }
.sched-app .sched-qa-ranked {
  align-items: flex-start; gap: var(--sp-2); padding: var(--sp-1_5) var(--sp-2);
}
.sched-app .sched-qa-ranked .sched-qa-dot { margin-top: var(--sp-1); flex: none; }
.sched-app .sched-qa-main { display: flex; flex-direction: column; gap: var(--sp-px); min-width: 0; text-align: left; }
.sched-app .sched-qa-why {
  font-size: 10.5px; color: var(--text-muted); line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis;
}
.sched-app .sched-qa-best {
  font-size: 9px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--app-accent); border: 1px solid color-mix(in srgb, var(--app-accent) 45%, transparent);
  border-radius: 999px; padding: 0 var(--sp-1); vertical-align: 1px;
}
/* The first three are the suggestion; the rest are the rest. */
.sched-app .sched-qa-ranked.is-top { background: color-mix(in srgb, var(--app-accent) 7%, transparent); }
.sched-app .sched-qa-ranked.is-out { opacity: .55; }
.sched-app .sched-qa-ranked.is-out .sched-qa-why { color: var(--app-danger); }

/* ── Lane state (feature_sched_lane_state, lanestate.js) ──
   What this person is doing right now, under their name. Icon plus words, in
   the muted register — it is a reading, not an alarm; only "over" earns colour. */
.sched-app .sched-lane-state {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: 10px; color: var(--text-muted); line-height: 1.4;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis; max-width: 100%;
}
.sched-app .sched-lane-state i { font-size: 11px; }
.sched-app .sched-lane-state.is-onsite i { color: var(--st-in_progress); }
.sched-app .sched-lane-state.is-driving i { color: var(--st-en_route); }
.sched-app .sched-tg-bytech .sched-lane-state { justify-content: center; }

/* "App open on their phone" (feature_tech_presence). Present-only: there is no
   offline variant, because a phone out of signal is not a tech who has gone
   home, so the pip's absence means "unknown" rather than "away". Sized to sit
   beside the lane state without competing with it — this is a reassurance, not
   an alert, and it must not read as a status the dispatcher has to act on.
   The dot is a styled span, deliberately NOT an icon: the Tabler webfont this
   page loads ships no filled variants, so ti-point-filled rendered as nothing
   and the pip was invisible while presence worked perfectly. */
.sched-app .sched-lane-live {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  margin-right: var(--sp-1); background: var(--st-complete);
  vertical-align: middle; flex: none; line-height: 1;
}
@media (prefers-reduced-motion: no-preference) {
  .sched-app .sched-lane-live { animation: schedLanePulse 2.4s ease-in-out infinite; }
  @keyframes schedLanePulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
}

/* Crew rail: the technician's name with their live state under it.

   The state used to exist only on a lane label, which lives in Timeline and
   Day-by-technician and only on today's column — so in Week, where most of the
   week is actually spent, the board could not say what anybody was doing. The
   rail is on screen in every view, which makes it the one place the question is
   always answerable.

   :empty collapses the second line entirely, so a technician with nothing on
   today gets the single-line row the rail has always had. Nothing is reserved
   for a state that is usually absent. */
.sched-app .sched-tech-txt {
  flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center;
}
.sched-app .sched-tech-txt .sched-tech-name { flex: none; }
.sched-app .sched-tech-sub { display: block; min-width: 0; }
.sched-app .sched-tech-sub:empty { display: none; }
/* The same "app open" dot on the Crew rail, as a badge ON the avatar.

   It sat between the avatar and the name first, and that was wrong: an online
   technician's name was pushed 15px right while an offline one's was not, so a
   column of names went ragged and re-ragged itself as phones came and went.
   Out of flow, it cannot move anything, and the names keep their full width —
   which the longest ones need, they already ellipsis at this rail width.

   Hidden rather than absent so the repaint stays a class toggle on a node that
   is already there: the rail is a click target carrying the edit pencil, and it
   must not be rebuilt under a dispatcher's cursor.

   The ring is what makes it legible. Avatars are user-chosen colours, so a bare
   green dot vanishes on a green avatar; a 2px ring in the card colour cuts it
   out of whatever it lands on. Offsets are logical (inset-inline-*) because
   they place a badge against a corner rather than set spacing rhythm — --sp-*
   tokens do not apply to a 1px optical nudge. */
.sched-app .sched-tech-av { position: relative; overflow: visible; }
.sched-app .sched-tech-live {
  position: absolute; inset-inline-end: -1px; inset-block-end: -1px;
  display: none; width: 8px; height: 8px; border-radius: 50%;
  background: var(--st-complete);
  box-shadow: 0 0 0 2px var(--card);
}
.sched-app .sched-tech-live.is-on { display: block; }
@media (prefers-reduced-motion: no-preference) {
  .sched-app .sched-tech-live.is-on { animation: schedLanePulse 2.4s ease-in-out infinite; }
}

/* Drop validity, while the pointer is still down. The existing
   .sched-drop-active highlight stays; this only adds the verdict. */
.sched-app .sched-drop-warn {
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--st-in_progress) 70%, transparent);
}
.sched-app .sched-drop-block {
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--app-danger) 70%, transparent);
  background-image: repeating-linear-gradient(45deg, transparent 0 6px,
    color-mix(in srgb, var(--app-danger) 12%, transparent) 6px 12px);
}

/* ── Board filters (feature_sched_filters, boardfilter.js) ── */
.sched-app .sched-bf-btn.is-on { border-color: var(--app-accent); color: var(--app-accent); }
.sched-app .sched-bf-n {
  display: inline-grid; place-items: center; min-width: 15px; height: 15px;
  margin-left: var(--sp-1); padding: 0 var(--sp-1); border-radius: 999px;
  background: var(--app-accent); color: var(--btn-primary-ink, #fff);
  font-size: 9.5px; font-weight: 700;
}
.sched-app .sched-bf-pop, .sched-bf-pop {
  position: fixed; z-index: 70; min-width: 250px; max-width: 340px;
  display: flex; flex-direction: column; gap: var(--sp-2_5);
  padding: var(--sp-3); background: var(--elev-3, var(--card));
  border: 1px solid var(--border); border-radius: var(--radius-md);
  box-shadow: var(--shadow-3, 0 18px 46px -12px rgba(0,0,0,.66));
  max-height: 70vh; overflow-y: auto;
}
.sched-bf-group { display: flex; flex-direction: column; gap: var(--sp-1_5); }
.sched-bf-t {
  font-size: 10px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-muted);
}
.sched-bf-chips { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.sched-bf-chip {
  border: 1px solid var(--border); border-radius: 999px; background: var(--card);
  color: var(--text-secondary); font-size: 12px; padding: var(--sp-1) var(--sp-2);
  cursor: pointer;
}
.sched-bf-chip:hover { color: var(--text-primary); border-color: var(--app-accent); }
.sched-bf-chip.is-on { background: var(--app-accent); border-color: var(--app-accent); color: var(--btn-primary-ink, #fff); }
.sched-bf-foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  border-top: 1px solid var(--border); padding-top: var(--sp-2);
}
.sched-bf-sum { font-size: 11.5px; color: var(--text-muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* ── Day-flow rail: quiet panel, loud rows ──
   The rail inherited .sched-attention's red banner. Alarm belongs on the row
   that is actually wrong — every row carries its own icon — not on the panel
   around it, and least of all around the words "nothing needs attention". */
.sched-app .sched-attention.sched-dayflow {
  border-color: var(--border);
  background: var(--card);
  border-radius: var(--radius-md);
  padding: var(--sp-2) var(--sp-2_5);
}
/* Clear: one quiet line, not a banner. It still renders, because an empty
   strip reads as "not loaded yet" — which is the one thing it must not mean. */
.sched-app .sched-attention.sched-dayflow.is-clear {
  border-color: transparent;
  background: transparent;
  padding: var(--sp-1) 0;
  margin-bottom: var(--sp-2);
}
.sched-app .sched-dayflow.is-clear .sched-df-clear { font-size: 12px; }
.sched-app .sched-dayflow.is-clear .sched-df-clear i { font-size: 14px; }

/* A colour-key entry is not a control. It inherited .sched-legend-item's pill —
   border, fill and a hover that lit it up — so a swatch you cannot click looked
   and behaved exactly like a status chip you can. Strip it back to a swatch and
   a word, and give it no hover at all. */
.sched-app .sched-legend-item.is-key,
.sched-app .sched-legend-item.is-key:hover {
  cursor: default; border-color: transparent; background: transparent;
  color: var(--text-muted); padding-left: 0; padding-right: var(--sp-2);
}

/* ── Co-dispatching: colleagues on the same board (feature_codispatch) ──────
   Every marker here is decoration over somebody else's intent, so all of it
   is pointer-events:none — a peer's ghost or badge must never intercept the
   drag or the click of the person actually working the board. */
.sched-peers { display: inline-flex; align-items: center; margin-inline-end: var(--sp-2); }
.sched-peers:empty { display: none; }
.sched-peer-av {
  width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 10px; font-weight: 700; color: #fff;
  background: var(--peer, #64748b);
  box-shadow: 0 0 0 2px rgba(0,0,0,.35);
  margin-inline-start: calc(-1 * var(--sp-1_5));
}
.sched-peer-av:first-child { margin-inline-start: var(--sp-0); }
.sched-peer-av.is-more { background: #64748b; }

/* A colleague is dragging this job right now — dim the card it is leaving. */
.sched-app .sched-peer-moving { opacity: .38; }

/* A colleague has this job open in the editor. Advisory: the card still
   drags and still opens. */
.sched-app .sched-peer-claimed { box-shadow: inset 0 0 0 2px var(--peer, #38bdf8); }
.sched-peer-badge {
  display: inline-grid; place-items: center; flex: 0 0 auto;
  width: 15px; height: 15px; border-radius: 50%;
  margin-inline-start: var(--sp-1);
  font-size: 8px; font-weight: 700; color: #fff;
  background: var(--peer, #64748b);
  vertical-align: middle; pointer-events: none;
}

/* The ghost: where they are about to drop it. */
.sched-peer-ghost {
  pointer-events: none; z-index: 6;
  display: flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-0_5) var(--sp-1_5);
  border: 1px dashed var(--peer, #38bdf8);
  border-radius: 6px;
  background: color-mix(in srgb, var(--peer, #38bdf8) 18%, transparent);
  font-size: 11px; font-weight: 600;
  overflow: hidden; white-space: nowrap;
}
.sched-peer-ghost.is-abs { position: absolute; left: var(--sp-1); right: var(--sp-1); }
.sched-peer-ghost.is-swim { right: auto; top: var(--sp-1); }
.sched-peer-ghost-who {
  flex: 0 0 auto;
  width: 14px; height: 14px; border-radius: 50%;
  display: inline-grid; place-items: center;
  font-size: 8px; color: #fff; background: var(--peer, #38bdf8);
}
.sched-peer-ghost-name { overflow: hidden; text-overflow: ellipsis; }
