/* =====================================================================
   style.css — the whole interface's appearance.

   A small utility stylesheet, hand-written: no build step and no framework.
   Authored in the Tailwind idiom (compose from single-purpose classes) but
   with a deliberately narrow vocabulary, per Refactoring UI: a constrained
   scale beats arbitrary values.

   Utilities carry all appearance. The semantic hook classes — cell, issue,
   pick, csmrow, sched — carry none and exist for script.js and the tests to
   select on.

   SCALES
     space   0 .. 8   ->  0 3 6 9 12 16 22 28 36 px
     text    sm md lg       -> 15 16 17 px   (15px is the floor and 16px is
             body text: the person using this reads it at arm's length, so
             nothing is small print)
     ink     1 (primary) 2 (secondary) 3 (muted) — three levels, no more
   ===================================================================== */
:root{
  /* neutrals, warm-tinted so the page reads like the paper it replaces */
  --bg:#f2f0ec;   --surface:#fff;  --surface2:#faf9f7;  --surface3:#f4f2ee;
  /* three ink levels, darker than AA asks for: the reader is in their sixties,
     and grey that merely passes is grey they squint at. */
  --ink1:#1c1b19; --ink2:#47433d;  --ink3:#57524b;
  /* Headings of tables and sections. Once a lighter grey than --ink3; now the
     same, because they are read as words, not decoration. */
  --ink-weak:#57524b;
  --line:#e4e0d9; --line2:#cfcac1;
  /* control borders must be identifiable, so they get their own darker
     token (>=3:1) while --line2 stays for decorative separators. */
  /* --quiet is the muted-control grey: a disabled chevron, the drag handle,
     a disabled menu item. It was #a5a096, which cleared 3:1 on white but only
     2.29:1 once the week selector moved off the white header onto the warm
     page ground. #8a8478 is 3.26:1 there and 3.71:1 on white, and still reads
     as plainly muted beside --ink2. */
  --control:#928c81; --quiet:#8a8478;

  /* one accent, used only for actionable and positive things */
  --brand:#2f6f4f; --brand-ink:#1e4a34; --brand-bg:#e9f1ec; --brand-line:#b7d3c4;
  /* status: each pairs an ink, a wash and a border so none relies on hue alone */
  --warn:#7d5a10;  --warn-bg:#fdf5e2; --warn-line:#e9d69c;
  --err:#9d2f2d;   --err-bg:#fcecea;  --err-line:#ebbcb8;
  /* "Off" — a day nobody is working. Red, because that is what this app
     already used for a blocked day on the Roster, but a duller and warmer red
     than --err so an actual error still reads as the more urgent of the two.
     The two tints never appear in the same view. Contrast: white on --off is
     6.33:1, --off-ink on --off-bg is 6.23:1 and on white 7.29:1. */
  --off:#9a463d;   --off-bg:#f9eae5;  --off-line:#e6bfb6; --off-ink:#8c3f36;
  /* CSMs in a soft blue. It was the paper sheet's highlighter yellow, but
     yellow is also every warning here, and a CSM row read as something wrong.
     One colour, one meaning. */
  --csm:#e2ecf8;  --csm-soft:#f2f6fc; --csm-line:#b8cce6; --csm-ink:#23446b;
  /* the CSM row's "usually works" cell: the green, cooled toward the row */
  --csm-yes:#e2efe9;
  --closed:#eae7e1;

  --s0:0;   --s1:3px;  --s2:6px;  --s3:9px;  --s4:12px;
  --s5:16px;--s6:22px; --s7:28px; --s8:36px;

  --r1:4px; --r2:6px; --r3:8px; --rf:999px;
  --sh1:0 1px 2px rgba(28,27,25,.05);
  --sh2:0 1px 3px rgba(28,27,25,.09), 0 4px 12px rgba(28,27,25,.05);
  --ring:0 0 0 3px var(--brand-bg);

  /* the select caret, drawn so it can be hidden and restored with the border
     rather than left on the page as 70 permanent chevrons */
  --caret:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' \
viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%236a655d' \
stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");

  /* Inter comes from the CDN link in the head. It is not guaranteed — no
     network, no webfont — so the fallback is the platform's own UI face rather
     than a generic sans, and the design does not depend on Inter's metrics.
     The product name gets a warm serif instead, so the wordmark reads as a
     name and not as more UI. */
  --font:"Inter",system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI Variable Text",
    "Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --font-brand:Georgia,"Iowan Old Style","Palatino Linotype","Times New Roman",
    serif;
}

/* ---------- reset ---------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--ink1);
  font:16px/1.55 var(--font);-webkit-font-smoothing:antialiased}
h1,h2,h3,h4,p{margin:0}
button{font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer}
input,select,textarea{font:inherit;color:inherit}
/* Native checkboxes read blue out of the box, which is the one hue this
   interface never uses. Green is "yes" everywhere else here, so it is green
   here too. */
input[type=checkbox]{accent-color:var(--brand)}
table{border-collapse:collapse;width:100%}
code{font:15px/1 var(--font);background:var(--surface3);padding:2px 5px;border-radius:3px}
:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
[hidden]{display:none!important}

/* ---------- layout ---------------------------------------------------
   The vocabulary below is deliberately kept whole even where a class is
   momentarily unused: pruning "dead" utilities has twice broken layout
   when later markup reached for one again. The sheet is small; the rules
   are cheaper than the bugs.
--------------------------------------------------------------------- */
.block{display:block}       .flex{display:flex}         .grid{display:grid}
.hidden{display:none!important} .wrap{flex-wrap:wrap}
.ic{align-items:center}       .is{align-items:flex-start} .jc{justify-content:center}
.col{flex-direction:column}
.w-full{width:100%}
.grow{flex:1}                   .min0{min-width:0}     .ovx{overflow-x:auto}
.nowrap{white-space:nowrap}
.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:280px} .gap-1{gap:var(--s1)} .gap-2{gap:var(--s2)} .gap-3{gap:var(--s3)}
.gap-5{gap:var(--s5)}
.gap-4{gap:var(--s4)} .gap-6{gap:var(--s6)}

.p-0{padding:0}                                   .p-5{padding:var(--s5)}
.px-7{padding-left:var(--s7);padding-right:var(--s7)}
.py-4{padding-top:var(--s4);padding-bottom:var(--s4)}
.py-5{padding-top:var(--s5);padding-bottom:var(--s5)}
.py-6{padding-top:var(--s6);padding-bottom:var(--s6)} .pt-5{padding-top:var(--s5)} .mt-3{margin-top:var(--s3)} .mt-5{margin-top:var(--s5)} .mt-6{margin-top:var(--s6)} .mb-1{margin-bottom:var(--s1)} .mb-2{margin-bottom:var(--s2)} .mb-3{margin-bottom:var(--s3)} .mb-5{margin-bottom:var(--s5)} .mb-6{margin-bottom:var(--s6)}

/* ---------- type ----------------------------------------------------- */
.t-xs{font-size:15px} .t-sm{font-size:15px} .t-md{font-size:16px}
.t-lg{font-size:17px} .fw-m{font-weight:500} .fw-sb{font-weight:600} .fw-b{font-weight:700}
.lh-t{line-height:1.25}
.ink1{color:var(--ink1)} .ink2{color:var(--ink2)} .ink3{color:var(--ink3)}
.c-brand{color:var(--brand-ink)} .c-warn{color:var(--warn)} .c-err{color:var(--err)}
.tnum{font-variant-numeric:tabular-nums}
/* Times were once in a typewriter face. They are in the app's own face now,
   with even-width digits so a column of them still lines up. */
.mono{font-variant-numeric:tabular-nums}
.italic{font-style:italic}

