/* ===== The roster grid's card views (Plan 16, spec 2026-10-17 §2) =====

   The same ONE table, reflowed into a card per staff member, so HTMX cell
   updates, the proposal preview, selection and spreadsheet mode keep
   working. The cards follow the GRID's width, not the window's: every rule
   here starts with the card prefix

     :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"])

   — gridsplit.js sets data-gmode="cards" on a pane too narrow for the staff
   group and three days (always, below 1024 px), and boot.js's html.g-cards-boot
   covers a phone's first paint, before the grid is measured. The print page
   has no .grid-pane, so paper never sees any of this.

   Two views, the one remembered per device (backlog 1: drawn from the first
   paint, before any deferred script): Week is html.m-wk (boot.js sets it
   from localStorage, gridmobile.js when the view changes), By day is
   html:not(.m-wk); By day's day is the table's data-active-day, which the
   server draws (today, or Monday) and gridmobile.js changes. gridmobile.js
   also mirrors the view as table.m-day / m-week, for scripts and tests;
   no rule here keys on those.
     By day  each card shows the active day's cell full width, with the reason
             an error or uncertain cell is marked; the day tabs and the day's
             head ("N on duty · H hours") stay at the top; a swipe changes day.
     Week    each card shows the seven days as small boxes (the code, or the
             start and end on two lines), errors red, uncertain amber.
   Either way a card is: the staff head (tick box, number + name + position,
   the week's total), the day(s), then the More... figures on one labelled
   line. The cell editor slides up from the bottom as a sheet; each day's ⋯
   holds its cut / copy / paste / swap. Above the cards, the table head is
   the strip of day heads (the PH / SH / peak marks and the day remark).

   Specificity: the prefix weighs three classes, so the reflow's
   display:block outranks the More... toggles' display:none (app.css); those
   are restated under the prefix. */

/* ---- the bar: By day / Week, the day tabs, the day's head ---- */
#grid-mobile-bar{display:none}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) #grid-mobile-bar{
  display:flex;flex-wrap:wrap;gap:6px 10px;align-items:center;
  /* stuck to the top while the cards scroll (pre-flight C7: the only sticky bar) */
  position:sticky;top:var(--env-top, 0px);z-index:6;
  margin:0 0 var(--s2,8px);padding:6px 0;background:var(--bg,#F7F4EF)}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-views{display:inline-flex;gap:4px}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) :is(.m-vbtn, .m-day-tab, .m-menu-btn){
  border:1px solid var(--border,#ddd);background:var(--surface,#fff);color:var(--muted,#666);
  font-weight:600;font-size:calc(12px * var(--fs, 1));line-height:1.15;font-family:system-ui;cursor:pointer;
  min-height:44px;touch-action:manipulation}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-vbtn{border-radius:var(--pill,20px);padding:6px 14px}
/* ☑ Select ▾ and ⇅ Sort ▾: the table head's own menus (hidden with the head) */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-menus{display:inline-flex;gap:4px;margin-left:auto}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-menu-btn{border-radius:var(--pill,20px);padding:6px 10px;white-space:nowrap}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-vbtn[data-view="day"],
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-vbtn[data-view="week"],
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-day-tab.on{
  background:var(--accent,#A8842C);color:#fff;border-color:var(--accent,#A8842C)}
/* ☑ Select in the card layout (colpick.js, customer 2026-10-20): the day
   heads' tick boxes are hidden, so "Select all columns" gives way to
   "Select column(s) ▸" and its list of days. #sel-menu moves to the body
   when it opens, so the switch is keyed on the page holding a grid in cards
   (body:has(...)), not on the menu's place; the desktop keeps "Select all
   columns". A chosen day's tab carries a small ☑. */
#sel-menu .m-colpick-open{display:none}
body:has(:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"])) #sel-menu .menu-item[data-sel="cols"]{display:none}
body:has(:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"])) #sel-menu .m-colpick-open{display:flex}
#col-pick{min-width:220px;max-width:calc(100vw - 12px);box-sizing:border-box;overscroll-behavior:contain}
#col-pick .menu-item{min-height:44px}
#col-pick .menu-item[aria-disabled="true"]{color:var(--muted,#6f6a61);cursor:default}
#col-pick .m-colpick-done{justify-content:center;font-weight:700;color:var(--accent,#A8842C);
  border-top:1px solid #f0ebe0;margin-top:4px}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-day-tab{position:relative}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-day-tab.m-col-on::after{content:"☑";position:absolute;top:1px;right:2px;
  font-size:calc(10px * var(--fs, 1));line-height:1}
/* the seven tabs share one row, the weekday over the day of the month */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-days{display:none}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) #grid-mobile-bar .m-days{
  display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px;width:100%}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-day-tab{
  border-radius:var(--radius-sm,6px);padding:4px 2px;min-width:0;white-space:normal;overflow-wrap:anywhere}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .m-day-tab > span{display:block}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) #m-dayhead{display:none}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) #grid-mobile-bar #m-dayhead{
  display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:2px 10px;width:100%;
  font-size:calc(13px * var(--fs, 1))}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) #m-dayhead .m-dh-day{font-size:calc(15px * var(--fs, 1))}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) #m-dayhead .m-dh-sum{color:var(--muted,#6f6a61)}
