/* ── Standalone shell additions ──
   app.css is a verbatim copy of AR Pro's design tokens and components, so
   the Scheduling views look exactly as they did inside that app. Two things
   it does NOT carry, added here:

   1. `.tbl` — scheduling.js uses this class as a plain hook and styles its
      own cells inline; the Outlets table in app.js has no such inline
      styling, so the table needs a real rule.
   2. `#tbh`/`#tbp` — the topbar's title/subtitle were styled inline in AR
      Pro's index.html markup rather than in its stylesheet. */

#tbh { font-size: 15px; font-weight: 700; color: var(--navy); }
#tbp { font-size: 11.5px; color: var(--g600); margin-top: 1px; }

.tbl { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.tbl th {
  text-align: left; font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .4px; color: var(--g400); padding: 8px var(--md);
  border-bottom: 1px solid var(--g100); white-space: nowrap;
}
.tbl td { padding: 8px var(--md); border-bottom: 1px solid var(--g50); color: var(--g800); }
.tbl tbody tr:hover { background: var(--g50); }
.tbl .num { text-align: right; font-variant-numeric: tabular-nums; }

/* Outlets -> Roster drill-down (app.js): the whole row is clickable. */
.outlet-row { cursor: pointer; }
.outlet-leader-link { color: var(--navy); font-weight: 600; border-bottom: 1px dashed var(--g300); }
.outlet-row:hover .outlet-leader-link { border-bottom-color: var(--navy); }

/* The Outlets search (app.js outletsInit). The design system's search field:
   tinted fill, no border, pill, 42px, a 16px leading icon, 13px text. */
.outlets-bar { align-items: center; flex-wrap: wrap; margin-bottom: var(--sm); }
.outlets-bar-gap { flex: 1 1 0; }
.outlets-search {
  display: flex; align-items: center; gap: 8px; height: 42px; padding: 0 16px;
  flex: 0 1 380px; min-width: 220px; border-radius: var(--rpill); background: var(--tint);
}
.outlets-search:focus-within { box-shadow: 0 0 0 3px rgba(22,39,122,.08); }
.outlets-search svg { width: 16px; height: 16px; fill: var(--g400); flex: 0 0 auto; }
.outlets-search input {
  flex: 1 1 auto; min-width: 0; border: 0; outline: 0; background: transparent;
  font: inherit; font-size: 13px; color: var(--g800);
}
.outlets-search input::placeholder { color: var(--g400); }
/* The header stays put while the rows scroll under it. */
.outlets-tbl thead th { position: sticky; top: 0; z-index: 1; background: var(--white); }
.outlets-import { margin-top: var(--xl); }
.outlets-import summary {
  cursor: pointer; font-size: 13px; font-weight: 700; color: var(--navy); margin-bottom: var(--md);
}

/* ════════ THE DOCK ════════
   The app's whole navigation surface, floating at the right edge. Before
   this there were three separate things: a left sidebar (.sb) for the views,
   an in-flow tab strip beside the roster grid for its sub-tabs, and a
   bottom-left box for the warning key. They are one bar now.

   It reuses the tab strip's own component classes (.bi-tabstrip-wrap,
   .bi-tabgroup, .bi-tab) rather than declaring a new look, so the
   collapse-to-a-rail-and-expand-on-hover behaviour and the active marker
   come along unchanged from app.css. All this adds is where it sits. */
.dock {
  position: fixed;
  /* LEFT since 2026-09-24 — swapped with the Assistant rail at the manager's
     instruction. Where to go now sits on the left, what to do on the right. */
  left: var(--lg);
  top: 50%;
  transform: translateY(-50%);
  /* Above every floating panel (plot 60, assistant 66, over-target 70): the
     dock is where you go next, so when it slides open it covers them, and
     they blur behind it like the page does. It was 40, under the plot panel. */
  z-index: 80;
  /* 8px from the top and bottom of the window, not 24 (2026-09-24): the dock
     holds every destination and key, and at 24px it came up ~40px short on an
     ordinary laptop window and scrolled its own last tabs out of sight. */
  max-height: calc(100vh - 2 * var(--sm));
}
/* Opening the warning key pins the bar open. Otherwise the panel sits at a
   fixed offset from the right edge while the bar it belongs to slides in and
   out from under the pointer — and hovering the bar would cover the panel.
   app.css expands the strip on :hover alone, so pinned-but-not-hovered has
   to repeat what that state does, or the bar sits 220px wide with its labels
   still collapsed to nothing. Same specificity, later sheet — this wins. */
/* app.css's tab strip is `overflow: hidden` (it has a width transition to
   clip). As a fixed rail with a max-height that is a trap: on a short window
   the dock runs out of room and silently swallows whatever is at the bottom
   — which, since the full-screen control was added there, meant the last
   button became unreachable at 557px of viewport. Let it scroll instead;
   horizontal stays hidden so the expand animation still clips. */
.dock { overflow-x: hidden; overflow-y: auto; scrollbar-width: thin; }

/* Hovering the dock open blurs the page behind it — ported from Finance
   Ecosystem (AR Pro index.html, `.sb:hover ~ .main`), same values, same
   reason: the eye stays on the list you are choosing from, and the half-covered
   screen underneath stops reading as part of it.

   One difference in the selector. AR Pro's sidebar comes BEFORE .main, so a
   sibling combinator reaches it; this dock comes AFTER, and `~` only looks
   forward. `:has()` asks the question from the body instead.

   Hover only, not the pinned state: a dock pinned open by Add staff or Leave is
   a form being filled in against the shift plot, and blurring the plot would
   hide what the form is about. Kept to a 2px blur because a filter on a
   container this size repaints it, and a month of cards is a lot of paint. */
/* The floating panels blur with the page. They live outside .main (appended to
   the body), so they are named here — the plot panel especially, which sits
   right beside the dock and is what the opening dock slides over. */
/* A veil, not a filter (2026-09-24). The blur used to be a `filter` on .main
   and every panel, which repaints the whole month of cards on every frame of
   the fade — and it ran at the same moment the bar was sliding, which is what
   made the slide stutter. Now one fixed layer with `backdrop-filter` sits
   between the page (panels top out at 70) and the two bars (80), and only its
   opacity animates, which the GPU does without repainting anything. The
   colour stands in for the old `opacity: .75`. */
body::after {
  content: ''; position: fixed; inset: 0; z-index: 75; pointer-events: none;
  background: rgba(244, 248, 251, .28);
  -webkit-backdrop-filter: blur(2px) saturate(.9); backdrop-filter: blur(2px) saturate(.9);
  opacity: 0; transition: opacity .2s ease .12s;
}
body:has(.dock:hover:not(.is-open))::after,
body:has(.assist-rail:hover)::after { opacity: 1; transition-delay: .06s; }
/* The other bar goes under the veil with the page, as it did under the blur. */
body:has(.dock:hover:not(.is-open)) .assist-rail,
body:has(.assist-rail:hover) .dock { z-index: 74; }
@media (prefers-reduced-motion: reduce) { body::after { transition: none; } }
/* On a phone the dock is a bottom bar that never widens over the page. */
@media (max-width: 640px) {
  body::after { display: none; }
}

.dock.is-open { width: 220px; }
.dock.is-open .nb-label { opacity: 1; width: auto; }
.dock.is-open .bi-tabgroup-label { opacity: 1; }
.dock.is-open .bi-tab { justify-content: flex-start; padding-left: var(--md); padding-right: var(--md); }

/* The rail is fixed, so the page has to leave room for it; without this the
   roster grid runs underneath. The collapsed 76px, not the expanded 220px —
   the expansion is transient and hovering over content is the point of it. */
.page { padding-right: calc(var(--xl) + 76px); }
/* And the same on the left for the Assistant rail, its twin. */
.page { padding-left: calc(var(--xl) + 76px); }

/* ── the warning key's panel ──
   A normal card, parked to the left of the expanded bar. Deliberately not
   inside the <aside>: the bar is 76px wide and clips its overflow, and the
   legend needs 300px and its own scrollbar. */
.legend-panel {
  position: fixed;
  left: calc(var(--lg) + 220px + var(--sm));
  top: 50%;
  transform: translateY(-50%);
  z-index: 79;           /* just under the dock it belongs to — see .dock */
  width: 300px;
  max-height: min(70vh, 520px);
  overflow-y: auto;
  background: var(--white);
  border: 1px solid var(--g100);
  border-radius: var(--rlg);
  box-shadow: var(--sf);
  padding: var(--md);
}
/* app.css styles the legend's rows under `.ac-legendbody`, the wrapper the
   old floating box had. The panel is a different container, so the same
   three rules are re-pointed at it here — values unchanged, and .ac-tag /
   .ac-crit / .ac-warn / .ac-info / .ac-ok still come straight from app.css.
   (Its .ac-legendbox and .ac-legendtoggle rules are dead now. They are left
   in place: that file is AR Pro's sheet, kept diffable, and it already
   carries plenty of components this app never renders.) */
.legend-panel .ac-legendtitle {
  font-size: 12px; font-weight: 800; color: var(--navy);
  letter-spacing: -.01em; margin: 0 2px 2px;
}
.legend-panel ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.legend-panel li { display: grid; grid-template-columns: 78px 1fr; gap: 7px; align-items: start; }
.legend-panel li em { font-style: normal; font-size: 10px; line-height: 1.35; color: var(--g600); }
.legend-panel .ac-ok { font-size: 13px; text-align: center; }
/* The Role key's rows carry a code, not a severity — one neutral tag style
   rather than app.css's red/amber/blue .ac-crit/.ac-warn/.ac-info. */
.legend-panel .rk-tag { background: var(--tint); color: var(--navy); border: 1px solid var(--g100); }
.legend-panel .ac-legendfoot {
  font-size: 10px; line-height: 1.45; color: var(--g400);
  margin: 10px 2px 0; padding-top: 8px; border-top: 1px solid var(--g100);
}

/* ── the panel as a form ──
 * Two of the four dock panels are forms rather than reference text: Add
 * staff and Leave. They get more width, because a leave entry alone is six
 * controls including two dates, and stacked at the reading width of the two
 * keys they turn into a column tall enough to need scrolling to reach its
 * own submit button.
 *
 * Fields stack with a label above each, reusing the header's `.fld`. That is
 * the actual gain in moving these out of the grid: as a row under the month
 * they were unlabelled dropdowns reading "— Religion —", where the only clue
 * to what a control was for was the placeholder inside it. */
/* the View as menu: one row per view, the current one marked */
.va-opts { display: flex; flex-direction: column; gap: 4px; }
.va-dms { max-height: 280px; overflow-y: auto; }
.va-opt {
  display: flex; justify-content: space-between; align-items: baseline; gap: 8px;
  width: 100%; text-align: left; padding: 7px 9px; cursor: pointer;
  border: 1px solid var(--g100); border-radius: var(--rsm); background: var(--white);
  font: inherit; color: var(--navy);
}
.va-opt:hover { border-color: var(--g200); background: var(--tint); }
.va-opt.is-on { border-color: var(--navy); box-shadow: inset 3px 0 0 var(--navy); }
.va-opt-l { font-size: 11.5px; font-weight: 700; }
.va-opt-s { font-size: 10px; color: var(--g600); white-space: nowrap; }
/* the three role rows read label-then-description, stacked */
.va-opts:not(.va-dms) .va-opt { flex-direction: column; align-items: flex-start; gap: 2px; }
.legend-panel.is-wide { width: 380px; left: calc(var(--lg) + 220px + var(--sm)); }
.pnl-note {
  font-size: 10.5px; line-height: 1.5; color: var(--g600);
  margin: 0 2px 10px; padding: 8px 10px;
  background: var(--tint); border-radius: var(--rmd);
}
.pnl-form { display: flex; flex-direction: column; gap: 9px; }
.pnl-form .fi { width: 100%; }
.pnl-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.pnl-form .btn { align-self: flex-start; margin-top: 2px; }
.pnl-row {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 8px;
  font-size: 11.5px; line-height: 1.4;
  padding: 7px 2px; border-bottom: 1px solid var(--g100);
}
.pnl-row .muted { font-size: 10px; }
/* Help under a field, not beside it. Only for settings somebody meets twice
   a year and will not remember the consequences of — the add-staff and leave
   fields say enough with a label. */
.pnl-hint { font-size: 10px; line-height: 1.5; color: var(--g400); margin: 4px 2px 0; }

/* ── the figure on the PT labour button ──
   The one number this app is asked for that is not on the grid. It rides on
   the button that opens its working, so the expanded rail answers "what does
   this month cost" without a click — which is what the header card used to
   do, at 540px of permanently covered roster instead of nothing. Sits under
   the label rather than beside it: a ringgit figure is 9 characters and the
   rail is 220px open, and a wrapped button label is worse than a second
   line that was always going to be one. */
.nb-sub {
  display: block; font-size: 10.5px; font-weight: 800; letter-spacing: -.01em;
  color: rgba(255,255,255,.72); font-variant-numeric: tabular-nums;
  margin-top: 1px; line-height: 1.2;
}
.nb-sub.is-ot { color: #FFC9C9; }   /* overtime in the total, same alarm as the +OT flag */
/* The label collapses to nothing with the rail; the figure has to go with
   it, or a stray "RM7,224.80" is left floating in a 76px column of icons. */
.dock:not(.is-open) .nb-sub { display: none; }
@media (hover: hover) {
  .dock:hover .nb-sub { display: block; }
  .dock:not(:hover):not(.is-open) .nb-sub { display: none; }
}

/* ── the pay estimate working (was PT labour) ──
   Three columns: what the hours are, how they were priced, what that came
   to. Aligned as a column of ringgit so the eye can add them up and check
   the total is the total — the point of showing a working at all. */
.cost-total { display: flex; align-items: baseline; gap: 8px; margin: 2px 2px 10px; }
.cost-total-v {
  font-size: 24px; font-weight: 800; color: var(--navy);
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
}
.cost-rows { display: flex; flex-direction: column; }
.cost-row {
  display: grid; grid-template-columns: 112px 1fr auto; gap: 8px; align-items: baseline;
  padding: 7px 2px; border-top: 1px solid var(--g100); font-size: 11.5px;
}
.cost-row-l { font-weight: 700; color: var(--navy); }
.cost-row-w { color: var(--g600); font-size: 10.5px; font-variant-numeric: tabular-nums; }
.cost-row-v { font-weight: 700; color: var(--navy); font-variant-numeric: tabular-nums; }
.cost-row.is-ot .cost-row-l, .cost-row.is-ot .cost-row-v { color: var(--err); }
.cost-row.is-sum { border-top-width: 2px; border-top-color: var(--navy); }

/* ── the pay estimate (2026-09-30) ──
   One collapsible row per person: name, role and rate, and the take-home on
   the right, where the eye lands. Overtime and holiday lines carry a gold
   edge, not the error red: extra pay is good news, not a fault. */
.pay-est { font-size: 9.5px; font-weight: 800; letter-spacing: .06em; color: var(--err); }
.pay-people { margin-top: 12px; }
.pay-person { border-top: 1px solid var(--g100); }
.pay-person > summary {
  display: grid; grid-template-columns: 1fr auto; gap: 0 8px; align-items: baseline;
  padding: 8px 2px; cursor: pointer; list-style: none;
}
.pay-person > summary::-webkit-details-marker { display: none; }
.pay-name { font-weight: 700; color: var(--navy); font-size: 12px; }
.pay-role { grid-column: 1; font-size: 10.5px; color: var(--g600); }
.pay-take { grid-column: 2; grid-row: 1 / span 2; font-variant-numeric: tabular-nums; color: var(--navy); }
.pay-person[open] { padding-bottom: 8px; }
.cost-row.is-extra { box-shadow: inset 3px 0 0 #E2BC5A; padding-left: 8px; }
.pay-rules { margin-top: 12px; border-top: 1px solid var(--g100); padding-top: 8px; }
.pay-rules > summary { cursor: pointer; font-weight: 700; color: var(--navy); font-size: 12px; }
.pay-rules-tbl { width: 100%; border-collapse: collapse; font-size: 10.5px; margin-top: 6px; }
.pay-rules-tbl th, .pay-rules-tbl td { text-align: left; padding: 5px 4px; border-top: 1px solid var(--g100); vertical-align: top; }
.pay-rules-tbl th { color: var(--g600); font-weight: 700; }
.pay-rules-tbl td.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; font-weight: 700; color: var(--navy); }

/* ── the dock has to fit ──
   Five groups and thirteen buttons is 725px of content against a rail that
   maxes out around 640px on a normal window, so the strip's own spacing —
   generous, and tuned for a five-item tab strip — has to come in. These are
   scoped to .dock so the component keeps its original metrics wherever else
   it is used. Measured: this reclaims 73px of the 84px overflow. */
.dock { gap: 10px; padding: var(--md) 0; }
.dock .bi-tabgroup { gap: 4px; }
.dock .bi-tab { padding-top: 5px; padding-bottom: 5px; }

/* The utility at the foot of the dock gets a rule above it — it is not one
   of the destinations, and without the line it reads as a sixth one.

   Pinned to the bottom of the scroll box, not merely last in it. Twice now a
   group has been added above it and pushed the full-screen control out of
   sight on a normal window — reachable only by scrolling a rail nobody
   expects to scroll. Sticky makes that structural rather than a thing to
   re-measure: however many groups arrive later, this one is on screen. It
   needs its own navy fill, or the buttons it overlaps show through. */
.dock-util {
  position: sticky; bottom: calc(-1 * var(--md)); z-index: 1;
  border-top: 1px solid rgba(255,255,255,.12);
  padding-top: var(--sm); padding-bottom: var(--md);
  margin-top: auto; background: var(--navy);
}

/* [hidden] is display:none in the UA sheet, which a class rule setting
   display:flex outranks — these two need an id's specificity to win. */
#dock-outlet[hidden], #dock-guide[hidden], #legend-panel[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) { .dock { transition: none; } }

/* app.css turns .bi-tabstrip-wrap into a full-width horizontal row below
   980px — right for the in-flow column it was written for, wrong for a fixed
   rail, which would become a 100%-wide bar lying across the page. Keep the
   rail, and keep its hover/pinned behaviour, which that block also undoes.
   (The Electron window's minWidth is 1100, so this is the browser's case.) */
@media (max-width: 980px) {
  /* !important only because the rule being undone is itself !important. */
  .dock { width: 76px !important; flex-direction: column; border-radius: var(--rlg); }
  .dock:hover, .dock.is-open { width: 220px !important; }
  .dock .bi-tabrow { flex-direction: column; }
  .dock:not(:hover):not(.is-open) .nb-label { opacity: 0; width: 0; }
  .dock:not(:hover):not(.is-open) .bi-tabgroup-label { opacity: 0; }
  .dock .bi-tab.active::after { left: 0; right: auto; top: 7px; bottom: 7px; width: 3px; height: auto; }
  /* The panel has to fit beside the pinned-open bar on a narrow window. */
  .legend-panel { width: min(300px, calc(100vw - 260px)); }
}

/* Arithmetic has no level and should not borrow a level's colour. Grey, and
   the left border stays the default .lvl-head grey rather than red/gold/navy. */
.lvl-none .lvl-num { background: var(--g100); color: var(--g400); }
.lvl-none .lvl-title { color: var(--g600); }

/* ════════ SETTINGS ════════
   One card, one row, one status vocabulary — for the statutory ceilings, the
   outlet's targets, this app's policy and the arithmetic alike.

   The law block was the most refined part of this page and it is now the
   pattern for all of it, because four sections that each looked slightly
   different taught that they were different KINDS of thing when the only real
   difference is who owns them. What still separates them is the level header's
   colour, the code in the row's gutter, and the lock on Level 1 — which is
   exactly the set of differences that matters.

   Classes were .law-* while only the law used them; .set-* now, since a class
   called "law" on a part-time costing row is a small lie that makes a page hard
   to read a year later. */

/* the level headers: colour carries precedence and nothing else */
.lvl-head {
  display: flex; align-items: center; gap: 12px;
  margin: 0 0 var(--md); padding: 10px 14px;
  border-radius: var(--rmd); border-left: 4px solid var(--g200);
  background: var(--white);
}
.lvl-head .lvl-num {
  font-size: 10px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  padding: 4px 8px; border-radius: var(--rpill); background: var(--g100); color: var(--g600);
  white-space: nowrap;
}
.lvl-title { font-size: 14px; font-weight: 700; color: var(--navy); }
.lvl-sub { font-size: 10.5px; color: var(--g400); margin-top: 1px; }
.lvl-1 { border-left-color: var(--err); }
.lvl-1 .lvl-num { background: var(--err-bg); color: var(--err); }
.lvl-2 { border-left-color: var(--gold-d); }
.lvl-2 .lvl-num { background: var(--gold-p); color: var(--gold-d); }
.lvl-3 { border-left-color: var(--navy); }
.lvl-none .lvl-num { background: var(--g100); color: var(--g400); }
.lvl-none .lvl-title { color: var(--g600); }

/* THE GRID. One shape for every section — law, outlet, system, arithmetic.
   Three columns on a wide window, two on a laptop, one on a narrow one.

   A TILE GRID (manager, 2026-09-23: "standardize those box sizes"). Every
   card is exactly one tile tall or exactly two, so every edge on the page
   lands on the same lines and the eye stops re-measuring boxes. Two things
   were tried the same day and rejected: rows that stretch to their tallest
   card (big empty boxes beside the surge card) and a masonry flow (no two
   boxes the same size).

   336px is the tile because the cards' natural heights fall into two
   clusters — about 200-335px and about 540-590px — and 336 holds the first
   in one tile and the second in two (2 x 336 + the 24px gap). Which cards
   take two is measured, not listed: schedulingTileFit() in scheduling.js.
   `dense` lets a one-tile card fill the hole a two-tile card leaves. */
.set-grid {
  --tile: 336px;
  display: grid; gap: var(--lg);
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: var(--tile);
  grid-auto-flow: row dense;
}
@media (max-width: 1180px) { .set-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* one column: nothing to line up against, so every card is its own height */
@media (max-width: 760px)  { .set-grid { grid-template-columns: minmax(0, 1fr); grid-auto-rows: auto; } }

/* The notes share the grid's measure rather than a narrower one of their own:
   a 860px paragraph above a full-width row of cards read as two different
   pages stacked. */
/* .pnl-note carries `margin: 0 2px` from the dock panel it was written for,
   which left every paragraph 2px inside the cards below it. */
.set-note { max-width: none; margin: 0 0 var(--lg); }

/* THE CARD. Same padding, same head, same fill, and the height of its row. */
.set-card {
  display: flex; flex-direction: column; height: 100%; min-width: 0;
  padding: var(--md) var(--lg) var(--lg);
}
.set-card-head { padding-bottom: 8px; border-bottom: 1px solid var(--g100); margin-bottom: 4px; }
.set-card-title {
  font-size: 13px; font-weight: 700; color: var(--navy); line-height: 1.35;
  display: flex; align-items: baseline; gap: 6px;
}
/* the same glyph the assistant shows for this rule's findings */
.set-card-ico { width: 15px; height: 15px; fill: currentColor; flex: 0 0 auto; align-self: center; }
.set-card-ref { font-size: 10px; color: var(--g400); margin-top: 3px; }
.set-card-ref code, .set-row-ref code { font-size: 10px; }
.set-card-why { font-size: 11px; line-height: 1.5; color: var(--g600); padding: 6px 0 2px; }

/* THE ROW. Label and reference left, value in a fixed slot right, always —
   which is what makes every value on the page share one right edge. */
.set-row {
  display: grid; grid-template-columns: minmax(0, 1fr) 108px;
  align-items: center; gap: 10px;
  padding: 7px 0; border-bottom: 1px solid var(--g100);
}
.set-row:last-child { border-bottom: none; }
.set-row-main { min-width: 0; }
.set-row-label { font-size: 11.5px; color: var(--g800); line-height: 1.35; }
.set-row-ref { font-size: 10px; color: var(--g400); margin-top: 2px; line-height: 1.35; }
.set-row-value { display: flex; align-items: center; justify-content: flex-end; gap: 4px; }
.set-row-none { font-size: 11px; color: var(--g400); }

/* A row whose control is too big for the value slot: label on top, the
   control full width under it (the Jumaat state picker). */
.set-row-stack { grid-template-columns: minmax(0, 1fr); gap: 6px; }
/* Beats .set-input's 72px for numbers, which sits later in this file: a
   description box takes the whole row (2026-10-01, it was a 72px column). */
/* Two cards that belong together, one above the other in one grid cell. */
.set-stack { display: flex; flex-direction: column; gap: var(--md, 16px); min-width: 0; }
.set-stack > .set-card { margin: 0; height: auto; flex: 0 0 auto; }
/* Measured at its natural height, like a card (schedulingTileFit). */
.set-stack.is-measuring { height: auto !important; align-self: start; }
.set-card .set-input.set-input-full { width: 100%; text-align: left; box-sizing: border-box; }
.set-note-box {
  min-height: 56px; resize: vertical; overflow: hidden;
  font: inherit; font-size: 11.5px; line-height: 1.45; padding: 6px 8px; white-space: pre-wrap;
}
.set-hp-lock { margin: 0 0 10px; }
.set-ops-sel { width: 108px; }
.set-row[hidden] { display: none; }
/* Locked: the track handles read as disabled, not as something to drag. */
.is-locked-section .set-brk-h { cursor: not-allowed; border-color: var(--g300); }

/* Each role: its code and fixed duty as a heading, its explanation under it. */
.set-rolelist { display: grid; gap: 10px; margin-top: 2px; }
.set-roleitem-h { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; font-size: 11.5px; color: var(--g800); }
.set-roleitem-code {
  min-width: 26px; padding: 1px 6px; border-radius: var(--rpill); text-align: center;
  background: var(--navy); color: #fff; font-size: 10.5px; font-weight: 700;
}
.set-roleitem-fixed { margin-left: auto; font-size: 10px; color: var(--g400); }

/* Where a statutory value came from, and who last moved it. */
.set-prov {
  margin-top: 8px; padding: 8px 10px; border-radius: var(--rsm);
  background: var(--tint); font-size: 10.5px; line-height: 1.5; color: var(--g600);
}
.set-prov-last { margin-top: 2px; font-weight: 600; color: var(--navy); }

/* Break entitlement on one track: zones coloured by the break each shift
   length earns, the two tier starts as handles, L5's trigger drawn across. */
.set-brk { margin-top: 6px; }
.set-brk-track {
  position: relative; height: 34px; border-radius: var(--rsm);
  background: var(--g50); border: 1px solid var(--g100);
}
.set-brk-zone {
  position: absolute; top: 0; bottom: 0; display: flex; align-items: center;
  justify-content: center; overflow: hidden; font-size: 10.5px; font-weight: 600; white-space: nowrap;
}
.set-brk-zone.is-none { color: var(--g400); }
.set-brk-zone.is-low  { background: #DDE4F8; color: var(--navy); }
.set-brk-zone.is-high { background: #283C9D; color: #fff; border-radius: 0 var(--rsm) var(--rsm) 0; }
.set-brk-gap {
  position: absolute; top: 0; bottom: 0; pointer-events: auto;
  background: repeating-linear-gradient(135deg, rgba(250,178,25,.35) 0 4px, transparent 4px 8px);
}
.set-brk-gap[hidden] { display: none; }
.set-brk-law { position: absolute; top: -4px; bottom: -4px; border-left: 2px dashed var(--err); }
.set-brk-law i {
  position: absolute; top: -16px; left: 50%; transform: translateX(-50%);
  font-style: normal; font-size: 9.5px; font-weight: 600; color: var(--err); white-space: nowrap;
}
.set-brk-h {
  position: absolute; top: -3px; bottom: -3px; width: 12px; margin-left: -6px; padding: 0;
  border: 2px solid var(--navy); border-radius: 6px; background: #fff;
  cursor: ew-resize; touch-action: none; box-shadow: var(--sc);
}
.set-brk-h:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
.set-brk-h.is-drag { box-shadow: var(--sr); }
.set-brk-h:disabled { cursor: not-allowed; border-color: var(--g300); }
.set-brk-axis { position: relative; height: 16px; margin-top: 3px; }
.set-brk-axis span {
  position: absolute; transform: translateX(-50%);
  font-size: 10px; color: var(--g400); font-variant-numeric: tabular-nums;
}
.set-brk-rows { display: grid; gap: 6px; margin-top: 6px; }
.set-brk-row { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--g800); flex-wrap: wrap; }
.set-brk-row b { color: var(--navy); font-variant-numeric: tabular-nums; }
.set-brk-sw { width: 14px; height: 10px; border-radius: 2px; }
.set-brk-sw.is-none { background: var(--g50); border: 1px solid var(--g200); }
.set-brk-sw.is-low { background: #DDE4F8; border: 1px solid #B9C6EF; }
.set-brk-sw.is-high { background: #283C9D; }
.set-brk-len { width: auto; }
.set-brk-eg { color: var(--g600); font-size: 11px; display: block; }
.set-brk-warn { color: #9A6100; }
.set-row-stack .set-row-value { display: block; }

/* The state picker: a select-shaped button that opens a list of ticks.
   Chips follow the design system's selected chip: navy fill, white text. */
.st-pick { position: relative; }
.st-pick-btn {
  display: flex; align-items: center; gap: 6px; min-height: 30px;
  padding: 4px 8px; border: 1px solid var(--g200); border-radius: var(--rsm);
  background: #fff; cursor: pointer; list-style: none;
}
.st-pick-btn::-webkit-details-marker, .st-pick-btn::marker { display: none; content: ''; }
.st-pick[open] .st-pick-btn, .st-pick-btn:focus-visible { border-color: var(--navy); outline: none; }
.st-pick-chips { display: flex; flex-wrap: wrap; gap: 4px; flex: 1; min-width: 0; }
.st-chip {
  font-size: 10.5px; font-weight: 600; color: #fff; background: var(--navy);
  border-radius: var(--rpill); padding: 2px 8px;
}
.st-pick-none { font-size: 11px; color: var(--g400); }
.st-pick-caret { font-size: 11px; color: var(--g600); }
.st-pick-menu {
  position: absolute; z-index: 20; left: 0; right: 0; top: calc(100% + 4px);
  max-height: 260px; overflow-y: auto; padding: 4px;
  background: #fff; border: 1px solid var(--g100); border-radius: var(--rsm); box-shadow: var(--sf);
}
.st-pick-opt {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 8px;
  padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 11.5px; color: var(--g800);
}
.st-pick-opt:hover { background: var(--tint); }
.st-pick-opt input { accent-color: var(--navy); margin: 0; }
.st-pick-meta { font-size: 10px; color: var(--g400); }

/* Every outlet the picked states close, grouped by state. */
.st-out-head { font-size: 11px; font-weight: 600; color: var(--navy); margin-top: 2px; }
.st-out-head span { display: block; font-weight: 400; font-size: 10px; color: var(--g400); }
.st-out-list {
  max-height: 220px; overflow-y: auto; margin-top: 4px;
  border: 1px solid var(--g100); border-radius: var(--rsm); background: var(--g50);
}
.st-out-grp + .st-out-grp { border-top: 1px solid var(--g100); }
.st-out-state {
  position: sticky; top: 0; background: var(--tint); padding: 5px 8px;
  font-size: 11px; font-weight: 600; color: var(--g800);
}
.st-out-state span { font-weight: 400; color: var(--g400); margin-left: 4px; }
.st-out-row { padding: 3px 8px; font-size: 10.5px; color: var(--g600); }
.st-out-row b { color: var(--g800); font-weight: 600; margin-right: 4px; }
.st-out-empty { color: var(--g400); font-style: italic; }

/* The slider row: one line, like every other row — label and reference on
   the left, then the slider and its value in words where a typed box would
   sit. The slot is wider than the 108px text slot because a slider needs
   room to be dragged. No tick numbers: the value is said beside it. */
.set-row-slider { grid-template-columns: minmax(0, 1fr) 196px; }
.set-slider { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px; }
.set-slider-out { font-size: 11.5px; font-weight: 600; color: var(--navy); white-space: nowrap; min-width: 58px; text-align: right; }
.set-slider input[type=range], .set-hc-cell input[type=range] {
  width: 100%; accent-color: var(--navy); cursor: pointer; margin: 0;
}
.set-slider .su-range-ticks { display: none; }
.set-slider .set-clear { grid-column: 1 / -1; justify-self: end; }
.set-tl-note { margin: -4px 0 8px; }
.set-card .su-tl { margin-top: 8px; }

/* Company headcount: one block per outlet type, three sliders side by side.
   Replaced a 4x3 grid of number boxes; the type and its outlet count stay on
   the left so the row still reads "Mall · 192 outlets → 2 / 1 / 2". */
.set-hc { display: flex; flex-direction: column; margin: 4px 0 2px; }
.set-hc-type { padding: 8px 0; border-top: 1px solid var(--g100); }
.set-hc-name { display: flex; align-items: baseline; gap: 8px; margin-bottom: 4px; }
.set-hc-name .set-row-ref { margin-top: 0; }
.set-hc-cells { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.set-hc-top { display: flex; justify-content: space-between; align-items: baseline; }
.set-hc-top span { font-size: 10px; color: var(--g400); }
.set-hc-top b { font-size: 12px; font-weight: 600; color: var(--navy); }
/* eight ticks do not fit a third of a card; the number above says the value */
.set-hc-cell .su-range-ticks { display: none; }
/* the off switch sits on the card's floor, so every card in a row agrees on
   where that line is */
.set-row-foot { margin-top: auto; border-top: 1px solid var(--g100); border-bottom: none; }

/* ── sign-in ── the bar under the Settings title, and what a locked control
   looks like. Locked = the signed-in person could not save it (auth.js). */
.auth-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 0 0 var(--lg); padding: 12px 16px; border-radius: var(--rmd);
  background: var(--tint); border: 1px solid var(--g100);
  font-size: 11.5px; line-height: 1.5; color: var(--g800);
}
.auth-bar > div { flex: 1; min-width: 260px; }
.auth-bar b { color: var(--navy); font-weight: 600; }
.auth-bar.is-in { border-left: 3px solid var(--ok); }
.auth-bar.is-off { background: var(--gold-p); border-color: var(--gold-l); }
.auth-bar.is-off b { color: var(--g800); }
.is-locked { opacity: .5; cursor: not-allowed !important; }

/* A dock button switched off in Permissions. `hidden` alone loses to .bi-tab's
   display:flex, which is why it needs saying. */
.bi-tab[hidden] { display: none !important; }

/* ── View as ──
   Amber, as in AR Pro: it reports a temporary state you are meant to leave,
   not a permanent part of the chrome. */
.view-as-banner {
  display: flex; align-items: center; gap: 12px;
  margin: 0 var(--xl) var(--md); padding: 10px 16px; border-radius: var(--rmd);
  background: #FCE7B0; color: #7A4B00; border: 1px solid #F2CF73;
  font-size: 12px; line-height: 1.45;
}
.view-as-banner[hidden] { display: none; }
.view-as-banner .ni svg { fill: currentColor; }
.view-as-banner .view-as-text { flex: 1; }
.view-as-banner strong { font-weight: 700; }
/* The dock button reads as "you are in a preview" while one runs. */
body.is-previewing #dock-view-as { background: #FCE7B0; color: #7A4B00; }

.perm-viewas {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; max-width: 920px;
  margin: 0 0 var(--md); padding: 12px 16px; border-radius: var(--rmd);
  background: var(--white); border: 1px solid var(--g100);
  font-size: 11.5px; line-height: 1.5; color: var(--g800);
}
.perm-viewas > div { flex: 1; min-width: 260px; }
.perm-viewas b { color: var(--navy); }
.perm-viewas select { width: 200px; }

/* ── the Permissions matrix ── */
.perm-table { max-width: 920px; }
.perm-table td { padding: 10px var(--lg); border-bottom: 1px solid var(--g100); vertical-align: middle; }
.perm-table thead th { cursor: default; }
.perm-col { text-align: center !important; width: 150px; }
.perm-fixed { font-size: 9px; font-weight: 600; text-transform: none; letter-spacing: 0; color: var(--g400); margin-top: 2px; }
.perm-sec td {
  background: var(--tint); font-size: 10px; font-weight: 700; color: var(--navy);
  text-transform: uppercase; letter-spacing: .6px; padding: 8px var(--lg);
}
.perm-area { font-size: 12.5px; font-weight: 600; color: var(--g800); }
.perm-note { font-size: 11px; color: var(--g400); margin-top: 2px; line-height: 1.4; }
.perm-ico { width: 18px; height: 18px; fill: currentColor; display: inline-block; vertical-align: middle; }
.perm-cb:disabled { cursor: not-allowed; opacity: .55; }
.perm-foot { font-size: 11px; margin-top: var(--md); max-width: 920px; line-height: 1.5; }
.su-tl-bar.is-locked { pointer-events: none; }
.set-lock {
  display: inline-block; padding: 1px 7px; border-radius: var(--rpill);
  font-size: 9.5px; font-weight: 600; color: var(--navy); background: var(--tint);
  border: 1px solid var(--g100);
}

.set-sub {
  font-size: 9.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--g400); margin-bottom: 4px;
}

/* A card being measured for its tile count, for the instant it takes. */
.set-card.is-measuring { height: auto !important; align-self: start; }


.set-input { width: 72px; text-align: right; }
.set-input-wide { width: 108px; text-align: left; }
.set-input:disabled { background: var(--g100); color: var(--g600); cursor: not-allowed; }
.set-check { width: auto; margin: 0; }
.set-clear {
  border: none; background: none; color: var(--navy); cursor: pointer;
  font-size: 10px; font-weight: 600; padding: 0 2px; opacity: .6;
}
.set-clear:hover { opacity: 1; text-decoration: underline; }

/* the six status words, one colour each, wherever they appear */
.set-st { font-weight: 700; }
.set-st-refuses { color: var(--err); }
.set-st-warns { color: var(--warn); }
.set-st-accepts { color: var(--ok2); }
.set-st-waiting, .set-st-costing, .set-st-reference, .set-st-arithmetic { color: var(--g400); }

/* Level 1's lock — the one thing no other section has */
/* Full width, like every other note on this page (see .set-note) — the old
   860px cap left it a narrow strip beside a wide empty window. One column,
   text running edge to edge; two side-by-side columns were tried and read as
   two uneven blocks. */
.law-warn {
  margin: 0 0 var(--lg); padding: 14px 18px;
  border: 1px solid var(--err); border-left-width: 4px;
  border-radius: var(--rmd); background: var(--err-bg);
}
.law-warn-title { font-size: 12px; font-weight: 700; color: var(--err); margin-bottom: 6px; }
.law-warn-body { font-size: 11px; line-height: 1.6; color: var(--g800); margin-bottom: 12px; }
.law-warn-body p { margin: 0; }
.law-warn-body p + p { margin-top: 6px; }
.law-warn-lock { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* headcount's grid: four outlet types x three sessions, the one place a table
   says less than a list would */
.set-tbl { width: 100%; border-collapse: collapse; margin: 4px 0 2px; }
.set-tbl th {
  font-size: 9.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--g400); text-align: center; padding-bottom: 4px;
}
.set-tbl td { padding: 5px 2px; border-top: 1px solid var(--g100); text-align: center; }
.set-tbl td:first-child { text-align: left; }
.set-tbl .set-input { width: 56px; }
.set-tbl td:not(:first-child) { width: 68px; }

/* ════════ THE PLOT PANEL ════════
   Opens beside the tapped card and answers for that one cell: the best shift
   first, then whatever else is wanted, then — folded away — the ones no rule
   wants, and last the ones the law refuses, which have no button at all.

   Each option is drawn as the CARD IT WOULD BECOME, in the grid's own session
   colours (.rc-MORNING / .rc-MIDDLE / .rc-CLOSING / .rc-LATE from app.css).
   Choosing between three shift times as text, six inches from a grid that says
   Closing by being purple, was making the reader translate. */
.plot-pop {
  /* 540 (was 420, briefly 600): wide enough for the custom-time boxes and the
     option cards, without covering more of the shift plot than it has to. */
  /* Full height: top and bottom are set by schedulingPlotPosition, so the
     panel always runs the height of the window and scrolls inside itself. */
  position: fixed; z-index: 60; width: 540px; max-width: calc(100vw - 24px); overflow-y: auto;
  background: var(--white); border-radius: var(--rlg); box-shadow: 0 12px 32px rgba(22,39,122,.18);
  border: 1px solid var(--g200); padding: var(--md) var(--lg) var(--lg);
}
.plot-load { font-size: 11.5px; color: var(--g400); padding: 6px 0; }
/* The card the open plot panel is about. */
.rc-card.is-plotting { outline: 2.5px solid var(--navy); outline-offset: 1px; z-index: 2; }
.plot-head { display: flex; align-items: flex-start; gap: 8px; padding-bottom: 8px; border-bottom: 1px solid var(--g100); }
.plot-title { font-size: 13px; font-weight: 700; color: var(--navy); }
.plot-sub { font-size: 10px; color: var(--g400); margin-top: 2px; line-height: 1.5; }
.plot-cov { font-weight: 600; }
.plot-cov-short { color: var(--warn); }
/* The floor, when it disagrees with the session counts. Red rather than amber:
   a session one body short is a staffing problem, somebody alone in a shop is
   the thing the outlet rule refuses shifts over. */
.plot-cov-alone { color: var(--err); font-weight: 700; }
.plot-x { margin-left: auto; border: none; background: none; color: var(--g400); cursor: pointer; font-size: 12px; padding: 2px 4px; }
.plot-x:hover { color: var(--navy); }
/* The OL's bar panel (schedulingOpenBarPanel): a slider, what it covers, the day. */
.olb-body { padding-top: var(--md); }
.olb-empty { cursor: crosshair; }
.olb-empty:hover { border-color: var(--navy); }
.olb-odd { font-size: 11.5px; color: var(--g600); background: var(--tint); border-radius: var(--rsm); padding: 8px 10px; }
.olb-cover { font-size: 11.5px; color: var(--g800); padding: 3px 0; display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.olb-cover span { color: var(--g400); font-variant-numeric: tabular-nums; }
.olb-cover i { font-style: normal; color: var(--g600); }
.olb-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: var(--md) 0; }
.olb-daycov { font-size: 11.5px; line-height: 1.8; }
.olb-fill { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 8px; }
.olb-fill .muted { font-size: 10.5px; line-height: 1.45; flex: 1 1 220px; }

.plot-lead {
  font-size: 9.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--g400); margin: 12px 0 5px;
}

/* an option: the card it would become, with the reasons beside it */
.plot-opt { display: grid; grid-template-columns: 128px minmax(0, 1fr); gap: 10px; align-items: start; padding: 6px 0; }
.plot-opt-best { background: var(--gold-p); border: 1px solid var(--gold-l); border-radius: var(--rmd); padding: 8px; }
.plot-opt-quiet { opacity: .82; }
.plot-card { height: auto; padding: 7px 8px; cursor: pointer; }
.plot-card-top { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; }
/* The shift text carries the grid's own .rc-time class, so theme.css colours it
   exactly as it colours the roster: dark navy on the light Morning card, dark
   rust on the light Closing card, white on the dark Middle and Late ones. This
   block overrides GEOMETRY only — never colour — because the first version set
   `color: #fff` here and put white text on a soft blue card, which is neither
   readable nor what the grid does. A card that claims to preview a cell has to
   be coloured by the same rules as the cell. */
.plot-card .rc-time { width: auto; text-align: left; padding: 0; cursor: inherit; }

/* The card's time is text now, not a text box (see schedulingCellHtml): the
   whole card is the button, and an empty cell keeps its height. */
div.rc-time { cursor: inherit; user-select: none; }
div.rc-time:empty::before { content: "\00a0"; }

/* Custom time in the plot panel: one start/end row, or two stacked for a split
   shift, then a footer with the length, "+ Add second block" and the button. */
.plot-custom { padding: 8px 0 10px; border-bottom: 1px solid var(--g100); }
/* Each row spans the panel: the two times share the width equally, so a
   block reads as one bar from start to end rather than two small boxes. */
.plot-custom-row {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: 8px; margin-bottom: 6px;
}
/* label · start · to · end · ✕-slot — identical on both rows */
.plot-custom-row.is-split { grid-template-columns: 52px 1fr auto 1fr 26px; }
.plot-custom-row select { width: 100%; min-width: 0; font-variant-numeric: tabular-nums; }
.plot-custom-blk {
  font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .4px; color: var(--g400);
}
.plot-custom-to { font-size: 11px; color: var(--g400); }
.plot-custom-x {
  border: none; background: none; cursor: pointer; color: var(--g400);
  font-size: 12px; padding: 4px 6px; border-radius: 6px;
}
.plot-custom-x:hover { background: var(--g100); color: var(--err); }
.plot-custom-foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.plot-custom-len { font-size: 11.5px; font-weight: 700; color: var(--navy); font-variant-numeric: tabular-nums; }
.plot-custom-bad { color: var(--err); font-weight: 600; }
.plot-custom-add {
  border: 1px dashed var(--g200); background: none; cursor: pointer;
  font-family: inherit; font-size: 11px; font-weight: 600; color: var(--navy);
  padding: 4px 10px; border-radius: var(--rpill);
}
.plot-custom-add:hover { border-color: var(--navy); background: var(--tint); }
.plot-custom .plot-use { margin-left: auto; }
.plot-card-time { font-size: 12px; }
/* The tag reads on a light card and a dark one because it borrows the text's
   own colour instead of assuming white. */
.plot-tag {
  font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: inherit; border: 1px solid currentColor; border-radius: var(--rpill);
  padding: 0 5px; opacity: .72;
}
.plot-card-rows { margin-top: 5px; }
.plot-card-rows .rc-row { padding: 1px 0; }
.plot-opt-side { display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
/* One colour vocabulary inside the panel, the same three roles Settings uses:
   the NUMBER carries the verdict's colour, the rule key is meta, the sentence
   is body text. Colouring the whole line amber made the reason itself look
   like a warning when only the weight was. */
.plot-why { font-size: 10px; color: var(--g600); line-height: 1.45; }
.plot-why-none { color: var(--g400); font-style: italic; }
.plot-use { padding: 4px 11px; font-size: 10.5px; margin-top: 3px; }

/* ── the reason, in one line ──
   What replaced four lines of `+11.25 min_on_floor covers 4.5h of the day when
   the floor drops below 2`. A tick for the reason it is being offered, a bang
   for the worst thing about it, and the rule named the way a manager would name
   it. The mark carries the colour; the sentence stays body text, because a
   sentence printed in amber reads as a warning when only the verdict is one. */
.plot-say {
  display: grid; grid-template-columns: 13px minmax(0, 1fr); gap: 5px;
  font-size: 10.5px; line-height: 1.45; color: var(--g800); padding: 1px 0;
}
.plot-say b { font-weight: 700; }
.plot-say-mark { font-weight: 800; line-height: 1.4; }
.plot-say-yes .plot-say-mark { color: var(--ok2); }
.plot-say-no .plot-say-mark { color: var(--warn); }
.plot-say-law .plot-say-mark { color: var(--err); }
.plot-say-flat { color: var(--g400); font-style: italic; grid-template-columns: minmax(0, 1fr); }

/* Refusals group by reason now, so the row leads with the sentence and carries
   the shifts it rules out underneath as chips. */
.plot-ref-shifts { display: flex; flex-wrap: wrap; gap: 4px; margin: 3px 0 0 18px; }
.plot-ref-shift {
  font-size: 9.5px; font-weight: 700; color: var(--g600); background: var(--tint);
  border-radius: var(--rpill); padding: 1px 7px; margin-right: 0;
}


/* the rotation: a different question, and the one action that writes a month */
.plot-pattern { border: 1px dashed var(--g200); border-radius: var(--rmd); padding: 9px 11px; margin-top: 12px; }
.plot-pattern-title { font-size: 11.5px; font-weight: 700; color: var(--navy); }
.plot-pattern-sub { font-size: 10px; color: var(--g400); margin-top: 2px; line-height: 1.45; }
.plot-pattern-acts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
.plot-pattern-state { font-size: 10px; color: var(--g600); margin-top: 5px; font-weight: 600; }
.plot-pattern-note { font-size: 9.5px; color: var(--g400); line-height: 1.45; margin-top: 6px; }
.plot-reset { color: var(--err); border-color: var(--err); }

/* the override gate, and the refusals that have no gate */
.plot-more { margin-top: 12px; }
.plot-more > summary {
  font-size: 10.5px; font-weight: 700; color: var(--navy); cursor: pointer;
  padding: 5px 0; list-style: none;
}
.plot-more > summary::marker, .plot-more > summary::-webkit-details-marker { display: none; }
.plot-more > summary::before { content: '▸ '; color: var(--g400); }
.plot-more[open] > summary::before { content: '▾ '; }
.plot-more-note { font-size: 10px; color: var(--g400); line-height: 1.5; margin: 2px 0 6px; }
.plot-ref { padding: 5px 0; border-bottom: 1px solid var(--g100); }
.plot-ref:last-child { border-bottom: none; }

.plot-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: 12px; padding-top: 9px; border-top: 1px solid var(--g100);
}
.plot-cur { font-size: 10px; color: var(--g400); }
.plot-clear { padding: 4px 10px; font-size: 10.5px; }

/* The ownership notice. Same red as Level 1's lock, and for the same reason:
   this is the one thing on the page that is not a preference. Kept at the top
   because whoever is about to change what the app enforces is exactly who
   needs to have read it — and because a bot or integration may one day be
   reading these rosters on somebody's behalf. */
/* Full width, text edge to edge — same measure and spacing as the law
   warning below it (.law-warn), so the two red notices read as one system
   rather than a narrow strip above a wide one. */
.own-note {
  margin: 0 0 var(--lg); padding: 14px 18px;
  border: 2px solid rgba(236, 13, 64, .45); border-radius: var(--rmd);
  background: var(--err-bg);
}
.own-note-title {
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--err); margin-bottom: 6px;
}
.own-note p { font-size: 11px; line-height: 1.6; color: var(--g800); margin: 0 0 6px; }
.own-note p:last-child { margin-bottom: 0; }

/* ════════ OVER TARGET ════════
   Bottom-right, above the grid, after the save that caused it. Amber rather
   than red: nothing here is illegal or refused, it is money — red is reserved
   for the law, and spending a warning colour on a judgement call is how the
   colour stops meaning anything. */
/* Left of the dock, not under it: the collapsed dock is 76px wide at the right
   edge and sits above this (z 80), so right: var(--lg) put the popup's buttons
   behind the rail. Phones override this below, where the dock is a bottom bar. */
.over-pop {
  position: fixed; z-index: 70; right: calc(var(--lg) + 76px + var(--md)); bottom: var(--lg);
  width: 400px; max-height: 74vh; overflow-y: auto;
  background: var(--white); border: 1px solid var(--warn);
  border-left: 4px solid var(--warn); border-radius: var(--rlg);
  box-shadow: 0 14px 36px rgba(22,39,122,.20); padding: var(--md) var(--lg) var(--lg);
}
.over-head { display: flex; align-items: flex-start; gap: 8px; padding-bottom: 8px; border-bottom: 1px solid var(--g100); }
.over-title { font-size: 12.5px; font-weight: 800; color: var(--warn); }
.over-sub { font-size: 10px; color: var(--g400); margin-top: 2px; line-height: 1.45; }
.over-sess { padding-top: 9px; }
.over-sess-head { font-size: 11px; line-height: 1.5; color: var(--g800); }
.over-sess-note { font-size: 9.5px; color: var(--g400); line-height: 1.45; margin: 4px 0 2px; }
.over-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 6px 0; border-bottom: 1px solid var(--g100);
}
.over-row:last-child { border-bottom: none; }
.over-name { font-size: 11.5px; font-weight: 700; color: var(--navy); }
.over-first {
  font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--warn); border: 1px solid var(--warn); border-radius: var(--rpill); padding: 0 4px;
}
.over-meta { font-size: 10px; color: var(--g400); margin-top: 1px; }
.over-use { padding: 4px 11px; font-size: 10.5px; flex-shrink: 0; }
.over-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--g100);
}
.over-keep { font-size: 9.5px; color: var(--g400); line-height: 1.45; }