/* ---------- surfaces ------------------------------------------------- */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r3);
  box-shadow:var(--sh1);padding:var(--s7)}
.bg-surface{background:var(--surface)} .bg-csm{background:var(--csm)} .r1{border-radius:var(--r1)} .r2{border-radius:var(--r2)} .bt{border-top:1px solid var(--line)}
.bb{border-bottom:1px solid var(--line)}

/* The one place the brand serif is used. Just the store's name now: the way
   back to the schedules is the New schedules tab, so the name does nothing
   when pressed and looks like nothing that could be. */
.wordmark{font-family:var(--font-brand);font-size:22px;font-weight:400;
  letter-spacing:.01em;color:var(--ink1)}

/* A section heading, in normal letters: small capitals are harder to read than
   words, and these are read. */
.label{font-size:16px;font-weight:600;color:var(--ink2)}
/* ---------- page shape ----------------------------------------------
   Every page is the same: its title outside the white box, the page's own
   controls at the right of that title, and everything else — tabs, tables,
   the schedule — inside the box. */
/* Close to the box under it, so the title reads as that box's heading
   rather than as something floating above the page. */
.pagehead{display:flex;flex-wrap:wrap;align-items:flex-start;gap:var(--s4) var(--s6);
  margin-bottom:var(--s4)}
/* Level with the buttons beside it, which are taller than the words. */
.pagehead .pagetitle{margin-top:7px}
/* Tabs at the head of a white box, the same on every page. They sit closer to
   the box's top than its padding would put them, so they read as the box's
   own heading. */
.cardtabs{display:flex;flex-wrap:wrap;gap:var(--s1);margin:calc(var(--s4) * -1) 0 var(--s6);
  border-bottom:1px solid var(--line)}
/* Every page says where you are, in large words. */
.pagetitle{font-size:24px;font-weight:600;line-height:1.25;color:var(--ink1);
  text-wrap:balance}

/* ---------- controls ------------------------------------------------- */
.field{font:inherit;font-size:16px;padding:8px 10px;border:1px solid var(--control);
  border-radius:var(--r1);
  background:var(--surface);color:var(--ink1);transition:border-color .12s,box-shadow .12s}
.field:hover{border-color:var(--ink3)}
.field:focus{outline:none;border-color:var(--brand);box-shadow:var(--ring)}

.btn{display:inline-flex;align-items:center;gap:var(--s3);padding:9px 16px;font-size:16px;
  border:1px solid var(--control);border-radius:var(--r2);background:var(--surface);
  color:var(--ink1);font-weight:500;box-shadow:var(--sh1);
  transition:background .12s,border-color .12s}
.btn:hover{background:var(--surface2);border-color:var(--ink3)}
.btn:active{background:var(--surface3)}
.btn:disabled{opacity:.45;cursor:not-allowed;box-shadow:none}
.btn:disabled:hover{background:var(--surface);border-color:var(--control)}
/* A disabled primary kept its brand green and lost nearly half its opacity,
   which on white reads as a broken button rather than an unavailable one.
   Unavailable is neutral. */
.btn-primary:disabled,
.btn-primary:disabled:hover{background:var(--surface3);border-color:var(--control);
  color:var(--ink3);opacity:1}