/* the first-time swipe hint (gridmobile.js): a chip floating just under the
   sticky bar, over the cards, so nothing moves; it fades out (.m-gone) */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) #grid-mobile-bar .m-swipe-hint{position:absolute;top:calc(100% + 2px);left:50%;
  transform:translateX(-50%);z-index:7;max-width:calc(100% - 16px);box-sizing:border-box;padding:6px 14px;
  border-radius:var(--pill,20px);background:var(--ink,#1c1b19);color:#fff;box-shadow:var(--shadow-lg);
  font-size:calc(13px * var(--fs, 1));font-weight:600;line-height:1.3;text-align:center;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;pointer-events:none;opacity:.92;transition:opacity .3s ease}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) #grid-mobile-bar .m-swipe-hint.m-gone{opacity:0}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) #grid-mobile-bar .m-swipe-hint{display:none}

/* ---- the table as cards ---- */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid-scroll{overflow:visible;max-height:none;border:0;background:transparent}
/* By day's slide (gridmobile.js) moves the cards a pane's width sideways:
   clipped here, so nothing passes the screen's edge (clip makes no scroller,
   so the sticky bar and the floating ⋯ tools above and below are untouched) */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .gs-clip{overflow-x:clip;overflow-y:visible}
/* the desktop app-shell never scrolls the page: the cards scroll inside the grid */
html.hdr-sticky :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid-scroll{overflow-x:hidden;overflow-y:auto}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid,
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid :is(thead, tbody, tr, th, td){display:block}
/* the per-day foot rows have no columns to sit under (customer 2026-09-07);
   the day's own figures are in the bar's day head */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tfoot{display:none}