/* ════════ THE FOSS ASSISTANT ════════
   Bottom-LEFT on purpose: the over-target popup owns bottom-right, and the two
   must never cover each other — one is asking about a day you just touched,
   the other is standing by. Always mounted, on every view. */
/* ── the Assistant rail ──
   The dock, mirrored: same component (app.css .bi-tabstrip-wrap — navy, 76px
   collapsed, 220px on hover), same inset, same centring, same scroll-not-clip
   on a short window. See schedulingAssistMount for why it exists. */
.assist-rail {
  position: fixed; right: var(--lg); top: 50%; transform: translateY(-50%);
  z-index: 80;                 /* level with the dock, over every panel */
  max-height: calc(100vh - 2 * var(--lg));
  overflow-x: hidden; overflow-y: auto; scrollbar-width: thin;
  gap: 10px; padding: var(--md) 0;
}
.assist-rail .bi-tabgroup { gap: 4px; }
.assist-rail .bi-tab { padding-top: 6px; padding-bottom: 6px; }
.assist-rail .ni { position: relative; }
/* How many days need somebody — on the icon, so the collapsed rail says it. */
.assist-rail-count {
  /* Top-LEFT of the icon: on the right it ran into the label when the rail
     expanded, covering the first letters of "Findings". */
  position: absolute; top: -7px; left: -9px;
  background: var(--warn); color: #fff; border-radius: var(--rpill);
  font-size: 9px; font-weight: 800; line-height: 1; padding: 2px 5px;
  font-family: inherit; pointer-events: none;
}
.assist-rail-count[hidden] { display: none; }