.btn-primary{background:var(--brand);border-color:var(--brand);color:#fff}
.btn-primary:hover{background:var(--brand-ink);border-color:var(--brand-ink)}
.btn-quiet{border-color:transparent;box-shadow:none;background:none;color:var(--ink2)}
.btn-quiet:hover{background:var(--surface3);border-color:var(--line);color:var(--ink1)}
/* One size for every button. The small one was harder to hit and made the
   same kind of button a different size from page to page; the class stays so
   markup that names it does not have to change. */
.btn-sm{}
.btn-danger:hover{background:var(--err-bg);border-color:var(--err-line);color:var(--err)}
/* The answer in a question box that deletes or wipes something. */
.btn-red{background:var(--err);border-color:var(--err);color:#fff}
.btn-red:hover{background:#7f2523;border-color:#7f2523}

.ta{font:inherit;font-size:16px;width:100%;min-height:80px;padding:var(--s4);
  resize:vertical;
  border:1px solid var(--control);border-radius:var(--r2);background:var(--surface)}
.ta:focus{outline:none;border-color:var(--brand);box-shadow:var(--ring)}

/* Toggle buttons carry their state on aria-pressed, so the DOM is the
   source of truth and nothing depends on hue alone. */
.tgl{padding:7px 11px;border:1px solid var(--control);border-radius:var(--r1);
  background:var(--surface);color:var(--ink2);font-size:15px;font-weight:500;
  min-width:34px}
.tgl:hover{border-color:var(--ink3);color:var(--ink1)}
/* A pressed day toggle means the same thing on the Roster and in the
   availability modal — this day is off — so it gets one treatment, not a
   green one here and a red one there. */
.tgl[aria-pressed=true]{background:var(--off);border-color:var(--off);color:#fff;
  font-weight:600}
/* No opacity here on purpose. The pressed rule sets white text, and a 40%
   near-white hatch painted over it made the day letter vanish completely — a
   toggle with no label on it. Disabled state is carried by real colours
   instead, so the contrast is knowable. */
.tgl:disabled{cursor:not-allowed;color:var(--ink3);border-color:var(--line2);
  background:repeating-linear-gradient(45deg,var(--surface2),var(--surface2) 4px,
    var(--surface3) 4px,var(--surface3) 8px)}
/* Off for a reason this modal cannot change — approved time off, or a standing
   Roster block. The tint of the same family, so weight of fill says whether it
   can be cleared here: solid means set here, tinted means set elsewhere. */
.tgl[aria-pressed=true]:disabled{background:var(--off-bg);color:var(--off-ink);
  border-color:var(--off-line);font-weight:600}
.tgl:disabled:hover{border-color:var(--line2);color:var(--ink3)}
.tgl[aria-pressed=true]:disabled:hover{color:var(--off-ink)}

/* ---------- tabs ----------------------------------------------------- */
.tab{padding:12px 16px;font-size:16px;color:var(--ink2);font-weight:500;
  border-bottom:2px solid transparent;margin-bottom:-1px}
.tab:hover{color:var(--ink1)}
.tab[aria-selected=true]{color:var(--brand-ink);border-bottom-color:var(--brand)}

/* ---------- tables --------------------------------------------------- */
.th{padding:10px 12px;text-align:left;font-size:15px;font-weight:600;
  color:var(--ink-weak);
  background:var(--surface2);border-bottom:1px solid var(--line2);white-space:nowrap}
/* Rows separate with a single hairline instead of a full box — fewer borders,
   per Refactoring UI, so the numbers carry the structure. */
.td{padding:10px 12px;border-bottom:1px solid var(--line);vertical-align:middle}
.tr:hover .td{background:var(--surface2)}
.tfoot .th{background:var(--surface);border-top:1px solid var(--line2);border-bottom:0;
  color:var(--ink1);font-size:15px;text-transform:none;letter-spacing:0}

/* ---------- the schedule grid ---------------------------------------
   Hook class is `sched`. A utility named `grid` means display:grid, and
   putting that on a <table> splits thead and tbody into separate anonymous
   table boxes so the header stops aligning with the columns.
--------------------------------------------------------------------- */
/* The shift names down the left, then seven days. Wide enough that a time
   and a name sit on one line each; narrower, they wrap rather than clip. */
.sched{min-width:1190px;table-layout:fixed}
.sched .rowhead{width:158px;text-align:left}
.sched th.rowlabel{padding:var(--s3) var(--s4);text-align:left;vertical-align:middle;
  font-size:15px;font-weight:400;color:var(--ink1);background:var(--surface2);
  border:1px solid var(--line)}
.csmrow th.rowlabel{background:var(--csm)}
.extras th.rowlabel{color:var(--ink2)}
.sched th,.sched td{border:1px solid var(--line)}
.sched thead th{padding:var(--s3) var(--s2);text-align:center;font-size:15px;font-weight:600;
  letter-spacing:.03em;color:var(--ink2);
  background:var(--surface2)}
.sched thead th small{display:block;font-size:15px;font-weight:400;
  text-transform:none;letter-spacing:0;color:var(--ink3)}
.sched thead th.today{color:var(--brand-ink);background:var(--brand-bg)}
/* Said in words, not just by the tint. */
.todaymark{display:block;font-size:15px;font-weight:600;letter-spacing:0;
  color:var(--brand-ink)}
/* the availability grid keeps a shift column; the build grid does not — its
   label is printed inside every cell, as on the paper sheet */
.slot{width:160px;padding:var(--s3) var(--s4);vertical-align:top;
  background:var(--surface2)}
.csmrow .slot{background:var(--csm)}
/* 180, not 160: shift times are written in full now, and "10:30am-7:00pm" is
   wider than "10:30a–7p" was. Under 180 the time menu cut its last letters
   off; with the side panel open the grid scrolls sideways instead. */
.cell{position:relative;padding:var(--s2);vertical-align:top}
.csmrow .cell{background:var(--csm-soft)}
.sched tbody tr:hover .cell{background:var(--surface2)}
.sched tbody tr.csmrow:hover .cell{background:var(--csm)}
.cell.bad{background:var(--err-bg)!important;box-shadow:inset 0 0 0 2px var(--err)}
.cell.dis{background:var(--closed);cursor:pointer;padding:0}

/* A box's time and person. Each is its own text — which wraps rather than
   being cut off when the week is squeezed — with the real menu laid over it,
   invisible, so pressing it opens the menu as usual.

   A filled choice is BORDERLESS at rest. Seventy outlined boxes read as a form
   to fill in; the point of a posted schedule is to read as names and times.
   The border is kept at 1px transparent so revealing it on approach never
   moves anything. An EMPTY one keeps its outline — that one is still a
   question, and it should look like one. */
.ctl{position:relative;display:block;padding:5px 18px 5px 7px;
  border:1px solid transparent;border-radius:var(--r1);
  background-repeat:no-repeat;background-position:right 7px center;
  background-size:9px 6px}
.ctl + .ctl{margin-top:var(--s1)}
/* Wraps after the hyphen of a time, never in the middle of a number. */
.ctl .show{display:block;overflow-wrap:break-word}
.ctl select{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;
  cursor:pointer;font-size:16px}
/* Ordinary digits, not even-width ones: one time per box never has to line up
   with another, and the narrower digits are what let 10:30am-7:00pm sit on
   one line. */
.ctl-time .show{font-size:15px;color:var(--ink2)}
.ctl-time.custom .show{color:var(--brand-ink);font-weight:600}
.ctl-name .show{font-size:16px;font-weight:600;color:var(--ink1)}
.ctl.empty .show{color:var(--ink3);font-weight:400}
.ctl.empty{border-color:var(--control);background-color:var(--surface);
  background-image:var(--caret)}
/* One control at a time: pointing at the time lights the time, not the name. */
.ctl:hover{border-color:var(--ink3);background-color:var(--surface);
  background-image:var(--caret)}
.ctl:focus-within{border-color:var(--brand);background-color:var(--surface);
  background-image:var(--caret);box-shadow:var(--ring)}
.cell-timeinput{width:100%;padding:5px 8px;border:1px solid var(--brand);
  border-radius:var(--r1);background:var(--surface);font-size:15px;
  font-variant-numeric:tabular-nums}
.cell-timeinput:focus{outline:none;box-shadow:var(--ring)}

.cell-closed{display:block;width:100%;padding:14px 4px;text-align:center;
  font-size:15px;letter-spacing:.1em;color:var(--ink3)}
.cell-closed:hover{background:var(--line);color:var(--ink1)}

/* ---------- extra cells ----------------------------------------------
   Up to five per day, added from the grid rather than the template, so a
   one-off shift never becomes a recurring slot row.
--------------------------------------------------------------------- */
.extracell{border:1px solid var(--line);border-top:2px solid var(--line2);
  padding:var(--s2) var(--s3);vertical-align:top;background:var(--surface2)}
.extra{margin-bottom:var(--s2);padding:var(--s2);border:1px dashed var(--line2);
  border-radius:var(--r1);background:var(--surface)}
/* Says what it does, at full strength: a faded "+" nobody can read is a
   control nobody uses. */
.addextra{display:flex;align-items:center;justify-content:center;width:100%;
  min-height:32px;padding:4px 6px;border:1px dashed var(--control);
  border-radius:var(--r1);color:var(--ink2);font-size:15px;line-height:1.2;
  transition:border-color .12s,background .12s}
.addextra:hover{background:var(--brand-bg);border-color:var(--brand);
  color:var(--brand-ink)}

/* ---------- read-only schedule (Past schedules, and printing) ---------- */
/* The weekly grid's own layout, with nothing to press: no outline, no caret,
   no hover. */
.sched.ro{table-layout:fixed;min-width:900px}
.sched.ro .ctl{padding:3px 2px}
.sched.ro .ctl.empty{border-color:transparent;background:none}
.sched.ro .ctl-time.empty{display:none}
.sched.ro .cell-closed{cursor:default}
.sched.ro .cell-closed:hover{background:none;color:var(--ink3)}
.sched.ro tbody tr:hover .cell{background:var(--surface)}
.sched.ro tbody tr.csmrow:hover .cell{background:var(--csm-soft)}
/* A finished day's typed lines are what was typed, as text. */
.profile.ro .pfield{display:none}
.profile.ro .prn{display:block}

/* ---------- badges & status ------------------------------------------ */
.badge{display:inline-block;padding:2px 9px;border-radius:var(--rf);font-size:15px;
  text-transform:none;letter-spacing:0;
  font-weight:500;border:1px solid var(--line);background:var(--surface);color:var(--ink3)}
.badge-csm{background:var(--csm);border-color:var(--csm-line);color:var(--csm-ink)}
.badge-count{background:var(--surface3);color:var(--ink2)}
.badge-err{background:var(--err-bg);border-color:var(--err-line);color:var(--err)}
.badge-warn{background:var(--warn-bg);border-color:var(--warn-line);color:var(--warn)}
.badge-ok{background:var(--brand-bg);border-color:var(--brand-line);
  color:var(--brand-ink)}

/* An icon plus a word plus a colour: three cues, so colour is never the only
   thing distinguishing an error from a warning. */
.issue{display:flex;gap:var(--s4);align-items:flex-start;padding:10px 12px;
  border-radius:var(--r1);border-left:3px solid transparent;font-size:16px;
  margin-bottom:3px}
.issue-icon{flex-shrink:0;font-size:15px;line-height:1.6;width:11px;text-align:center}
.issue-tag{flex-shrink:0;width:64px;font-size:15px;font-weight:700;line-height:1.6}
/* The words and, for an open shift, the people who could take it. */
.issue-body{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s2) var(--s3);
  min-width:0}
/* Text that is also a way to the shift: it reads as the sentence it is, and
   underlines when pointed at. */
.issue-go{text-align:left;color:inherit;line-height:1.6}
.issue-go:hover{text-decoration:underline;text-underline-offset:3px}
.issue-give{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s2)}
/* The same size as every other button: one size, everywhere. */
.issue-btn{color:var(--ink1)}
/* The box a message points to, lit for a moment. */
.cell.flash{box-shadow:inset 0 0 0 3px var(--brand)}
@media (prefers-reduced-motion:no-preference){
  .cell.flash{animation:flash 2.4s ease-out}
  @keyframes flash{0%,40%{background:var(--brand-bg)}100%{background:inherit}}
}
.issue.error{background:var(--err-bg);border-left-color:var(--err);color:var(--err)}
.issue.warn{background:var(--warn-bg);border-left-color:var(--warn);color:var(--warn)}
.issue.info{background:var(--surface3);border-left-color:var(--line2);color:var(--ink2)}

/* ---------- availability picker -------------------------------------- */
/* The CELL carries the state colour, not the button inside it.

   A button is inline-block and sizes to its own padding, so as soon as a row
   was taller than the button — a shift label wrapping to two lines is enough —
   the cell's own background showed through as a band above and below every
   hatched, amber and shaded state. height:100% cannot fix it either: the td's
   height is auto, so there is nothing for the percentage to resolve against.
   Painting the td removes the question, and it is the same answer the closed
   cell in the build grid needed. */
.pcell{padding:0}
/* Three states, and the one that needs no colour is the common one. Most
   cells for most people are 'open' — nobody has said anything — so open is
   plain paper and only a stated preference is tinted. Green for the shifts
   somebody usually works, red for the ones to avoid: the two hues the rest of
   the interface already uses for yes and no. */
.pcell.p-open{background:var(--surface)}
.pcell.p-prefer{background:var(--brand-bg)}
.pcell.p-avoid{background:var(--off-bg)}
/* This week's grid uses the same three states as Regular shifts, so the same
   classes: the meanings are the same now, which is what sharing a name should
   say. On top of them, time off — avoid's ground, with an × — which is not
   the manager's to change here; it is set on the Time off page, on dates. */
.pcell.p-off{background:var(--off-bg)}
/* This week disagrees with the regular shifts here. A corner mark rather than
   another ground colour: the ground already carries the state, and a second
   colour on top of it would compete with it. */
.pcell.p-diff{position:relative}
.pcell.p-diff::after{content:'';position:absolute;top:3px;right:3px;
  width:0;height:0;border-top:6px solid var(--ink3);
  border-left:6px solid transparent}
.p-off .pick:disabled{color:var(--off-ink)}
/* the CSM row keeps the sheet's highlighter warmth, as it does in the build
   grid, carried into the green so the row is still identifiable as a row */
.csmrow .pcell.p-prefer{background:var(--csm-yes)}
.csmrow .pcell.p-open{background:var(--csm-soft)}
.pcell.p-closed{background:repeating-linear-gradient(45deg,
  var(--surface2),var(--surface2) 4px,var(--surface3) 4px,var(--surface3) 8px)}
.csmrow .pcell.p-closed{background:repeating-linear-gradient(45deg,
  var(--csm-soft),var(--csm-soft) 4px,var(--surface3) 4px,var(--surface3) 8px)}

/* An open cell carries no mark at all, so the grid reads as the few things
   somebody has actually said rather than 35 answers they never gave. */
.pick{display:block;width:100%;padding:14px 12px;font-size:15px;
  background:none;color:var(--ink2);font-weight:600}
.p-prefer .pick{color:var(--brand-ink)}
.p-avoid  .pick{color:var(--off-ink)}
.pick:not(:disabled){cursor:pointer}
.pick:disabled{cursor:not-allowed;color:transparent}
/* Hover keeps the state colour and rings the cell instead, so approaching a
   cell never makes it look like a different state. */
.pcell:hover .pick:not(:disabled){color:var(--ink1)}
.pcell:has(.pick:not(:disabled)):hover{box-shadow:inset 0 0 0 2px var(--brand-line)}
.pick:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}
/* The box whose three choices are open, marked until one is picked. */
.pcell.picking{box-shadow:inset 0 0 0 2px var(--brand)}
/* A standing line above the daily sheet. Quieter than an issue row, which
   belongs to a list, and not a toast, which is gone in two seconds — this is
   a fact about the sheet you are looking at and stays as long as it is true. */