/* ---- the table head: the day-head strip ----
   The real thead stays, as the strip of day heads above the cards: the PH /
   SH / peak marks and the day remark's ✎ (an HTMX swap of #dayrem-<date>
   keeps working). By day shows the active day's head under the bar's day
   name; Week shows the seven, small, side by side. The staff, select, Total
   and More... heads are hidden (Select and Sort are on the bar). A template
   grid's heads hold only the weekday, already on the tabs: no strip. */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead{display:block;margin:0 0 8px}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead:not(:has(.day-marks)){display:none}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead tr{display:flex;flex-wrap:wrap;gap:4px;margin:0;
  border:0;border-radius:0;overflow:visible;background:transparent}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead :is(tr.head-sub, th:not(.day-head)){display:none}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead th.day-head{display:none;position:static;min-width:0;
  border:1px solid var(--border,#e3dccb);border-radius:var(--radius-sm,6px);background:var(--surface,#fff);font-weight:600}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead th .col-sel{display:none}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead .day-remark{margin:0;min-width:0}
/* By day: the active day's marks and remark on one line (its name is the bar's) */
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="0"] thead th.day-head[data-day="0"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="1"] thead th.day-head[data-day="1"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="2"] thead th.day-head[data-day="2"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="3"] thead th.day-head[data-day="3"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="4"] thead th.day-head[data-day="4"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="5"] thead th.day-head[data-day="5"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="6"] thead th.day-head[data-day="6"]{display:flex}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead th.day-head{flex:1 1 100%;flex-wrap:wrap;
  align-items:center;gap:4px 8px;padding:6px 10px;text-align:left}
/* (the same weight as the rule above, so it wins by coming later) a day
   with no marks and no remark to show or add has no strip */
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead th.day-head:not(:has(.day-marks > *)):not(:has(.day-remark-text, form)){display:none}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead th.day-head :is(.day-wd, .day-md){display:none}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead .day-marks{justify-content:flex-start;gap:4px}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead .day-remark{flex:1 1 auto}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead .day-remark-text{font-size:calc(13px * var(--fs, 1));min-height:32px;
  display:inline-flex;align-items:center}
/* Week: seven small heads in a row, the weekday over its marks and the ✎ */
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead th.day-head{display:flex;flex:1 1 0;flex-direction:column;
  align-items:center;gap:2px;padding:3px 1px;overflow:hidden;font-size:calc(10px * var(--fs, 1));line-height:1.2}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead th.day-head .day-md{display:none}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead :is(.day-tag, .day-ico){font-size:calc(9px * var(--fs, 1));padding:1px 3px}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead .day-remark{max-width:100%}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead .day-remark-text{display:block;max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:calc(10px * var(--fs, 1));min-height:20px}
/* a remark being written takes the strip's whole width, under the seven */
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid thead th.day-head:has(.day-remark form){flex:1 1 100%;order:1;
  padding:6px 10px;font-size:inherit}
/* what the More... toggles hide stays hidden */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid.no-bal :is(th.bal-head, td.lv-bal, tr.head-sub),
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid.no-lw :is(th.lw-head, td.ot-acc, td.lw-hours),
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid.no-bor tr.row-borrowed{display:none}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr{margin-bottom:10px;border:1px solid var(--border,#e3dccb);
  border-radius:var(--radius,8px);overflow:hidden;background:var(--surface,#fff)}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td{border:0;border-bottom:1px solid var(--border,#eee);text-align:left}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid .totals-cell{font-weight:700}

/* A staff card is a wrapping flex row, its lines forced apart by the row's
   two zero-height pseudo items: the head (drag, tick box, staff, total, OT wk),
   then the day(s), then the More... figures. One table, no new markup. */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr:has(> td.cell),
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr.sep-row{display:flex;flex-wrap:wrap;align-items:stretch}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr:has(> td.cell)::before{content:"";order:4;flex:0 0 100%;height:0}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr:has(> td.cell)::after{content:"";order:6;flex:0 0 100%;height:0}
/* the head */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tbody td.drag{order:0;flex:0 0 auto;position:static;width:auto;
  display:flex;align-items:center;padding:0 4px}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tbody td.drag:empty{display:none}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.sel{order:1;flex:0 0 auto;position:static;width:auto;
  display:flex;flex-direction:column;align-items:center;justify-content:center;padding:4px 8px;background:var(--bg,#faf7f0);text-align:center}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.sel:not(:has(input)){display:none}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.staff{order:2;flex:1 1 0;min-width:0;position:relative;left:auto;
  background:var(--bg,#faf7f0);font-weight:700;display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:0 8px}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.staff .staff-lines{flex:1 1 auto;min-width:0}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.staff .staff-pos{max-width:100%}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.staff .bor-from{flex:1 0 100%;white-space:normal}
/* the week's total, on the card's head */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr > td.totals-cell:not([data-gx]){order:3;flex:0 0 auto;
  display:flex;flex-direction:column;align-items:flex-end;justify-content:center;padding:4px 6px;background:var(--bg,#faf7f0);color:var(--ink,#1c1b19)}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid .m-move{display:inline-flex;align-items:center}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid .m-move button{min-width:44px;min-height:44px;padding:0;border:0;background:none;
  color:#A6572E;font:inherit;font-size:calc(14px * var(--fs, 1));cursor:pointer}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid .m-move button:disabled{color:var(--muted,#9a9484);opacity:.35;cursor:default}
/* a separator band: its drag handle beside the note */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr.sep-row > td.sep-cell{flex:1 1 0;min-width:0}

/* the days: hidden until a view shows them */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell{display:none;order:5;flex-direction:column}
/* a day cell's editor keeps the day's place (not the staff editor's td) */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr > td:is([id^="cell-"], [id^="tpcell-"]):has(> .editor){order:5}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .cell-drag-handle{display:none}   /* the drag-swap stays a desktop gesture; touch scroll wins */
/* ⋯ per day: the clipboard and two-tap-swap tools wait behind it (no hover
   on touch, and no three big buttons on every card); cellclip.js opens them
   as td.ca-open, one cell at a time, paste greyed with nothing to paste */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .cell-actions{display:flex;align-items:center;gap:6px;
  background:transparent;border:0;box-shadow:none;padding:0;z-index:3}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .cell-actions .ca-more{display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;padding:0;border:1px solid #E2C4AE;border-radius:var(--radius-sm,8px);background:var(--surface,#fff);
  color:#A6572E;font-weight:700;font-size:calc(16px * var(--fs, 1));line-height:1;touch-action:manipulation}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell.ca-open .cell-actions .ca-more{background:#A6572E;border-color:#A6572E;color:#fff}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .ca-tools{display:none}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell.ca-open .ca-tools{display:flex;gap:6px}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .ca-tools button{display:inline-flex;border:1px solid #E2C4AE;
  background:var(--surface,#fff);padding:8px 10px}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .ca-tools button svg{width:calc(18px * var(--fs, 1));height:calc(18px * var(--fs, 1))}

/* By day: the active day's cell, full width, saying why it is marked */
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="0"] td.cell[data-day="0"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="1"] td.cell[data-day="1"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="2"] td.cell[data-day="2"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="3"] td.cell[data-day="3"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="4"] td.cell[data-day="4"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="5"] td.cell[data-day="5"],
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid[data-active-day="6"] td.cell[data-day="6"]{display:flex}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid :is(td.cell, td:is([id^="cell-"], [id^="tpcell-"]):has(> .editor)){flex:1 1 100%;min-width:0}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .cell-why{display:block}
/* the ⋯ on the shift's line, at the right; its tools open to its left —
   they come first in the markup, so they are tabbed in the order seen
   (backlog 14b; no row-reverse) */
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell{padding-right:54px;min-height:48px}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .cell-actions{position:absolute;top:6px;right:8px;bottom:auto}
html:not(.m-wk) :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell.ca-open .ca-tools{background:var(--surface,#fff);
  border-radius:var(--radius-sm,8px);box-shadow:-8px 0 8px var(--surface,#fff)}

/* Week: seven boxes side by side, the weekday over the code or the times.
   The part above the ⋯ strip — the day and its value, a tap on which opens
   the sheet — is at least 44 px tall even when every box holds just a code
   (customer 2026-10-20: about 30 px upright, 25 sideways): 72 px = 44 + the
   strip's 3 px gap and 24 px button + the 1 px it leaves below. Only the
   height grows; the boxes keep their seventh of the card's width. */
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell{display:flex;flex:1 1 0;min-width:0;min-height:72px;
  padding:4px 2px;text-align:center;font-size:calc(11px * var(--fs, 1));line-height:1.25;
  border-left:1px solid var(--border,#eee);overflow:hidden;overflow-wrap:anywhere}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td:is([id^="cell-"], [id^="tpcell-"]):has(> .editor){flex:1 1 0;min-width:0;border-left:1px solid var(--border,#eee)}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell[data-day="0"]{border-left:0}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell::before{content:"";display:block;
  font-weight:700;font-size:calc(9px * var(--fs, 1));line-height:1.3;font-family:system-ui;text-transform:uppercase;color:var(--muted,#999)}
/* each box's weekday: the table's --m-wd<N>, drawn by the server (review.html,
   _grid_pane.html), so a box is labelled from the first paint (backlog 1) */
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell[data-day="0"]::before{content:var(--m-wd0, "")}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell[data-day="1"]::before{content:var(--m-wd1, "")}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell[data-day="2"]::before{content:var(--m-wd2, "")}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell[data-day="3"]::before{content:var(--m-wd3, "")}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell[data-day="4"]::before{content:var(--m-wd4, "")}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell[data-day="5"]::before{content:var(--m-wd5, "")}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell[data-day="6"]::before{content:var(--m-wd6, "")}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell > .rec{white-space:normal}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell > .rec :is(.rec-time, .rec-s, .rec-e){display:block}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell > .rec :is(.rec-s, .rec-e){font-weight:700}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell :is(.rec-dash, .rec-h, .rec-place, .rec-note, .rec-ot, .cell-why){display:none}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .chip{display:inline-block;max-width:100%;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;vertical-align:top;padding:1px 4px;font-size:calc(11px * var(--fs, 1))}
/* each box's ⋯ is a slim strip at its foot (a tap on the box above it still
   opens the sheet); its tools float under the box, over the next card,
   from the box's left edge — or its right edge for Friday to Sunday, so
   they stay on the screen */
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .cell-actions{position:static;display:block;order:99;margin:auto 0 -2px;padding-top:3px}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell .cell-actions .ca-more{display:flex;width:100%;height:24px;
  font-size:calc(13px * var(--fs, 1))}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr:has(> td.cell.ca-open),
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell.ca-open{overflow:visible}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell.ca-open .ca-tools{position:absolute;top:calc(100% + 2px);left:0;
  z-index:8;padding:6px;background:var(--surface,#fff);border:1px solid #E2C4AE;border-radius:var(--radius-sm,8px);box-shadow:var(--shadow-lg)}
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell:is([data-day="4"], [data-day="5"], [data-day="6"]).ca-open .ca-tools{left:auto;right:0}
/* near the screen's foot they open above the box (cellclip.js ca-up) */
html.m-wk :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.cell.ca-open.ca-up .ca-tools{top:auto;bottom:calc(100% + 2px)}

/* a chosen column's cells look selected in the cards too (spreadsheet mode,
   whose style this is, is off on a phone) */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tbody td.cell.cell-sel{background:#EAF1F8}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tbody td.cell.cell-sel.cell-amber{background:#F3ECD2}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tbody td.cell.cell-sel.cell-error{background:#F6E2E0}

/* the More... figures: one labelled line at the card's foot */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr > td[data-gx]{order:7;flex:1 1 0;min-width:0;padding:4px 3px;
  text-align:center;border-left:1px solid var(--border,#eee);border-bottom:0;white-space:normal}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td[data-gx] .ot-acc-in{width:100%;max-width:6em}
/* OT wk is a weekly figure like the Total, so it sits beside it on the
   card's head, never on a line of its own (customer 2026-10-20); same order
   as the Total, which comes first in the row. Its box holds four characters
   ("99.5") and its refusal wraps under it. On a phone the head is tight, so
   the staff lines ellipsis; the figures never do. */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid tr > td[data-gx="tw"]{order:3;flex:0 0 auto;width:auto;
  display:flex;flex-direction:column;align-items:flex-end;justify-content:center;padding:4px 8px 4px 0;
  border-left:0;border-bottom:1px solid var(--border,#eee);background:var(--bg,#faf7f0);text-align:right}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td[data-gx="tw"] .ot-acc-in{width:calc(4ch + 12px);max-width:none}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td[data-gx="tw"] .ot-why{width:0;min-width:100%;text-align:right}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td.staff :is(.staff-no, .staff-name){overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
/* every labelled card cell names itself: Select, Total, OT wk, RD, PH/SH, AL, accum, last wk */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td[data-label]::before{content:attr(data-label);display:block;
  font-size:calc(10px * var(--fs, 1));font-weight:700;letter-spacing:.03em;text-transform:uppercase;line-height:1.2;
  color:var(--muted,#6f6a61);margin-bottom:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
/* the head's labels are never cut: their cells take the width they need */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid :is(td.sel, td.totals-cell:not([data-gx]), td[data-gx="tw"])[data-label]::before{overflow:visible;max-width:none}

/* ---- the cell editor: a sheet sliding up from the bottom ----
   (the popup in layout.css, moved to the bottom edge and stacked in one
   column; Save / Cancel stay on its sticky foot, and it fits the visible
   screen — dvh, so a phone's browser bars don't hide its foot) */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td .editor{
  inset:auto 0 0 0;margin:0;width:100%;max-height:calc(100dvh - 24px);
  border-bottom:0;border-radius:16px 16px 0 0;box-shadow:0 -6px 24px rgba(0,0,0,.18);
  padding-bottom:env(safe-area-inset-bottom, 0px);
  overflow-y:auto;overflow-x:hidden;animation:cdg-sheet-up .22s ease-out}
/* the grab bar */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td .editor::before{content:"";display:block;flex:0 0 auto;
  width:40px;height:4px;border-radius:2px;background:#ccc;margin:-6px auto 6px}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td .editor .editor-x{position:sticky;top:0;align-self:flex-end;margin:0 0 6px 0}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td .editor .ed-mid{padding-top:0;contain:none}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td .editor .ed-grid{grid-template-columns:1fr;grid-template-rows:none;
  grid-template-areas:"ctx" "mid" "hints" "right" "btns";flex:0 0 auto;min-height:auto}
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td .editor :is(.ed-hints, .ed-mid, .ed-right){overflow-y:visible;min-height:auto}
/* only when it opens: a sheet re-rendered in place (Reset, a refused save) is
   .ed-again (gridmobile.js) and stays where it is (backlog 2) */
:is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td .editor.ed-again{animation:none}
@keyframes cdg-sheet-up{from{transform:translateY(100%)}to{transform:translateY(0)}}
@media (prefers-reduced-motion:reduce){
  :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid td .editor{animation:none}
  :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) #grid-mobile-bar .m-swipe-hint{transition:none}
}

/* ===== The review and template pages below 1024 px (Plan 16 Task 10, spec §2a) =====
   The title on two lines with ‹ Back first; the desktop action bar gives way
   to _m_actions.html's bar — Download · Upload · Confirm · More (the template
   page: Add · Highlight · Delete · More) — and More is ONE flat menu.
   Every item there clicks a desktop control (mactions.js). The bar scrolls
   away with the page: only the cards' bar sticks (pre-flight C7). From
   1024 px up nothing here shows and .title-sub is display:contents, so the
   desktop header and the ≤1299 rule are as they were. */
.m-actionbar,.back-chev,.wk-date-m{display:none}
.title-sub{display:contents}
.m-actionbar [hidden],.m-more .menu-item[hidden],.m-more .m-grp[hidden]{display:none}
.m-act{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:44px;padding:6px 12px;
  border:1px solid var(--border,#e3dccb);border-radius:var(--radius-sm,8px);background:var(--surface,#fff);
  color:var(--ink,#1c1b19);font:inherit;font-weight:600;font-size:calc(13px * var(--fs, 1));line-height:1.15;
  cursor:pointer;touch-action:manipulation;white-space:nowrap}
.m-act .m-ico{display:inline-flex;align-items:center;justify-content:center;font-size:calc(16px * var(--fs, 1));line-height:1;color:var(--accent,#A8842C)}
.m-act .m-lbl{font-size:calc(12px * var(--fs, 1))}
.m-act .m-s{display:none}
/* a refused item is aria-disabled, not disabled, so a tap still reaches
   mactions.js, which says why (2026-10-20, customer) */
.m-act:is(:disabled, [aria-disabled="true"]){cursor:default}
.m-act:is(:disabled, [aria-disabled="true"]) :is(.m-ico, .m-lbl){opacity:.45}
/* why a control is refused, in words: never inside the button (written under
   Delete it made the template bar twice as tall, customer 2026-10-20) — the
   item's aria-describedby reads it, and a tap shows it for a moment in the
   .m-why-tip that mactions.js places beside the item, over the page */
.m-why{display:none}
.m-why-tip{position:fixed;z-index:70;box-sizing:border-box;max-width:min(320px, calc(100vw - 24px));padding:8px 12px;
  border-radius:var(--radius-sm,8px);background:var(--ink,#1c1b19);color:#fff;box-shadow:var(--shadow-lg);
  font-size:calc(13px * var(--fs, 1));font-weight:500;line-height:1.3;text-align:center;white-space:normal;
  pointer-events:none}
.m-why-tip[hidden]{display:none}
/* the More menu: flat, its groups headed, scrolling inside itself */
.m-more{max-height:calc(100dvh - 24px);overflow-y:auto;overscroll-behavior:contain;min-width:240px;max-width:calc(100vw - 12px);box-sizing:border-box}
.m-more .m-grp{margin:4px 0 0;padding:8px 12px 2px;border-top:1px solid #f0ebe0;
  font-size:calc(11px * var(--fs, 1));font-weight:700;color:var(--muted,#6f6a61)}
.m-more .m-grp:first-child{border-top:0;margin-top:0;padding-top:2px}
.m-more .m-grp-sep{padding:0}
.m-more .menu-item{min-height:44px;flex-wrap:wrap}
.m-more .menu-item:is(:disabled, [aria-disabled="true"]){cursor:default;color:var(--muted,#6f6a61);opacity:1}
.m-more .menu-item:is(:disabled, [aria-disabled="true"]):hover{background:transparent}
.m-more .menu-item .menu-ico svg{margin:0 auto}
.m-more .menu-item.m-primary{font-weight:700;color:var(--accent,#A8842C)}
.m-more .m-note{margin:4px 12px}

/* the week's counts at the end of the action row (_m_actions.html), on an
   upright tablet only: 600-1023.98 px and not a phone held sideways
   (html.phone-dev, boot.js; customer ruling 2026-10-20). There the title row
   drops its own. With all four buttons the chips stay on the row when they
   fit; else margin-left:auto puts them on a line of their own, at the right. */
.m-counts{display:none}
.m-count{min-height:44px;padding:0 4px;border:0;background:none;font-family:inherit;line-height:1.2;
  white-space:nowrap;touch-action:manipulation}
button.m-count{cursor:pointer}
@media screen and (min-width:600px) and (max-width:1023.98px){
  html:not(.phone-dev) .m-actionbar .m-counts{display:inline-flex;flex-wrap:wrap;align-items:center;
    justify-content:flex-end;gap:0 8px;margin-left:auto}
  html:not(.phone-dev) .review-page #title-counts > *{display:none}
}

@media screen and (max-width:1023.98px){
  .review-page .actionbar{display:none}
  .tp-tools{display:none}
  .m-actionbar{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 var(--s3,12px)}
  /* the spreadsheet switch and its ⓘ live in More (tablets) */
  .sheet-ctl{display:none}
  /* the title wraps, Back first with its ‹ */
  .review-page .title-row{flex-wrap:wrap;row-gap:4px}
  .review-page .title-row .back-link{order:-1;padding-left:8px;padding-right:10px}
  .back-chev{display:inline;margin-right:4px;font-size:calc(18px * var(--fs, 1));line-height:.8}
  /* the template page's Add · Highlight · Delete at 75 % of the review bar's
     buttons — font, icon, padding and gap — still a 44 px target (customer
     2026-10-20); the phone's own 75 % is in the block below */
  .m-tp-bar .m-act{gap:4.5px;min-height:44px;padding:4.5px 9px;font-size:calc(9.75px * var(--fs, 1))}
  .m-tp-bar .m-act .m-ico{font-size:calc(12px * var(--fs, 1))}
  .m-tp-bar .m-act .m-lbl{font-size:calc(9px * var(--fs, 1))}
}
/* ...but on a phone, upright or sideways (a touch screen under 600 px tall
   is a phone held sideways), the labels are 10.5 px: 9 px was hard to read
   (ruling 18, 2026-10-20); the buttons keep their 75 % */
@media screen and (max-width:599.98px), screen and (max-width:1023.98px) and (max-height:599.98px) and (pointer:coarse){
  .m-tp-bar .m-act .m-lbl{font-size:calc(10.5px * var(--fs, 1))}
}

@media screen and (max-width:599.98px){
  /* no spreadsheet mode on a phone (sheetmode.js): its items go (!important:
     .bar-menu .menu-item's display:flex outweighs a single class) */
  .m-tablet-only{display:none !important}
  /* four equal buttons, the icon over a short label */
  .m-actionbar{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:6px}
  .m-act{flex-direction:column;gap:2px;min-width:0;min-height:52px;padding:5px 2px;white-space:normal;text-align:center}
  .m-act .m-ico{font-size:calc(17px * var(--fs, 1))}
  .m-act .m-lbl{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .m-act .m-s{display:inline}
  .m-act .m-l{display:none}
  .m-tp-bar .m-act{gap:1.5px;min-height:44px;padding:3.75px 1.5px}
  .m-tp-bar .m-act .m-ico{font-size:calc(12.75px * var(--fs, 1))}
  /* the title's second line: the date, the status, the 💡 and the counts */
  .review-page .title-row .page-title{flex:1 1 0;min-width:0}
  .review-page .title-row .wk-date{display:none}
  .review-page .title-row .title-sub{display:flex;flex:1 0 100%;flex-wrap:wrap;align-items:center;gap:4px 8px;min-width:0}
  .review-page .title-row .wk-date-m{display:inline;font-size:calc(13px * var(--fs, 1));color:var(--muted,#6f6a61)}
  .review-page .title-row .status-lbl{display:none}
  .review-page .title-row .title-msg{max-width:100%}
  /* a card's ▲ over its ▼ (each still 44 px), so the head beside Total and
     OT wk leaves the staff number room to show in full (coordinator 2026-10-20) */
  :is(.g-cards-boot .grid-pane:not([data-gmode]), .grid-pane[data-gmode="cards"]) .grid .m-move{flex-direction:column}
}