/* Glanceable first, readable on demand: counts and short labels on the
   surface, the full sentence behind every hover. The panel used to read as a
   page; it should read as a dashboard. */
/* The dock's shape, mirrored on the left (2026-09-24): the same inset from the
   screen edge, the same full height, the same corners and the same shadow —
   read from the dock's own variables, so the two cannot drift apart. The two
   floating bars are the app's two halves, where to GO on the right and what to
   DO on the left, and they should look like a pair. Only the shape is shared;
   the body stays white, because this one holds forms and findings to read,
   not a column of icons.

   It opens beside the Assistant rail rather than over it, so the rail's
   buttons stay in reach while a form is open. */
.assist-panel {
  position: fixed; right: calc(var(--lg) + 76px + var(--sm)); top: var(--lg); bottom: var(--lg); z-index: 66;
  /* 440 not 360: each finding now carries its fix button on its own line, and
     the short line should fit on one row beside its icon. Capped so a narrow
     window never loses the panel's right edge. */
  width: 440px; max-width: calc(100vw - 2 * var(--lg) - 76px - var(--sm)); overflow-y: auto;
  scrollbar-width: thin;
  background: var(--white); border: 1px solid var(--g200); border-radius: var(--rlg);
  box-shadow: var(--sf); padding: var(--md) 16px 12px;
}
.assist-load { font-size: 12px; color: var(--g400); padding: 6px 0; }
.assist-head { display: flex; align-items: center; gap: 8px; padding-bottom: 8px; border-bottom: 1px solid var(--g100); }
.assist-title { font-size: 14px; font-weight: 700; color: var(--navy); cursor: help; }
.assist-sub { flex: 1; font-size: 11px; color: var(--g400); }
.assist-sec {
  font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--g400); margin: 12px 0 6px;
}

/* month findings: one chip each — a finding is a button, because a finding you
   cannot act on is a complaint */
.assist-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.assist-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--tint); border: 1px solid transparent; border-radius: var(--rpill);
  padding: 4px 10px; cursor: pointer; font-family: inherit; font-size: 12px; color: var(--g800);
}
.assist-chip:hover { border-color: var(--g200); }
.assist-chip b { color: var(--navy); font-weight: 700; }
.assist-none { font-size: 12px; color: var(--g600); background: var(--tint); border-radius: var(--rmd); padding: 8px 12px; }

/* severity as a colour, not a word — the word is the dot's hover text */
.assist-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; background: var(--g300); }
.assist-dot.d-crit { background: var(--err); }
.assist-dot.d-warn { background: var(--warn); }
.assist-dot.d-info { background: var(--g300); }

/* actions: a 4-wide grid of tiles, the open one's form below the grid. The
   icon is the dock's `.ni` box and SVG, so it inherits the dock's size and
   colour rather than restating them. */
.assist-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
/* Navy tiles, white icon and label — the icon is currentColor, so it follows
   the label. The open tile goes one step lighter with a white ring rather than
   inverting, so the grid stays one colour and the choice still reads. */
.assist-tile {
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 4px;
  background: var(--navy); border: none; border-radius: var(--rmd);
  padding: 9px 2px; cursor: pointer; font-family: inherit; text-align: center;
  font-size: 11px; font-weight: 600; line-height: 1.25; color: var(--white);
}
.assist-tile:hover { background: var(--navy2); }
.assist-tile.on { background: var(--navy2); box-shadow: inset 0 0 0 2px rgba(255,255,255,.7); }
.assist-tile:focus-visible { outline: 2px solid var(--navy2); outline-offset: 2px; }
.assist-tile-ico { width: 18px; }

/* clear: the confirm button is the only red button in the panel, because it
   is the only one that removes work */
.clear-confirm { padding: 2px 0; }
/* A toggle in the shape of "Clear all of <month>" (manager, 2026-10-13: "same
   design as clear whole month . it like a toggle . not tickbox"). Off: the red
   outline of the day / week buttons. On: filled red like the month button,
   with a tick. The checkbox is still there for the keyboard and the state,
   only hidden. */