.note{padding:10px 14px;border-radius:var(--r2);font-size:15px;
  background:var(--surface2);border:1px solid var(--line);color:var(--ink2)}
.note-warn{background:var(--warn-bg);border-color:var(--warn-line);
  color:var(--warn)}

/* Right under the grid, in two groups: what someone's availability can be,
   and the two things laid over it this week. */
.picklegend{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s7);margin-top:var(--s4);
  font-size:15px;color:var(--ink2)}
.lgroup{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s2) var(--s5)}
.lhead{font-weight:600;color:var(--ink1)}
.legend-key{display:inline-block;min-width:18px;text-align:center;
  color:var(--brand-ink);font-weight:600}
.legend-no{color:var(--off-ink)}
.legend-swatch{display:inline-block;width:18px;height:14px;vertical-align:-2px;
  border:1px solid var(--line)}
.legend-yes{color:var(--brand-ink)}
.legend-open{background:var(--surface);border-color:var(--line2)}
.legend-off{background:var(--off-bg);border-color:var(--off-line)}
.legend-diff{background:var(--surface);border-color:var(--line2);position:relative}
.legend-diff::after{content:'';position:absolute;top:0;right:0;
  width:0;height:0;border-top:6px solid var(--ink3);
  border-left:6px solid transparent}
.legend-hatch{background:repeating-linear-gradient(45deg,var(--surface2),
  var(--surface2) 4px,var(--surface3) 4px,var(--surface3) 8px)}

/* Print twins: plain text versions of the two cell controls, hidden on screen
   and swapped in for print. See the print block at the foot of this file. */
.prn{display:none}

/* ---------- misc ----------------------------------------------------- */
/* Drawn, not typed: the braille glyph this used to use (U+283F) is not in
   Inter, and a missing glyph falls back to whatever face has it. */
.grab{padding:0 0 0 var(--s2);user-select:none}
/* touch-action:none is the whole reason reordering works on a touchscreen:
   without it the browser claims the gesture for scrolling and the pointermove
   stream stops after the first event. */
.grabbtn{display:flex;align-items:center;justify-content:center;
  width:32px;height:36px;cursor:grab;color:var(--quiet);
  touch-action:none;border-radius:var(--r1)}
.grabbtn:hover{background:var(--surface3);color:var(--ink2)}
.grabbtn:active{cursor:grabbing}
.grabbtn:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}
.grabdots{display:block;width:8px;height:14px;
  background-image:radial-gradient(currentColor 42%,transparent 46%);
  background-size:4px 4px;background-position:0 1px;color:var(--quiet)}

/* Seniority's up and down buttons, beside its number. */
.senrow{display:inline-flex;align-items:center;justify-content:flex-end;gap:var(--s2)}
.senrow .tnum{min-width:22px;text-align:right}
/* A normal button's height, made square. */
.senbtn{width:44px;padding-left:0;padding-right:0;justify-content:center}
/* One box per other time on Shift times, each with a way to take it off. */
.vbox{display:inline-flex;align-items:center;gap:2px}
.badfield{border-color:var(--err)}
.dragging{opacity:.4}
/* The time-off row currently loaded into the form above, so it is obvious
   which record the fields belong to. */
.tr.editing > .td{background:var(--brand-bg)}
.tr.editing:hover > .td{background:var(--brand-bg)}
.drop-target > .td{box-shadow:inset 0 2px 0 var(--brand)}
/* The message at the bottom. It takes clicks only while it is showing, so a
   faded one never sits invisibly on top of the page. */
.toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);z-index:60;
  display:flex;align-items:center;gap:var(--s4);max-width:calc(100vw - 32px);
  padding:8px 8px 8px 18px;border-radius:var(--r2);background:var(--ink1);color:#fff;
  font-size:16px;box-shadow:var(--sh2);opacity:0;transition:opacity .18s;
  pointer-events:none}