.clear-people {
  position: relative; box-sizing: border-box; display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; height: 38px; padding: 0 12px; margin: 0 0 6px; user-select: none;
  border: 1.5px solid var(--err); border-radius: var(--rmd); background: var(--white);
  font-size: 12.5px; font-weight: 600; color: var(--err); cursor: pointer;
  transition: background-color .15s, color .15s;
}
.clear-people:hover { background: var(--err-bg); }
.clear-people input[type="checkbox"] { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.clear-people:has(input:checked) { background: var(--err); color: var(--white); }
.clear-people:has(input:checked):hover { background: #A82E2E; border-color: #A82E2E; }
/* OFF / ON said in words (manager, 2026-10-13), as a pill after the label. */
.clear-people::after {
  content: 'OFF'; margin-left: 6px; padding: 2px 8px; border-radius: 999px;
  font-size: 10px; font-weight: 800; letter-spacing: .06em;
  background: var(--err-bg); color: var(--err); border: 1px solid var(--err);
}
.clear-people:has(input:checked)::after { content: 'ON'; background: var(--white); color: var(--err); }
.clear-people:has(input:focus-visible) { box-shadow: 0 0 0 3px var(--err-bg); }
.assist-form { margin-top: 8px; padding: 8px 12px; background: var(--tint); border-radius: var(--rmd); }
.assist-form-what { font-size: 11px; color: var(--g600); line-height: 1.45; margin-bottom: 8px; }
.assist-row { display: flex; gap: 6px; margin-bottom: 6px; flex-wrap: wrap; }
.assist-row .fi { flex: 1; min-width: 108px; font-size: 11px; }
.assist-note { min-width: 170px !important; }
.assist-go { padding: 5px 12px; font-size: 11px; white-space: nowrap; }
/* Auto-fill's and Clear's three rows, all the size of the month button
   (manager, 2026-10-13: "make this box larger .. all dropdown design follow
   this box"), one colour per form: Auto-fill green, Clear red ("autofill <--
   green , clear <-- red"). The dropdowns and the day / week buttons are an
   outline of that colour, the month button is filled with it. */
.pick-green { --pick: #1F7047; --pick-dark: #175838; --pick-tint: rgba(31,112,71,.07); }
.pick-red { --pick: var(--err); --pick-dark: #A82E2E; --pick-tint: var(--err-bg); }
/* A fixed grid, not flex (2026-10-13: "box shape size not standardized"):
   flex sized each button to its words, so "Clear week" pushed its dropdown
   narrower than the one above. Now the dropdown is the column, every button
   the same width, every box the same 38px. */
.fill-pick { display: grid; grid-template-columns: minmax(0, 1fr) 112px; gap: 6px; align-items: stretch; }
.fill-pick .fi, .fill-pick .assist-go {
  box-sizing: border-box; height: 38px; min-height: 38px; margin: 0; width: 100%;
  font-size: 12.5px; line-height: 1.2; border-radius: var(--rmd);
}
.fill-pick .fi {
  min-width: 0; padding: 8px 32px 8px 12px; font-weight: 600; color: var(--pick);
  border: 1.5px solid var(--pick); background-color: var(--white); cursor: pointer;
  appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%237F7F7F' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 18px;
}
.fill-pick .fi:focus { border-color: var(--pick); box-shadow: 0 0 0 3px var(--pick-tint); }
.fill-pick .assist-go { padding: 0 12px; justify-content: center; }
.fill-pick .bo.assist-go { border: 1.5px solid var(--pick); color: var(--pick); background: var(--white); }
.fill-pick .bo.assist-go:hover { background: var(--pick-tint); }
.fill-pick .fill-all, .fill-pick .pick-solid { background: var(--pick); color: var(--white); border: 1.5px solid var(--pick); }
.fill-pick .fill-all:hover, .fill-pick .pick-solid:hover { background: var(--pick-dark); border-color: var(--pick-dark); }
.fill-pick .fill-all, .fill-pick .pick-wide { grid-column: 1 / -1; }
/* Two equal boxes: "Clear N | Cancel", "Undo this clear | Done". */
.fill-pick.fill-pair { grid-template-columns: 1fr 1fr; margin-top: 8px; }
.assist-hint { font-size: 11px; color: var(--g400); line-height: 1.45; }
.assist-hint[title] { cursor: help; }
.assist-out { margin-top: 4px; }
.assist-prop { border: 1px solid var(--g200); border-radius: var(--rmd); padding: 8px; margin-top: 6px; background: var(--white); }
.assist-prop-no { opacity: .8; border-style: dashed; }
.assist-prop-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.assist-prop-top b { font-size: 12px; color: var(--navy); }
.assist-prop-meta { font-size: 10px; color: var(--g400); }
.assist-prop-why { font-size: 10px; color: var(--g600); line-height: 1.45; margin: 4px 0; }

/* recorded absences: one line each */
.assist-abs { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: 12px; }
.assist-abs-who { flex: 1; font-weight: 600; color: var(--navy); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.assist-abs-when { color: var(--g400); white-space: nowrap; }
.assist-foot { font-size: 10px; color: var(--g400); margin-top: 12px; padding-top: 8px; border-top: 1px solid var(--g100); }

/* ════════ THE FROZEN DAY ROW ════════
   What kind of day this is: the date, its weekday, and the calendar's own facts
   — a gazetted public holiday, a school break, a surge multiplier. The rule
   alerts that used to live here moved into the assistant on 2026-08-23, which
   can ask which day needs help and answer in sentences instead of abbreviating
   "Middle is 0 of 1 on the floor" into a chip reading "Middle −1".

   Quiet by default. A row of 31 cards is a ruler, and a ruler that shouts is
   hard to read along. */
.dc-day { background: var(--white); border: 1px solid var(--g100); }
.dc-weekend { background: var(--tint); }
.dc-has { border-color: var(--gold-l); background: var(--gold-p); }
.dc-tag {
  font-size: 8px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  border-radius: var(--rpill); padding: 1px 5px; margin: 3px auto 0; display: inline-block;
}
.dc-ph { background: var(--err-bg); color: var(--err); }
.dc-sb { background: rgba(255,150,0,.14); color: #9A5B00; }
/* A promotion is a surge, so it sits in the warm range with the other
   two. A delivery is NOT a surge — it is a morning that needs somebody
   who can receive stock — so it takes the neutral navy and does not
   compete for attention with the days that are actually busier. */
.dc-promo { background: rgba(250,178,25,.18); color: #8A5A00; }
.dc-deliv { background: var(--tint); color: var(--navy); }
.dc-name { font-size: 8.5px; line-height: 1.25; color: var(--g600); margin-top: 2px; padding: 0 3px; }
.dc-surge { font-size: 8px; font-weight: 800; color: var(--warn); margin-top: 2px; text-transform: uppercase; letter-spacing: .04em; }

/* Problem strip — the top of each day's header card, above the date and its
   events. Same red/amber/grey as the assistant's icons, so a day and its
   findings read as the same thing. Full card width: it is caught out of the
   corner of an eye while scrolling sideways, not read. */
.dc-det {
  align-self: stretch; display: flex; align-items: center; justify-content: center; gap: 5px;
  margin: -1px -1px 4px; padding: 7px 6px; min-height: 30px; border: none; border-radius: 7px;
  font-family: inherit; font-size: 13px; font-weight: 800; line-height: 1.1;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.dc-det svg { width: 15px; height: 15px; fill: currentColor; flex: 0 0 auto; }
.dc-det-word { font-weight: 700; font-size: 11px; }
button.dc-det { cursor: pointer; }
.dc-det-crit { background: var(--err); color: var(--white); }
/* Solid, white text, like Nothing to fix (2026-10-13: "make check similar too"). */
.dc-det-warn { background: #C2410C; color: #fff; }   /* the late shift's colour (app.css .rc-LATE) */
button.dc-det:hover { filter: brightness(.93); }
/* Same height as a red/amber strip, so the dates below line up across the row. */
/* Nothing to fix: said in green, so a clean day reads as done rather than
   as a gap where a strip did not load (2026-10-12). */
/* Dark green, white text (2026-10-13). */
.dc-det-ok { background: #1F7047; color: #fff; font-size: 13px; }
.dc-det-ok .dc-det-word { font-size: 10.5px; }
/* A day the outlet is shut, on purpose and with a reason: grey, not red. */
.dc-det-closed { background: var(--g100); color: var(--g600); font-size: 11px; font-weight: 800;
                 text-transform: uppercase; letter-spacing: .06em; }
.dc-closed { background: var(--g100); color: var(--g600); }

/* Problem, then Fix, then problem (2026-09-30): the two faces share one cell,
   so the strip never changes size. Tap = auto-fix.

   "make sure the transition all similar, not weirdly" -- so:
   - ONE after the other, never both: the problem fades fully out before Fix
     fades in, and back, so the two words are never on top of each other.
   - IN STEP across the whole month: every badge is pinned to the same clock
     (schedulingSyncDayFades), so all the days flip together, however many
     times the grid redraws.
   - Hover and busy only OVERRIDE the opacity (!important beats an
     animation); they never stop it, because a stopped animation restarts
     out of step with the rest. */
.dc-det-alt { display: grid; place-items: center; }
.dc-det-alt .dc-det-face { grid-area: 1 / 1; display: inline-flex; align-items: center; gap: 5px; }
.dc-det-alt .dc-det-face.is-prob { animation: dcProb 5s ease-in-out infinite; }
.dc-det-alt .dc-det-face.is-fix { animation: dcFix 5s ease-in-out infinite; font-weight: 800; letter-spacing: .02em; }
.dc-det-alt:is(:hover, :focus-visible) .dc-det-face.is-prob { opacity: 0 !important; }
.dc-det-alt:is(:hover, :focus-visible) .dc-det-face.is-fix { opacity: 1 !important; }
.dc-det-alt.is-busy { cursor: progress; }
.dc-det-alt.is-busy .dc-det-face.is-prob { opacity: 0 !important; }
.dc-det-alt.is-busy .dc-det-face.is-fix { opacity: .6 !important; }
/* 5s: the problem 2.1s, out 0.3s, Fix 1.7s in the middle, out 0.3s, back in. */
@keyframes dcProb { 0%, 42% { opacity: 1; } 48%, 94% { opacity: 0; } 100% { opacity: 1; } }
@keyframes dcFix  { 0%, 48% { opacity: 0; } 54%, 88% { opacity: 1; } 94%, 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .dc-det-alt .dc-det-face { animation: none !important; }
  .dc-det-alt .dc-det-face.is-fix { display: none; }
}
.assist-closed { display: flex; justify-content: space-between; align-items: center; gap: 8px;
                 font-size: 11.5px; color: var(--g600); background: var(--g50);
                 border-radius: var(--rsm); padding: 6px 8px; margin: 4px 0 8px; }
.assist-close-sel { width: auto; margin-left: 6px; }

/* the day's own findings, in the words the rule wrote, each with its button */
.assist-day { background: var(--tint); border-radius: var(--rmd); padding: 8px 12px; }
.assist-day-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.assist-day-title { flex: 0 0 auto; font-size: 13px; font-weight: 700; color: var(--navy); }
.assist-day-cal { font-size: 11px; color: var(--g600); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Problem on top, its fix underneath — the line gets the full width to read,
   and the button sits where the eye lands next. Rows are separated by a hairline
   so each problem and its button read as one unit. */
.assist-day-row {
  display: flex; align-items: flex-start; gap: 10px; padding: 8px 0;
  border-top: 1px solid var(--g100);
}
.assist-day-head + .assist-day-row, .assist-undo + .assist-day-row { border-top: none; }
.assist-day-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.assist-day-msg { font-size: 12.5px; font-weight: 600; line-height: 1.35; color: var(--g800); padding-top: 2px; }
.assist-day-acts { display: flex; align-items: center; gap: 6px; }

/* One icon style for every finding: a 22px rounded square tinted by severity,
   the glyph in the severity's ink. Same filled-SVG family as the dock. */
.assist-ico {
  width: 22px; height: 22px; border-radius: 6px; flex: 0 0 auto;
  display: grid; place-items: center;
}
.assist-ico svg { width: 14px; height: 14px; fill: currentColor; display: block; }
.assist-ico.d-crit { background: var(--err-bg); color: var(--err); }
.assist-ico.d-warn { background: rgba(250,178,25,.18); color: #9A5B00; }
.assist-ico.d-info { background: var(--g100); color: var(--g600); }

/* The fix is a real button, not a link — it is the thing to press. */
.assist-fix {
  flex: 0 0 auto; white-space: nowrap; padding: 4px 10px; min-height: 0;
  font-size: 11px; font-weight: 700; border-radius: var(--rpill);
}
/* Secondary to the fix: a quiet text button beside it, same height. */
.assist-open {
  flex: 0 0 auto; border: none; background: none; cursor: pointer;
  font-family: inherit; font-size: 11px; font-weight: 600; line-height: 1;
  color: var(--g600); padding: 6px 10px; border-radius: var(--rpill);
}
.assist-open:hover { background: var(--g100); color: var(--navy); }

.assist-undo {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-size: 11.5px; color: var(--g800); background: var(--white);
  border: 1px solid var(--g100); border-radius: var(--rmd);
  padding: 5px 10px; margin: 2px 0 4px;
}
.assist-undo .set-clear { font-size: 11px; opacity: 1; }
/* The judge bar: what Auto-fix just did, and the two verdicts on it. Gold edge
   because it is waiting on a person, the same signal as the best plot option. */
.assist-judge { border-color: var(--gold-l); background: var(--gold-p); align-items: flex-start; }
.assist-judge-what { min-width: 0; overflow-wrap: anywhere; line-height: 1.45; }
.assist-judge-tag {
  font-size: 9px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--g600); margin-right: 4px;
}
.assist-judge-acts { display: flex; gap: 4px; flex: 0 0 auto; }
.assist-more {
  background: none; border: none; padding: 4px 0 0 32px; cursor: pointer;
  font-family: inherit; font-size: 11px; font-weight: 600; color: var(--navy);
}

/* ════════ THE THREE-DAY VIEW ════════
   Opened by a finding in the assistant. The named day in the middle, live; the
   days either side in grey, reference only.

   The grey is doing real work — it is the difference between "you may edit this"
   and "this is here so you can see it". Reference days are dimmed AND have
   pointer-events off, because a colour convention nobody has been taught is not
   a safeguard. Two ways of saying the same thing, one of which is enforced.

   It floats rather than docking: the roster underneath is the thing being
   reasoned about, and a panel that pushes the grid aside makes you lose your
   place in it. */
/* THE ENTRANCE ANIMATES TRANSFORM ONLY, AND DELIBERATELY.
   It faded in at first — from { opacity: 0 } with fill-mode both — and driving it
   caught the failure that hides: in a window that does not advance animations,
   the panel held its FIRST keyframe forever and rendered at opacity 0. Present
   in the DOM, correct in every assertion, invisible on screen.
   A stalled transform costs nine pixels of offset. A stalled fade costs the
   whole panel, so nothing that can hide it is allowed in here. */
@keyframes day-pop-in {
  from { transform: translateX(-50%) translateY(9px) scale(.986); }
  to   { transform: translateX(-50%) translateY(0) scale(1); }
}
.day-pop {
  position: fixed; z-index: 58; left: 50%; top: 10vh;
  transform: translateX(-50%);
  width: min(720px, 94vw); max-height: 78vh; overflow-y: auto;
  /* left is set by schedulingDayFocusPosition() against the live rects of
     whatever else is on screen; 50% is only the value before it runs. */
  background: var(--white); border: 1px solid var(--g200); border-radius: var(--rlg);
  box-shadow: 0 18px 44px rgba(22,39,122,.22);
  padding: var(--md) var(--lg) var(--lg);
  opacity: 1;
  animation: day-pop-in .17s cubic-bezier(.2,.7,.3,1) both;
}

.day-head { display: flex; align-items: flex-start; gap: 8px; padding-bottom: 9px; border-bottom: 1px solid var(--g100); }
.day-title { font-size: 13.5px; font-weight: 800; color: var(--navy); }
/* the finding, in the words the rule wrote — not a re-summary of it */
.day-note { font-size: 10.5px; color: var(--g600); margin-top: 3px; line-height: 1.5; }
.day-note-q { color: var(--g400); font-style: italic; }

.day-cols { display: grid; grid-template-columns: 1fr 1.18fr 1fr; gap: 8px; padding-top: 11px; align-items: start; }

.day-col { border-radius: var(--rmd); padding: 7px 7px 8px; min-width: 0; }
/* The one you came here to change: full colour, its own border, and the only
   column whose cards answer a click. */
.day-col-focus { background: var(--gold-p); border: 1px solid var(--gold-l); }
/* Reference. Dimmed, desaturated, and inert. */
.day-col-ghost { background: var(--tint); border: 1px solid var(--g100); opacity: .74; filter: grayscale(.42); }
.day-col-ghost .day-col-body { pointer-events: none; }
.day-col-ghost:hover { opacity: .92; filter: grayscale(.2); }
.day-col-out { opacity: .6; }

.day-col-head { text-align: center; padding-bottom: 6px; border-bottom: 1px solid var(--g100); margin-bottom: 6px; }
.day-col-head-go { cursor: pointer; pointer-events: auto; }
.day-col-head-go:hover .day-col-when { color: var(--navy); text-decoration: underline; }
.day-col-when { font-size: 11.5px; font-weight: 800; color: var(--g800); }
.day-col-focus .day-col-when { color: var(--navy); font-size: 12.5px; }
.day-col-role {
  font-size: 8px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--g400); margin-top: 1px;
}
.day-col-cal { font-size: 8.5px; color: var(--err); font-weight: 700; margin-top: 2px; line-height: 1.3; }
/* the shape of the day in three numbers, so the columns can be compared at a glance */
.day-col-tally { font-size: 9px; font-weight: 700; color: var(--g600); margin-top: 3px; letter-spacing: .02em; }
.day-col-flag { color: var(--warn); }

.day-col-body { display: flex; flex-direction: column; gap: 3px; }
.day-row { display: grid; grid-template-columns: 46px minmax(0, 1fr); gap: 5px; align-items: stretch; }
.day-who {
  font-size: 9px; font-weight: 700; color: var(--g600); align-self: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* A shift at reference size. Same session classes as the grid — .rc-MORNING /
   .rc-MIDDLE / .rc-CLOSING / .rc-LATE / .rc-off — so a column here and a column
   there are the same picture at two scales, and nobody has to translate. */
.day-mini {
  height: auto; min-height: 26px; padding: 4px 6px; display: flex; flex-direction: column;
  justify-content: center; gap: 0; cursor: default;
}
.day-mini-live { cursor: pointer; }
.day-mini-live:hover { box-shadow: 0 3px 10px rgba(22,39,122,.16); transform: translateY(-1px); }
.day-mini-sess { font-size: 8.5px; font-weight: 800; letter-spacing: .03em; line-height: 1.2; }
.day-mini-time { font-size: 10px; font-weight: 700; line-height: 1.25; }
.day-mini-meta { font-size: 8px; opacity: .8; line-height: 1.2; }
.day-empty { font-size: 9.5px; color: var(--g400); line-height: 1.45; padding: 10px 4px; text-align: center; }

.day-foot {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 12px;
  margin-top: 11px; padding-top: 9px; border-top: 1px solid var(--g100);
}
.day-hint { font-size: 9.5px; color: var(--g400); line-height: 1.45; }

/* the assistant's own fix button: one line, never wrapped */
.assist-day-row .set-clear { white-space: nowrap; flex: 0 0 auto; align-self: center; }
.day-act { white-space: nowrap; flex: 0 0 auto; }

/* the severity a rule declared, not one inferred from its wording */
.assist-day-sev {
  font-size: 7.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  border-radius: var(--rpill); padding: 2px 6px; white-space: nowrap;
  flex: 0 0 auto; align-self: center;
}
.sev-crit { background: var(--err-bg); color: var(--err); }
.sev-warn { background: rgba(255,150,0,.14); color: #9A5B00; }
.sev-info { background: var(--tint); color: var(--g600); }
.day-col-block { color: var(--err); font-weight: 800; }

/* ════════ CONNECT YOUR CLAUDE ════════
   Shows the exact JSON before the button, because the button edits a file that
   belongs to Claude Code and holds the person's other MCP servers. */
.set-ai-body { padding: 4px 0 2px; }
.set-ai-row { font-size: 11px; line-height: 1.6; color: var(--g800); }
.set-ai-yes { color: #0F9D58; font-weight: 800; }
.set-ai-no { color: var(--g400); font-weight: 800; }
.set-ai-note { font-size: 9.5px; color: var(--g400); line-height: 1.5; margin: 5px 0 2px; }
.set-ai-err {
  font-size: 10px; line-height: 1.5; color: var(--err); background: var(--err-bg);
  border-radius: var(--rmd); padding: 7px 9px; margin-top: 6px;
}
.set-ai-pre-lbl {
  font-size: 8.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  color: var(--g400); margin: 9px 0 3px;
}
.set-ai-pre {
  font-family: ui-monospace, Consolas, monospace; font-size: 9.5px; line-height: 1.45;
  background: var(--tint); border: 1px solid var(--g100); border-radius: var(--rmd);
  padding: 7px 9px; margin: 0; overflow-x: auto; color: var(--g800); white-space: pre;
}
.set-ai-check {
  display: flex; align-items: center; gap: 6px; font-size: 10.5px;
  color: var(--g800); margin-top: 10px; cursor: pointer;
}
.set-ai-btns { display: flex; align-items: center; gap: 10px; margin-top: 10px; }

/* ════════ FINISHES THE NEXT MORNING ════════
   Not an error and not a warning — a question. Bordered in navy rather than the
   over-target amber, because amber says "this costs money" and this costs
   nothing; it might simply not be what somebody meant. */
.night-pop { border-color: var(--navy); border-left-color: var(--navy); }
.night-pop .over-title { color: var(--navy); }

/* the mark on the card itself, so an overnight cell is not four digits that
   look like any other four digits */
.rc-xmid {
  position: absolute; top: 3px; right: 4px; font-size: 9px; line-height: 1;
  opacity: .85; pointer-events: none;
}
.rc-card { position: relative; }
.over-foot .set-clear { white-space: nowrap; align-self: center; }

/* ════════ LET CLAUDE FIX THIS DAY ════════
   Absent entirely without the CLI — see schedulingFixBarHtml. Changes land
   immediately and the diff is the receipt, so the result block has to be as
   readable as the roster it just edited. */
.fix-bar { border-radius: var(--rmd); padding: 8px 10px; margin: 6px 0 8px; font-size: 10.5px; }
.fix-idle { background: var(--tint); border: 1px solid var(--g100); }
.fix-run { background: var(--gold-p); border: 1px solid var(--gold-l); display: flex; align-items: center; gap: 8px; }
.fix-done { background: var(--white); border: 1px solid var(--navy); }
.fix-go { margin-bottom: 5px; }
.fix-note { font-size: 9.5px; color: var(--g400); line-height: 1.45; display: block; }
.fix-none { font-size: 9.5px; color: var(--g400); font-style: italic; }

@keyframes fix-spin { to { transform: rotate(360deg); } }
.fix-spin {
  width: 11px; height: 11px; flex: 0 0 auto; border-radius: 50%;
  border: 2px solid var(--gold-l); border-top-color: var(--navy);
  animation: fix-spin .7s linear infinite;
}

.fix-done-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; margin-bottom: 5px; }
.fix-done-head b { font-size: 11.5px; color: var(--navy); }
.fix-meta { font-size: 9px; color: var(--g400); }
.fix-err {
  font-size: 9.5px; line-height: 1.5; color: var(--err); background: var(--err-bg);
  border-radius: var(--rmd); padding: 6px 8px; margin: 4px 0;
}
.fix-row {
  display: grid; grid-template-columns: 58px 62px 1fr 12px 1fr; gap: 5px;
  align-items: center; padding: 3px 0; border-bottom: 1px solid var(--g100);
  font-size: 9.5px;
}
.fix-row:last-of-type { border-bottom: none; }
.fix-who { font-weight: 700; color: var(--g800); }
.fix-when { color: var(--g400); }
.fix-was { color: var(--g400); text-decoration: line-through; }
.fix-arrow { color: var(--g400); text-align: center; }
.fix-now { font-weight: 700; color: var(--navy); }
/* a change that landed on a day nobody asked about */
.fix-off .fix-when, .fix-off .fix-now { color: var(--err); }
.fix-said {
  font-family: ui-monospace, Consolas, monospace; font-size: 9px; line-height: 1.45;
  background: var(--tint); border-radius: var(--rmd); padding: 6px 8px;
  margin: 6px 0 0; max-height: 130px; overflow: auto; white-space: pre-wrap; color: var(--g600);
}
.fix-foot { display: flex; gap: 10px; align-items: center; margin-top: 7px; }

/* ════════ TOO FEW HOURS TO SLEEP ════════
   Not red: nothing here is illegal, and red is reserved for the law. Not amber
   either — that is the over-target colour and means "this costs money". This one
   is about a person, so it borrows the navy the app uses when it is asking
   rather than warning. */
.rest-pop { border-color: var(--navy); border-left-color: var(--navy); width: 340px; }
.rest-pop .over-title { color: var(--navy); font-size: 13px; }
.rest-pop .over-head { align-items: center; }
.rest-pop .over-foot { justify-content: flex-end; }
.rest-row {
  font-size: 10.5px; line-height: 1.5; color: var(--g800); background: var(--tint);
  border-radius: var(--rmd); padding: 6px 9px; margin: 4px 0;
}

/* ════════ HOW IT DECIDES ════════
   The decision path as a diagram (frontend/js/decide.js). One vertical spine
   of numbered steps, with each step owning whatever shape explains it — three
   input cards, the Auto-fill engine's rules and weights, the plot's three
   stages across.

   Drawn with borders, not boxes with shadows: the design system's first
   elevation level is the 1px hairline, and a page of forty small panels each
   casting a shadow reads as clutter at any zoom. Colour carries exactly one
   thing here, the same thing it carries in Settings — precedence. Level 1 is
   the red left edge, Level 2 tan, Level 3 navy, and nothing else on the page
   is allowed those three. */

.dc-intro { max-width: none; }
.dc-intro a { color: var(--navy); font-weight: 600; }

/* the three verbs, as a strip: the counts are the page's thesis in four numbers */
.dc-verbs { display: flex; flex-wrap: wrap; gap: var(--sm); margin-top: var(--md); }
.dc-verb {
  flex: 1 1 140px; display: flex; align-items: baseline; gap: 7px;
  padding: 8px 12px; border-radius: var(--rmd);
  background: var(--white); border: 1px solid var(--g100); border-left: 3px solid var(--g200);
}
.dc-verb b { font-size: 18px; font-weight: 800; color: var(--navy); line-height: 1; }
.dc-verb span { font-size: 10.5px; color: var(--g600); }
.dc-verb-filter { border-left-color: var(--err); }
.dc-verb-filter b { color: var(--err); }
.dc-verb-rank { border-left-color: var(--navy); }
.dc-verb-build { border-left-color: var(--gold-d); }
.dc-verb-build b { color: var(--gold-d); }
.dc-verb-total { border-left-color: var(--g200); }
.dc-verb-total b { color: var(--g600); }

/* ── the spine ──
   The connector is a border on the step's own left gutter rather than a
   separate element, so adding a step to decideRender() cannot leave a dangling
   arrow behind. The last step's line is cut at its own number. */
.dc-flow { position: relative; }
.dc-step { display: grid; grid-template-columns: 34px 1fr; gap: var(--md); padding-bottom: var(--lg); position: relative; }
.dc-step::before {
  content: ''; position: absolute; left: 16px; top: 34px; bottom: 0;
  border-left: 2px solid var(--g100);
}
.dc-step:last-child { padding-bottom: 0; }
.dc-step:last-child::before { display: none; }
.dc-step-n {
  width: 34px; height: 34px; border-radius: 50%; background: var(--navy); color: var(--white);
  font-size: 14px; font-weight: 800; display: flex; align-items: center; justify-content: center;
  position: relative; z-index: 1;
}
.dc-step-t { font-size: 15px; font-weight: 700; color: var(--navy); margin: 5px 0 4px; }
.dc-step-p { font-size: 12px; line-height: 1.55; color: var(--g600); max-width: 78ch; margin-bottom: var(--sm); }
.dc-step-p b { color: var(--g800); }
.dc-step-p code { font-family: ui-monospace, Consolas, monospace; font-size: 11px; color: var(--g800); background: var(--tint); padding: 1px 5px; border-radius: 5px; }

/* ── step 1: the three inputs ── */
.dc-inputs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--md); margin-top: var(--sm); }
@media (max-width: 1100px) { .dc-inputs { grid-template-columns: minmax(0, 1fr); } }
.dc-input {
  position: relative; background: var(--white); border: 1px solid var(--g100);
  border-radius: var(--rmd); padding: 12px 14px 12px 18px; overflow: hidden;
}
/* A stripe rather than a border-left, because the middle card holds two levels
   and a single border colour would have had to pick one of them. Level 2 above
   Level 3, in precedence order, so the stripe reads top-down like the ladder. */
.dc-input::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--g200);
}
.dc-input.lvl-1::before { background: var(--err); }
.dc-input.lvl-2::before { background: linear-gradient(var(--gold-d) 0 50%, var(--navy) 50% 100%); }
.dc-input-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sm); margin-bottom: 6px; }
.dc-input-kind { font-size: 12.5px; font-weight: 800; color: var(--navy); }
.dc-input-bend { font-size: 9.5px; font-weight: 700; color: var(--g400); text-align: right; }
.dc-input-what { font-size: 11.5px; line-height: 1.5; color: var(--g800); }
.dc-input-owner { font-size: 10.5px; font-weight: 600; color: var(--g600); margin-top: 6px; }
.dc-input-note { font-size: 10.5px; line-height: 1.45; color: var(--g400); margin-top: 4px; font-style: italic; }

/* ── step 2: the Auto-fill engine ──
   Rungs sit flush in one stack under a shared hairline, which is what makes it
   read as one list rather than as twenty unrelated cards. CP-SAT has two
   stacks (never broken, weighed), each under a small caps label. */
.dc-sub {
  font-size: 10px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--g400); margin: var(--md) 0 6px;
}
.dc-ladder { border: 1px solid var(--g100); border-radius: var(--rmd); overflow: hidden; background: var(--white); }
.dc-rung {
  display: grid; grid-template-columns: 38px 1fr auto; gap: 10px; align-items: center;
  padding: 9px 12px; border-bottom: 1px solid var(--g50); border-left: 4px solid var(--g200);
}
.dc-rung:last-child { border-bottom: none; }
.dc-rung-lvl {
  font-size: 10px; font-weight: 800; color: var(--g600); background: var(--tint);
  border-radius: var(--rpill); padding: 3px 0; text-align: center;
}
.dc-rung.lvl-1 { border-left-color: var(--err); }
.dc-rung.lvl-2 { border-left-color: var(--gold-d); }
.dc-rung.lvl-3 { border-left-color: var(--navy); }
.dc-rung.lvl-1 .dc-rung-lvl { background: var(--err-bg); color: var(--err); }
.dc-rung.lvl-2 .dc-rung-lvl { background: var(--gold-p); color: var(--gold-d); }
.dc-rung.lvl-3 .dc-rung-lvl { background: rgba(34,52,136,.08); color: var(--navy); }
.dc-rung-t { font-size: 12px; font-weight: 600; color: var(--g800); }
.dc-rung-t code { font-family: ui-monospace, Consolas, monospace; font-size: 11px; color: var(--navy); margin-right: 6px; }
.dc-rung-why { font-size: 10.5px; line-height: 1.45; color: var(--g400); margin-top: 2px; }
/* a preference, and the per-cell line, are not one rule and do not borrow a
   level's colour — the same reason .lvl-none exists in Settings */
.dc-rung-base { background: var(--tint); }

/* a penalty's weight, right-aligned: the number is what the rung is for */
.dc-rung-delta { display: flex; flex-direction: column; align-items: flex-end; min-width: 0; text-align: right; }
.dc-w { font-size: 12px; font-weight: 800; color: var(--g800); font-variant-numeric: tabular-nums; }
.dc-w-per { font-size: 9.5px; font-weight: 600; color: var(--g400); }

/* ── step 4: the plot's three stages, across ──
   Across rather than down on purpose: they happen to one cell in one pass, and
   stacked they read as three more constraints. */
.dc-lane { display: flex; align-items: stretch; gap: 6px; margin-top: var(--sm); flex-wrap: wrap; }
.dc-lane-step {
  flex: 1 1 210px; background: var(--white); border: 1px solid var(--g100);
  border-radius: var(--rmd); padding: 11px 13px;
}
.dc-lane-n {
  width: 18px; height: 18px; border-radius: 50%; background: var(--tint); color: var(--navy);
  font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center; margin-bottom: 6px;
}
.dc-lane-t { font-size: 12.5px; font-weight: 700; color: var(--navy); margin-bottom: 4px; }
.dc-lane-p { font-size: 10.5px; line-height: 1.5; color: var(--g600); }
.dc-lane-p b { color: var(--g800); }
.dc-lane-p code { font-family: ui-monospace, Consolas, monospace; font-size: 10px; }
.dc-lane-src {
  display: inline-block; margin-top: 7px; font-family: ui-monospace, Consolas, monospace;
  font-size: 9.5px; color: var(--g400);
}
.dc-lane-arrow { align-self: center; color: var(--g300); font-size: 16px; font-weight: 700; }

.dc-nothing {
  font-size: 11px; line-height: 1.55; color: var(--g600); background: var(--tint);
  border-radius: var(--rmd); padding: 10px 13px; margin-top: var(--sm);
}
.dc-nothing b { color: var(--g800); }

/* ── step 5: precedence, and the three commitments ── */
.dc-prec {
  background: var(--white); border: 1px solid var(--g100); border-radius: var(--rmd);
  padding: 12px 14px; margin-top: var(--sm);
}
.dc-prec-t { font-size: 10px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--g400); margin-bottom: 8px; }
.dc-prec-chain { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dc-prec-link {
  font-family: ui-monospace, Consolas, monospace; font-size: 11.5px; font-weight: 700; color: var(--navy);
  background: var(--tint); border-radius: var(--rpill); padding: 4px 12px;
}
/* leave outranks even a hand-typed cell, so it is the one link that is not
   ours to overrule — the law's colour, for the same reason Level 1 has it */
.dc-prec-link.is-first { background: var(--err-bg); color: var(--err); }
.dc-prec-gt { color: var(--g300); font-weight: 700; }
.dc-prec-why { font-size: 10.5px; line-height: 1.5; color: var(--g400); margin-top: 8px; }

.dc-commit { margin: var(--md) 0 0 16px; padding: 0; }
.dc-commit li { font-size: 11.5px; line-height: 1.6; color: var(--g600); margin-bottom: 6px; }
.dc-commit b { color: var(--g800); }
.dc-commit code { font-family: ui-monospace, Consolas, monospace; font-size: 10.5px; background: var(--tint); padding: 1px 5px; border-radius: 5px; }

/* ── the loop back ──
   The feedback edge of the diagram. Dashed, because it is the one arrow that
   goes backwards. */
.dc-loop {
  display: flex; gap: 12px; align-items: flex-start; margin: var(--lg) 0 0;
  padding: 12px 14px; border: 2px dashed var(--g200); border-radius: var(--rmd);
  background: var(--white); font-size: 11.5px; line-height: 1.6; color: var(--g600);
}
.dc-loop b { color: var(--g800); }
.dc-loop-arrow { font-size: 20px; color: var(--navy); line-height: 1; }

/* ── the closing sections ── */
.dc-proofs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--md); }
@media (max-width: 900px) { .dc-proofs { grid-template-columns: minmax(0, 1fr); } }
.dc-proof { padding: 14px 16px; border: 1px solid var(--g100); }
.dc-proof-t { font-size: 13px; font-weight: 700; color: var(--navy); margin-bottom: 5px; }
.dc-proof-p { font-size: 11.5px; line-height: 1.55; color: var(--g600); }
.dc-proof-test {
  font-size: 10px; color: var(--g400); margin-top: 8px; padding-top: 7px;
  border-top: 1px solid var(--g100); font-family: ui-monospace, Consolas, monospace;
}
.dc-ties td { vertical-align: top; line-height: 1.5; }
.dc-ties code { font-family: ui-monospace, Consolas, monospace; font-size: 11px; color: var(--navy); }
.dc-status { max-width: none; }

/* ════════ THE AUTO-FILL REPORT ════════
   What one press wrote, inside the assistant panel that launched it. Three
   parts in the order somebody asks about them: how much landed, what could not
   and why, and the way back out. */
.fill-done {
  margin-top: 8px; padding: 9px 11px; border: 1px solid var(--g100);
  border-left: 3px solid var(--ok2); border-radius: var(--rmd); background: var(--white);
}
/* A clear's result: the same card without Auto-fill's green edge. */
.fill-done.clear-done { border-left: 1px solid var(--g100); }
.fill-head { font-size: 11.5px; font-weight: 700; color: var(--navy); line-height: 1.4; }
/* Not a warning colour. A stretched shift is the floor rule doing its job, and
   the only reason it is mentioned is that the day card will flag it. */
.fill-note {
  font-size: 10px; line-height: 1.5; color: var(--g600); background: var(--tint);
  border-radius: var(--rsm); padding: 6px 8px; margin-top: 6px;
}
.fill-sec {
  font-size: 9px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--g400); margin: 9px 0 4px;
}
.fill-skip { border-top: 1px solid var(--g100); padding: 6px 0; font-size: 10.5px; color: var(--g800); }
.fill-skip b { color: var(--err); }
.fill-skip-why { font-size: 10px; line-height: 1.45; color: var(--g600); margin-top: 2px; }
.fill-skip-who { font-size: 9.5px; color: var(--g400); margin-top: 3px; }

/* ════════ FIRST RUN ════════
   One card on a navy scrim, covering everything. It is the only surface in the
   app that cannot be dismissed, so it is also the only one allowed to cover
   the whole window — and it earns that by being six questions long.

   No shadow-heavy chrome and no gradient: the design system's §6 keeps rich
   colour fields for campaign surfaces, and this is the opposite of a campaign.
   A flat navy wash, one white card, the mark at the top. */
.su-scrim {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(34, 52, 136, .82);
  display: flex; align-items: center; justify-content: center;
  padding: var(--lg);
  overflow-y: auto;
}
.su-card {
  width: 100%; max-width: 520px; background: var(--white);
  border-radius: var(--rlg); padding: var(--xl); box-shadow: var(--sf);
  max-height: calc(100vh - var(--xl)); overflow-y: auto;
}
.su-welcome { text-align: center; }
/* The app's own mark (FOSS, with the Zeus head at its shoulder — generated by
   scripts/build_foss_logo.py, never redrawn). On the white card, never on the
   navy — §1. It is wide, about 2.8:1, so it is sized by width. */
.su-mark { display: block; width: 168px; height: auto; margin: 0 auto var(--lg); }
.su-h1 { font-size: 22px; font-weight: 800; color: var(--navy); line-height: 1.2; margin-bottom: 10px; }
.su-h2 { font-size: 18px; font-weight: 700; color: var(--navy); line-height: 1.25; margin-bottom: 6px; }
.su-lead { font-size: 13px; line-height: 1.6; color: var(--g800); margin-bottom: var(--md); }
.su-lead b { color: var(--navy); }
.su-why { font-size: 12px; line-height: 1.6; color: var(--g600); margin-bottom: var(--lg); }
.su-list {
  text-align: left; margin: 0 0 var(--md) 18px; padding: 0;
  font-size: 12px; line-height: 1.8; color: var(--g600);
}
.su-fine {
  font-size: 10.5px; line-height: 1.6; color: var(--g400); text-align: left;
  background: var(--tint); border-radius: var(--rmd); padding: 10px 12px; margin-bottom: var(--lg);
}

/* progress: a dot per question, filled as they are answered */
.su-dots { display: flex; gap: 5px; margin-bottom: var(--md); }
.su-dot { width: 22px; height: 4px; border-radius: 2px; background: var(--g100); }
.su-dot.is-done { background: var(--gold); }
.su-dot.is-on { background: var(--navy); }
.su-step {
  font-size: 9.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--g400); margin-bottom: 4px;
}

/* The three-step explainer on the Google Sheet question. Numbered because
   this one genuinely IS a sequence somebody performs — link, paste, done —
   unlike the rest of the wizard, where a number would be decoration.
   (Not .su-step: that is already the "step 3 of 8" eyebrow above the title.) */
.su-how { display: flex; flex-direction: column; gap: 9px; margin-bottom: 14px; }
.su-how-row { display: grid; grid-template-columns: 20px minmax(0, 1fr); gap: 9px; align-items: start; }
.su-how-row > b {
  width: 20px; height: 20px; border-radius: 50%; background: var(--navy); color: #fff;
  font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center;
}
.su-how-row span { font-size: 11.5px; line-height: 1.5; color: var(--g600); }
.su-how-row span b { color: var(--navy); font-weight: 600; }
/* a step already behind the person: ticked, and quieter than the one ahead */
.su-how-row.is-done > b { background: var(--ok); }
.su-how-row.is-done span { color: var(--g400); }

/* The Google step, while the browser is open or the sheet is being made. A
   spinner because this is a real wait on somebody else's server — the one
   place in the wizard where nothing the person does here moves it forward. */
.su-wait {
  display: flex; gap: 12px; align-items: center;
  background: var(--tint); border-radius: var(--rmd); padding: 12px 14px; margin-bottom: 14px;
}
.su-wait b { display: block; font-size: 13px; font-weight: 600; color: var(--navy); }
.su-wait span { display: block; font-size: 11px; line-height: 1.5; color: var(--g600); }
.su-spin {
  flex: none; width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--g100); border-top-color: var(--navy);
  animation: su-spin .8s linear infinite;
}
@keyframes su-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .su-spin { animation-duration: 2.4s; } }
.su-row { display: flex; gap: 8px; flex-wrap: wrap; }
.su-sub {
  font-size: 9.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--g400); margin: 4px 0 8px;
}

/* Linked and made: the guide beside what staff will see. The card widens for
   this one state only, because a preview squeezed into 520px is a preview
   nobody can read. Below 900px the two stack, guide first. */
.su-card--wide { max-width: 1040px; }
.su-split { display: grid; grid-template-columns: minmax(0, 340px) minmax(0, 1fr); gap: var(--lg); }
@media (max-width: 900px) { .su-split { grid-template-columns: 1fr; } }
.su-peek { display: flex; flex-direction: column; min-width: 0; }
.su-peek-frame {
  width: 100%; height: 380px; border: 1px solid var(--g100); border-radius: var(--rmd);
  background: var(--white);
}

/* The divider before the no-account alternative. A rule with a word in it,
   because "or" between two options reads as a genuine choice where a second
   paragraph would read as a footnote about the first. */
.su-or {
  display: flex; align-items: center; gap: 9px; margin: 14px 0 10px;
  font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--g400);
}
.su-or::before, .su-or::after {
  content: ""; flex: 1; height: 1px; background: var(--g100);
}

.su-body { margin-bottom: var(--lg); }
.su-field { margin-bottom: 12px; }
.su-field .fld-l { display: block; margin-bottom: 4px; }
.su-field .fi { width: 100%; }
.su-hint { font-size: 10.5px; line-height: 1.55; color: var(--g400); margin-top: 8px; }
.su-hint b { color: var(--g600); }
.su-warn {
  font-size: 11px; line-height: 1.55; color: var(--g800); background: var(--err-bg);
  border: 1px solid var(--err); border-radius: var(--rmd); padding: 9px 11px; margin-top: 10px;
}