.toast[data-on]{opacity:1;pointer-events:auto}
.toastbtn{padding:6px 12px;border-radius:var(--r1);border:1px solid #6d675e;
  color:#fff;font-weight:600;text-decoration:underline;text-underline-offset:2px}
.toastbtn:hover{background:#3a3833}
.toastx{display:inline-flex;align-items:center;justify-content:center;width:32px;
  height:32px;border-radius:var(--r1);color:#d8d3ca;font-size:20px;line-height:1}
.toastx:hover{background:#3a3833;color:#fff}
/* Stretch rather than start-align: the left column is asked to match the
   matrix's height so the list's box ends where the matrix does, instead of
   leaving a ragged gap of nothing beneath it. */


.scroll-y{max-height:400px;overflow-y:auto}
.page.hidden,.sub.hidden{display:none!important}

/* ---------- the save warning -----------------------------------------
   Full width, under the header, in the error family — the only thing in this
   interface that is allowed to shout, because it is the only one that means
   the work is not being kept.
--------------------------------------------------------------------- */
.savewarn{padding:var(--s4) var(--s7);background:var(--err-bg);
  border-bottom:1px solid var(--err-line);color:var(--err);
  font-size:15px;font-weight:500}

/* ---------- the toolbar, at the head of the grid's box ----------------- */
.weekbar{padding:0 0 var(--s5);margin-bottom:var(--s5);border-bottom:1px solid var(--line)}
/* The open-shifts count is a way to the list of them. */
.flagbtn{cursor:pointer}
.flagbtn:hover{border-color:currentColor}
.weeknav{display:flex;flex-direction:column;align-items:flex-end;gap:2px}
/* "Saved", for a moment after each change, at the end of the tab row. */
.savedflag{margin-left:auto;align-self:center;font-size:15px;color:var(--brand-ink);
  opacity:0;transition:opacity .25s}
.savedflag[data-on]{opacity:1}
/* Held in place rather than removed, so the week never shifts sideways. */
.gone{visibility:hidden}

/* ---------- the week selector ---------------------------------------
   One button at the right of the tab strip, naming the week both tabs read,
   with a calendar behind it. Rows are weeks, not days: a week is the only
   unit this app schedules in, so a week is what you click.
--------------------------------------------------------------------- */
.weekpick{}
/* 14px is this interface's floor and the caret is rendered text, so it keeps
   to it like everything else — a 11px glyph here was the only thing on the
   page below the floor. */
.caret{font-size:15px;line-height:1;color:var(--ink3)}
.calpop{width:340px;padding:var(--s4)}
.calhead{display:flex;align-items:center;justify-content:space-between;
  margin-bottom:var(--s2)}
.calgrid{width:100%;border-collapse:separate;border-spacing:0 var(--s1)}
.calgrid th{padding:var(--s2) 0;text-align:center;font-size:15px;font-weight:600;
  color:var(--ink-weak);letter-spacing:.02em}
.calweek{cursor:pointer}
.calweek > td{padding:var(--s2) 0;text-align:center;font-size:15px;
  color:var(--ink2);background:var(--surface2)}
.calweek > td:first-child{border-radius:var(--r1) 0 0 var(--r1)}
.calweek > td:last-child{border-radius:0 var(--r1) var(--r1) 0}
.calweek:hover > td{background:var(--line)}
.calweek[aria-selected=true] > td{background:var(--brand);color:#fff;font-weight:600}
.calweek:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
/* A finished week is shown, so the month reads as a month, but it is not a
   choice here: it is read on the Past schedules tab instead. */
/* A week this calendar will not take: a finished one on New schedules, one
   still to come — or with nothing in it — on Past schedules. Shown, so the
   month reads as a month, but not a choice. */
.calweek.shut{cursor:not-allowed}
.calweek.shut > td{color:var(--quiet);background:var(--surface)}
.calweek.shut:hover > td{background:var(--surface)}
.calweek td.other{color:var(--ink3);opacity:.55}
.calweek[aria-selected=true] > td.other{color:#fff;opacity:.72}
.calweek.has > td{color:var(--ink1);font-weight:500}
.calweek.has[aria-selected=true] > td{color:#fff}
.caldot{display:inline-block;width:5px;height:5px;border-radius:var(--rf);
  background:var(--brand);vertical-align:2px;margin-left:3px}
.calweek[aria-selected=true] .caldot{background:#fff}
.calnote{margin-top:var(--s3);line-height:1.4}

/* ---------- the daily sheet -----------------------------------------
   A day picker that carries the date, because "Tuesday" alone is not enough
   to pin a sheet to a board by.
--------------------------------------------------------------------- */
.daytab{display:flex;flex-direction:column;align-items:center;gap:1px;
  min-width:64px;padding:7px 10px;border:1px solid var(--control);
  border-radius:var(--r1);background:var(--surface);color:var(--ink2)}
.daytab:hover{border-color:var(--ink3);color:var(--ink1)}
.daytab-d{font-size:15px;font-weight:500}
.daytab-n{font-size:15px;color:var(--ink3)}
.daytab[aria-selected=true]{background:var(--brand);border-color:var(--brand);
  color:#fff;font-weight:600}
.daytab[aria-selected=true] .daytab-n{color:#fff}
.daytab:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
/* ---------- whose availability --------------------------------------
   Names only, under their role: a compact list to pick from, not a row of
   cards. The one picked is tinted, in bold, with a check. A column of them in
   the empty week's workspace; rows of them, wrapping rather than scrolling, in
   the side panel and the Regular availability drawer. */
.who{display:flex;flex-direction:column;gap:var(--s5)}
.whogroup{display:flex;flex-direction:column;gap:var(--s1);min-width:0}
/* The role over its names, heavy enough to read as a heading among them. */
.whohead{padding:0 var(--s4);font-size:16px;font-weight:600;color:var(--ink1)}
.whoitems{display:flex;flex-direction:column;gap:2px}
.whoitem{display:flex;align-items:center;justify-content:space-between;gap:var(--s4);
  min-height:44px;padding:8px 12px;border:1px solid transparent;border-radius:var(--r2);
  font-size:16px;color:var(--ink1);text-align:left;cursor:pointer}
.whoitem:hover{background:var(--surface3)}
.whoitem[aria-selected=true]{background:var(--brand-bg);border-color:var(--brand-line);
  color:var(--brand-ink);font-weight:600}
.whoname{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.whocheck{visibility:hidden;color:var(--brand);font-weight:700}
.whoitem[aria-selected=true] .whocheck{visibility:visible}
.whoitem:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
.who-row{flex-direction:row;flex-wrap:wrap;gap:var(--s4) var(--s6)}
.who-row .whohead{padding:0}
.who-row .whoitems{flex-direction:row;flex-wrap:wrap;gap:var(--s2)}
.who-row .whoitem{border-color:var(--control);background:var(--surface)}
.who-row .whoitem[aria-selected=true]{border-color:var(--brand);background:var(--brand-bg)}

/* ---------- the empty week: review availability, then build ---------- */
.intro{display:flex;flex-direction:column;gap:2px;margin-bottom:var(--s5)}
.introtitle{font-size:20px;line-height:1.3;font-weight:600;color:var(--ink1)}
/* Names on the left choose whose; the right is theirs, for this week. */
.workspace{display:grid;grid-template-columns:220px minmax(0,1fr);
  border:1px solid var(--line);border-radius:var(--r3);overflow:hidden}
.ws-list{padding:var(--s5) var(--s3);background:var(--surface2);
  border-right:1px solid var(--line)}
.ws-main{display:flex;flex-direction:column;gap:var(--s4);min-width:0;
  padding:var(--s5) var(--s6) var(--s6)}
.ws-top{display:flex;flex-wrap:wrap;align-items:flex-start;gap:var(--s3) var(--s5)}
.ws-name{font-size:20px;line-height:1.3;font-weight:600;color:var(--ink1)}
@media (max-width:900px){
  .workspace{grid-template-columns:minmax(0,1fr)}
  .ws-list{border-right:0;border-bottom:1px solid var(--line)}
  .ws-list .who{flex-direction:row;flex-wrap:wrap;gap:var(--s4) var(--s6)}
  .ws-list .whoitems{flex-direction:row;flex-wrap:wrap}
}
/* The next step, below and apart from the one before it. */
.buildbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s4) var(--s6);
  margin-top:var(--s6);padding-top:var(--s6);border-top:1px solid var(--line)}
.buildtitle{font-size:18px;line-height:1.3;font-weight:600;color:var(--ink1)}
/* The words give up width, not the buttons: they wrap, and the two ways to
   build stay together at the right. */
.buildbar > .min0{flex:1 1 320px}

/* ---------- the Front End Profile -----------------------------------
   The store's posted daily sheet. It is a ruled form, not a data table, so
   it keeps every border: the hour columns only read as a coverage bar if the
   grid they sit in is drawn.
--------------------------------------------------------------------- */
/* The day buttons head the sheet's own box, and the sheet runs edge to edge
   under them. */
/* The day buttons, then the sheet, inside the schedule's box. */
.daybar{margin-bottom:var(--s5)}
/* The form's heading bar and the form under it, boxed as the paper is. */
.sheetbox .profhead{border:1px solid var(--line2);border-bottom:0;
  border-radius:var(--r2) var(--r2) 0 0}
.profhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--s5);
  padding:var(--s3) var(--s4);background:var(--surface);
  font-size:15px;color:var(--ink2)}
.proftitle{font-size:16px;font-weight:600;color:var(--ink1)}
.profile{table-layout:fixed;min-width:1180px;font-size:15px}
.profile th,.profile td{border:1px solid var(--line2)}
.ph{padding:5px 6px;text-align:center;font-size:15px;font-weight:600;
  background:var(--surface2);color:var(--ink1);white-space:nowrap}
.ph-name{width:132px;text-align:left}
.ph-pos{width:104px}
.ph-t{width:62px}
.ph-hr{width:40px;font-weight:500;color:var(--ink2);font-size:15px}
.pn{padding:3px 6px;font-size:15px}
.pp{padding:3px 6px;text-align:center;font-size:15px;color:var(--ink2)}
.pt{padding:3px 4px;text-align:center;font-size:15px;
  font-variant-numeric:tabular-nums}
/* The coverage bar: the hours this person is on the floor, with the unpaid
   lunch cut out of the middle of it. Drawn, where the paper has it in pen. */
.phr{height:26px;padding:0}
.phr.on{background:var(--brand-bg)}
.phr.lunch{background:var(--surface);color:var(--ink2);text-align:center;
  font-size:15px;font-weight:600}
.prow:hover > td{background:var(--surface2)}
.prow:hover > .phr.on{background:var(--brand-line)}
.prow-gap > td{height:12px;padding:0;background:var(--surface2);border-left:0;
  border-right:0}
/* A typed line's fields sit inside the ruled box rather than beside it, so
   the form keeps its shape whether it is filled in or not. */
.pfield{width:100%;padding:2px 4px;border:1px solid transparent;
  border-radius:var(--r1);background:none;font-size:15px}
.pfield:hover{border-color:var(--line2);background:var(--surface)}
.pfield:focus{outline:none;border-color:var(--brand);background:var(--surface);
  box-shadow:var(--ring)}
.pfield-t{font-variant-numeric:tabular-nums;text-align:center}
.calllog{width:auto;min-width:230px;flex-shrink:0}
.calllog th,.calllog td{border:1px solid var(--line2)}
.calllog .ph{text-align:left;width:74px}
.calllog .pt{height:26px}

/* The three roster tables share one set of column widths, so Front end, Other
   and Removed line up as one roster in three parts. Without table-layout:fixed
   each sizes its columns to its own contents and the three drift apart. */
/* 760 was enough until the Removed tab's actions column grew to hold a pair of
   buttons: fixed columns plus percentages over-constrain, so the percentages
   are scaled down and "Weekly minimum" ran out of room again. Below this the
   table scrolls sideways inside .ovx, which is what that wrapper is for. */
.rostertable{table-layout:fixed;min-width:900px}
.rostertable .td{overflow:hidden;text-overflow:ellipsis}
/* Fixed columns hold their width, so a header too long for its column does not
   widen it — it spills over the next one. "Weekly minimum" did exactly that,
   printing itself across "Preferences" on a narrow window. Let it wrap. */
.rostertable .th{white-space:normal}


/* Regular shifts on Employees: the words are the button. They read as the
   cell's text, and the button shows itself — a light ground and an edge —
   when pointed at or tabbed to. It fills the cell, so the target is the whole
   width rather than the width of the words. */
.prefbtn{width:100%;justify-content:flex-start;text-align:left;font-weight:400;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.prefbtn:focus-visible{background:var(--surface3);border-color:var(--line)}

/* One group at a time, so a hidden one renders nothing at all. */
.rpanel.hidden{display:none!important}


/* ---------- "set availability" gate ----------------------------------
   Until the week's availability is set there is no grid at all — only this.
   A greyed-out table behind the message was something to read and reason
   about before the one decision the screen was actually asking for, and it
   invited clicks that went nowhere.
--------------------------------------------------------------------- */
.emptybox{display:flex;flex-direction:column;align-items:center;gap:var(--s4);
  padding:var(--s8) var(--s6);text-align:center}
.emptybox p{color:var(--ink2)}


/* ---------- who can work this week, beside the schedule ----------------
   Part of the page, not laid over it: the weekly view becomes two columns and
   the schedule gives up the room, scrolling sideways inside its own card if
   it has to. The panel sticks while the page scrolls, so a long grid never
   carries it out of reach. */
.schedlayout.with-side{display:grid;grid-template-columns:minmax(0,1fr) min(520px,42%);
  gap:var(--s6);align-items:start}
.sidepanel{position:sticky;top:var(--s5);max-height:calc(100vh - var(--s7));
  overflow-y:auto}
.sidehead{display:flex;align-items:center;gap:var(--s3);margin-bottom:var(--s5)}
/* The panel's grid gives up its own minimum width and most of its padding,
   so all seven days fit beside the shift names rather than Friday and
   Saturday scrolling out of sight. */
.sidepanel .mini{min-width:0}
.sidepanel .mini th{padding:8px 2px}
.sidepanel .mini td.slot{padding:var(--s3) var(--s3);width:120px}
/* Narrow here, so a time may take two lines rather than run into Sunday. */
.sidepanel .mini .slot .mono{white-space:normal}
.sidepanel .pick{padding:12px 0}
/* The schedule beside it gives up width rather than scrolling Thursday to
   Saturday out of sight: its minimum goes, the shift column narrows, and the
   times and names wrap inside their boxes instead. */
.with-side .sched{min-width:0}
.with-side .sched .rowhead{width:104px}
.with-side .sched th.rowlabel{padding:var(--s2)}
.with-side .ctl{padding:4px 6px}
.with-side .ctl:hover,.with-side .ctl:focus-within,.with-side .ctl.empty{
  background-image:none}
/* Too narrow for two columns: the panel follows the schedule instead. */
@media (max-width:1100px){
  .schedlayout.with-side{grid-template-columns:minmax(0,1fr)}
  .sidepanel{position:static;max-height:none}
}

/* ---------- popover ---------------------------------------------------
   The week selector's calendar. There was an overflow menu here too, holding
   Clear all and nothing else; it is on the toolbar now, where the sketch puts
   it, and a ••• with one item behind it was a door in front of a door.
--------------------------------------------------------------------- */
.menuwrap{position:relative}
.menu{position:absolute;right:0;top:calc(100% + var(--s2));z-index:30;
  min-width:196px;padding:var(--s2);background:var(--surface);
  border:1px solid var(--line2);border-radius:var(--r2);box-shadow:var(--sh2)}

/* ---------- the three choices for a box --------------------------------- */
.pickmenu{position:fixed;z-index:55;display:flex;flex-direction:column;gap:2px;
  min-width:200px;padding:var(--s2);background:var(--surface);
  border:1px solid var(--line2);border-radius:var(--r2);box-shadow:var(--sh2)}
.pickmenu button{display:flex;align-items:center;gap:var(--s3);padding:10px 12px;
  border-radius:var(--r1);font-size:16px;color:var(--ink1);text-align:left}
.pickmenu button:hover{background:var(--surface3)}
/* The box's current choice. */
.pickmenu button[aria-checked=true]{background:var(--brand-bg);font-weight:600}
.pickmenu button:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}

/* ---------- the preferences panel -------------------------------------
   A side sheet, not a modal: preferences belong to one person, and the page
   it was opened from is worth keeping in view behind it. The scrim dims and
   desaturates that page — a colourful half-lit grid still pulls the eye —
   while leaving it legible as context.
--------------------------------------------------------------------- */
.panelwrap{position:fixed;inset:0;z-index:40;display:flex;justify-content:flex-end}
.panelscrim{position:absolute;inset:0;background:rgba(28,27,25,.35);
  -webkit-backdrop-filter:grayscale(1);backdrop-filter:grayscale(1)}
.panel{position:relative;display:flex;flex-direction:column;
  width:min(680px,100vw);height:100%;background:var(--surface);
  border-left:1px solid var(--line);box-shadow:var(--sh2)}
/* The print dialog is a centred box rather than a side sheet: it asks one
   question about the whole page, not about something the page is showing, so
   there is nothing behind it worth keeping in view. It borrows the panel's
   head, body and foot so the two read as one family. */
.modalwrap{position:fixed;inset:0;z-index:45;display:flex;align-items:center;
  justify-content:center;padding:var(--s6)}
.modal{position:relative;display:flex;flex-direction:column;
  width:min(440px,100%);max-height:100%;background:var(--surface);
  border-radius:var(--r3);box-shadow:var(--sh2);overflow:hidden}
.modalwrap.hidden{display:none}
/* A whole row is the target, not the 13px circle in it. */
.choice{display:flex;align-items:center;gap:var(--s4);padding:11px var(--s4);
  border:1px solid var(--control);border-radius:var(--r2);cursor:pointer;
  background:var(--surface)}
.choice:hover{background:var(--surface2);border-color:var(--ink3)}
.choice:has(input:checked){background:var(--brand-bg);border-color:var(--brand);
  color:var(--brand-ink);font-weight:500}
.choice:has(input:focus-visible){outline:2px solid var(--brand);outline-offset:1px}
.choice input{accent-color:var(--brand);width:16px;height:16px;margin:0}
/* Seven equal columns rather than seven boxes sized to their contents, which
   came to 8px more than the dialog has and left Saturday alone on a second
   line. Each still clears the 44px touch target. */
.daychoice{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:var(--s2)}
.daychoice.hidden{display:none}
/* Seven of these across a 440px box, so they are compact — but each still
   clears the 40px touch target in both directions. */
.daybox{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:1px;min-width:44px;min-height:44px;padding:var(--s2) 0;
  border:1px solid var(--control);border-radius:var(--r2);
  background:var(--surface);color:var(--ink2);font-size:15px;cursor:pointer}
.daybox:hover{border-color:var(--ink3);color:var(--ink1)}
.daybox[aria-pressed=true]{background:var(--brand-bg);border-color:var(--brand);
  color:var(--brand-ink);font-weight:600}
.daybox:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
.daybox small{font-size:15px;font-variant-numeric:tabular-nums;opacity:.8}

.panelhead{display:flex;align-items:center;gap:var(--s3);
  padding:var(--s5) var(--s6);border-bottom:1px solid var(--line);flex-shrink:0}
.panelbody{padding:var(--s6);overflow-y:auto;flex:1;min-height:0}
.panelfoot{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3);
  padding:var(--s4) var(--s6);border-top:1px solid var(--line);
  background:var(--surface2);flex-shrink:0}
/* A fixed square, not padding around a glyph: padding sizes the box to the
   glyph, so an "i" made a narrower button than an "×" and the calendar's
   chevrons were narrower still. One size on the spacing scale, comfortably
   over the 24px hit-target floor. */
.iconbtn{display:inline-flex;align-items:center;justify-content:center;
  width:var(--s7);height:var(--s7);padding:0;
  border-radius:var(--r1);color:var(--ink2);font-size:18px;line-height:1}
.iconbtn:hover{background:var(--surface3);color:var(--ink1)}
.iconbtn:disabled{color:var(--quiet);cursor:not-allowed;background:none}

/* ---------- time off -------------------------------------------------- */
.onebox{font-size:16px;color:var(--ink2);cursor:pointer}
.onebox input{width:18px;height:18px;margin:0}
/* A date is picked, not typed: the box reads as the day it holds. */
.datebtn{display:flex;align-items:center;text-align:left;cursor:pointer;
  font-variant-numeric:tabular-nums}
/* The time-off box. Its calendars open past its edges rather than being
   clipped by them, so the box does not hide its own overflow. */
.offmodal{width:min(520px,100%);overflow:visible}
.offmodal .panelhead{border-radius:var(--r3) var(--r3) 0 0}
.offmodal .panelfoot{border-radius:0 0 var(--r3) var(--r3)}
.offmodal .panelbody{overflow:visible;display:flex;flex-direction:column;gap:var(--s5)}
.offmodal .field{height:44px}
.offdates{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s4)}
@media (max-width:520px){.offdates{grid-template-columns:minmax(0,1fr)}}
.datepick{display:block}
.daypop{left:0;right:auto;width:340px}
/* The last day's calendar opens leftwards, so it stays over the box. */
.daypop-end{left:auto;right:0}
.daygrid td{padding:1px;text-align:center}
.calday{width:100%;min-height:38px;border-radius:var(--r1);font-size:15px;
  color:var(--ink1);font-variant-numeric:tabular-nums}
.calday:hover{background:var(--surface3)}
.calday.other{color:var(--ink3)}
.calday.today{box-shadow:inset 0 0 0 1px var(--brand)}
.calday[aria-pressed=true]{background:var(--brand);color:#fff;font-weight:600}
.calday:focus-visible{outline:2px solid var(--brand);outline-offset:1px}

.offchip{display:inline-flex;align-items:center;gap:var(--s3);padding:var(--s2) var(--s3);
  border-radius:var(--r1);background:var(--off-bg);border:1px solid var(--off-line);
  color:var(--off-ink);font-size:15px}
.cell.off-blocked{background:repeating-linear-gradient(45deg,var(--surface2),
  var(--surface2) 6px,var(--off-bg) 6px,var(--off-bg) 12px)}
.dayoff{display:block;font-size:15px;font-weight:500;color:var(--off-ink);
  text-transform:none;letter-spacing:0}

/* ---------- availability matrix -------------------------------------- */
/* width:100% so the columns use the width the panel gives them; min-width
   keeps them readable and lets the wrapper scroll instead when it is narrow. */
.mini{table-layout:fixed;width:100%;min-width:596px}
.mini th{padding:10px 12px;text-align:center;font-size:15px;font-weight:600;
  letter-spacing:.03em;color:var(--ink-weak);
  background:var(--surface2);border:1px solid var(--line)}
.mini th small{display:block;font-size:15px;font-weight:400;text-transform:none;
  letter-spacing:0;color:var(--ink3)}
.mini td{padding:0;text-align:center;border:1px solid var(--line)}
/* .mini td (0,1,1) outranks .slot (0,1,0), so the shift column was inheriting
   the zero padding meant for the day cells — its label sat flush against the
   border. It needs the class on the element AND the descendant to win. */
.mini td.slot{padding:var(--s3) var(--s4)}
.mini .slot{position:static;box-shadow:none;text-align:left}
/* "10:30am-7:00pm" is one time and reads as one only on one line. Written in
   full it is a few characters wider than "10:30a–7p" was, which split it in
   two; the seven day columns give up the width instead. */
.mini .slot .mono{white-space:nowrap}
/* Rounded like every other surface here. Overflow clips to the radius, which
   is what rounds the corner cells of a border-collapse table — there is no
   border-radius a collapsed table's own outer cells will honour. The same
   overflow is what lets a narrow modal scroll the matrix sideways. */
.tablebox{overflow:auto;border-radius:var(--r2)}
.cursor-pointer{cursor:pointer}

/* ---------- hours bar ------------------------------------------------
   A one-glance read on how full someone's week is, so the numbers do not
   have to be compared by eye. */
.meter{height:3px;border-radius:2px;background:var(--surface3);overflow:hidden;
  margin-top:3px}
.meter > i{display:block;height:100%;background:var(--brand);border-radius:2px}
.meter.under > i{background:var(--warn-line)}
/* Over the minimum is not a fault: the same brand green, just full. */
.meter.over  > i{background:var(--brand)}

/* ---------- print ---------------------------------------------------- */
@page{size:landscape;margin:10mm}
/* The paper sheet has to say which week it is, exactly as the store's own
   printed schedule does. Screen-hidden, print-only. */
.printonly{display:none}
/* ---------- the posted sheet -----------------------------------------
   One page, always. A schedule pinned to the wall in two halves is not a
   schedule, and extra cells make the height unpredictable — five a day on
   seven days was three pages before this.

   The height is bought back three ways: landscape, tighter cells, and
   printing an extra as one line of text rather than as a stack of three
   controls. Nothing is scaled down, so nothing gets harder to read.
--------------------------------------------------------------------- */
@page{size:landscape;margin:10mm}
#printOut{display:none}
@media print{
  .noprint{display:none!important}
  /* When a print has been built, it is the only thing on the page — the live
     views hold one day at a time and cannot show a week and three sheets at
     once. */
  body.printing > main{display:none}
  body.printing #printOut{display:block}
  /* One sheet per page, and never a trailing blank one. */
  .printsheet{break-after:page;page-break-after:always}
  .printsheet:last-child{break-after:auto;page-break-after:auto}
  .printonly{display:flex;align-items:baseline;gap:var(--s5);
    margin-bottom:var(--s3);padding-bottom:var(--s2);
    border-bottom:2px solid #000;font-size:14px}
  #printWeek{font-variant-numeric:tabular-nums}
  body{background:#fff}
  main{padding:0}
  .card{border:0;box-shadow:none;padding:0}
  /* Who can work, open beside the schedule, does not print — and neither may
     the column it holds, or the sheet is laid out at two-thirds width. */
  .schedlayout.with-side{display:block}
  .sheetbox .profhead{border:0}
  /* The Front End Profile, as the form it is: every rule drawn, the typed
     fields replaced by their text, and the hour bar in grey so it survives a
     black-and-white printer. */
  .profhead{border:0;padding:0 0 var(--s2);font-size:12px}
  .profile{min-width:0;width:100%;font-size:10px}
  .profile th,.profile td{border:1px solid #000}
  /* Proportions, not pixels. The screen widths add up to 1244px and a
     landscape Letter page is about 980px of printable width, so fixed columns
     ran the last five hours off the right edge — and a sheet that is cut off
     still prints as exactly one page, which is why the page count alone never
     caught it. */
  .ph-name{width:14%}
  .ph-pos{width:10%}
  .ph-t{width:6.5%}
  .ph-hr{width:auto;font-size:9px}
  .ph{background:none;color:#000;font-size:10px;padding:2px 3px}
  .pn,.pp,.pt{font-size:10px;padding:1px 3px;color:#000}
  .phr{height:15px}
  .phr.on{background:#d8d8d8}
  .phr.lunch{background:#fff;font-size:9px}
  .prow-gap > td{height:7px;background:none}
  /* The fields do not print; their text twins do, so the In column still
     carries a time on paper. */
  .pfield{display:none}
  .profile .prn{display:block;color:#000}
  .calllog{min-width:0;width:230px}
  .calllog th,.calllog td{border:1px solid #000}
  .profile tr,.calllog tr{break-inside:avoid;page-break-inside:avoid}
  .ovx{overflow:visible}
  .sched{min-width:0;font-size:12px;width:100%}
  .slot{position:static;box-shadow:none}
  /* The menus do not print; the text they sit on does. An empty one prints
     nothing at all, rather than "Pick a person". */
  .cell-time,.cell-name,.cell-timeinput{display:none}
  .prn{display:block;color:#000;line-height:1.3}
  .ctl{border:0;padding:0;background:none!important;box-shadow:none}
  .ctl .show{color:#000;line-height:1.3}
  .ctl.empty .show{visibility:hidden}
  .ctl-time .show{font-size:11px;font-weight:400}
  .ctl-name .show{font-size:12px;font-weight:600}
  .cell{width:auto;padding:2px 5px}
  .sched th{padding:2px 4px;font-size:11px}
  .sched .rowhead{width:13%}
  .sched th.rowlabel{padding:2px 4px;background:none;font-size:11px}
  .sched th.rowlabel .t-sm{font-size:10px}
  .todaymark{display:none}
  .dayoff{font-size:10px}
  /* controls and affordances are not part of a posted sheet */
  .addextra{display:none}

  /* An extra is one line on paper — its time and its name, nothing else. On
     screen it is a stack of controls about 90px tall; printed like that, one
     extra was enough to start a second page. */
  .extracell{padding:2px 4px}
  /* tight, because five of these in a day is the case that decides whether the
     sheet is one page: 31px a line was 8px over, 15px a line is 60px under */
  .extra{display:flex;align-items:baseline;gap:6px;line-height:1.15;
    margin:0;padding:0;border:0;border-radius:0}
  .extra .ctl + .ctl{margin-top:0}
  .extra .ctl .show{font-size:11px;line-height:1.15}
  .extra .ctl-time{flex:0 0 auto}
  /* wraps rather than clips: a name cut in half on a posted sheet is worse
     than a name on a second line */
  .extra .ctl-name{flex:1 1 auto;min-width:0}

  /* Never break a day's row across the fold. */
  .sched,.sched tr,.sched td,.sched th{break-inside:avoid;page-break-inside:avoid}
  .printonly{break-after:avoid;page-break-after:avoid}
}

/* =====================================================================
   OVERRIDES — last so they win
   The alignment utilities are declared here rather than up in the type
   section: .th and .td set their own text-align, and at equal specificity
   whichever comes last wins. Declared earlier, `ta-r` on a table header
   silently lost, which is why the Weekly target column read left-aligned
   while its inputs sat right.
   ===================================================================== */
.ta-l{text-align:left}
.ta-c{text-align:center}
.ta-r{text-align:right}