/* the site-type picker: four cards, one answer */
.su-choices { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
@media (max-width: 520px) { .su-choices { grid-template-columns: 1fr; } }
.su-choice {
  text-align: left; padding: 11px 13px; border-radius: var(--rmd);
  border: 1.5px solid var(--g100); background: var(--white); cursor: pointer;
  font-family: inherit; display: flex; flex-direction: column; gap: 3px;
  transition: border-color .12s, background .12s;
}
.su-choice b { font-size: 13px; font-weight: 700; color: var(--navy); }
.su-choice span { font-size: 10px; line-height: 1.45; color: var(--g400); }
.su-choice:hover { border-color: var(--g300); }
.su-choice.is-on { border-color: var(--navy); background: var(--tint); }

.su-acts { display: flex; gap: 8px; justify-content: flex-end; align-items: center; }
.su-welcome .su-acts { justify-content: center; }
.su-acts .btn { padding: 10px 20px; font-size: 13px; }

/* ── the outlet search ── the pick shown as a chip, the results as a list
   under the box. The list scrolls on its own so the card never grows to 50
   rows tall. */
.su-pick {
  display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px;
  padding: 10px 12px; border-radius: var(--rmd); border: 1.5px solid var(--navy); background: var(--tint);
}
.su-pick b { font-size: 13px; font-weight: 600; color: var(--navy); }
.su-pick span { font-size: 12px; color: var(--g800); }
.su-olist { max-height: 232px; overflow-y: auto; margin-top: 6px; display: flex; flex-direction: column; gap: 2px; }
.su-olist:empty { display: none; }
.su-oitem {
  display: grid; grid-template-columns: 64px minmax(0, 1fr) auto; gap: 10px; align-items: baseline;
  text-align: left; padding: 8px 10px; border: 0; border-radius: var(--rsm);
  background: transparent; font-family: inherit; cursor: pointer;
}
.su-oitem b { font-size: 12px; font-weight: 600; color: var(--navy); }
.su-oitem span { font-size: 12px; color: var(--g800); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.su-oitem i { font-style: normal; font-size: 10px; font-weight: 600; color: var(--g400); }
.su-oitem:hover, .su-oitem.is-hi { background: var(--tint); }
.su-oitem.is-hi { box-shadow: inset 2px 0 0 var(--navy); }
.su-oempty { font-size: 11px; color: var(--g400); padding: 8px 10px; }

/* ── the session timeline ── one axis, three bars, the shop's hours shaded
   behind. Bar colours are the roster's own session colours (theme.css
   .rc-MORNING/-MIDDLE/-CLOSING), so a bar here is the same colour as the
   shift it becomes on the grid and in the sheet. */
.su-tl { margin-bottom: 12px; }
.su-tl-row { margin-bottom: 10px; }
.su-tl-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 4px; }
.su-tl-head span { font-size: 11px; font-weight: 500; color: var(--g600); min-width: 56px; }
.su-tl-head b { font-size: 13px; font-weight: 600; color: var(--navy); font-variant-numeric: tabular-nums; }
.su-tl-head i { font-style: normal; font-size: 11px; color: var(--g400); }
.su-tl-track {
  position: relative; height: 34px; border-radius: var(--rsm);
  background: var(--g50); border: 1px solid var(--g100);
}
.su-tl-open { position: absolute; top: 0; bottom: 0; background: var(--tint); border-left: 1px dashed var(--g200); border-right: 1px dashed var(--g200); }
.su-tl-bar {
  position: absolute; top: 3px; bottom: 3px; border-radius: 6px; border: 1px solid;
  cursor: grab; touch-action: none; user-select: none;
  transition: box-shadow .12s;
}
.su-tl-bar:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
.su-tl-bar.is-drag { cursor: grabbing; box-shadow: var(--sr); }
.su-tl-MORNING { background: #DDE4F8; border-color: #B9C6EF; }
.su-tl-MIDDLE  { background: #283C9D; border-color: #1D2E7D; }
.su-tl-CLOSING { background: #FBE4D6; border-color: #F1C3A6; }
/* An Outlet Leader's time on the bar: one block of their own, not a session. */
.su-tl-OLBAR   { background: #1F7047; border-color: #175838; }
/* An Outlet Leader's working day: admin, in the brand's gold (--zus-gold-light
   on --zus-gold-deep). Not a session and never coverage; the bar sits in it. */
.su-tl-OLDAY   { background: #EFD9BB; border-color: #C18F59; }
/* The part-timer's shift in each session: that session's colour, dashed --
   not a session of its own, the part-timer's usual shift inside it. */
.su-tl-PT-MORNING { background: #DDE4F8; border-color: #8FA2E0; border-style: dashed; }
.su-tl-PT-MIDDLE  { background: #283C9D; border-color: #9DAAF0; border-style: dashed; }
.su-tl-PT-CLOSING { background: #FBE4D6; border-color: #E0A47E; border-style: dashed; }
/* the ends: a wider hit area than the grip that shows */
.su-tl-h { position: absolute; top: 0; bottom: 0; width: 14px; cursor: ew-resize; }
.su-tl-h.is-s { left: -4px; }
.su-tl-h.is-e { right: -4px; }
.su-tl-h::after {
  content: ""; position: absolute; top: 7px; bottom: 7px; left: 6px; width: 2px;
  border-radius: 1px; background: currentColor; opacity: .45;
}
.su-tl-MORNING .su-tl-h, .su-tl-CLOSING .su-tl-h,
.su-tl-PT-MORNING .su-tl-h, .su-tl-PT-CLOSING .su-tl-h { color: var(--navy); }
.su-tl-MIDDLE .su-tl-h, .su-tl-PT-MIDDLE .su-tl-h { color: var(--white); }
.su-tl-axis { position: relative; height: 16px; margin-top: 2px; }
.su-tl-axis span {
  position: absolute; transform: translateX(-50%);
  font-size: 10px; color: var(--g400); font-variant-numeric: tabular-nums;
}
.su-tl-key { display: flex; align-items: center; gap: 6px; font-size: 10.5px; color: var(--g400); margin-top: 6px; }
.su-tl-swatch { width: 14px; height: 10px; border-radius: 2px; background: var(--tint); border: 1px dashed var(--g200); }

/* ── sliders ── the design system's navy, the value said in words above */
.su-range { margin-bottom: 16px; }
/* three sliders side by side: a session's roles, a busy day's sessions */
.su-grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 14px; }
.su-grid3 .su-range { margin-bottom: 10px; }
.su-sub { font-size: 12px; font-weight: 600; color: var(--navy); margin: 4px 0 2px; }
/* the staff step: the team so far, then the add form */
.su-staff { display: flex; flex-direction: column; gap: 4px; max-height: 180px; overflow-y: auto; margin-bottom: 12px; }
.su-staff-row { display: grid; grid-template-columns: 1.4fr 1fr 1.4fr auto; gap: 8px; align-items: center;
  font-size: 12px; padding: 5px 8px; border-radius: 6px; background: var(--tint); }
.su-staff-row b { color: var(--navy); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.su-staff-row span { color: var(--g400); }
.su-staff-row .btn { padding: 2px 8px; }
.su-staff-tag { font-size: 10.5px; }
.su-staff-form .su-field { margin-bottom: 10px; }
.su-range-top { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 4px; }
.su-range-top b { font-size: 13px; font-weight: 600; color: var(--navy); }
.su-range input[type=range] { width: 100%; accent-color: var(--navy); cursor: pointer; margin: 4px 0 0; }
/* Each label is placed by its value (rangeHtml works out the left offset,
   inset by half the 16px thumb), so it sits under the thumb at that value. */
.su-range-ticks { position: relative; height: 14px; }
.su-range-ticks span {
  position: absolute; transform: translateX(-50%);
  font-size: 10px; color: var(--g400); font-variant-numeric: tabular-nums;
}

/* the facts MY UOD already holds, shown rather than asked */
.su-known {
  background: var(--tint); border-radius: var(--rmd); padding: 10px 12px; margin-bottom: 12px;
}
.su-known-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
  font-size: 11.5px; color: var(--g600); padding: 2px 0;
}
.su-known-row b { color: var(--navy); font-weight: 700; }
.su-known-note { font-size: 10px; line-height: 1.5; color: var(--g400); margin-top: 6px; }

/* ════════ LETTER OF AGREEMENT ════════
   A contract term was moved. The banner is for the DM, who was not the person
   who moved it, so it sits above the whole app on every view until somebody
   says the DM has been told. Red, and the only banner in this app that is:
   red is reserved for the law, and a signed agreement is the nearest thing to
   it that the company writes itself. */
.loa-banner {
  position: fixed; top: 0; left: 0; right: 0; z-index: 180;
  background: var(--err-bg); border-bottom: 2px solid var(--err);
  box-shadow: 0 2px 10px rgba(16,24,40,.10);
}
.loa-banner-in {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 10px var(--lg); max-width: 1180px; margin: 0 auto;
}
.loa-ico { font-size: 18px; color: var(--err); line-height: 1.2; }
.loa-body { flex: 1; min-width: 0; }
.loa-title { font-size: 12.5px; font-weight: 800; color: var(--err); }
.loa-rows { margin: 5px 0 4px; }
.loa-row {
  display: flex; flex-wrap: wrap; gap: 7px; align-items: baseline;
  font-size: 11px; color: var(--g800); padding: 1px 0;
}
.loa-row b { font-weight: 700; }
.loa-was { text-decoration: line-through; color: var(--g400); }
.loa-arrow { color: var(--g400); }
.loa-now { font-weight: 800; color: var(--err); }
.loa-when { font-size: 9.5px; color: var(--g400); }
.loa-more { font-size: 10px; color: var(--g400); }
.loa-say { font-size: 11px; line-height: 1.5; color: var(--g800); }
.loa-ack { white-space: nowrap; flex-shrink: 0; }
/* the lock on the LOA rows in Settings, matching Level 1s */
.loa-lock { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 8px; }

/* The app makes room for it rather than being covered by it. */
body.has-loa .main { padding-top: var(--loa-h, 0px); }
body.has-loa .dock { margin-top: var(--loa-h, 0px); }

.loa-ack { display: flex; gap: 6px; align-items: center; flex-shrink: 0; }
.loa-ack .fi { width: 120px; font-size: 11px; }

/* the consent gate on the LOA card — the only place in this app where
   somebody has to say, in writing, that a risk is theirs */
.loa-gate {
  margin-top: 10px; padding: 12px 14px; border: 2px solid var(--err);
  border-radius: var(--rmd); background: var(--err-bg);
}
.loa-gate-t {
  font-size: 11px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  color: var(--err); margin-bottom: 8px;
}
.loa-gate-text {
  font-family: inherit; font-size: 11px; line-height: 1.6; color: var(--g800);
  white-space: pre-wrap; margin: 0 0 10px; background: var(--white);
  border-radius: var(--rsm); padding: 10px 12px;
}
.loa-gate-who { font-size: 11px; color: var(--g800); margin-bottom: 10px; }
.loa-gate-tick { display: flex; gap: 8px; align-items: flex-start; font-size: 11.5px; color: var(--g800); cursor: pointer; }
.loa-gate-tick input { margin-top: 2px; flex-shrink: 0; }
.loa-gate-row { display: flex; gap: 8px; margin: 10px 0; flex-wrap: wrap; }
.loa-gate-row .fi { flex: 1; min-width: 150px; }
.loa-gate-acts { display: flex; gap: 8px; }

/* the LOA terms on the setup wizard: shown, never asked */
.su-loa { border-left: 3px solid var(--err); }

/* ════════ 1000b — PUBLISH ════════
   The one panel that reports on something outside this machine, so it reads as
   a receipt rather than a form: what would change, then what did. */
.pub-box {
  margin-top: 8px; padding: 9px 11px; border: 1px solid var(--g100);
  border-left: 3px solid var(--navy); border-radius: var(--rmd); background: var(--white);
}
.pub-done { border-left-color: var(--ok2); }

/* A publish that FAILED, which is a different thing from one that warned.
   The whole point of the auto-publish status line is that silence is the
   feared failure, so the one state nobody should be able to skim past
   gets the warm border rather than another quiet grey card. */
.pub-warn-box { border-color: #F1C3A6; background: #FDF3EC; }
.pub-warn-box .pub-head { color: #9A340A; }
.pub-head { font-size: 12px; font-weight: 700; color: var(--navy); }
.pub-note { font-size: 10px; line-height: 1.5; color: var(--g400); margin-top: 4px; }
.pub-rows { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 5px; }
.pub-stat { font-size: 10.5px; color: var(--g600); }
.pub-stat b { font-size: 13px; font-weight: 800; margin-right: 3px; }
.pub-created b { color: var(--ok2); }
.pub-updated b { color: var(--gold-d); }
/* removed is the number worth seeing: it is the only irreversible half */
.pub-removed b { color: var(--err); }
.pub-unchanged b { color: var(--g400); }

.pub-warn { font-size: 10px; line-height: 1.5; color: var(--err); margin-top: 5px; }

.pub-sep {
  font-size: 9.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--g400); margin: 14px 0 6px; padding-top: 10px; border-top: 1px solid var(--g100);
}
.bak-row {
  display: flex; justify-content: space-between; gap: 10px;
  font-size: 10.5px; color: var(--g600); padding: 2px 0;
}
.bak-row b { color: var(--navy); }

/* ════════════════════════════════════════════════════════════════════════
   PHONE  (≤ 640px)

   THE SAME APP, NOT A SECOND ONE. Everything below re-lays out the shell
   that already exists — the same dock, the same roster grid, the same
   panels, the same palette. Nothing here introduces a component the desktop
   does not have, and nothing hides a feature. A manager who builds the month
   on the desktop and a barista who reads it on a phone are looking at one
   product, and it has to be recognisable as one at a glance: a stakeholder
   seeing two different interfaces will reasonably ask which is the real one.

   The desktop stays the engine. This is the same engine on a smaller pane of
   glass, which is a layout problem, not a design problem — so it is solved
   here, in the shell's own stylesheet, rather than in a page of its own.

   Three things genuinely have to move on a phone:
     1. the dock, from a right rail to a bottom bar — 76px of fixed rail is
        a fifth of a 390px screen, and the thumb is at the bottom anyway;
     2. the floating panels, from right-anchored cards to bottom sheets —
        they are 300-420px wide and would hang off the edge;
     3. the roster grid, which cannot be 31 legible columns at any phone
        width and so scrolls sideways under a pinned staff column.
   ════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

  :root { --dockh: 88px; }

  /* ── the dock, as a bottom bar ── */
  .dock {
    position: fixed;
    inset: auto 0 0 0;
    top: auto;
    transform: none;
    width: auto !important;
    max-height: none;
    border-radius: 0;
    border: 0;
    border-top: 1px solid var(--g100);
    background: var(--white);
    box-shadow: 0 -2px 14px rgba(0, 22, 136, .07);
    z-index: 60;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    padding: 4px 6px calc(4px + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: row;
    gap: 2px;
  }
  .dock::-webkit-scrollbar { display: none; }

  /* The groups run along the bar instead of down it. Their labels go: five
     words of section heading in a 56px-tall bar is the bar.

     NOWRAP everywhere, which is the whole trick. app.css lets the strip wrap,
     which is right for a rail with vertical room and wrong for a bar with
     none: seven tabs at a 60px minimum need 420px, so on a 390px screen the
     row wrapped to three lines, each group grew, and the bar came out 718px
     tall — nearly the entire phone. One row that scrolls sideways instead. */
  .dock { flex-wrap: nowrap !important; align-items: center; }
  .dock .bi-tabgroup {
    flex-direction: row !important; display: flex; gap: 2px;
    flex: 0 0 auto; flex-wrap: nowrap !important;
  }
  .dock .bi-tabgroup-label { display: none !important; }
  .dock .bi-tabrow {
    flex-direction: row !important; display: flex; gap: 2px;
    flex: 0 0 auto; flex-wrap: nowrap !important;
  }
  /* The group labels carried the only visible break between sections, so with
     them gone a hairline does the same job in the width a bar can spare. */
  .dock .bi-tabgroup + .bi-tabgroup {
    border-left: 1px solid var(--g100); margin-left: 4px; padding-left: 6px;
  }

  /* Every tab keeps its icon AND its label — the label is what makes this
     the same app rather than a row of anonymous glyphs, and it is the one
     thing the collapsed desktop rail has to drop. Stacked, small, and never
     wrapped. */
  .dock .bi-tab {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    flex: 0 0 auto;
    min-width: 58px;
    height: 52px;
    padding: 5px 7px !important;
    border-radius: var(--rmd);
  }
  .dock .nb-label {
    opacity: 1 !important;
    width: auto !important;
    font-size: 9.5px;
    line-height: 1.1;
    font-weight: 600;
    white-space: nowrap;
    max-width: 62px;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .dock .nb-sub { display: none !important; }
  .dock .ni svg { width: 19px; height: 19px; }

  /* The page gives back the rail's width and takes the bar's height. */
  .page {
    padding-right: var(--md) !important;
    padding-left: var(--md);
    padding-bottom: calc(var(--dockh) + env(safe-area-inset-bottom, 0px)) !important;
  }

  /* ── panels, as bottom sheets ──
     Same card, same contents; it just arrives from the bottom edge and takes
     the width, because 380px of fixed panel does not fit beside anything on
     a 390px screen. */
  .legend-panel,
  .legend-panel.is-wide {
    position: fixed;
    inset: auto 0 0 0;
    right: 0 !important;
    left: 0;
    top: auto;
    transform: none;
    width: auto !important;
    max-width: none;
    max-height: 72vh;
    border-radius: var(--rlg) var(--rlg) 0 0;
    border-bottom: 0;
    padding-bottom: calc(var(--md) + var(--dockh) + env(safe-area-inset-bottom, 0px));
    z-index: 61;
    box-shadow: 0 -6px 30px rgba(0, 22, 136, .16);
  }
  .legend-panel li { grid-template-columns: 70px 1fr; }
  .pnl-2col { grid-template-columns: 1fr; }

  /* The other floating surfaces are the same problem with different names. */
  .plot-pop, .assist-pop, .assist-find {
    position: fixed !important;
    inset: auto 0 0 0 !important;
    width: auto !important;
    max-width: none !important;
    max-height: 72vh;
    border-radius: var(--rlg) var(--rlg) 0 0;
    padding-bottom: calc(var(--md) + var(--dockh) + env(safe-area-inset-bottom, 0px));
    z-index: 61;
  }
  .plot-opt { grid-template-columns: 1fr; gap: 4px; }

  /* ── the topbar ── */
  .topbar { padding-left: var(--md); padding-right: var(--md); gap: 8px; }
  .tb-lockup { height: 22px; }
  .tb-div { display: none; }
  #tbp { display: none; }               /* the subtitle; the title carries it */
  .tb-slot { margin-left: auto; }

  /* ── the roster ──
     31 columns cannot be legible on a phone, so the month scrolls sideways
     and the staff column is pinned to the left edge: scrolling to the 23rd
     is useless if you can no longer see whose row you are on. Momentum
     scrolling on, because this is the one surface here that gets flicked. */
  .rc-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .rc-staff,
  .rc-grid > .rc-corner {
    position: sticky;
    left: 0;
    z-index: 5;
    background: var(--white);
  }
  .rc-grid { grid-template-columns: 104px repeat(var(--sv-days, 31), 84px) !important; }
  .rc-staff-name { font-size: 11.5px; }
  .rc-staff-meta { font-size: 9.5px; }
  .rc-card { padding: 5px 4px; }
  .rc-time { font-size: 11.5px; }
  .rc-rows { display: none; }           /* hours/break/role live in the tooltip */
  .rc-key { font-size: 10px; gap: 8px; flex-wrap: wrap; }

  /* ── forms and tables ── */
  .sh { flex-direction: column; align-items: stretch; gap: 8px; }
  .set-row { grid-template-columns: minmax(0, 1fr); }
  .set-input-wide { width: 100%; }
  .fi, .btn { font-size: 13px; }
  table.set-tbl { display: block; overflow-x: auto; }
}

/* Between the tablet rail and the phone bar. The 980px block above keeps the
   rail but collapses it; below 780px the panels are the part that stops
   fitting beside it, so they widen before the dock moves. */
@media (max-width: 780px) and (min-width: 641px) {
  .legend-panel, .legend-panel.is-wide {
    width: min(340px, calc(100vw - 76px - 3 * var(--lg))) !important;
  }
}

/* A dock panel's body mounted as an Assistant form (Add staff, Publish): the
   tile above already names it, so the panel's own heading would say it twice. */
.assist-form .ac-legendtitle { display: none; }

/* The panel's own action tiles duplicate the rail, so they are hidden wherever
   the rail is showing; the phone layout below brings them back. */
.assist-do { display: none; }
.assist-form-sec { display: flex; align-items: center; justify-content: space-between; margin-top: 4px; }

/* app.css flattens .bi-tabstrip-wrap into a full-width row under 980px; keep
   the rail a rail, the same undo the dock gets. */
@media (max-width: 980px) {
  .assist-rail { width: 76px !important; flex-direction: column; border-radius: var(--rlg); }
  .assist-rail:hover { width: 220px !important; }
  .assist-rail .bi-tabrow { flex-direction: column; }
}
/* On a phone the dock is a bottom bar, and a second rail would eat the screen.
   The rail shrinks to its Findings button, floating over the bar; the actions
   come back as tiles inside the panel. */
@media (max-width: 640px) {
  .assist-rail {
    top: auto; transform: none; bottom: calc(var(--dockh) + var(--sm));
    right: var(--md); width: auto !important; padding: 4px; border-radius: var(--rpill);
  }
  .assist-rail .bi-tabgroup + .bi-tabgroup, .assist-rail .bi-tabgroup-label, .assist-rail .nb-label { display: none; }
  .assist-do { display: block; }
  .assist-panel {
    left: var(--md); right: var(--md); width: auto; max-width: none;
    top: var(--md); bottom: calc(var(--dockh) + 64px);
  }
  .page { padding-left: var(--md); }
}

/* ── the shift plot keeps its width (2026-09-24) ──
   Day columns are `minmax(140px, 1fr)` inside a `max-content` grid, and in
   that sizing every 1fr column grows to the widest content in ANY of them. So
   one long cell — the Friday Jumaat opener, "630 - 1030, 1100 - 1300,
   1430 - 1600" — widened every column in the month the moment Auto-fill wrote
   it. Size containment takes a cell's content out of its column's sizing: the
   columns stay 140px (or share the pane evenly on a short month) and the text
   wraps inside the card instead. */
.rc-grid > * { contain: inline-size; }
.rc-time-split { font-size: 11px; line-height: 1.25; padding-top: 6px; }

/* ── the plot and the two floating bars ──
   For an afternoon on 2026-09-24 the month scrolled on under the dock. The
   manager asked for it, looked at it, and asked for it back: the plot should
   sit between the two bars in the same proportion on both sides — the left
   rail has a gap before the plot (the frozen staff names must never be under
   anything), so the right does too. The page's equal left and right padding
   (`.page`, 76px + --xl each side) is what does it; nothing here overrides it. */


/* ── the shift plot on one big card (2026-09-24) ──
   Three layers, the way the design system builds a screen (§4, §5 Cards):
   a pale blue page, one white card holding the month, and the shift cards on
   it. Before this the cards sat straight on a #FAFAFA page — near white on
   near white, so the month had no edge and the two floating bars had nothing
   to frame.

   The card is the scroll box itself, so it clips the month to its rounded
   corners and the frozen day row still sticks flush to its top edge. Its
   inner margin is padding on the GRID, not on the scroll box: padding on a
   scroll container moves where sticky cells stop, and the month would show
   through above the frozen row.

   Roster only — Calendar, Outlets and Settings are documents on the page, not
   one surface, and keep their own background. */
body:has(#sched-grid > .rc-wrap) .page { background: #F4F8FB; }      /* --surface-blue-faint */
#sched-grid > .rc-wrap {
  --plot-surface: var(--white);
  background: var(--plot-surface);
  border: 1px solid #E5E5E5;                                         /* --border, hairline */
  border-radius: var(--rlg);
  box-shadow: 0 2px 8px rgba(22, 39, 122, .06);                      /* --shadow-card */
}
#sched-grid > .rc-wrap > .rc-grid { padding: 12px; }

/* The card lines up with the two floating bars (2026-09-24): its top 8px
   under the topbar and its foot 8px off the window's bottom, the same frame
   the dock and the Assistant rail sit in — three panels, one top line and one
   bottom line. */
@media (min-width: 641px) {
  body:has(#sched-grid > .rc-wrap) .page { padding-top: var(--sm); padding-bottom: var(--sm); }
}

/* FROZEN MEANS NOT MOVING. The month sits 12px inside the card, so at rest
   the day row is 12px below the card's top edge — and with sticky at 0 it
   jumped up those 12px the moment the month scrolled, and the staff column
   jumped 12px sideways. The manager read it, rightly, as "top freeze not
   fixed". So both freeze where they rest (12px), and the 12px strip between
   them and the card's edge is covered by the card's own white.

   The covers are the same trick theme.css already uses for the gaps between
   frozen cells ("Solid, and sealed on every side"): an offset copy of the cell
   in the surface colour. These are white now — the surface is the card — and
   gain one copy pointing into the margin: up for the day row, left for the
   staff column, both (and the diagonal) for the corner. */
#sched-grid .rc-frz-a { top: 12px; }
#sched-grid .rc-staff, #sched-grid .rc-grid > .rc-corner { left: 12px; }
#sched-grid .rc-frz-a {
  box-shadow: 0 0 0 3px var(--plot-surface), 0 var(--rc-gap) 0 var(--plot-surface),
              0 -12px 0 3px var(--plot-surface);
}
#sched-grid .rc-staff, #sched-grid .rc-grid > .rc-corner {
  box-shadow: 0 0 0 3px var(--plot-surface), var(--rc-gap) 0 0 var(--plot-surface),
              -12px 0 0 3px var(--plot-surface);
}
#sched-grid .rc-grid > .rc-corner.rc-frz-a {
  box-shadow: 0 0 0 3px var(--plot-surface), var(--rc-gap) 0 0 var(--plot-surface),
              0 var(--rc-gap) 0 var(--plot-surface), 0 -12px 0 3px var(--plot-surface),
              -12px 0 0 3px var(--plot-surface), -12px -12px 0 3px var(--plot-surface);
}

/* ── today, in the corner ──
   Where "Staff" used to be. A date is what a glance at a month is measured
   from; when today is in this month the corner is a button that scrolls to it,
   and today's own day card wears the gold ring the dock uses for "you are here". */
.rc-today {
  display: flex; padding-left: 10px; text-align: left;
  flex-direction: column; justify-content: center; align-items: flex-start !important;
  gap: 2px; line-height: 1.15;
}
.rc-today-k {
  font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--gold, #C9A227);
}
.rc-today-d { font-size: 24px; font-weight: 800; color: var(--navy); }
.rc-today-w { font-size: 12.5px; font-weight: 600; color: var(--g600); }
.rc-today.is-here { cursor: pointer; }
.rc-today.is-here:hover .rc-today-w { color: var(--navy); text-decoration: underline; }
.rc-today.is-here:focus-visible { outline: 2px solid var(--navy); outline-offset: -2px; }
#sched-grid .dc-day.is-today { outline: 2px solid var(--gold, #C9A227); outline-offset: -2px; }

/* White on white needs its edge: the staff labels take the page's pale blue,
   which also sets them apart from the shift cards as the row headings they
   are. */
#sched-grid .rc-staff { background: #F4F8FB; border-color: #E3EDF6; }

/* ── the plot's two scrollbars, one size ──
   app.css sets `::-webkit-scrollbar { width: 5px }` for the whole app — width
   only, which sizes the VERTICAL bar and leaves the horizontal one at the
   browser's own ~15px. On the month, the one place both show at once, that was
   a thin bar down the right and a thick one along the bottom. Both are the
   same here, and between the two: 8px at first, then 11px when the manager
   asked for a slightly bigger slider to grab (2026-09-24). */
#sched-grid > .rc-wrap::-webkit-scrollbar { width: 11px; height: 11px; }
#sched-grid > .rc-wrap::-webkit-scrollbar-track { background: transparent; }
#sched-grid > .rc-wrap::-webkit-scrollbar-corner { background: transparent; }
#sched-grid > .rc-wrap::-webkit-scrollbar-thumb {
  background: var(--g200); border-radius: 999px;
  border: 1px solid var(--plot-surface, #fff);    /* a hair of air round the thumb */
}
#sched-grid > .rc-wrap::-webkit-scrollbar-thumb:hover { background: var(--g400); }

/* ── Findings: every day with a problem (2026-09-24) ──
   One row per day — date, red and amber counts, the worst finding — in its
   own scroll box so a month full of problems cannot push the Day card below
   it out of reach. The picked day is lit navy, the same "you are here" the
   rails use. */
.assist-sec-n { float: right; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--g400); }
/* .assist-days / .assist-dayrow*: the Days with problems list, removed 2026-09-30. */

/* ── the two bars, swapped (2026-09-24) ──
   The dock (where to go) is on the LEFT now and the Assistant rail (what to
   do) on the RIGHT. Two things follow from which side is which:

   * The dock is the tall one — every destination and key — so on an ordinary
     window its top reaches up into the topbar, where it would sit on the ZUS
     lockup. The topbar starts after it instead. (The short Assistant rail on
     the right never reaches the topbar, and the month field keeps its own
     padding from when the dock was on that side.)
   * The rails' "you are here" marker is a gold bar on the edge that faces the
     page: the left edge for a rail on the left (app.css), the right edge for
     the one on the right. */
@media (min-width: 641px) {
  .topbar { padding-left: calc(var(--lg) + 76px + var(--md)); }
}
.assist-rail .bi-tab.active::after { left: auto; right: 0; border-radius: 4px 0 0 4px; }

/* ── override shifts, shown (2026-09-24) ──
   The shifts the rules do not want today are listed, not folded away, and
   grouped under one short question ("Add one more staff?"; the per-card
   OVERRIDE tag went 2026-10-13). Amber heading, like every other "you may,
   but it costs something" on the panel. */
.plot-lead-override { color: #9A5B00; }
/* A divider above the group (manager, 2026-10-13), so "Change their shift?" /
   "Add one more staff?" reads as its own section, apart from the picks. Same
   hairline as the Clear / Lock rows. */
.plot-lead.plot-lead-override { border-top: 1px solid var(--g100); padding-top: 10px; margin-top: 14px; }

/* ── the two bars' tab spacing follows the window (2026-09-24) ──
   Both floating bars are as roomy as the window allows and never scroll. The
   first attempt used a fixed 720px cut-off to go compact, and at 150% display
   scaling a maximised FOSS window is ~700px tall — so the manager only ever saw
   the squeezed version. Now each tab's top and bottom padding grows with the
   window height instead: the dock's 15 tabs need about 500px before padding,
   so every pixel above that is shared out among their 30 padded edges, between
   3px (a very short window) and 10px (a tall one). About 7px at 700px tall,
   8px at 750. The Assistant rail uses the same spacing so the two bars match. */
:root {
  --bar-tab-pad: clamp(3px, calc((100vh - 496px) / 30), 10px);
  /* The Assistant rail holds 10 tabs, not 15, so the same window gives it far
     more room: its ~290px of tabs share out the rest across 20 edges, up to
     12px — noticeably taller than the dock's, as the manager asked. */
  --rail-tab-pad: clamp(6px, calc((100vh - 300px) / 20), 12px);
}
.dock .bi-tab { padding-top: var(--bar-tab-pad); padding-bottom: var(--bar-tab-pad); }
.assist-rail .bi-tab { padding-top: var(--rail-tab-pad); padding-bottom: var(--rail-tab-pad); }
.assist-rail { gap: 14px; }


/* The Assistant rail belongs to the shift plot (app.js dockSync): hidden
   everywhere else, and the page takes its width back. */
#assist-rail[hidden] { display: none; }
@media (min-width: 641px) {
  body.no-assist-rail .page { padding-right: var(--xl); }
}

/* ── the dock keeps its shape on every page (2026-09-24) ──
   Its height used to follow its contents, and the Outlet and Guide groups are
   shown on the shift plot only — so the bar shrank and re-centred every time
   the page changed. Fixed at the full window height instead: the same shape
   everywhere, the utility buttons pinned to its foot (.dock-util's
   `margin-top: auto`), and any groups a page does not use simply leave space. */
@media (min-width: 641px) {
  .dock { height: calc(100vh - 2 * var(--sm)); }
}

/* ── the dock starts under the topbar (2026-09-24) ──
   Full window height put the dock over the frozen topbar, so the topbar had to
   indent its lockup to make room and the bar looked taller than the page it
   serves. It now runs from just under the topbar (62px, app.css .topbar — plus
   the LOA banner when one shows) to 8px off the bottom: still one fixed shape
   on every page, just no longer over the topbar. The tab spacing below shares
   out what is left, so on a short window the tabs sit a little closer. */
@media (min-width: 641px) {
  .dock {
    top: calc(62px + var(--sm)); bottom: var(--sm);
    transform: none; height: auto; max-height: none; margin-top: 0 !important;
  }
  /* --loa-h outlives the banner (loa.js only drops the class), so read it
     only while the banner is up. */
  body.has-loa .dock { top: calc(62px + var(--loa-h, 0px) + var(--sm)); }
  /* The Assistant rail is the dock's twin, so it takes the same frame (the
     manager, 2026-09-24): under the topbar to 8px off the bottom, whatever it
     holds. Its panel opens in that same frame beside it. */
  .assist-rail, .assist-panel {
    top: calc(62px + var(--sm)); bottom: var(--sm);
    transform: none; height: auto; max-height: none;
  }
  body.has-loa :is(.assist-rail, .assist-panel) { top: calc(62px + var(--loa-h, 0px) + var(--sm)); }
  /* And under the View as bar while a preview runs (auth.js
     authPlaceUnderViewAs), so nothing floats over the way out of it. Last, so
     it wins over the LOA line above; its measure already includes that banner. */
  body.is-previewing :is(.dock, .assist-rail, .assist-panel) { top: calc(var(--viewas-bottom, 62px) + var(--sm)); }
  /* 11 tabs under four headings now, in 78px less height: about 370px of
     tabs, headings and gaps, the rest shared across 22 padded edges. */
  :root { --rail-tab-pad: clamp(4px, calc((100vh - 500px) / 22), 12px); }
  .topbar { padding-left: var(--xl); }
  :root { --bar-tab-pad: clamp(3px, calc((100vh - 558px) / 30), 10px); }
}

/* ── borrowed staff (lending.js, 2026-09-24) ── */
.rc-staff-guest { border-style: dashed; border-color: #B9C6EF; background: #F3F6FF; }
.rc-card.rc-lent { border-style: dashed; border-width: 1.5px; }
.lend-box {
  border: 1px solid var(--g100); border-radius: var(--rmd); background: var(--white);
  padding: 6px 10px;
}
.lend-sub {
  font-size: 9.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--g400); margin: 6px 0 2px;
}
.lend-row { padding: 7px 0; border-top: 1px solid var(--g100); font-size: 12px; color: var(--g800); }
.lend-sub + .lend-row { border-top: none; }
.lend-row-top { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.lend-row-what { margin-top: 2px; font-size: 11.5px; color: var(--g600); }
.lend-note { font-size: 11px; color: var(--g400); margin-top: 2px; }
.lend-row-acts { display: flex; align-items: center; gap: 6px; margin-top: 6px; flex-wrap: wrap; }
.lend-pick { max-width: 200px; }
/* The outlets to ask, as a tick-list: one ask can go to several. Scrolls
   past six, since a DM can hold a dozen outlets. */
.lend-homes {
  border: 1px solid var(--g200); border-radius: var(--rmd); background: var(--white);
  max-height: 188px; overflow-y: auto; scrollbar-width: thin; margin-bottom: 8px;
}
.lend-home {
  display: flex; align-items: center; gap: 8px; padding: 6px 10px; cursor: pointer;
  font-size: 12px; color: var(--g800);
}
.lend-home + .lend-home { border-top: 1px solid var(--g100); }
.lend-home:hover { background: var(--g50); }
.lend-home input { accent-color: var(--navy); margin: 0; }
.lend-home span:first-of-type { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lend-home-id { font-size: 10px; color: var(--g400); }
.lend-chip {
  font-size: 9.5px; font-weight: 700; padding: 1px 8px; border-radius: var(--rpill);
  text-transform: uppercase; letter-spacing: .04em;
}
.lend-chip.is-pending   { background: #FDF0D5; color: #9A5B00; }
.lend-chip.is-approved  { background: #1F7047; color: #fff; }
.lend-chip.is-declined  { background: var(--g100); color: var(--g600); }
.lend-chip.is-cancelled { background: var(--g100); color: var(--g400); }

/* ── the two bars open and close the same way (2026-09-24) ──
   Three things made the slide feel rough, and the right bar worse than the
   left:
     1. Collapsed, each icon was centred; open, it jumped to the left edge.
        Now it never moves: 21px in, which is the centre of the 76px bar.
     2. Labels switched from zero width to full in one frame. Now they keep
        their width and are simply clipped by the bar, fading in once it has
        opened enough to show them.
     3. The right bar grows LEFTWARD from its screen edge. Its content keeps
        the normal reading order — icon, then label, left-aligned (a mirrored
        right-aligned version was tried and read as text stuck to the wall) —
        and rides the bar's left edge at a fixed width, so it slides out as
        one piece with the bar instead of re-flowing as it goes.
   Plus a little hover intent: 60ms before opening, so passing the pointer
   over a bar on the way to the page does not flash it open, and 120ms before
   closing, so slipping off the edge for a moment does not snap it shut. */
@media (min-width: 641px) {
  .bi-tabstrip-wrap:is(.dock, .assist-rail) {
    transition: width .26s cubic-bezier(.22, .9, .3, 1) .12s;
  }
  .bi-tabstrip-wrap:is(.dock, .assist-rail):is(:hover, .is-open) { transition-delay: .06s; }

  /* Fixed-width content, so nothing re-wraps while the bar moves. */
  .bi-tabstrip-wrap:is(.dock, .assist-rail) .bi-tabgroup { width: 220px; flex-shrink: 0; }
  .bi-tabstrip-wrap:is(.dock, .assist-rail) .bi-tabgroup { align-self: flex-start; }

  .bi-tabstrip-wrap:is(.dock, .assist-rail) .bi-tab {
    justify-content: flex-start; padding-left: 21px; padding-right: 12px;
  }

  .bi-tabstrip-wrap:is(.dock, .assist-rail):not(:hover):not(.is-open) :is(.nb-label, .bi-tabgroup-label) {
    width: auto; opacity: 0; transition: opacity .1s ease .12s;
  }
  .bi-tabstrip-wrap:is(.dock, .assist-rail):is(:hover, .is-open) :is(.nb-label, .bi-tabgroup-label) {
    width: auto; opacity: 1; transition: opacity .16s ease .16s;
  }
}
@media (prefers-reduced-motion: reduce) {
  .bi-tabstrip-wrap:is(.dock, .assist-rail),
  .bi-tabstrip-wrap:is(.dock, .assist-rail) :is(.nb-label, .bi-tabgroup-label) { transition: none !important; }
}

/* ── zooming the shift plot (scheduling.js schedulingZoomHtml, 2026-09-24) ──
   One pill in the topbar beside the month: − 100% + and Overview. Navy ink
   on white, like the month field next to it, so it reads as a control of
   the same family and not as a second title. */
.plot-zoom {
  display: inline-flex; align-items: center; gap: 2px; margin-right: 10px;
  border: 1px solid var(--g200); border-radius: var(--rpill); background: var(--white);
  padding: 2px;
}
.plot-zoom button {
  border: none; background: none; cursor: pointer; font-family: inherit; color: var(--navy);
  border-radius: var(--rpill); height: 28px; display: inline-flex; align-items: center; gap: 5px;
  transition: background .15s;
}
.plot-zoom button:hover { background: var(--g50); }
.plot-zoom svg { width: 15px; height: 15px; fill: currentColor; display: block; }
.plot-zoom-b { width: 28px; justify-content: center; }
.plot-zoom-pct { min-width: 46px; justify-content: center; font-size: 11.5px; font-weight: 700; }
.plot-zoom-fit {
  padding: 0 11px 0 9px; font-size: 11.5px; font-weight: 700;
  border-left: 1px solid var(--g100) !important; border-radius: 0 var(--rpill) var(--rpill) 0 !important;
  margin-left: 2px;
}
.plot-zoom-fit.is-on { background: var(--navy) !important; color: #fff; border-radius: var(--rpill) !important; }

/* ── Overview: the whole month on one screen (2026-09-24) ──
   Toggled by the topbar's Overview button (scheduling.js schedulingZoomFit).
   The same grid, compacted: narrow day columns that share the card's width,
   each card only its start time in its session colour (data-short — the full
   shift is still the tooltip and one tap away), the day header down to date
   and weekday, and each person's card to their name and hours. What it is
   for is the month's SHAPE — who opens, who closes, where the gaps are —
   which the full-size plot shows a week at a time. */
#sched-grid.is-overview { --rc-h: 30px; --rc-gap: 3px; }
#sched-grid.is-overview .rc-grid {
  grid-template-columns: 112px repeat(var(--sv-days, 31), minmax(26px, 1fr)) !important;
}
#sched-grid.is-overview .rc-card { border-radius: 6px; justify-content: center; }
#sched-grid.is-overview .rc-card:hover { transform: none; }
#sched-grid.is-overview .rc-time {
  font-size: 0; padding: 0; text-align: center; line-height: 1;
}
#sched-grid.is-overview .rc-time::before {
  content: attr(data-short); font-size: 10px; font-weight: 700; letter-spacing: -.02em;
}
#sched-grid.is-overview :is(.rc-rows, .rc-xmid, .rc-err, .rc-sess) { display: none; }
/* The OL's task note has no time to show: a thin striped slot, so the row
   still reads as "no bar shift" without the note field. */
#sched-grid.is-overview .rc-tasknote :is(.rc-tasklbl, .rc-tasktxt) { display: none; }
/* An OL's card is a shift card here too: its start time, no note. */
#sched-grid.is-overview .rc-olcard .rc-olnote { display: none; }
/* Day header: the date over the weekday, nothing else (the tooltip keeps
   the holidays and promotions). */
#sched-grid.is-overview .ac-day :is(.dc-tag, .dc-name, .dc-surge, .dc-det) { display: none; }
#sched-grid.is-overview .ac-day { padding: 4px 0; text-align: center; min-height: 0; }
#sched-grid.is-overview .ac-d { font-size: 11px; display: flex; flex-direction: column; align-items: center; line-height: 1.1; }
#sched-grid.is-overview .ac-dow { font-size: 8.5px; margin: 0; }
#sched-grid.is-overview .rc-today { padding: 4px 8px; }
#sched-grid.is-overview .rc-today-w { display: none; }
#sched-grid.is-overview .rc-today-d { font-size: 14px; }
/* A person: name and hours; the rest-day picker waits for the full plot. */
#sched-grid.is-overview .rc-staff > :not(.rc-staff-name):not(.rc-staff-meta) { display: none; }
#sched-grid.is-overview .rc-staff { padding-top: 3px; padding-bottom: 3px; justify-content: center; }
#sched-grid.is-overview .rc-staff-name { font-size: 11px; }
#sched-grid.is-overview .rc-staff-meta { font-size: 9px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#sched-grid.is-overview .rc-totrow { font-size: 9.5px; }

/* An Auto-fix waiting on the rules' answer (scheduling.js
   schedulingAssistProbeFixes) is drawn hidden; .btn's display would
   otherwise show it anyway. A row whose only fix stayed hidden keeps no gap. */
.assist-fix[hidden] { display: none; }
.assist-day-acts:not(:has(> :not([hidden]))) { display: none; }

/* Who is free at each ticked outlet (lending.js schedulingLendFree). */
.lend-free { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; }
.lend-free-h {
  display: flex; justify-content: space-between; align-items: baseline; margin-top: 4px;
  font-size: 11.5px; font-weight: 700; color: var(--navy);
}
.lend-free-h span { font-size: 10px; font-weight: 600; color: var(--g400); }
.lend-person {
  display: grid; grid-template-columns: 1fr auto; gap: 0 8px; text-align: left; width: 100%;
  border: 1px solid var(--g200); border-radius: var(--rmd); background: var(--white);
  padding: 6px 10px; cursor: pointer; font-family: inherit; transition: border-color .15s, background .15s;
}
.lend-person:hover { border-color: var(--navy); }
.lend-person.is-on { border-color: var(--navy); background: #EEF1FA; box-shadow: inset 3px 0 0 var(--navy); }
.lend-person-n { font-size: 12px; font-weight: 700; color: var(--g800); }
.lend-person-h { font-size: 10.5px; color: var(--g600); grid-row: 1 / span 2; grid-column: 2; align-self: center; }
.lend-person-t { font-size: 10px; color: var(--g400); }
.lend-blocked { font-size: 11px; color: var(--g600); }
.lend-blocked summary { cursor: pointer; color: var(--g400); font-size: 10.5px; padding: 2px 0; }
.lend-blocked-r { padding: 3px 0 3px 8px; border-left: 2px solid var(--g200); margin: 3px 0; line-height: 1.4; }

/* A day somebody asked not to work, approved in Lark (availability.js). */
.rc-asked {
  font-size: 9.5px; font-weight: 700; color: #9A5B00; background: #FDF0D5;
  border-radius: var(--rpill); padding: 1px 7px; align-self: center; margin: 4px 0 0;
}
.rc-card.rc-off.rc-askedoff { border-style: dashed; border-color: #E8C77A; background: #FFFBF2; }
#sched-grid.is-overview .rc-asked { display: none; }
#sched-grid.is-overview .rc-card.rc-askedoff .rc-time::before { content: '🙅'; }

/* -- Auto-fill in progress (2026-10-04) --------------------------------------
   A popup over the whole app while a fill runs: the manager asked for it once
   CP-SAT made a fill take up to a minute, and a still panel read as frozen.
   The scrim is the design system's one sanctioned use of blur (a modal scrim,
   ZUS-Design-System.md 6) - light, navy-tinted, not glass. The bar moves on an
   ESTIMATE (schedulingFillProgress explains why) and so carries no looping
   shimmer: motion here means "progress", never decoration (9, no infinite
   animation). Above every panel and both bars (80), with the modals (200). */
.fpop {
  position: fixed; inset: 0; z-index: 210;
  display: flex; align-items: center; justify-content: center;
  background: rgba(22, 39, 122, .14);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  opacity: 0; transition: opacity .2s ease;
}
.fpop.is-open { opacity: 1; }
.fpop-card {
  width: 380px; max-width: calc(100vw - 32px);
  background: var(--white); border: 1px solid var(--g100);
  border-radius: var(--rlg); box-shadow: var(--sf);
  padding: 24px; font-family: var(--font-sans);
  transform: translateY(8px); transition: transform .2s ease;
}
.fpop.is-open .fpop-card { transform: none; }
.fpop-title { font-size: 16px; font-weight: 600; color: var(--navy); }
.fpop-engine { font-size: 13px; color: var(--g600); margin-top: 4px; }
.fpop-track {
  height: 8px; margin-top: 20px; background: var(--g100);
  border-radius: var(--rpill); overflow: hidden;
}
.fpop-bar {
  height: 100%; width: 0%; background: var(--navy);
  border-radius: var(--rpill); transition: width .4s ease;
}
.fpop-meta {
  display: flex; justify-content: space-between; gap: 12px;
  margin-top: 12px; font-size: 13px; color: var(--g600);
}
.fpop-step { font-weight: 500; color: var(--navy); }
.fpop-note { font-size: 11px; color: var(--g600); margin-top: 16px; }
@media (prefers-reduced-motion: reduce) {
  .fpop, .fpop-card, .fpop-bar { transition: none; }
}

/* -- Management: one outlet's month in a popup (2026-10-04) ------------------
   Opened from a Management row, so a DM can look at an outlet and come back to
   the list without losing her place (management.js, mgmtOpenOutlet). The scrim
   is the design system's sanctioned blur (a modal scrim); the session colours
   are the roster's own .rc-MORNING / .rc-MIDDLE / .rc-CLOSING, so a Closing here
   is the same purple as on the grid. Read-only: editing is the roster's job. */
.mpop {
  position: fixed; inset: 0; z-index: 205;
  display: flex; align-items: center; justify-content: center;
  background: rgba(22, 39, 122, .14);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  opacity: 0; transition: opacity .2s ease;
}
.mpop.is-open { opacity: 1; }
.mpop-panel {
  width: min(1280px, calc(100vw - 32px)); height: min(88vh, 900px);
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--white); border: 1px solid var(--g100);
  border-radius: var(--rlg); box-shadow: var(--sf); font-family: var(--font-sans);
  transform: translateY(8px); transition: transform .2s ease;
}
.mpop.is-open .mpop-panel { transform: none; }
.mpop-head { display: flex; align-items: flex-start; gap: 16px; padding: 20px 24px 12px; }
.mpop-title { font-size: 18px; font-weight: 600; color: var(--navy); }
.mpop-sub { font-size: 13px; color: var(--g600); margin-top: 4px; }
.mpop-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.mpop-x {
  width: 32px; height: 32px; border-radius: var(--rsm); border: 1px solid var(--g100);
  background: var(--white); color: var(--g600); cursor: pointer; font-size: 16px;
}
.mpop-x:hover { background: var(--g50); }
.mpop-chips { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 24px 12px; }
.mpop-chip {
  display: inline-flex; gap: 6px; align-items: baseline; padding: 6px 12px;
  border-radius: var(--rpill); background: var(--g50); border: 1px solid var(--g100);
  font-size: 13px; color: var(--g600);
}
.mpop-chip b { color: var(--navy); font-weight: 600; }
.mpop-chip.is-crit { background: var(--err-bg); border-color: transparent; }
.mpop-chip.is-crit b { color: var(--err); }
.mpop-chip.is-warn { background: rgba(255, 150, 0, .12); border-color: transparent; }
.mpop-chip.is-warn b { color: #9A5B00; }
.mpop-tabs { display: flex; gap: 4px; padding: 0 24px; border-bottom: 1px solid var(--g100); }
.mpop-tab {
  padding: 8px 12px; border: none; background: none; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 500; color: var(--g600);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.mpop-tab.is-on { color: var(--navy); border-bottom-color: var(--navy); font-weight: 600; }
.mpop-body { flex: 1; min-height: 0; overflow: auto; padding: 16px 24px 24px; }

/* the roster: scrolls both ways, names and dates stay put */
.mpop-grid-wrap { overflow: auto; max-height: 100%; border: 1px solid var(--g100); border-radius: var(--rmd); }
.mpop-grid { border-collapse: separate; border-spacing: 0; font-size: 12px; }
.mpop-grid th, .mpop-grid td { border-bottom: 1px solid var(--g100); border-right: 1px solid var(--g100); }
.mpop-grid thead th {
  position: sticky; top: 0; z-index: 2; background: var(--white);
  min-width: 52px; padding: 6px 4px; text-align: center; font-weight: 500; color: var(--g600);
  cursor: pointer;
}
.mpop-grid thead th.is-weekend, .mpop-grid td.is-weekend { background: var(--g50); }
.mpop-grid thead th.is-holiday { box-shadow: inset 0 -3px 0 var(--gold-d); }
.mpop-grid thead th.is-sel { background: rgba(22, 39, 122, .08); color: var(--navy); }
.mpop-dn { display: block; font-size: 14px; font-weight: 600; color: var(--navy); }
.mpop-dots { display: flex; gap: 3px; justify-content: center; margin-top: 3px; min-height: 8px; }
.mpop-dot { width: 7px; height: 7px; border-radius: 50%; }
.mpop-dot.d-crit { background: var(--err); }
.mpop-dot.d-warn { background: var(--warn); }
.mpop-grid .mpop-who {
  position: sticky; left: 0; z-index: 1; background: var(--white);
  min-width: 190px; max-width: 190px; padding: 6px 12px; text-align: left;
}
.mpop-grid thead .mpop-who { z-index: 3; cursor: default; }
.mpop-name { font-size: 13px; font-weight: 600; color: var(--navy); }
.mpop-role { font-size: 11px; color: var(--g600); }
.mpop-cell { padding: 3px; text-align: center; }
.mpop-c {
  display: block; min-width: 44px; padding: 5px 2px; border-radius: 6px;
  font-size: 11px; font-weight: 600; color: #fff; border: 1px solid transparent;
}
.mpop-c.k-leave { background: var(--err-bg); color: var(--err); }
.mpop-c.k-rest { background: var(--g50); color: var(--g600); font-weight: 500; }
.mpop-c.k-asked { background: rgba(255, 150, 0, .12); color: #9A5B00; font-weight: 500; }
.mpop-foot td { font-size: 11px; color: var(--g600); text-align: center; padding: 4px 2px; }
.mpop-foot .mpop-who { font-size: 11px; font-weight: 500; }
.mpop-foot .is-short { color: var(--err); font-weight: 600; }
.mpop-legend { display: flex; flex-wrap: wrap; gap: 12px; margin: 12px 0 0; font-size: 11px; color: var(--g600); }
.mpop-legend .mpop-c { display: inline-block; min-width: 0; padding: 2px 6px; }
.mpop-day {
  margin-top: 16px; padding: 12px 16px; border: 1px solid var(--g100);
  border-radius: var(--rmd); background: var(--g50);
}
.mpop-day h4 { margin: 0 0 8px; font-size: 13px; font-weight: 600; color: var(--navy); }
.mpop-f { display: flex; gap: 8px; align-items: flex-start; font-size: 13px; color: var(--g600); margin-top: 6px; }
.mpop-f .mpop-dot { margin-top: 6px; flex: none; }

/* requests, leave and conditions */
.mpop-sec { font-size: 13px; font-weight: 600; color: var(--navy); margin: 0 0 8px; }
.mpop-sec + .mpop-sec, .mpop-tbl + .mpop-sec { margin-top: 24px; }
.mpop-tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.mpop-tbl th { text-align: left; font-size: 11px; font-weight: 500; color: var(--g600); padding: 6px 8px; border-bottom: 1px solid var(--g100); }
.mpop-tbl td { padding: 8px; border-bottom: 1px solid var(--g100); color: var(--g800, #333); vertical-align: top; }
.mpop-pill { display: inline-block; padding: 2px 10px; border-radius: var(--rpill); font-size: 11px; font-weight: 600; }
.mpop-pill.s-pending { background: rgba(255, 150, 0, .12); color: #9A5B00; }
.mpop-pill.s-approved { background: rgba(72, 167, 41, .12); color: #2E7A17; }
.mpop-pill.s-rejected { background: var(--g50); color: var(--g600); }
.mpop-empty { font-size: 13px; color: var(--g600); padding: 12px 0; }
/* Why this cost (management.js mpopCostHtml). */
.mcost-sum { display: flex; align-items: center; gap: 16px; padding: 12px 16px; border-radius: 12px;
  margin-bottom: 12px; background: var(--g50); }
.mcost-sum.is-over { background: var(--err-bg); }
.mcost-big { font-size: 22px; font-weight: 700; color: var(--navy); white-space: nowrap; }
.mcost-sum.is-over .mcost-big { color: var(--err); }
.mcost-line { font-size: 13px; color: var(--g800, #333); }
.mcost-head { font-size: 13px; font-weight: 600; color: var(--navy); margin-top: 2px; }
.mcost-tbl { margin-top: 12px; }
.mcost-tbl .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.mcost-tbl td.is-over { color: var(--err); font-weight: 600; }
.mcost-tbl td.is-under { color: var(--ok2); font-weight: 600; }
.mcost-total td { font-weight: 600; color: var(--navy); border-bottom: none; border-top: 2px solid var(--g100); }
.mcost-foot { margin-top: 12px; }
.mgmt-why { display: block; margin: 2px 0 0 auto; padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 10.5px; font-weight: 500; color: var(--err); text-decoration: underline; }
.mpop-cond { display: flex; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--g100); }
.mpop-cond .mpop-dot { margin-top: 6px; flex: none; }
.mpop-cond-h { font-size: 13px; font-weight: 600; color: var(--navy); }
.mpop-cond-m { font-size: 13px; color: var(--g600); margin-top: 2px; }
.mpop-cond-days { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.mpop-cond-days button {
  font: inherit; font-size: 11px; padding: 2px 8px; border-radius: var(--rpill);
  border: 1px solid var(--g100); background: var(--white); color: var(--navy); cursor: pointer;
}
.mpop-cond-days button:hover { background: var(--g50); }
@media (prefers-reduced-motion: reduce) { .mpop, .mpop-panel { transition: none; } }
@media (max-width: 640px) {
  .mpop-panel { width: 100vw; height: 100vh; border-radius: 0; }
  .mpop-grid .mpop-who { min-width: 120px; max-width: 120px; }
}
/* The letter in each session cell takes the theme's own text colour for that
   session (theme.css .rc-* .rc-time): navy on Opening's light blue, white on
   Middle's navy, burnt orange on Closing's peach. White on all three left the
   Opening and Closing letters unreadable. */
.mpop-c.rc-MORNING { color: #223488; }
.mpop-c.rc-MIDDLE  { color: #fff; }
.mpop-c.rc-CLOSING { color: #9A3B0C; }
/* On the Roster tab the grid takes whatever height is left, and the legend and
   the tapped day's findings stay pinned under it. Below the fold, tapping a
   date looked like it did nothing. */
.mpop-body.is-roster { display: flex; flex-direction: column; overflow: hidden; }
.mpop-body.is-roster .mpop-grid-wrap { flex: 1 1 auto; min-height: 160px; max-height: none; }
.mpop-body.is-roster .mpop-legend { flex: none; }
.mpop-body.is-roster .mpop-day { flex: none; max-height: 30%; overflow: auto; margin-top: 12px; }
/* A Management row opens its outlet (management.js, mgmtRowClick): say so. */
.mgmt-row { cursor: pointer; }
.mgmt-row:hover td { background: var(--g50); }
/* -- Setup's last screen: can this team cover the outlet? (2026-10-04) --------
   setup.js setupTeamRender. The verdict's colour is the only loud thing on it;
   the demo week reuses the Management popup's grid (.mpop-grid), so a week here
   reads exactly like a week there. */
.su-team-ok { color: var(--ok); }
.su-team-warn { color: #9A5B00; }
.su-team-bad { color: var(--err); }
.su-team-fix { font-size: 12px; line-height: 1.6; color: var(--g600); margin: calc(-1 * var(--sm)) 0 var(--lg); }
.su-team-checks { display: flex; flex-direction: column; gap: 6px; }
.su-team-check { display: flex; gap: 8px; align-items: flex-start; font-size: 13px; color: var(--g600); }
.su-team-check > span:first-child {
  flex: none; width: 18px; height: 18px; border-radius: 50%; display: inline-flex;
  align-items: center; justify-content: center; font-size: 11px; font-weight: 600; margin-top: 1px;
}
.su-team-yes { background: rgba(72, 167, 41, .14); color: #2E7A17; }
.su-team-no { background: rgba(255, 150, 0, .16); color: #9A5B00; }
.su-team-demo { margin-top: 20px; }
.su-team-demo .mpop-grid-wrap { max-height: 320px; }


/* ════════ STAFF ASKING TO WORK (2026-10-12) ════════
   A REQ shift: the person asked for it and the OL approved. A small tag, the
   card keeps its session colour (it IS coverage), and a gold edge so it is
   seen as theirs before anybody taps it. */
.rc-req { box-shadow: inset 0 0 0 2px #E0A400; }
.rc-reqtag {
  position: absolute; top: 3px; right: 4px; z-index: 1; font-size: 8px; font-weight: 800;
  letter-spacing: .06em; color: #5A3B00; background: #FCD34D; border-radius: 4px; padding: 1px 4px;
}
/* Changing a REQ shift: a form over the page, not a browser dialog. */
.req-ov { position: fixed; inset: 0; z-index: 80; background: rgba(15,23,60,.28); display: grid; place-items: center; }
.req-ov-box { width: min(420px, calc(100vw - 32px)); background: var(--white); border-radius: var(--rlg);
  padding: var(--lg); box-shadow: 0 16px 40px rgba(22,39,122,.25); }
.req-ov-title { font-size: 14px; font-weight: 800; color: var(--navy); margin-bottom: 6px; }
.req-ov-p { font-size: 12px; line-height: 1.5; color: var(--g600); margin-bottom: 10px; }
.req-ov-l { display: block; font-size: 11px; font-weight: 600; color: var(--g600); margin-bottom: 8px; }
.req-ov-l textarea { display: block; width: 100%; margin-top: 4px; font: inherit; font-size: 12px;
  border: 1px solid var(--g200); border-radius: var(--rsm); padding: 6px 8px; resize: vertical; }
.req-ov-chk { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; color: var(--g800); }
.req-ov-acts { display: flex; justify-content: flex-end; gap: 8px; margin-top: var(--md); }
/* Who can come in, under the Assistant's day. */
.assist-oncall-btn { margin-top: 8px; }
.oc-box { margin-top: 10px; border: 1px solid var(--g100); border-radius: var(--rmd); padding: 8px 10px; background: var(--white); }
.oc-head { display: flex; justify-content: space-between; align-items: center; font-size: 12px; font-weight: 800; color: var(--navy); }
.oc-tier { margin-top: 8px; }
.oc-tier-h { font-size: 10px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: var(--g400); margin-bottom: 4px; }
.oc-row { padding: 5px 0; border-top: 1px solid var(--g50); }
.oc-who { font-size: 12px; color: var(--g800); }
.oc-role { font-size: 9.5px; font-weight: 800; color: var(--g400); margin-left: 4px; }
.oc-why { font-size: 10.5px; color: var(--g400); margin-left: 6px; }
.oc-offers { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.oc-offer { font: inherit; font-size: 10.5px; font-weight: 700; color: var(--navy); background: var(--tint);
  border: 1px solid var(--g100); border-radius: var(--rpill); padding: 2px 9px; cursor: pointer; }
.oc-offer:hover { border-color: var(--navy); }
.oc-room { font-size: 10.5px; color: var(--g600); }
.oc-none, .oc-foot { font-size: 10.5px; color: var(--g400); }
.oc-foot { margin-top: 8px; line-height: 1.45; }

/* Rule exceptions: the Settings card and the line on the Assistant's day. */
.exc-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; padding: 6px 0;
  border-top: 1px solid var(--g50); font-size: 12px; color: var(--g800); }
.exc-why { font-size: 10.5px; color: var(--g400); margin-top: 2px; }
.exc-none { font-size: 11px; color: var(--g400); padding: 4px 0; }
.exc-form { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--g100); }
.exc-dates { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--g600); }
.exc-days { display: flex; flex-wrap: wrap; gap: 8px; font-size: 11px; color: var(--g600); align-items: center; }
.exc-days label { display: inline-flex; align-items: center; gap: 3px; }
.exc-hint { color: var(--g400); font-size: 10px; }
.assist-exc { font-size: 11px; color: #5A3B00; background: #FFF4D6; border-radius: var(--rsm); padding: 5px 8px; margin: 4px 0; }

/* A Fix's message, with its Undo (schedulingFixToast). */
.fix-toast { align-items: center; }
.fix-toast-undo { margin-left: auto; font: inherit; font-size: 12px; font-weight: 800; color: var(--navy);
  background: var(--white); border: 1px solid var(--g200); border-radius: var(--rpill); padding: 3px 12px; cursor: pointer; }
/* A day's own small panel (schedulingDayPopupOpen). */
.dp-body { padding-top: var(--md); }
.dp-row { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--g800); padding: 6px 0;
  border-bottom: 1px solid var(--g50); }
.dc-exc { background: #FFF4D6; color: #5A3B00; }

/* The OL bar slider's split / back-to-one button, under the blocks. */
.olb-split { margin-top: 2px; }

/* Removing leave: the row asks first (schedulingAbsConfirmHtml). */
.assist-abs-confirm { flex-direction: column; align-items: stretch; gap: 6px; background: #FFF4F2; border-radius: var(--rsm); padding: 8px; }
.abs-q { font-size: 12px; color: var(--g800); line-height: 1.45; }
.abs-lark { font-size: 10.5px; color: var(--err); margin-top: 4px; }
.abs-acts { display: flex; gap: 6px; justify-content: flex-end; }
.abs-remove { background: var(--err); color: #fff; border: 0; }

/* The plot panel's custom time slider: the link to the time boxes. */

/* Leaving or joining, under Add staff (schedulingStaffDatesHtml). */
.sd-list { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; }
.sd-row { display: grid; grid-template-columns: 1fr auto auto auto; gap: 6px; align-items: center; padding: 5px 0; border-top: 1px solid var(--g50); font-size: 11.5px; }
.sd-f { display: flex; flex-direction: column; font-size: 9.5px; color: var(--g400); gap: 2px; }
.sd-f input { font-size: 10.5px; width: 118px; }
.sd-confirm { grid-template-columns: 1fr; background: #FFF4F2; border-radius: var(--rsm); padding: 8px; }
.sd-acts { display: flex; gap: 6px; justify-content: flex-end; }

/* The OL's day panel: the two colours named, and a day with no bar time on
   the shift plot (admin only, so not coverage). */
.olb-daysum { font-size: 11.5px; margin: 6px 0; display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.olb-sw { display: inline-block; width: 10px; height: 10px; border-radius: 3px; border: 1px solid; }
.olb-sw-day { background: #EFD9BB; border-color: #C18F59; }
.olb-sw-bar { background: #1F7047; border-color: #175838; margin-left: 6px; }
.rc-card.rc-oladmin { background: #F9F4EE; border: 1px solid #EFD9BB; box-shadow: none; }
.rc-card.rc-oladmin .rc-time { color: #8A6236; }

/* The plot panel slider's stops (scheduling.js schedulingPlotGuard). */
.plot-limit { margin: 6px 0; padding: 8px 10px; border-radius: var(--rsm); font-size: 11.5px; line-height: 1.45;
  background: #FFF6E5; border: 1px solid #F5D08A; color: var(--g700, #4D4D4D); }
.plot-limit-acts { display: flex; gap: 6px; justify-content: flex-end; margin-top: 6px; }
.plot-limit .plot-bend { background: #FF9600; color: #fff; border: 1px solid #E08400; }
.plot-limit-bent { background: #FFF1E0; border-color: #FF9600; }
.plot-limit-law { background: #FDE7EC; border-color: #F3A3B5; }

/* ── The CP-SAT lab (js/cpsat-lab.js): How it decides, ABP only ── */
.lab { margin: 0 0 28px; padding: 20px; border: 1px solid var(--g100); border-radius: 16px; background: #fff; }
.lab-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.lab-t { font-size: 18px; font-weight: 600; color: var(--navy); margin: 0; }
.lab-tag { font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; padding: 3px 9px; border-radius: 100px; background: #DFEAF5; color: var(--navy); }
.lab-form { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-end; margin: 12px 0 16px; }
.lab-fgroup { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end; padding: 10px 12px; border: 1px solid var(--g100); border-radius: 12px; background: var(--g50); }
.lab-fg-t { width: 100%; font-size: 11px; font-weight: 500; color: #747474; }
.lab-f { display: flex; flex-direction: column; gap: 4px; font-size: 11px; color: #747474; }
.lab-f input { width: 84px; }
.lab-flow { display: flex; align-items: stretch; gap: 4px; overflow-x: auto; padding: 4px 2px 10px; }
.lab-arrow { align-self: center; color: #B2B2B2; font-size: 16px; flex: none; }
.lab-node { flex: 1 1 0; min-width: 120px; text-align: left; display: flex; flex-direction: column; gap: 2px; padding: 10px 12px;
  border: 1px solid var(--g100); border-radius: 12px; background: #fff; cursor: pointer; font: inherit; color: inherit;
  transition: box-shadow .15s, border-color .15s; }
.lab-node:hover { box-shadow: 0 6px 20px rgba(22,39,122,.10); }
.lab-node.on { border-color: var(--navy); box-shadow: 0 0 0 3px rgba(22,39,122,.08); }
.lab-node-n { width: 20px; height: 20px; border-radius: 50%; background: var(--navy); color: #fff; font-size: 11px; font-weight: 600; display: grid; place-items: center; }
.lab-node-t { font-size: 11px; font-weight: 500; color: #747474; margin-top: 4px; }
.lab-node-big { font-size: 20px; font-weight: 700; color: var(--navy); line-height: 1.15; }
.lab-node-sub { font-size: 10.5px; color: var(--g600); line-height: 1.35; }
.lab-detail { border-top: 1px solid var(--g100); padding-top: 14px; }
.lab-p { font-size: 12.5px; line-height: 1.55; color: #4D4D4D; margin-bottom: 10px; max-width: 90ch; }
.lab-p code, .lab-tbl code { font-family: ui-monospace, Consolas, monospace; font-size: 11px; background: var(--tint); padding: 1px 5px; border-radius: 5px; }
.lab-sub { font-size: 11px; font-weight: 600; color: var(--g600); text-transform: uppercase; letter-spacing: .06em; margin: 12px 0 6px; }
.lab-tbl { border-collapse: collapse; font-size: 12px; width: 100%; max-width: 720px; }
.lab-tbl th, .lab-tbl td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--g100); }
.lab-tbl th { font-size: 11px; font-weight: 500; color: #747474; }
.lab-tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
.lab-fams { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 8px; }
.lab-fam { border: 1px solid var(--g100); border-radius: 12px; padding: 10px 12px; border-left: 4px solid #FF9600; }
.lab-fam-hard { border-left-color: var(--navy); }
.lab-fam-h { display: flex; align-items: center; gap: 6px; font-size: 12.5px; flex-wrap: wrap; }
.lab-fam-n { margin-left: auto; font-size: 11px; color: var(--g600); font-variant-numeric: tabular-nums; }
.lab-kind { font-size: 9.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; padding: 2px 7px; border-radius: 100px; background: #FFF1E0; color: #B35F00; }
.lab-fam-hard .lab-kind { background: #DFEAF5; color: var(--navy); }
.lab-math { font-family: ui-monospace, Consolas, monospace; font-size: 11.5px; background: var(--tint); color: var(--g800); padding: 8px 10px; border-radius: 8px; margin: 8px 0 6px; white-space: pre-wrap; }
.lab-obj { font-size: 11px; }
.lab-fam-why { font-size: 11.5px; color: var(--g600); line-height: 1.45; }
.lab-ctrl { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.lab-range { flex: 1 1 160px; accent-color: var(--navy); }
.lab-fr { font-size: 12px; color: #4D4D4D; }
.lab-split { display: grid; grid-template-columns: 1fr minmax(280px, 420px); gap: 20px; align-items: start; margin-top: 8px; }
@media (max-width: 900px) { .lab-split { grid-template-columns: 1fr; } }
.lab-chart { width: 100%; height: auto; display: block; }
.lab-ax { stroke: #CCCCCC; stroke-width: 1; }
.lab-obj-line { fill: none; stroke: var(--navy); stroke-width: 2; }
.lab-bound-line { fill: none; stroke: #48A729; stroke-width: 1.5; stroke-dasharray: 4 3; }
.lab-dot { fill: var(--navy); }
.lab-dot-on { fill: #fff; stroke: var(--navy); stroke-width: 2.5; }
.lab-lbl { font-size: 10px; fill: var(--g600); }
.lab-legend { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 11px; color: var(--g600); margin: 4px 0 8px; }
.lab-sw { display: inline-block; width: 14px; height: 3px; border-radius: 2px; margin-left: 6px; }
.lab-sw-obj { background: var(--navy); }
.lab-sw-bound { background: repeating-linear-gradient(90deg, #48A729 0 4px, transparent 4px 7px); }
.lab-costs { display: flex; flex-direction: column; gap: 5px; }
.lab-cost { display: grid; grid-template-columns: minmax(120px, 1.3fr) 1fr auto; gap: 8px; align-items: center; font-size: 11.5px; }
.lab-cost-k { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #4D4D4D; }
.lab-bar { height: 8px; background: var(--g50); border-radius: 4px; overflow: hidden; }
.lab-bar i { display: block; height: 100%; border-radius: 4px; background: #B2B2B2; transition: width .4s ease-in-out; }
.lab-bar .lab-bar-crit { background: #EC0D40; }
.lab-bar .lab-bar-warn { background: #FF9600; }
.lab-cost-v { font-variant-numeric: tabular-nums; color: var(--g600); white-space: nowrap; }
.lab-cost-v em { font-style: normal; font-size: 10.5px; }
.lab-cost-v em.down { color: #48A729; }
.lab-cost-v em.up { color: #EC0D40; }
.lab-week { display: grid; gap: 3px; font-size: 10.5px; overflow-x: auto; }
.lab-wh { text-align: center; font-weight: 600; color: #4D4D4D; font-size: 11px; }
.lab-wh span { font-weight: 400; color: var(--g400); }
.lab-who { display: flex; justify-content: space-between; align-items: center; gap: 4px; font-size: 11px; padding-right: 4px; }
.lab-who span { color: var(--g600); font-size: 10px; }
.lab-who-sum { color: var(--g600); font-size: 10px; }
.lab-c { min-height: 26px; border-radius: 6px; display: grid; place-items: center; text-align: center; padding: 2px; border: 1px solid transparent; transition: background .3s; }
.lab-c-off { background: var(--g50); }
.lab-c-MORNING { background: #DDE4F8; color: #16277A; }
.lab-c-MIDDLE { background: #283C9D; color: #fff; }
.lab-c-CLOSING { background: #FBE4D6; color: #8A4B1F; }
.lab-c-chg { border: 2px solid #FF9600; }
.lab-sum { display: flex; flex-direction: column; align-items: center; font-size: 10px; color: var(--g600); line-height: 1.3; }
.lab-sum .short { color: #EC0D40; font-weight: 600; }
.lab-sum .over { color: #B35F00; font-weight: 600; }
.lab-key { padding: 1px 7px; border-radius: 100px; font-size: 10.5px; }
.lab-blank-line { stroke: #B2B2B2; stroke-width: 1.5; stroke-dasharray: 2 3; }
.lab-dot-blank { fill: #B2B2B2; }
.lab-sw-blank { background: #B2B2B2; }
.lab-tot { display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 10.5px; color: var(--g600); border-radius: 6px; }
.lab-tot b { color: #4D4D4D; }
.lab-tot.lab-tot-full { background: #FFF1E0; }
.lab-tot.lab-tot-full b { color: #B35F00; }
.lab-bend { margin-top: 14px; padding: 12px 14px; border: 1px solid var(--g100); border-radius: 12px; background: var(--g50); }
.lab-bent { margin: 0 0 10px 18px; padding: 0; font-size: 12px; line-height: 1.6; color: #4D4D4D; }
.lab-bent span { color: var(--g600); }
.lab-tbl-why { font-size: 11px; color: var(--g600); }
.lab-tbl tr.lab-short td:last-child { color: #EC0D40; }
.lab-wh-dlv { color: #B35F00; }

/* ── Auto-fill, live (scheduling.js schedulingLiveFill) ── */
.live-shield { position: fixed; inset: 0; z-index: 900; background: transparent; cursor: progress; }
.live-card { position: fixed; right: 20px; bottom: 20px; z-index: 950; width: 300px; padding: 14px 16px;
  background: #fff; border: 1px solid #E5E5E5; border-radius: 16px; box-shadow: 0 6px 20px rgba(22,39,122,.14);
  opacity: 0; transform: translateY(12px); transition: opacity .2s ease-in-out, transform .2s ease-in-out; }
.live-card.is-open { opacity: 1; transform: none; }
.live-head { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--navy); }
.live-tag { margin-left: auto; font-size: 9.5px; font-weight: 700; letter-spacing: .08em; color: #fff; background: #EC0D40; padding: 2px 7px; border-radius: 100px; }
.live-card.is-done .live-tag { background: #48A729; }
.live-dot { width: 8px; height: 8px; border-radius: 50%; background: #EC0D40; animation: live-pulse 1.1s ease-in-out infinite; }
.live-card.is-done .live-dot { background: #48A729; animation: none; }
@keyframes live-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.8); } }
.live-engine { font-size: 11.5px; color: var(--g600); margin-top: 3px; }
.live-stage { font-size: 12.5px; font-weight: 500; color: var(--navy); margin-top: 10px; }
.live-stats { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: 11.5px; color: #4D4D4D; margin-top: 4px; font-variant-numeric: tabular-nums; }
.live-note { font-size: 10.5px; color: var(--g600); margin-top: 10px; line-height: 1.4; }
.live-bubble { position: fixed; z-index: 960; max-width: 250px; padding: 9px 14px; border-radius: 14px;
  background: var(--navy); color: #fff; font-size: 12.5px; font-weight: 500; box-shadow: 0 6px 20px rgba(22,39,122,.25);
  pointer-events: none; animation: live-bubble-in .18s ease-out; transition: opacity .35s; }
.live-bubble.is-gone { opacity: 0; }
@keyframes live-bubble-in { from { transform: scale(.85) translateY(6px); opacity: 0; } to { transform: none; opacity: 1; } }
.rc-card.rc-live { border: 1.5px dashed rgba(22,39,122,.45); box-shadow: none; opacity: .92; }
.rc-card.rc-live.rc-live-saved { border-style: solid; opacity: 1; }
.rc-card.rc-live-new { animation: live-cell-in .45s ease-out; }
@keyframes live-cell-in { from { transform: scale(.7); opacity: 0; } 60% { transform: scale(1.06); } to { transform: none; opacity: .92; } }
.rc-live-tag { font-size: 8.5px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; opacity: .7; margin-top: 2px; }
@media (prefers-reduced-motion: reduce) { .live-dot, .rc-card.rc-live-new, .live-bubble { animation: none; } .live-card { transition: none; } }
.live-acts { display: flex; gap: 6px; }

/* The live card (2026-10-12: "not really understand what is it"; the graph became number boxes 2026-10-13). */
.live-card { width: 340px; }
.live-stats { display: block; }
/* The live fill's number boxes (2026-10-13: "make it a number box that the
   number is moving"). Two to four across, the number big, the label under. */
.live-boxes { display: grid; grid-template-columns: repeat(auto-fit, minmax(64px, 1fr)); gap: 6px; margin: 8px 0 6px; }
.live-box { border: 1px solid var(--g100); border-radius: var(--rmd); background: var(--white); padding: 8px 6px 6px; text-align: center; }
.live-box-n { font-size: 20px; font-weight: 800; color: var(--navy); line-height: 1.1; font-variant-numeric: tabular-nums; white-space: nowrap; }
.live-box-l { font-size: 10px; font-weight: 600; color: var(--g600); margin-top: 3px; text-transform: uppercase; letter-spacing: .04em; }
.live-box.is-warn .live-box-n { color: #C2260B; }
.live-box.is-ok .live-box-n { color: #1F7047; }
.live-q-t { font-size: 11.5px; color: #4D4D4D; line-height: 1.45; }
.live-sub { font-size: 10.5px; font-weight: 600; color: var(--g600); text-transform: uppercase; letter-spacing: .05em; margin-top: 10px; }
.live-unmet { margin: 4px 0 0; padding: 0; list-style: none; font-size: 11.5px; line-height: 1.6; color: #4D4D4D; }
.live-unmet li::before { content: ''; display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 6px; background: #B2B2B2; }
.live-unmet .live-u-crit::before { background: #EC0D40; }
.live-unmet .live-u-warn::before { background: #FF9600; }
.live-fair { font-size: 11px; color: #4D4D4D; margin-top: 8px; padding: 6px 8px; border-radius: 8px; background: var(--g50); line-height: 1.45; }
.live-fair.is-on { background: #F3F6FF; border: 1px solid #DFEAF5; }
.lab-week .lab-c { font-size: 9.5px; line-height: 1.2; min-height: 30px; padding: 2px 3px; overflow-wrap: anywhere; min-width: 0; }
.lab-week .lab-who { font-size: 10.5px; min-width: 0; }
.lab-tot { min-width: 0; font-size: 10px; }

/* The lab's whole rulebook (cpsat-lab.js labRulebookHtml). */
.lab-book { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 8px; margin-bottom: 8px; }
.lab-book-g { border: 1px solid var(--g100); border-radius: 12px; padding: 10px 12px; border-top: 4px solid #B2B2B2; }
.lab-book-hard { border-top-color: var(--navy); }
.lab-book-soft { border-top-color: #FF9600; }
.lab-book-cell { border-top-color: #48A729; }
.lab-book-h { display: flex; justify-content: space-between; font-size: 12.5px; color: #4D4D4D; }
.lab-book-h span { font-weight: 700; color: var(--navy); }
.lab-book-why { font-size: 11px; color: var(--g600); margin: 2px 0 6px; }
.lab-book-r { display: grid; grid-template-columns: 24px 1fr; gap: 6px; font-size: 11.5px; line-height: 1.4; padding: 4px 0; border-top: 1px solid var(--g50); }
.lab-book-r code { font-family: ui-monospace, Consolas, monospace; font-size: 10px; color: var(--g600); }
.lab-book-r i { font-style: normal; color: var(--g600); font-size: 11px; }
.lab-lvl { font-size: 9.5px; font-weight: 700; color: var(--navy); background: #DFEAF5; border-radius: 6px; text-align: center; height: 16px; line-height: 16px; }
/* A stock-take day on the day header (rules.py stock_take). */
.dc-tag.dc-stock { background: #EFD9BB; color: #8A6236; }
.rc-avail[role="button"] { cursor: pointer; }
.rc-avail[role="button"]:hover { text-decoration: underline; }

/* The plot panel's "Not on this outlet's floor" (schedulingPlotAwayHtml), and the Auto-fill & clear hub. */
.plot-away { display: flex; gap: 6px; flex-wrap: wrap; margin: 4px 0 6px; }
.plot-away-btn.on { border-color: var(--navy); background: #F3F6FF; }
.plot-away-form { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding: 8px; border: 1px solid var(--g100); border-radius: 10px; margin-bottom: 8px; }
.plot-away-form #plot-away-note { flex: 1 1 180px; }
.plot-away-until { display: flex; align-items: center; gap: 4px; font-size: 11px; color: var(--g600); }
.assist-hub-sec { margin-top: 16px; padding-top: 10px; border-top: 1px solid var(--g100); }

/* Shift availability as hours (schedulingShiftAvailFormHtml). */
.su-tl-AVAIL { background: #1F7047; border-color: #175838; }   /* the Nothing to fix green (2026-10-13) */
.av-days { display: flex; gap: 4px; margin: 6px 0 8px; flex-wrap: wrap; }
.av-day { font: inherit; font-size: 11px; font-weight: 600; padding: 4px 9px; border-radius: 100px; cursor: pointer;
  border: 1px solid var(--g200, #CCCCCC); background: #fff; color: var(--g600); }
.av-day.on { background: #1F7047; border-color: #1F7047; color: #fff; }
.su-tl-track.av-off { background: repeating-linear-gradient(45deg, var(--g50) 0 6px, #fff 6px 12px); }

/* The Assistant's list of every check (schedulingAssistChecksHtml). */
.chk-lvl { font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--g600); margin: 10px 0 4px; }
.chk { display: grid; grid-template-columns: 18px 1fr auto; gap: 8px; align-items: center; padding: 6px 8px; border-radius: 8px; font-size: 12px; }
.chk[role="button"] { cursor: pointer; }
.chk[role="button"]:hover, .chk.is-open { background: var(--g50); }
.chk-ico { width: 18px; height: 18px; border-radius: 50%; display: grid; place-items: center; font-size: 10px; font-weight: 700; color: #fff; background: #B2B2B2; }
.chk-crit .chk-ico { background: #EC0D40; }
.chk-warn .chk-ico { background: #FF9600; }
.chk-info .chk-ico { background: #30AFE5; }
.chk-ok .chk-ico { background: #1F7047; }
.chk-none .chk-ico, .chk-off .chk-ico { background: #E5E5E5; color: #7F7F7F; }
.chk-label { color: #333; line-height: 1.3; }
.chk-off .chk-label, .chk-none .chk-label { color: var(--g600); }
.chk-state { font-size: 11px; color: var(--g600); white-space: nowrap; }
.chk-crit .chk-state { color: #C2260B; font-weight: 600; }
.chk-warn .chk-state { color: #B35F00; font-weight: 600; }
.chk-days { margin: 2px 0 6px 26px; border-left: 2px solid var(--g100); padding-left: 8px; }
.chk-day { font-size: 11.5px; padding: 4px 6px; border-radius: 6px; cursor: pointer; color: #4D4D4D; }
.chk-day:hover { background: var(--g50); }
.chk-day i { font-style: normal; color: var(--g600); }
.chk-foot { margin-top: 8px; }
/* A live preview card: its time and its word in the middle of the box (2026-10-13). */
.rc-card.rc-live { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 2px; }
.rc-card.rc-live .rc-time { width: 100%; text-align: center; margin: 0; }
.rc-card.rc-live .rc-live-tag { margin: 0; align-self: center; padding: 1px 7px; border-radius: 100px; background: rgba(22,39,122,.08); }
.rc-card.rc-live.rc-MIDDLE .rc-live-tag { background: rgba(255,255,255,.18); }
.rc-card.rc-live .rc-live-tag { color: #fff; background: rgba(255,255,255,.22); opacity: 1; font-size: 9px; letter-spacing: .08em; }
.fld-req { font-size: 9.5px; font-weight: 600; color: #C2260B; text-transform: uppercase; letter-spacing: .04em; margin-left: 4px; }
.fi.fi-need { border-color: #EC0D40; box-shadow: 0 0 0 3px rgba(236,13,64,.12); }
/* The timeline past midnight (setup.js tlHtml overnight). */
.su-tl-midnight { position: absolute; top: 0; bottom: 0; width: 0; border-left: 1.5px dashed #16277A; opacity: .35; pointer-events: none; }
.su-tl-axis span.su-tl-next { color: #16277A; font-weight: 600; }
/* Which shifts fit each day's availability (schedulingAvailFitHtml). */
.av-fit { margin: 6px 0 8px; padding: 8px 10px; border-radius: 10px; background: var(--g50); font-size: 11.5px; line-height: 1.6; }
.av-fit.has-none { background: #FFF6E5; border: 1px solid #F5D08A; }
.av-fit code { font-family: ui-monospace, Consolas, monospace; font-size: 10.5px; background: #fff; padding: 0 4px; border-radius: 4px; }
.av-fit-none { color: #8A4B00; }

/* One green for "yes, done, fine" (2026-10-13: "approve request ... get green in
   colour similar to nothing to fix"): the day strip's Nothing to fix, Approve,
   Approved, and the checks list's ticks, all #1F7047 with white text. */
.btn.btn-ok { background: #1F7047; border: 1.5px solid #1F7047; color: #fff; }
.btn.btn-ok:hover { background: #175838; border-color: #175838; }


/* The shift plot: asked-for is green, not-available is red, both on white
   (scheduling.js SCHED_ICON_REQ / SCHED_ICON_OFF). #sched-grid so these beat
   theme.css's session colours, which load last. */
.rc-ico { width: 11px; height: 11px; fill: currentColor; vertical-align: -1.5px; flex: 0 0 auto; }
#sched-grid .rc-card.rc-req { background: #fff; border: 1.5px solid #1F7047; box-shadow: none; }
#sched-grid .rc-card.rc-req .rc-time, #sched-grid .rc-card.rc-req .rc-time-pattern,
#sched-grid .rc-card.rc-req .rc-v, #sched-grid .rc-card.rc-req .rc-sess { color: #1F7047; }
#sched-grid .rc-card.rc-req .rc-k { color: rgba(31,112,71,.75); }
#sched-grid .rc-card.rc-req .rc-reqtag { background: #1F7047; color: #fff; display: inline-flex; align-items: center; gap: 3px; }
/* Locked — they asked to keep this shift (2026-10-13). REQ's shape in ZUS
   navy: the outlet's promise to them, where green is their own request. */
#sched-grid .rc-card.rc-kept { background: #fff; border: 1.5px solid #16277A; box-shadow: none; }
#sched-grid .rc-card.rc-kept .rc-time, #sched-grid .rc-card.rc-kept .rc-time-pattern,
#sched-grid .rc-card.rc-kept .rc-v, #sched-grid .rc-card.rc-kept .rc-sess { color: #16277A; }
#sched-grid .rc-card.rc-kept .rc-k { color: rgba(22,39,122,.7); }
#sched-grid .rc-card.rc-kept .rc-time { display: flex; align-items: center; justify-content: center; gap: 4px; }
.plot-keep { margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--g100);
  display: flex; flex-wrap: wrap; gap: 6px; }
.plot-keep-btn { display: inline-flex; align-items: center; gap: 4px; }
.plot-keep-btn .ni svg { width: 13px; height: 13px; fill: currentColor; }
.plot-keep .plot-pattern-note { flex-basis: 100%; }
#sched-grid .rc-card.rc-leave { background: #fff; border: 1.5px solid #C2260B; box-shadow: none; }
#sched-grid .rc-card.rc-leave .rc-sess, #sched-grid .rc-card.rc-leave .rc-time,
#sched-grid .rc-card.rc-leave .rc-time-pattern { color: #C2260B; }
#sched-grid .rc-card.rc-leave .rc-sess { display: inline-flex; align-items: center; gap: 3px; font-weight: 700; }
#sched-grid .rc-card.rc-off.rc-askedoff { background: #fff; border: 1.5px dashed #C2260B; }
#sched-grid .rc-asked { background: #fff; color: #C2260B; border: 1px solid #C2260B; display: inline-flex; align-items: center; gap: 3px; }

/* Leave, asked off and REQ on the plot: everything in the middle of the card,
   icons in the rail's style (2026-10-13: "those text make on the middle . icon
   standardize . follow floating bar styling"). */
#sched-grid .rc-card.rc-leave, #sched-grid .rc-card.rc-off.rc-askedoff {
  display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 3px; }
#sched-grid .rc-card.rc-leave .rc-sess { display: block; font-weight: 700; margin: 0; }
#sched-grid .rc-card.rc-leave .rc-time { margin: 0; }
.rc-mid-ico { height: auto; }
.rc-mid-ico svg { width: 20px; height: 20px; }
#sched-grid .rc-asked, #sched-grid .rc-reqtag { display: inline-flex; align-items: center; justify-content: center; gap: 4px; }
#sched-grid .rc-asked .ni, #sched-grid .rc-reqtag .ni { width: auto; height: auto; }
#sched-grid .rc-asked .ni svg, #sched-grid .rc-reqtag .ni svg { width: 13px; height: 13px; }
#sched-grid .rc-asked { font-size: 10px; padding: 2px 8px; margin: 0; }
#sched-grid .rc-card.rc-leave { color: #C2260B; }
#sched-grid .rc-card.rc-req .rc-time { display: flex; align-items: center; justify-content: center; gap: 4px; }
#sched-grid .rc-card.rc-req .rc-time-ico { width: auto; height: auto; color: #1F7047; }
#sched-grid .rc-card.rc-req .rc-time-ico svg { width: 14px; height: 14px; }

/* Not employed that day (before the first day, after the last): grey, plain. */
#sched-grid .rc-card.rc-gone { background: #F4F4F4; border: 1.5px dashed #CCCCCC; box-shadow: none; color: #7F7F7F;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; }
#sched-grid .rc-card.rc-gone .rc-sess { color: #7F7F7F; font-weight: 600; margin: 0; }
.rc-mid-ico svg { width: 22px; height: 22px; }
#sched-grid .rc-card.rc-req .rc-time-ico svg { width: 15px; height: 15px; }
#sched-grid .rc-card.rc-kept .rc-time-ico { width: auto; height: auto; color: #16277A; }
#sched-grid .rc-card.rc-kept .rc-time-ico svg { width: 14px; height: 14px; fill: currentColor; }
#sched-grid .rc-asked .ni svg { width: 14px; height: 14px; }
/* The cost bars in one line (2026-10-13: "make those bar selaras"): every row
   the same three columns, the value column a fixed width, so each bar starts
   and ends where the one above it does. */
.lab-cost { grid-template-columns: minmax(0, 1.4fr) minmax(80px, 1fr) 132px; }
.lab-cost-v { text-align: right; }
.lab-people { width: 100%; font-size: 11.5px; color: #4D4D4D; padding-top: 2px; }
.lab-people-bad { color: #C2260B; }
.lab-f { max-width: 120px; }
