﻿/* The design tokens, all of them, here and nowhere else (no colour is written outside this block).
   Blue and white with a sky accent (the owner, 2026-10-31; DECISIONS.md § Blue, white and one sky),
   replacing the demo's navy and brass. Each hue has one job:
   blue — the primary action and links; sky — where you are and how far along (the current tab,
   focus, selection, a progress bar, the room in hand); green — done; amber — waiting on someone;
   red — a problem. Sky never means "needs you", and never "press me": it sits 24° from the button blue. Text shades are AA (4.5:1) on white and on the
   ground; a fill's own -ink shade is the text set on its -soft tint. */
:root{
  --ink:#0F1D3A; --slate:#24406E; --ground:#F3F6FB; --card:#FFFFFF; --on-fill:#FFFFFF;
  --blue:#1F55D6; --blue-deep:#1844B0; --blue-ink:#1A4BC2; --blue-soft:#E8EEFC;
  --accent:#0A8FC7; --accent-ink:#0A6A96; --accent-soft:#E2F3FB; --accent-on-rail:rgba(10,143,199,.22);
  --rail-bg:#0F2A5E; --rail-text:#D5DFF3; --rail-muted:#93A6CC;
  --verde:#1D7653; --verde-deep:#165E42; --verde-soft:#E2F3EA; --verde-line:#BFE0CF;
  --flag:#C2382C; --flag-deep:#9E2C22; --flag-soft:#FCEAE8; --flag-wash:#F9DEDA; --flag-line:#F1C7C2;
  --line:#C9D3E3; --line-soft:#E4EAF3;
  --muted:#4A5A78; --muted-2:#5E6F8F;
  /* Amber is waiting on someone; the room grid's two extra statuses are amber and gold, as housekeeping asked. */
  --amber:#C4741A; --amber-ink:#8C4A0B; --amber-soft:#FDF0E0; --amber-line:#F0D3AC; --gold:#B8960B; --gold-soft:#FAF3D0;
  --sans:"Public Sans",ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
  --head:var(--sans);
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  /* Six sizes. Small print, body small, body, a card's title, a page's title, a figure. */
  --fs-1:12.5px; --fs-2:14px; --fs-3:15px; --fs-4:17px; --fs-5:21px; --fs-6:26px;
  /* Inputs and buttons, cards and panels, pills and chips. */
  --r-input:6px; --r-card:10px; --r-pill:999px;
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px;
  /* The phone's bottom nav: its 1px border, 4px padding, a fixed 57px tab and 4px (step 4, 2026-10-28). What sits
     above it — the toast, the room sheet, a bar pinned to the bottom — stands on this, not on a number. */
  --nav-h:66px;
  /* The top bar's height; the department row stands under it. */
  --bar-h:52px;
  /* The redesign run of 2026-11-05 (REDESIGN-PROMPT.md, Phase 0): every value that was written raw below is named here.
     White laid over the navy bar (a hover, an open menu, a rule, a thin border, a scrollbar, a button's edge on a toast). */
  --veil-1:rgba(255,255,255,.08); --veil-2:rgba(255,255,255,.12); --veil-3:rgba(255,255,255,.14); --veil-4:rgba(255,255,255,.18);
  --veil-5:rgba(255,255,255,.28); --veil-6:rgba(255,255,255,.6);
  /* Depth: an offset and a soft blur, in the ink's own hue. A menu, a toast, a raised card, the phone's sheet, a pinned bar. */
  --shadow-menu:0 10px 28px rgba(15,29,58,.22); --shadow-pop:0 6px 20px rgba(15,29,58,.22); --shadow-toast:0 4px 16px rgba(15,29,58,.18);
  --shadow-raised:0 4px 12px rgba(15,29,58,.12); --shadow-soft:0 4px 12px rgba(15,29,58,.06); --shadow-sheet:0 -14px 34px rgba(15,29,58,.26);
  --shadow-bar:0 -4px 12px rgba(15,29,58,.06);
  /* A hairline round a swatch or a mark on a coloured cell, and the dark behind an enlarged photo. */
  --edge:rgba(15,29,58,.15); --edge-strong:rgba(15,29,58,.45); --scrim:rgba(15,29,58,.6);
  /* The focus ring: sky, where you are. One width and one offset everywhere. */
  --focus:var(--accent); --focus-w:2.5px; --focus-off:2px; --tap:rgba(10,143,199,.3);
  /* Sizes outside the six: the smallest (a code in a cell, a badge), a form box on a phone (16px stops iOS zooming),
     the manager's figure, the housekeeper's timer. */
  --fs-0:11px; --fs-input:16px; --fs-7:30px; --fs-8:46px;
  /* Small radii: a tick box and a swatch; a round dot or avatar. */
  --r-xs:3px; --r-sm:4px; --r-round:50%;
  /* What a thumb needs to hit, and the height of a text box, a select and a date in a row. */
  --hit:44px; --box-h:42px;
}
/* Public Sans for every word, IBM Plex Mono for times, rooms and codes; served from wwwroot/fonts
   (OFL-PublicSans.txt and OFL.txt beside them): the app loads nothing from another origin. Public Sans
   replaced Plex Sans and its condensed titles on 2026-10-31: the owner saw Plex's stems land
   a pixel apart at 14-15px on a 1x Windows screen, the d shorter than the k. Until a file arrives the system face
   stands in (swap), so text is never invisible on a slow line. */
@font-face{font-family:"Public Sans";font-style:normal;font-weight:400;font-display:swap;src:url("/fonts/public-sans-latin-400-normal.woff2") format("woff2")}
@font-face{font-family:"Public Sans";font-style:normal;font-weight:500;font-display:swap;src:url("/fonts/public-sans-latin-500-normal.woff2") format("woff2")}
@font-face{font-family:"Public Sans";font-style:normal;font-weight:600;font-display:swap;src:url("/fonts/public-sans-latin-600-normal.woff2") format("woff2")}
@font-face{font-family:"Public Sans";font-style:normal;font-weight:700;font-display:swap;src:url("/fonts/public-sans-latin-700-normal.woff2") format("woff2")}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:400;font-display:swap;src:url("/fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2")}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:500;font-display:swap;src:url("/fonts/ibm-plex-mono-latin-500-normal.woff2") format("woff2")}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:600;font-display:swap;src:url("/fonts/ibm-plex-mono-latin-600-normal.woff2") format("woff2")}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{background:var(--ground);color:var(--ink);caret-color:var(--accent-ink);font-family:var(--sans);font-size:var(--fs-3);line-height:1.5;
  -webkit-font-smoothing:antialiased;padding-bottom:env(safe-area-inset-bottom);overflow-wrap:break-word}
button,input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}
:focus-visible{outline:var(--focus-w) solid var(--focus);outline-offset:var(--focus-off);border-radius:var(--r-xs)}
/* Deliberate (ui-polish audit, 2026-11-02): the stylesheet has no animation and six transitions, none of them a
   state a person would miss with motion off, so the whole switch is honest here. Add a spinner and revisit. */
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
a{color:var(--blue-ink);text-underline-offset:.18em;text-decoration-thickness:1px}
a:hover{text-decoration-thickness:2px}
/* The skip link: the Tab key's first stop, out of sight until then. The page it lands on takes
   the focus without a ring of its own: the ring would be the whole screen. */
.skip{position:absolute;left:var(--sp-2);top:var(--sp-2);z-index:120;padding:var(--sp-2) var(--sp-3);border-radius:var(--r-input);
  background:var(--card);color:var(--blue-ink);font-weight:600;font-size:var(--fs-2);box-shadow:var(--shadow-toast)}
.skip:not(:focus){width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.main:focus,.main:focus-visible{outline:none}

/* ---------- layout: the page's four blocks ----------
   A page lays itself out with these, and every one asks the column it sits in, never the window
   (docs/plans/done/responsive-layout.md, DECISIONS.md § Layout reacts to its container). Today's quick
   actions wrapped one letter a line on a laptop because their rule was keyed to the window while
   the column was narrower by the rail and the "Needs you" list. The container is .wrap, the main
   column (named "main"), and a region narrower than that (a .split's two sides) is its own, so a
   block inside it asks that region with no further work. A content rule never writes a viewport
   @media: where a block does not fit, add an @container rule to the component. The shell — the
   rail turning into the bottom bar and what stands on that bar — is the window's alone, between
   the /* shell */ markers below. */
.flow{display:flex;flex-direction:column;gap:var(--sp-3)}
.flow.tight{gap:var(--sp-2)}
.flow.loose{gap:var(--sp-5)}
/* A row of buttons or chips that wraps; none shrinks below its label. */
.cluster{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2)}
.cluster>*{flex:0 0 auto;max-width:100%}
.cluster.end>:last-child{margin-left:auto}
/* As many equal tracks as fit; --min is the narrowest a track may be (a .min-* utility). min(…,100%)
   is what keeps one track from overflowing a column narrower than --min. */
.autogrid{display:grid;gap:var(--sp-3);grid-template-columns:repeat(auto-fit,minmax(min(var(--min,180px),100%),1fr))}
.min-120{--min:120px}.min-150{--min:150px}.min-180{--min:180px}.min-300{--min:300px}
/* A main column and a side of --side (360px unless a .side-* says otherwise): beside each other when
   the column holds both and 560px of reading room (360 + 24 gap + 560 = 944), else stacked, main first. */
.split{display:grid;grid-template-columns:minmax(0,1fr);gap:0 var(--sp-5);align-items:start}
.split>*{min-width:0;container-type:inline-size}
@container main (min-width:944px){.split{grid-template-columns:minmax(0,1fr) var(--side,360px)}}

/* ---------- shell ----------
   The top bar (the nav by department, 2026-11-04, DECISIONS.md § The nav is a bar of departments): the brand, the hotel, one place for
   each department the person has pages in, the bell and the person. Under it, the row of the department being read. On a phone the
   places leave the bar: the tab bar at the foot (.rail, all that is left of the old side rail) and its Menu sheet carry them, and the
   row stays. */
.shell{display:flex;flex-direction:column;min-height:100vh}
.main{flex:1;min-width:0;display:flex;flex-direction:column}
.topbar{background:var(--rail-bg);color:var(--rail-text);display:flex;align-items:center;gap:var(--sp-1);
  height:var(--bar-h);padding:0 var(--sp-3) 0 var(--sp-4);position:sticky;top:0;z-index:55}
.brand{margin-right:var(--sp-3);font-family:var(--head);font-weight:700;font-size:var(--fs-4);letter-spacing:.02em;color:var(--on-fill);
  text-decoration:none;white-space:nowrap}
.brand:hover{text-decoration:none}
.wrap{padding:var(--sp-5);max-width:1120px;width:100%;container:main/inline-size}
/* The room grid only. 1120px caps the chart at about a third of a 1920 screen and wraps 207
   cells into cramped ragged rows with the space going spare beside them — "the rooms grid looks
   very messed up" (the owner, 2026-09-23). Width is what this page is for: more columns is a
   shorter grid. .lede is already capped at 64ch, so the prose above it does not stretch. */
.wrap.wide{max-width:none}
.wrap.wide .pmline{max-width:110ch}

/* A menu is a <details>: a click opens it, with no script (page.js closes the one beside it, and on Escape and a click elsewhere). It draws
   its own caret, so the general chevron below leaves it alone. */
.navmenu>summary{list-style:none;cursor:pointer}
.navmenu>summary::-webkit-details-marker{display:none}
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
.caret{width:10px;height:10px;flex:none;stroke:currentColor;fill:none;stroke-width:2;opacity:.75}
.hotelpick{position:relative;margin-right:var(--sp-3);min-width:64px}
.hotelpick>summary,.hotelpick>.hpstatic{display:flex;align-items:center;gap:6px;padding:6px 10px;border:1px solid var(--veil-4);
  border-radius:var(--r-input);font-size:var(--fs-2);font-weight:500;color:var(--on-fill);white-space:nowrap}
.hotelpick>summary:hover{background:var(--veil-1)}
.hname{overflow:hidden;text-overflow:ellipsis;min-width:0}
.hcode{font-family:var(--mono);font-size:var(--fs-1);color:var(--rail-muted)}
/* The departments keep their width and the hotel's name gives way: on a bilingual seat at 901px the places ran under the bell. */
.depts{display:flex;align-items:stretch;align-self:stretch;gap:2px;flex:1 0 auto}
.dept{position:relative;display:flex}
.dept>summary,.dept>a{display:flex;align-items:center;gap:6px;padding:0 var(--sp-3);border-top:3px solid transparent;border-bottom:3px solid transparent;
  color:var(--rail-text);font-weight:500;font-size:var(--fs-3);text-decoration:none;white-space:nowrap}
.dept>summary:hover,.dept>a:hover{background:var(--veil-1);color:var(--on-fill)}
/* The department you are in is underlined in sky: where you are. */
.dept.here>summary,.dept.here>a{color:var(--on-fill);border-bottom-color:var(--accent);font-weight:600}
.dept[open]>summary{background:var(--veil-2);color:var(--on-fill)}
.dept .glyph{opacity:.85}

.menu{position:absolute;top:100%;left:0;width:320px;max-width:calc(100vw - 2*var(--sp-4));background:var(--card);color:var(--ink);
  border:1px solid var(--line);border-radius:0 0 var(--r-card) var(--r-card);box-shadow:var(--shadow-menu);padding:var(--sp-2)}
/* The last two places open leftwards, so a menu never runs off the right of a laptop; a two-column one is the first place's and stays. */
.dept:nth-last-child(-n+2) .menu:not(.menu-two),.person .menu{left:auto;right:0}
.menu.menu-two{width:560px;display:grid;grid-template-columns:1fr 1fr;gap:0 var(--sp-2)}
.menu-two .mcol+.mcol{border-left:1px solid var(--line-soft);padding-left:var(--sp-2)}
.msec{padding:var(--sp-2) 10px 3px;font-size:var(--fs-1);font-weight:600;color:var(--muted-2)}
.mcol:first-child>.msec:first-child{padding-top:var(--sp-1)}
.mi{display:flex;gap:10px;align-items:flex-start;min-height:var(--hit);padding:7px 10px;border-radius:var(--r-input);color:var(--ink);text-decoration:none}
.mi:hover{background:var(--blue-soft)}
.mi[aria-current="page"]{background:var(--blue-soft);color:var(--blue-ink)}
.mi .glyph{opacity:1;color:var(--slate);margin-top:1px}
.mi[aria-current="page"] .glyph{color:var(--accent)}
.mtext{display:flex;flex-direction:column;min-width:0}
.mi .nlong,.mi .navlabel{font-weight:600;font-size:var(--fs-2);line-height:1.3}
.mhint{font-size:var(--fs-1);color:var(--muted);line-height:1.35}
/* Where a department's badge leads: the menu's first line while something waits, amber as everything waiting on someone is. */
.mwait{background:var(--amber-soft);border:1px solid var(--amber-line);margin-bottom:var(--sp-1)}
.mwait:hover{background:var(--amber-soft);border-color:var(--amber)}
.mwait[hidden],.sheetwait[hidden]{display:none}
.mwait .navlabel{color:var(--amber-ink)}
/* Setup is last and quieter: ruled off, plainer words, a muted icon. */
.msetup{border-top:1px solid var(--line-soft);margin-top:6px;padding-top:var(--sp-1)}
.msetup .mi .nlong{font-weight:500;color:var(--slate)}
.msetup .mi .glyph{color:var(--muted-2)}

.whoami{margin-left:auto;display:flex;align-items:center;gap:var(--sp-2)}
.person{position:relative}
.person>summary{display:flex;align-items:center;gap:var(--sp-2);padding:5px 8px 5px 5px;border-radius:var(--r-pill);color:var(--on-fill);font-size:var(--fs-2);white-space:nowrap}
.person>summary:hover{background:var(--veil-1)}
.avatar{width:30px;height:30px;border-radius:var(--r-round);background:var(--accent-ink);color:var(--on-fill);display:inline-flex;align-items:center;justify-content:center;
  font-weight:700;font-size:var(--fs-1)}
.person .menu{width:auto;min-width:250px}
.pinfo{padding:var(--sp-2) 10px 10px;border-bottom:1px solid var(--line-soft);margin-bottom:6px}
.pinfo b{display:block;font-size:var(--fs-3)}
.pinfo span{font-size:var(--fs-1);color:var(--muted)}
.pout{padding:var(--sp-2) 10px 4px}

/* The department being read: a row of tabs under the bar. Its setup is at the right end, in plainer words. */
.deptrow{background:var(--card);border-bottom:1px solid var(--line);display:flex;align-items:stretch;gap:2px;padding:0 var(--sp-4);
  overflow-x:auto;scrollbar-width:none}
.deptrow .crumb{display:flex;align-items:center;margin-right:6px;padding-right:14px;border-right:1px solid var(--line-soft);
  font-size:var(--fs-1);font-weight:600;color:var(--muted-2);white-space:nowrap}
.tab{display:flex;align-items:center;gap:6px;padding:11px var(--sp-3) 9px;border-bottom:2.5px solid transparent;
  font-size:var(--fs-2);font-weight:500;color:var(--slate);text-decoration:none;white-space:nowrap}
.tab:hover{color:var(--ink);background:var(--ground)}
.tab[aria-current="page"]{color:var(--blue-ink);border-bottom-color:var(--accent);font-weight:600}
.tab-setup{margin-left:auto;color:var(--muted-2)}
.tab-setup~.tab-setup{margin-left:0}
.tab-setup .glyph{width:16px;height:16px;flex-basis:16px;opacity:1}
.tab-setup .glyph svg{width:16px;height:16px}

/* The icon is an inline SVG drawn in currentColor (Views/Shared/_NavIcon.cshtml), so it takes the link's colour. */
.glyph{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;flex:0 0 20px;opacity:.75}
.glyph svg{width:20px;height:20px;display:block}
.nshort{display:none}

/* The phone's Menu sheet, built on <details> so it opens with no JavaScript. Absolute to the fixed tab bar (the bar is its containing
   block, and does not clip), so it stands on the bar's top edge, inside the bar's own z-index 50. It scrolls within the height above the
   bar: a general manager's twenty pages are a screen and a half. */
.moresheet{position:absolute;left:0;right:0;bottom:100%;
  max-height:calc(100dvh - var(--nav-h) - env(safe-area-inset-bottom) - var(--bar-h));overflow-y:auto;overscroll-behavior:contain;
  background:var(--rail-bg);border-top:1px solid var(--veil-3);border-radius:0;
  padding:0;display:grid;grid-template-columns:1fr;gap:0}
.moreitem{display:flex;flex-direction:row;align-items:center;justify-content:flex-start;gap:var(--sp-3);
  min-height:48px;padding:0 var(--sp-4);border-top:1px solid var(--veil-2);text-decoration:none;
  color:var(--rail-text);font-family:var(--head);font-weight:600;font-size:var(--fs-3);text-align:left;line-height:1.25}
.moreitem:first-child{border-top:0}
.moreitem .glyph{width:22px;height:22px;flex:none}
.moreitem .glyph svg{width:22px;height:22px}
.moreitem[aria-current="page"]{background:var(--accent-on-rail);color:var(--on-fill);box-shadow:inset 3px 0 0 var(--accent)}
.moreitem[aria-current="page"] .glyph{color:var(--accent);opacity:1}
/* A department's block: its name and badge, its pages two to a row, its setup folded under. */
.sheetdept{border-top:1px solid var(--veil-2);padding-bottom:var(--sp-1)}
.sheetdept:first-child{border-top:0}
.sheethd{display:flex;align-items:center;justify-content:space-between;padding:var(--sp-3) var(--sp-4) var(--sp-1);
  font-size:var(--fs-1);font-weight:700;color:var(--rail-muted)}
.sheetitems{display:grid;grid-template-columns:1fr 1fr}
.sheetitems .moreitem{border-top:0;padding:0 var(--sp-3);font-size:var(--fs-2)}
.sheetsetup>summary{list-style:none;cursor:pointer;min-height:var(--hit);display:flex;align-items:center;padding:0 var(--sp-4);
  font-size:var(--fs-1);font-weight:600;color:var(--rail-muted)}
.sheetsetup>summary::-webkit-details-marker{display:none}
.sheetsetup>summary::before{content:"";display:inline-block;width:6px;height:6px;margin:0 var(--sp-2) 2px 2px;border:solid var(--rail-muted);
  border-width:0 1.5px 1.5px 0;transform:rotate(-45deg)}
.sheetsetup[open]>summary::before{transform:rotate(45deg);margin-bottom:4px}

.rail{display:none}
/* The tab bar below ends where the bar above is shorter: the brand word goes, then the department icons, then the name beside the avatar. */
/* shell */ @media(max-width:1200px){.brand{display:none}} /* end shell */
/* shell */ @media(max-width:1100px){.dept .glyph,.pname{display:none}} /* end shell */

/* shell */ @media(max-width:900px){
  .rail{display:flex;position:fixed;bottom:0;left:0;right:0;width:100%;z-index:50;background:var(--rail-bg);color:var(--rail-text);
    border-top:1px solid var(--veil-3);padding-bottom:env(safe-area-inset-bottom)}
  /* A tab is a fixed 57px — 8 + a 22px icon + 4 + a 15px line + 8 — so the bar is 1 + 4 + 57 + 4 =
     --nav-h by arithmetic, not by measuring whatever the glyph's font happened to draw. */
  .railnav{display:flex;flex:1;padding:4px;gap:2px;overflow:visible}
  .railbtn{display:flex;align-items:center;flex:1 1 0;flex-direction:column;gap:4px;padding:8px 2px;font-size:var(--fs-1);line-height:15px;min-width:0;
    justify-content:center;white-space:nowrap;text-align:center;height:57px;min-height:0;border-radius:var(--r-input);
    color:var(--rail-text);font-family:var(--head);font-weight:600;text-decoration:none;background:none;border:0;cursor:pointer}
  .railbtn:hover{background:var(--veil-1);color:var(--on-fill)}
  .railbtn .nshort{overflow:hidden;text-overflow:ellipsis;max-width:100%}
  .rail .nlong,.actions .nlong{display:none}.rail .nshort,.actions .nshort{display:inline}
  .glyph,.glyph svg{width:22px;height:22px;flex:none}
  .wrap{padding:var(--sp-4)}
  body{padding-bottom:calc(var(--nav-h) + 6px + env(safe-area-inset-bottom))}
  .moretab{display:flex;flex:1 1 0;min-width:0;position:static}
  .moretab[open]>summary{background:var(--veil-2);color:var(--on-fill)}
  /* The bar scrolls away with the page and keeps one line: the hotel takes the width, the bell and the avatar stay. The departments are
     the tab bar's, so only the row stays under it, and a housekeeper's own row would repeat her tabs. */
  .topbar{position:static;padding:0 var(--sp-3)}
  .depts,.pname,.deptrow.own{display:none}
  .hotelpick{flex:1;margin-right:0}
  .hotelpick>summary,.hotelpick>.hpstatic{max-width:100%;border-color:transparent;font-weight:600}
} /* end shell */

/* A superseded ledger is still the record of what was turned in, so it stays legible —
   just clearly no longer the current one. */
tr.superseded td{color:var(--muted-2)}

.tips{margin-top:var(--sp-3);border-top:1px solid var(--line-soft);padding-top:var(--sp-3)}
.tips>summary{cursor:pointer;font-size:var(--fs-1);font-weight:600;color:var(--muted)}
.tips>summary:hover{color:var(--ink)}
.tips ol{margin:var(--sp-2) 0;padding-left:var(--sp-5);font-size:var(--fs-2);color:var(--slate)}
.tips li{padding:var(--sp-1) 0}

/* The shift's hand-in pack — the demo's numbered slots, carried over. A slot reads as done,
   needing somebody, or not there yet, at a glance and without reading the words. */
.paperpack{margin:var(--sp-2) 0 var(--sp-1);padding:var(--sp-3);border:1px solid var(--line);border-radius:var(--r-card);
  background:var(--ground)}
.slot{display:flex;gap:var(--sp-3);align-items:center;border:1px solid var(--line);border-radius:var(--r-card);
  background:var(--card);padding:var(--sp-3);margin-bottom:var(--sp-2);flex-wrap:wrap}
.slot.filled{border-color:var(--verde);background:var(--verde-soft)}
.slot.flagged{border-color:var(--amber-line);background:var(--amber-soft)}
.slotno{font-family:var(--mono);font-size:var(--fs-1);font-weight:600;color:var(--muted);width:20px;flex:none}
.slot.filled .slotno{color:var(--verde)}
.slot.flagged .slotno{color:var(--amber-ink)}
.slotbody{flex:1;min-width:150px}
.slotname{font-weight:600;font-size:var(--fs-2)}
.slot .meta{font-size:var(--fs-1);color:var(--muted);margin-top:2px}

/* ---------- typography ---------- */
.eyebrow{font-size:var(--fs-1);font-weight:600;color:var(--muted);margin:0 0 var(--sp-2)}
h2.sec{font-family:var(--head);font-size:var(--fs-6);font-weight:700;margin:0 0 var(--sp-4)}
h3.sub{font-family:var(--head);font-size:var(--fs-4);font-weight:700;margin:0 0 var(--sp-3)}
.lede{color:var(--muted);font-size:var(--fs-2);margin:0 0 var(--sp-5);max-width:64ch}
.hint{color:var(--muted);font-size:var(--fs-1)}
.srctag{font-size:var(--fs-1);color:var(--muted-2);margin-top:var(--sp-3);
  padding-top:10px;border-top:1px solid var(--line-soft)}

/* ---------- surfaces ---------- */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);padding:var(--sp-5);margin-bottom:var(--sp-4)}
.card.tight{padding:var(--sp-3) var(--sp-4)}
/* On the phone a card gives its width to the words. After .card, or it loses on source order. */
/* shell */ @media(max-width:900px){.card:not(.tight){padding:var(--sp-4)}} /* end shell */
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));gap:var(--sp-4)}
/* A row of figures on one ruled line, as the paper report prints its totals: the figure left-aligned
   in Public Sans tabular, its label under it, 1px rules between, no boxes. A .card.tight.stat inside
   (Boards) is stripped to the same; .statgrid.card (Observations) keeps its one card around the line. */
.statgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:0;align-items:start}
.stat,.statgrid>.stat.card{text-align:left;padding:var(--sp-1) var(--sp-4);border:0;border-left:1px solid var(--line-soft);
  border-radius:0;background:none;margin:0}
.stat:first-child,.statgrid>.stat.card:first-child{border-left:0;padding-left:0}
@container (max-width:600px){.statgrid{grid-template-columns:repeat(2,minmax(0,1fr));row-gap:var(--sp-3)}
  .stat:nth-child(2n+1),.statgrid>.stat.card:nth-child(2n+1){border-left:0;padding-left:0}
  .bignum{font-size:var(--fs-4)}}
.bignum{font-family:var(--sans);font-size:var(--fs-5);font-weight:600;line-height:1.1;font-variant-numeric:tabular-nums}
.bignum .of{font-size:var(--fs-3);font-weight:400;color:var(--muted)}
.numlbl{font-size:var(--fs-1);font-weight:500;color:var(--muted);margin-top:var(--sp-1);font-variant-numeric:tabular-nums}

.pill{display:inline-block;font-size:var(--fs-1);font-weight:500;line-height:1.4;
  padding:var(--sp-1) var(--sp-2);border-radius:var(--r-pill);background:var(--line-soft);color:var(--muted)}
.pill.ok{background:var(--verde-soft);color:var(--verde)}
.pill.warn{background:var(--amber-soft);color:var(--amber-ink)}
.pill.bad{background:var(--flag-soft);color:var(--flag)}

.alert{background:var(--amber-soft);border:1px solid var(--amber-line);border-radius:var(--r-card);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-2)}
.alert.bad{background:var(--flag-soft);border-color:var(--flag-line)}
.alert.ok{background:var(--verde-soft);border-color:var(--verde-line)}

/* ---------- controls ---------- */
.btn{background:var(--blue);color:var(--on-fill);border:0;border-radius:var(--r-input);padding:var(--sp-2) var(--sp-4);font-weight:600;
  font-size:var(--fs-2);cursor:pointer;text-decoration:none;display:inline-block}
.btn:hover{background:var(--blue-deep)}
.btn:active{background:var(--ink);transform:translateY(1px)}
.btn.ghost{background:var(--card);border:1px solid var(--line);color:var(--ink)}
.btn.ghost:hover{background:var(--ground)}
.btn.verde{background:var(--verde)}.btn.verde:hover{background:var(--verde-deep)}
.btn.flag{background:var(--flag)}.btn.flag:hover{background:var(--flag-deep)}
/* A destructive action before its confirm — Remove, Delete, Discard: never the same white as Show
   beside it. Filled .flag is the confirm that actually deletes (2026-10-31). */
.btn.danger{background:var(--card);border:1px solid var(--flag-line);color:var(--flag)}
.btn.danger:hover{background:var(--flag-soft)}
summary.btn{list-style:none}
summary.btn::-webkit-details-marker{display:none}
/* The confirm opens beside its opener, on the same line in a table row. */
.confirmfold{display:inline-flex;gap:var(--sp-2);align-items:center}
.confirmfold[open]>summary{background:var(--flag-soft)}
.confirmfold.calm[open]>summary{background:var(--accent-soft)}
.confirmfold.calm{flex-wrap:wrap}
.btn.sm{padding:var(--sp-1) var(--sp-3);font-size:var(--fs-1)}
.btn:disabled{opacity:.45;cursor:not-allowed}
.row{display:flex;gap:var(--sp-2);align-items:center;flex-wrap:wrap}
.spread{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--sp-3);flex-wrap:wrap}

label.fld,span.fld{display:block;font-size:var(--fs-1);font-weight:600;color:var(--slate);margin-bottom:var(--sp-1)}
/* "Room, optional": optional is said in the label, in plain weight, never in a placeholder that vanishes when typed over. */
label.fld .opt{font-weight:400;color:var(--muted)}
input.txt,select.txt,textarea.txt{width:100%;border:1px solid var(--line);border-radius:var(--r-input);padding:var(--sp-2) var(--sp-3);background:var(--card)}
/* One height for a text box, a select, a date and a file box in a row: they drew 40, 42 and 46px side by side on the ledger. */
input.txt,select.txt{line-height:1.5;min-height:var(--box-h)}
input[type=file].txt{padding-block:5px}
/* The native arrow is the platform's, in the platform's grey; this one is --muted and the control is the input's height. */
select.txt{appearance:none;-webkit-appearance:none;padding-right:30px;
  background:var(--card) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%234A5A78' stroke-width='1.6'/%3E%3C/svg%3E") no-repeat right 11px center}
::placeholder{color:var(--muted-2);opacity:1}
.txt.input-validation-error{border-color:var(--flag);box-shadow:0 0 0 2px var(--flag-soft)}
textarea.txt{min-height:64px;resize:vertical}
.field{margin-bottom:var(--sp-4)}
.logrow{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:var(--sp-2);margin-bottom:var(--sp-3)}
.val{color:var(--flag);font-size:var(--fs-1);margin-top:var(--sp-1);display:block}

/* ---------- checklist ---------- */
.meter{height:7px;background:var(--line-soft);border-radius:var(--r-input);overflow:hidden}
.meter span{display:block;height:100%;background:var(--verde);border-radius:var(--r-input);transition:width .35s ease}
.meter.going span{background:var(--accent)}

.clist{margin:0;padding:0;list-style:none}
.clrow{border-top:1px solid var(--line-soft);padding:2px 0;position:relative}
.clrow:first-child{border-top:0}
/* A checkbox with its words beside it, in body case — .fld is the eyebrow-style field label. */
.chk{display:flex;gap:var(--sp-2);align-items:center;padding:9px var(--sp-1);cursor:pointer;margin:var(--sp-2) 0 0;font-size:var(--fs-2)}
.chk input{appearance:none;-webkit-appearance:none;flex:0 0 19px;width:19px;height:19px;margin:1px 0 0;
  border:1.8px solid var(--muted-2);border-radius:var(--r-sm);background:var(--card);cursor:pointer;position:relative}
.chk input:checked{background:var(--verde);border-color:var(--verde)}
.chk input:checked::after{content:"";position:absolute;left:5.5px;top:2px;width:5px;height:10px;
  border:solid var(--on-fill);border-width:0 2.2px 2.2px 0;transform:rotate(42deg)}
.chk input:disabled{opacity:.5;cursor:default}
.chk .lbl{flex:1;min-width:0;font-size:var(--fs-3)}
/* The checklist line's detail. Two rules caught it — the desk dashboard's .note (a rule and 12px
   above) and .chk's centring — so the box sat beside the detail with a line under the title
   (the desk clerk's walk, 2026-10-27). Named here at higher specificity. */
.chk .note,.chk .note:first-of-type{display:block;color:var(--muted);font-size:var(--fs-1);margin-top:2px;overflow-wrap:anywhere;
  border-top:0;padding:0}
.chk:has(> span > .note),.chk:has(> .note){align-items:flex-start}
/* The note's How soon means nothing until Needs action is ticked (ui-polish, 2026-11-02): shown only then, so the
   form no longer needs a sentence saying so. The field still posts while hidden; the service ignores it unticked. */
form:has(#note-needs-action:not(:checked)) #note-how-soon{display:none}
.chk input:checked~.lbl{color:var(--muted-2)}
.chk input:checked~.lbl .title{text-decoration:line-through;text-decoration-thickness:1px}
.sectionhd{margin:var(--sp-4) 0 var(--sp-2);padding-top:var(--sp-3);border-top:2px solid var(--line)}
/* The mid-page kicker is the sheet's section heading: the ruled header, then the title in the face the paper prints it. */
.sectionhd .eyebrow{font-family:var(--head);font-size:var(--fs-4);font-weight:700;color:var(--ink);margin:0}
.byline{font-size:var(--fs-1);color:var(--verde);margin-top:var(--sp-1);display:block}
.countrow{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px;
  padding:10px 4px 14px 34px;align-items:end}
.critical{border-left:3px solid var(--amber);padding-left:9px}

.chiprow{display:flex;gap:var(--sp-2);flex-wrap:wrap;margin-bottom:var(--sp-4)}
/* A tick box with its word, where a list has several in a row (a housekeeper's floors and duties). */
.tick{display:inline-flex;align-items:center;gap:var(--sp-1)}
.tick input{flex:none}
.chip{background:var(--card);border:1px solid var(--line);border-radius:var(--r-pill);padding:var(--sp-2) var(--sp-4);cursor:pointer;
  font-family:var(--head);font-weight:600;font-size:var(--fs-2);text-decoration:none;color:var(--ink)}
.chip[aria-pressed="true"]{background:var(--blue);color:var(--on-fill);border-color:var(--blue)}

/* ---------- tables ---------- */
.tblwrap{overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}
td.r,th.r,.txt.r{text-align:right}
tr.unread td:first-child{box-shadow:inset 3px 0 var(--amber)}
table{width:100%;border-collapse:collapse;font-size:var(--fs-2);font-variant-numeric:tabular-nums}
th{font-size:var(--fs-1);font-weight:600;color:var(--muted);
  text-align:left;padding:var(--sp-2) var(--sp-3);border-bottom:1px solid var(--line)}
td{padding:var(--sp-2) var(--sp-3);border-bottom:1px solid var(--line-soft);vertical-align:top}
/* A row's own heading (the shift, in "What each shift hands in") reads as the row's first cell, ruled like the cells beside it;
   it drew the column heading's darker rule, a step short of the row's. A button under a table keeps a gap. */
tbody th{font-size:var(--fs-2);font-weight:500;color:var(--ink);border-bottom:1px solid var(--line-soft);padding:var(--sp-2) var(--sp-3);vertical-align:top}
.tblwrap+.btncell,.tablewrap+.btncell{margin-top:var(--sp-3)}
tr:last-child td,tbody tr:last-child th{border-bottom:0}
td.ctr,th.ctr{text-align:center}
.pill::first-letter,.eyebrow::first-letter,th::first-letter,label.fld::first-letter,.numlbl::first-letter{text-transform:uppercase}
/* A metric's name is the hotel's own word ("pH"), so its label keeps the case it was typed in. */
label.fld.metric::first-letter{text-transform:none}

/* ---------- history ---------- */
.evlist{list-style:none;margin:0;padding:0}
.evlist li{border-top:1px solid var(--line-soft);padding:var(--sp-3) 0;display:flex;gap:var(--sp-3);align-items:flex-start}
.evlist li:first-child{border-top:0}
/* The Boards page: the three steps of the day, the one it is at in ink, the ones done in muted. */
.steps{margin:var(--sp-2) 0 0;padding-left:var(--sp-5)}
.steps li{padding:var(--sp-1) 0;color:var(--muted)}
.steps li.now{color:inherit}
.steps li.done{text-decoration:line-through}
details.stepsdone{margin:var(--sp-2) 0 0}
details.stepsdone summary{cursor:pointer;color:var(--muted);font-size:var(--fs-2)}
details.stepsdone .steps{margin-top:var(--sp-1)}
.plain{list-style:none;margin:0;padding:0}
.plain li{padding:var(--sp-2) 0;border-top:1px solid var(--line-soft);display:flex;gap:var(--sp-2);align-items:center;flex-wrap:wrap}
.plain li:first-child{border-top:0}
/* The board page: each read row's strip of the paper, cut from the upright photo with CSS. */
.strip-scroll{overflow-x:auto;margin-top:6px;border:1px solid var(--line);background:var(--card);max-width:720px}
.strip{overflow:hidden;min-width:400px}
.strip img{display:block;width:100%}
/* The board's rows (_BoardForm). The paper's boxes wrap in one line; each sits in a .bf label whose
   words (.bfl) are for the phone's card layout below, so here the label is display:contents. */
.boardrows td.bpaper{min-width:170px}
.bfields{display:flex;flex-wrap:wrap;gap:4px}
.bf{display:contents}
.bfl{display:none}
/* The housekeepers card: due and not in. */
/* The review page: the day's photos in a strip, each with its status and control. */
.photos{display:flex;gap:var(--sp-3);overflow-x:auto;padding-bottom:var(--sp-2)}
.photo{flex:0 0 220px;margin:0;border:1px solid var(--line);border-radius:var(--r-card);padding:var(--sp-2);background:var(--card)}
.photo.waiting{border-color:var(--amber-line)} .photo.failed{border-color:var(--flag-line)}
.photo img{display:block;width:100%;height:150px;object-fit:cover;object-position:top;border-radius:var(--r-sm);background:var(--line-soft)}
.photo .doc{display:flex;align-items:center;justify-content:center;height:150px;border-radius:var(--r-sm);background:var(--line-soft);font-size:var(--fs-1);text-align:center;padding:var(--sp-2)}
.photo figcaption{margin-top:var(--sp-2);font-size:var(--fs-2)}
.review-board .card{margin-bottom:var(--sp-3)}
/* Check the rooms and Assign rooms (2026-10-28): one column the height of the screen under the top bar — the top
   and the bottom stand still and only the list between them scrolls, on a phone too (the nav rail is --nav-h there).
   The top's folds cap themselves so a long list of problems cannot push the rooms off the screen. */
.daypage{display:flex;flex-direction:column;height:calc(100dvh - 144px);min-height:420px;gap:8px}
/* The top is short by design and a fold that opens long caps itself. But the photos' fold is whole on a wide screen (its
   cards must not hang out), and with it and the problems both open the top alone was taller than the 900px screen:
   the rooms and Add room began below the fold, behind the page's own scroll (the maintenance live test, 3 Nov 2026). The top
   now gives up the column's last 20rem to the rooms and scrolls inside itself past that; a short top is untouched. */
.dayhead{flex:0 0 auto;display:flex;flex-direction:column;gap:8px;max-height:max(40%,calc(100% - 20rem - 8px));overflow:auto}
.daytitle{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.daytitle h2.sec{margin:0}
.dayhead .lede{margin:0;max-width:none}
.dayhead .card{padding:var(--sp-2) var(--sp-3);margin:0}
.dayfold>summary{cursor:pointer;font-weight:600;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.dayfold>summary>span{flex:1 1 auto}
.dayfold[open]>:not(summary){max-height:30vh;overflow:auto}
.dayfold[open]>summary{margin-bottom:8px}
/* The photo cards are not capped with the rest of the fold. The strip is a flex row whose items stretch, so under the
   30vh cap every card took the strip's height rather than its own and its buttons ("Add a board the reader missed")
   hung below the border, outside the card (the owner's screenshot, 31 Oct 2026). Wide: the cards are whole and the
   strip is as tall as the tallest; a phone's list is still capped above. */
@container (min-width:601px){.photos{align-items:flex-start}.dayfold[open]>.photos{max-height:none}}
.dayproblems.blocking{border-color:var(--flag-line);background:var(--flag-soft)}
.dayproblems.checking{border-color:var(--amber-line);background:var(--amber-soft)}
.dayproblems.clear{border-color:var(--verde-line)}
.dayproblems .tofix{margin:0}
.paperchips{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
.paperchip{display:inline-block;border:1px solid var(--line);border-radius:var(--r-pill);padding:var(--sp-1) var(--sp-3);background:var(--card);
  font-size:var(--fs-2);text-decoration:none;color:var(--ink)}
.paperchip.ok{border-color:var(--verde);background:var(--verde-soft)}
.paperchip.unknown{border-style:dashed;color:var(--muted)}
.paperchip.short{border-color:var(--flag);background:var(--flag-soft);color:var(--flag);font-weight:600}
/* The lists' floor headings: one quiet line between floors, the same on both pages. */
.daylist tr.floorsep th{background:var(--line-soft);font-size:var(--fs-1);font-weight:600;
  color:var(--muted);text-align:left;padding:var(--sp-1) var(--sp-3);position:static}
.daylist tr.floorsep label{display:inline-flex;align-items:center;gap:8px;cursor:pointer}
.daylist.onlyfix tbody tr:not(.unread):not(.flagged):not(.floorsep){display:none}
/* One room, one line on Check the rooms: the paper's place in two short lines, the paper's fields behind a fold. */
.boardrows td.bpos{white-space:nowrap;font-size:var(--fs-1);line-height:1.3;width:1%}
.boardrows td.bpos .ppname,.boardrows td.bpos .pprow{display:block}
.boardrows td.bpos .pprow{font-family:var(--mono);color:var(--muted-2)}
.paperfold>summary{cursor:pointer;list-style-position:outside;font-size:var(--fs-2)}
.paperfold>summary .pcode{font-family:var(--mono);color:var(--ink)}
.paperfold[open]>summary{margin-bottom:6px}
.boardrows td.bact{width:1%;white-space:nowrap}
.daylist .boardrows td.bpaper{min-width:300px}
.daylist .boardrows td.broom{max-width:340px}
.daylist .boardrows td.broom .strip-scroll{max-width:320px}
.daylist .boardrows td.bclean select.txt{max-width:210px}
.bactline{display:flex;align-items:center;justify-content:flex-end;gap:12px;flex-wrap:nowrap}
.bactline .bcheck{white-space:nowrap;margin:0}
.bactline .nextunread{flex-basis:100%}
/* The rooms and the Save bar keep a floor under them. With the problems, the photos and the papers all open the top took
   the whole column, the form shrank to nothing, and Add room (the end of the list) sat clipped under the folds and the
   Save bar — unclickable at 1280x900 (the maintenance live test, 3 Nov 2026). The column is a fixed height; when the
   top is taller than the screen allows, the page scrolls instead of the rooms being squeezed out. */
.daybody{flex:1 1 auto;min-height:20rem;display:flex;flex-direction:column;margin:0}
.daylist{flex:1 1 auto;min-height:12rem;overflow:auto;-webkit-overflow-scrolling:touch;background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);padding:0 var(--sp-3)}
.daylist thead th{position:sticky;top:0;background:var(--card);z-index:1}
.dayadd{border-top:1px solid var(--line-soft);padding:12px 0}
.dayfoot{flex:0 0 auto;background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);padding:var(--sp-2) var(--sp-3);margin-top:var(--sp-2)}
.dayfootrow{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.dayshort{border:1px solid var(--flag-line);background:var(--flag-soft);border-radius:var(--r-input);padding:var(--sp-2) var(--sp-3);margin-bottom:var(--sp-2)}
.assignbar{display:flex;align-items:center;justify-content:space-between;gap:8px 18px;flex-wrap:wrap}
.assignbar .row{margin:0;align-items:center}
.assignrows{width:100%}
.assignrows th.apickcol{width:36px}
.assignrows th.agoes{width:190px}
.assignrows td{vertical-align:middle;padding-top:5px;padding-bottom:5px}
.assignrows .anum{font-family:var(--mono);font-size:var(--fs-3);margin-right:8px}
.staffchips{display:flex;gap:8px;flex-wrap:wrap;margin:0}
.staffchip{border:1px solid var(--line);border-radius:var(--r-pill);padding:var(--sp-1) var(--sp-3);background:var(--card);font-size:var(--fs-2)}
.staffchip[aria-disabled="true"]{color:var(--muted);background:var(--line-soft);text-decoration:none}
.staffchip[role="tab"]{cursor:pointer}
.staffchip[role="tab"]:hover{border-color:var(--muted)}
.staffchip[aria-selected="true"]{background:var(--blue);border-color:var(--blue);color:var(--on-fill)}
.staffchip[aria-selected="true"] .tally{color:var(--blue-soft)}
.staffchip .tally{font-family:var(--mono);font-size:var(--fs-1);color:var(--muted)}
.assignrows tr.held td{color:var(--muted)}
.assignrows select.txt{width:auto;min-width:150px;padding-top:5px;padding-bottom:5px}
/* shell */ @media(max-width:900px){.daypage{height:calc(100dvh - 96px - 96px - env(safe-area-inset-bottom))}} /* end shell */
/* The table's rows loosen their minimums when the column is narrower than the widest the table needs (868px
   is a phone's 900 less its gutters; with the rail the column is that narrow in a laptop's window too). */
@container (max-width:868px){
  .boardrows tr.floorsep,.boardrows tr.floorsep th{display:block}
  .boardrows td.bpos{width:auto}
  .bactline{justify-content:flex-start;flex-wrap:wrap}
  .boardrows td.bact{width:auto}
  .daylist .boardrows td.bpaper{min-width:0}
  .assignrows th.agoes{width:auto}
  .assignrows select.txt{min-width:0;max-width:150px}}
.evtime{font-family:var(--mono);font-size:var(--fs-1);color:var(--muted-2);flex:0 0 130px;white-space:nowrap}
.evwho{font-weight:600}

/* ---------- toast ---------- */
/* A new ask on an open page. Under the bar, because a toast holds the bottom; it stays until it is read or closed. */
.askbanner{position:fixed;top:calc(var(--bar-h) + var(--sp-2));left:50%;transform:translateX(-50%);z-index:101;width:min(92vw,520px);
  display:flex;align-items:center;gap:var(--sp-2);background:var(--amber-soft);border:1px solid var(--amber-line);border-left:4px solid var(--amber);
  border-radius:var(--r-input);padding:var(--sp-2) var(--sp-3);box-shadow:var(--shadow-toast)}
.askbanner[hidden]{display:none}
.askbannerlink{flex:1;min-width:0;color:var(--amber-ink);font-weight:600;font-size:var(--fs-2);overflow-wrap:anywhere}
.askbannerclose{flex:none;min-width:44px;min-height:var(--hit);display:inline-flex;align-items:center;justify-content:center;background:none;border:0;border-radius:var(--r-input);color:var(--amber-ink);cursor:pointer}
.toast{position:fixed;left:50%;bottom:26px;transform:translateX(-50%);background:var(--ink);color:var(--on-fill);
  padding:var(--sp-3) var(--sp-4);border-radius:var(--r-input);font-size:var(--fs-2);z-index:100;
  max-width:min(92vw,520px)}
.toast.bad{background:var(--flag)}
.toast .toastok{margin-left:var(--sp-3);background:none;border:1px solid var(--veil-6);color:var(--on-fill);border-radius:var(--r-input);
  padding:2px var(--sp-3);font-weight:600;font-size:var(--fs-1);cursor:pointer}
/* On the phone the nav is a 66px bar along the bottom; a toast at 26px sat on it, under the tabs. */
/* shell */ @media(max-width:900px){.toast{bottom:calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--sp-3))}} /* end shell */

/* ---------- auth ---------- */
.authwrap{min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:var(--sp-5)}
.authcard{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);padding:0;overflow:hidden;
  width:100%;max-width:420px}
.authcard .cy{font-family:var(--head);font-weight:700;font-size:var(--fs-6);margin:0 0 var(--sp-1)}
.validation{background:var(--flag-soft);border:1px solid var(--flag-line);border-radius:var(--r-card);color:var(--flag);
  padding:var(--sp-3) var(--sp-4);font-size:var(--fs-2);margin-bottom:var(--sp-3)}
.validation ul{list-style:none;padding:0;margin:0}
/* asp-validation-summary="All" draws its box with an invisible <li> inside even when there is nothing
   to say (the owner saw an empty red bar on New company, 2026-11-01); the framework marks that state. */
.validation:empty,.validation.validation-summary-valid{display:none}

/* ---------- coverage grid ---------- */
.covgrid th .sh{display:block;font-size:var(--fs-1);font-weight:400;color:var(--muted-2);margin-top:2px}
.covgrid td{padding:6px 8px;vertical-align:middle}
.covgrid th:first-child{width:120px}
.covgrid .daycell{font-size:var(--fs-2);white-space:nowrap;color:var(--muted)}
.covgrid .daycell.istoday{color:var(--ink);font-weight:600}
.covgrid .daycell .sh{font-size:var(--fs-1);font-weight:600;color:var(--accent-ink);margin-left:var(--sp-1)}

/* Each cell carries its own colour so the week reads as a block, not a list. */
.cov{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;
  min-height:var(--hit);border-radius:var(--r-input);border:1px solid var(--line-soft);text-decoration:none;
  padding:5px 6px;transition:transform .12s ease}
a.cov:hover{transform:translateY(-1px);border-color:var(--muted-2)}
.cov .who{font-size:var(--fs-1);
  max-width:9ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.cov.ok{background:var(--verde-soft);border-color:var(--verde-line);color:var(--verde)}
.cov.waiting{background:var(--amber-soft);border-color:var(--amber-line);color:var(--amber-ink)}
.cov.running{background:var(--blue-soft);border-color:var(--line);color:var(--blue-ink)}
.cov.back{background:var(--flag-soft);border-color:var(--flag-line);color:var(--flag)}
.cov.gap{background:repeating-linear-gradient(135deg,var(--flag-soft),var(--flag-soft) 4px,var(--flag-wash) 4px,var(--flag-wash) 8px);
  border-color:var(--flag-line);color:var(--flag)}
.cov.soon{background:transparent;border-style:dashed;border-color:var(--line-soft);color:var(--muted-2)}

.legend{display:flex;gap:var(--sp-4);flex-wrap:wrap;margin-top:var(--sp-3);
  font-size:var(--fs-1);color:var(--muted)}
.legend span{display:flex;align-items:center;gap:6px}
.legend .sw{width:11px;height:11px;border-radius:var(--r-xs);border:1px solid var(--line);display:inline-block}
.legend .sw.ok{background:var(--verde-soft);border-color:var(--verde-line)}
.legend .sw.waiting{background:var(--amber-soft);border-color:var(--amber-line)}
.legend .sw.running{background:var(--blue-soft)}
.legend .sw.back{background:var(--flag-soft);border-color:var(--flag-line)}
.legend .sw.gap{background:repeating-linear-gradient(135deg,var(--flag-soft),var(--flag-soft) 3px,var(--flag-wash) 3px,var(--flag-wash) 6px);border-color:var(--flag-line)}
.legend .sw.soon{background:transparent;border-style:dashed}

@container (max-width:600px){
  /* Three shift columns and the day fit a 360 phone without the table scrolling the Night column away. */
  .covgrid{width:100%;table-layout:fixed}
  .covgrid th:first-child{width:26%}
  .covgrid td:not(.ctr){padding:6px 4px}
  .covgrid .daycell{font-size:var(--fs-1)}
  /* "today" under the date: beside it, on a 360 phone, it ran into the A.M. cell (seen 2026-11-05). */
  .covgrid .daycell .sh{display:block;margin-left:0}
  .cov .who{max-width:7ch}
}

/* ---------- desk dashboard ---------- */
.note,.esc{border-top:1px solid var(--line-soft);padding:var(--sp-3) 0}
.note:first-of-type,.esc:first-of-type{border-top:0;padding-top:var(--sp-1)}
.note.action{border-left:3px solid var(--amber);padding-left:var(--sp-3)}
.esc.urgent{border-left:3px solid var(--flag);padding-left:var(--sp-3)}
.minilist{list-style:none;margin:var(--sp-3) 0 0;padding:var(--sp-3) 0 0;border-top:1px dashed var(--line-soft);
  font-size:var(--fs-2)}
.minilist li{padding:var(--sp-1) 0;color:var(--ink)}

/* The script staff read on a courtesy call — set apart so it reads as speech, not instruction. */
/* What to say on the call is reference, not a state: the ground's own tint (it was amber, which means waiting on someone). */
.say{background:var(--ground);border-color:var(--line)}
.say p{font-size:var(--fs-3);line-height:1.6;color:var(--slate)}

/* Standing rules on the dashboard — a prompt, not a form. */
.reminders{list-style:none;margin:0 0 var(--sp-1);padding:0;font-size:var(--fs-2)}
.reminders li{padding:var(--sp-1) 0 var(--sp-1) var(--sp-4);position:relative;color:var(--slate)}
.reminders li::before{content:"·";position:absolute;left:4px;color:var(--accent);font-weight:700}
.minilist li.ticked{color:var(--muted-2)}

/* ---------- shift log ---------- */
.logentry{border-top:1px solid var(--line-soft);padding:var(--sp-3) 0}
.logentry:first-child{border-top:0}
.logentry.action{border-left:3px solid var(--amber);padding-left:var(--sp-3)}
.logentry p{font-size:var(--fs-3)}

.closure{margin:var(--sp-1) 0 var(--sp-2);padding:var(--sp-2) var(--sp-3);background:var(--verde-soft);border-radius:var(--r-input);
  font-size:var(--fs-2);color:var(--verde)}
.closure .hint{color:var(--verde);opacity:.75}

/* ---------- observation audit ---------- */
.obsrow{display:flex;align-items:flex-start;gap:4px;border-top:1px solid var(--line-soft);padding:4px 0}
.obsrow:first-child{border-top:0}
.obspts{font-family:var(--mono);font-size:var(--fs-1);font-weight:600;color:var(--blue-ink);
  background:var(--blue-soft);border-radius:var(--r-sm);padding:3px 7px;margin-top:9px;
  min-width:30px;text-align:center;flex:none;font-variant-numeric:tabular-nums}
.scorebar{position:sticky;bottom:0;background:var(--rail-bg);color:var(--on-fill);border-radius:var(--r-card);
  padding:var(--sp-4) var(--sp-5);display:flex;gap:var(--sp-5);align-items:center;flex-wrap:wrap;margin-bottom:var(--sp-4);
  box-shadow:var(--shadow-pop)}
.scorebar .n{font-family:var(--mono);font-size:var(--fs-6);font-weight:600;line-height:1;
  font-variant-numeric:tabular-nums}
.scorebar .numlbl,.scorebar .hint{color:var(--rail-muted)}

/* ---------- checklist editor ---------- */
.edititem{border-top:1px solid var(--line-soft);padding:0}
.edititem:first-child{border-top:0}
.edititem summary{display:flex;align-items:baseline;gap:10px;padding:11px 4px;cursor:pointer;
  flex-wrap:wrap;list-style:none}
.edititem summary::-webkit-details-marker{display:none}
.edititem summary::before{content:"▸";font-family:var(--mono);color:var(--muted-2);flex:none}
.edititem details[open] summary::before{content:"▾"}
.edititem summary:hover{background:var(--line-soft);border-radius:var(--r-input)}
.edititem .ord{font-family:var(--mono);font-size:var(--fs-1);color:var(--muted-2);min-width:22px;
  text-align:right;flex:none;font-variant-numeric:tabular-nums}
.edititem .summary-title{flex:1;min-width:200px;font-size:var(--fs-3)}
.edit-body{padding:12px 4px 4px 32px;border-left:2px solid var(--line-soft);margin-left:10px}
.edit-actions{padding:0 4px 14px 42px}

/* ---------- start screen ---------- */
/* The one action the shift is about, given weight the other cards do not have. */
.btn.big{padding:var(--sp-3) var(--sp-5);font-size:var(--fs-3)}

.card.alertcard{padding:var(--sp-4) var(--sp-5)}
.card.alertcard.warn{background:var(--amber-soft);border-color:var(--amber-line)}
.card.alertcard.flag{background:var(--flag-soft);border-color:var(--flag-line)}
.card.alertcard.ok{background:var(--verde-soft);border-color:var(--verde-line)}
.brief{list-style:none;margin:var(--sp-3) 0 0;padding:0;font-size:var(--fs-2)}
.brief li{padding:var(--sp-2) 0;border-top:1px solid var(--line-soft);line-height:1.45}
.brief li:first-child{border-top:0}
.brief .hint{font-size:var(--fs-1)}

.q-title{font-family:var(--head);font-weight:700;font-size:var(--fs-3);margin-top:var(--sp-1)}
.q-sub{font-size:var(--fs-1);color:var(--muted)}

@container (max-width:480px){.logrow{grid-template-columns:1fr}}

/* The phone, looked at as each role on 2026-10-26 (390px). Nothing here reaches the desktop. It is the shell's,
   not the column's: with the rail the work-order list fits a 1024px window with its prose crushed and scrolls
   sideways with this guard, so the guard stays with the layout that has no rail (a container rule at 868px
   put it on a laptop, 2026-11-01). */
/* shell */ @media(max-width:900px){
  /* A table wider than the window scrolls in its .tblwrap, and auto layout then gives every
     column only its longest word. The work-order list's "What" came out 93px wide and 271px
     tall, one word a line, beside a nowrap "Reported" column. A cell marked .prose keeps a
     readable measure, so the table grows and scrolls instead of crushing the sentence. */
  .tblwrap td.prose{min-width:22ch}
  /* A figure is one thing: "12 / 12" and "1 · 12 min" broke across two lines in the HK report. */
  .tblwrap td.r{white-space:nowrap}
} /* end shell */
@container (max-width:600px){
  /* The audit trail's 130px time column left the sentence 150px on a phone. Stacked, the time is
     the line's eyebrow. The direction flip re-reads the cross axis (align-items back to stretch),
     and the time's flex-basis would become a 130px height in a column, so both are reset. */
  .evlist li{flex-direction:column;align-items:stretch;gap:2px}
  .evtime{flex:none}
}
@container (max-width:600px){
  /* The board and its review (_BoardForm): six columns left each cell about 75px at 390, the
     paper's six boxes a column of their own and the clean-type select cut off (2026-10-26).
     Each row becomes a card — number, room and minutes on top, then what was read, the clean
     type, and the row's ticks and Remove — every cell under its own data-label. Only the boxes
     move: names, indexes and the one form are the desktop's, so the post is the same post. */
  .boardrows,.boardrows tbody{display:block}
  .boardrows thead{display:none}
  .boardrows tr{display:grid;grid-template-columns:auto minmax(0,1fr) auto;
    grid-template-areas:"pos room min" "paper paper paper" "clean clean clean" "act act act";
    border:0;border-bottom:1px solid var(--line-soft);border-radius:0;margin:0;background:none}
  table.stack tr:last-child{border-bottom:0}
  /* minmax(0,…) and min-width:0 keep a 400px strip of the paper scrolling inside its own box
     instead of widening the card past the phone. */
  .boardrows td{display:block;min-width:0;border:0;padding:var(--sp-2) var(--sp-3);text-align:left}
  .boardrows td.bpos{grid-area:pos;padding-right:0}
  .boardrows td.broom{grid-area:room}
  .boardrows td.bmin{grid-area:min;text-align:right}
  .boardrows td.bpaper{grid-area:paper;min-width:0;border-top:1px solid var(--line-soft)}
  .boardrows td.bclean{grid-area:clean}
  .boardrows td.bact{grid-area:act;display:flex;flex-wrap:wrap;align-items:center;gap:0 18px;border-top:1px solid var(--line-soft)}
  .boardrows td.bact:not(:has(*)){display:none}
  .boardrows td[data-label]::before{content:attr(data-label)}
  .boardrows td[data-label]::before,.bfl{display:block;margin-bottom:var(--sp-1);
    font-size:var(--fs-1);font-weight:600;color:var(--muted)}
  /* The unread stripe moves from the first cell to the card's own edge. */
  .boardrows tr.unread{box-shadow:inset 3px 0 var(--amber)}
  .boardrows tr.unread td:first-child{box-shadow:none}
  .boardrows .txt{min-height:var(--hit)}
  .boardrows select.txt{max-width:100%}
  .bfields{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-2)}
  .bf{display:block;min-width:0}
  /* The boxes carry the desktop's widths inline (72px, 110px, auto); here each fills its half. */
  .bfields .txt{width:100%!important}
  /* Checked and Pet: a 20px tick in a 44px-tall target, side by side, Remove at the far end. */
  .boardrows td.bact label{padding:12px 0;margin:0!important}
  .boardrows td.bact input[type=checkbox]{width:20px;height:20px;vertical-align:-4px;margin:0 6px 0 0}
  .boardrows td.bact>.btn{margin-left:auto;min-height:var(--hit)}
}

/* Touch. The width query alone misses a large phone in landscape, hence the pointer test. */
/* shell */ @media(max-width:900px),(pointer:coarse){
  /* Off the scale on purpose: under 16px iOS zooms the page into the box on focus. */
  input,select,textarea,.txt{font-size:var(--fs-input)}
} /* end shell */

/* WCAG 2.2 SC 2.5.8 wants 24px targets; a thumb wants more. */
@media(pointer:coarse){
  .btn{display:inline-flex;align-items:center;justify-content:center;min-height:var(--hit);padding:11px 18px}
  .btn.sm{min-height:var(--hit);padding:var(--sp-2) var(--sp-4);font-size:var(--fs-2)}
  /* An inbox line of one line was a 21px link to a thumb (the redesign run, 2026-11-05). */
  .inbox .inboxitem>span>a{display:block;min-height:var(--hit)}
  /* A money figure's name and the Rooms heading are links a line tall: the thumb's area grows, the layout does not. */
  .kpis .k-label,.todayrooms .gridhead h3 a{display:inline-block;padding-block:13px;margin-block:-13px}
  /* A text box and a select measured 42px; a thumb's 44 everywhere (a textarea is taller already). */
  input.txt,select.txt{min-height:var(--hit)}
  /* A link in a table.s cell is a line tall (16px on the ledger.s history, 15 on a board.s name): the thumb's area grows, the row does not. */
  .main td>a:not(.btn){display:inline-block;padding-block:13px;margin-block:-13px}
  /* A coverage cell is a link to its shift: 40px was four short. */
  a.cov{min-height:var(--hit)}
  /* A tick in a row of ticks: the label is the target and the box grows with it. */
  .tick{min-height:var(--hit);padding-right:var(--sp-2);gap:var(--sp-2)}
  .tick input{width:22px;height:22px}
  /* The report's tabs and its Simple/Advanced switch measured 41 and 33px; a ticked line with its padding taken off, 35. */
  .reporttabs a,.modeseg a{display:inline-flex;align-items:center;min-height:var(--hit)}
  label.chk{min-height:var(--hit)}
  /* A link that stands alone as a line (back to a list, an asset's name, "3 more on Today") is a thumb's area too. */
  .back,.backlink a,.inboxmore a,h3>a,h4>a{display:inline-block;padding-block:13px;margin-block:-13px}
  /* A tick or a radio that stands bare in a setup table or a line of options was the browser's 13px: WCAG's 24 is the floor. */
  .main td>input[type=checkbox],.main label>input[type=radio]{width:22px;height:22px;vertical-align:-5px}
  .main label:has(>input[type=radio]){display:block;padding-block:var(--sp-2)}
  /* Chips, the hotel select and a bare <summary> are tapped like buttons. "Performance over dates",
     "Add a note", "Log a found item" were 17–23px tall to a thumb (2026-10-26). :where keeps the
     summary rule at the bottom of the cascade, so a summary that sets its own padding keeps it. */
  .chip,.staffchip,.paperchip,.reportstrip .chip{display:inline-flex;align-items:center;gap:var(--sp-1);min-height:var(--hit)}
  :where(.main details)>summary{min-height:var(--hit);padding-block:10px;box-sizing:border-box}
  .chk{padding:var(--sp-3) var(--sp-1)}
  .clrow.done .chk{min-height:var(--hit)}   /* the folded line keeps the thumb's height */
  .chk input{flex:0 0 24px;width:24px;height:24px}
  /* The tick is drawn to the box, so it has to grow with it. */
  .chk input:checked::after{left:7px;top:2.5px;width:6px;height:12.5px;border-width:0 2.6px 2.6px 0}
  .moreitem,.railbtn{-webkit-tap-highlight-color:var(--tap)}
}
/* ---------- room grid ----------
   The four statuses housekeeping works from, coloured as they asked for them: green, yellow,
   red, orange. Occupied-clean and out-of-order are muted so the four that need somebody stand
   out. Colour is never the only signal — every cell carries the two-letter code as well. */
.roomkey{display:flex;flex-wrap:wrap;gap:var(--sp-2) var(--sp-4);margin:0 0 var(--sp-3);font-size:var(--fs-2);color:var(--muted)}
.roomkeyitem{display:inline-flex;align-items:center;gap:6px}
.roomkeyitem strong{color:var(--ink);font-family:var(--sans);font-weight:600;font-variant-numeric:tabular-nums}
.roomswatch{display:inline-block;width:11px;height:11px;border-radius:var(--r-xs);border:1px solid var(--edge);vertical-align:-1px;margin-right:3px}
.roomswatch.vr{background:var(--verde)} .roomswatch.vc{background:var(--gold)} .roomswatch.vd{background:var(--flag)}
.roomswatch.od{background:var(--amber)} .roomswatch.oc{background:var(--slate)} .roomswatch.ooo{background:var(--muted-2)}
.roomgridcard{padding:var(--sp-3) var(--sp-4)}
.floorrow{display:flex;gap:12px;align-items:flex-start;padding:8px 0;border-top:1px solid var(--line-soft)}
.floorrow:first-child{border-top:0;padding-top:0}
.floorlabel{font-size:var(--fs-1);font-weight:600;color:var(--muted);
  width:64px;flex:none;padding-top:10px}
.roomgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(58px,1fr));gap:5px;flex:1}
.roomcell{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;min-height:var(--hit);
  border-radius:var(--r-input);text-decoration:none;color:var(--on-fill);border:2px solid transparent;font-variant-numeric:tabular-nums;position:relative}
.roomcell .roomnum{font-family:var(--mono);font-weight:600;font-size:var(--fs-2);line-height:1}
.roomcell .roomcode{font-family:var(--mono);font-size:var(--fs-0);letter-spacing:.06em;opacity:.85;line-height:1}
.roomcell.vr{background:var(--verde)} .roomcell.vc{background:var(--gold)} .roomcell.vd{background:var(--flag)}
.roomcell.od{background:var(--amber)} .roomcell.oc{background:var(--slate)} .roomcell.ooo{background:var(--muted-2)}
/* White on the orange is 3.7:1 and on the gold 2.8:1, under AA for a room number; the ink is 4.6:1 and 6.0:1 (the redesign run,
   2026-11-05). The fills are the four housekeeping asked for and stay. */
.roomcell.vc,.roomcell.od{color:var(--ink)}
/* The line under the status buttons and their note box stood against the box. */
.sheettoday{padding-top:var(--sp-2)}
.roomcell.sel{border-color:var(--ink);box-shadow:0 0 0 2px var(--on-fill) inset}
.roomcell:hover{filter:brightness(1.08)}
/* An open work order is a wrench in the corner; a room with repeat issues has a dark top edge. Drawn, not typed, so no glyph can turn into an emoji. */
.roomcell.busy{outline:var(--focus-w) solid var(--focus);outline-offset:-2px}
.roomcell .roommark{position:absolute;top:3px;right:3px;width:14px;height:14px;display:flex;filter:drop-shadow(0 0 1px var(--edge-strong))}
.roomcell .roommark svg{width:14px;height:14px;stroke-width:2.2}
.roomcell.rep{border-top-color:var(--ink)}
/* A cell the timed read just redrew: a soft outline for three seconds (site.js removes the class), faded out by a
   transition that prefers-reduced-motion switches off with every other one. A shadow, not an outline, because busy owns the outline. */
.roomcell.justchanged{box-shadow:0 0 0 3px var(--accent-soft),0 0 0 4px var(--accent);transition:box-shadow .6s}
.roomcell.sel.justchanged{box-shadow:0 0 0 2px var(--on-fill) inset,0 0 0 3px var(--accent-soft),0 0 0 4px var(--accent)}
/* The line at the top of an open sheet whose room changed under it, and the label saying how old the grid is. */
.roomchanged{margin-bottom:var(--sp-3);display:flex;gap:var(--sp-3);align-items:center;flex-wrap:wrap}
.gridfresh{margin:0 0 var(--sp-2)}
.gridfresh[data-state=failed],.gridfresh[data-state=out],.gridfresh[data-state=gone],.gridfresh[data-state=behind]{color:var(--flag);font-weight:600}
/* PM due: a bar along the foot of the cell, opposite corner to the work-order dot so a room can
   carry both. No new colour — the demo's PM chip is the plain one, not a flag. */
.roomcell.pm::before{content:"";position:absolute;left:4px;right:4px;bottom:3px;height:2px;border-radius:var(--r-xs);background:var(--ink);opacity:.55}
.roomstatusform{margin-top:14px}
/* ---------- the room sheet: an accordion on a desktop, a sheet on a phone ----------
   "I want an accordion to pop up, not to scroll the screen down when I click the room… can we do
   that on web and phone?" (the owner, 2026-09-23). Two shapes, one node and one partial: the
   panel is always inserted as a full-width item straight after its cell, and only these rules
   differ. Wide, it opens inline under that row and the rows below move down — which is what an
   accordion is. On a phone the whole collapsed panel is ~410px against a ~700px screen, so a cell
   tapped below the top third would open almost entirely under the fold; there it is lifted out of
   flow instead and the grid does not move by a pixel. Nothing on the ancestor chain sets
   transform, filter, contain or will-change, so position:fixed resolves against the viewport (.wrap's container-type
   leaves that alone: DECISIONS.md § Layout reacts to its container). */
.roomsheet{grid-column:1/-1;margin-top:10px}
.sheethead{margin-bottom:4px}
.sheetgroup{border-top:1px solid var(--line-soft)}
.sheetgroup>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:10px;
  padding:var(--sp-3) 2px;font-size:var(--fs-1);font-weight:600;color:var(--muted);min-height:var(--hit);box-sizing:border-box}
.sheetgroup>summary::-webkit-details-marker{display:none}
.sheetgroup>summary::after{content:"";width:7px;height:7px;border:solid var(--muted-2);
  border-width:0 1.6px 1.6px 0;transform:rotate(45deg);margin-left:auto;margin-top:-4px}
.sheetgroup[open]>summary::after{transform:rotate(-135deg);margin-top:2px}
.sheetgroup>summary:hover{color:var(--ink)}
/* The tally is the whole point of a closed bar: it must still say whether there is work behind it. */
.grouptally{font-size:var(--fs-1);font-weight:400;color:var(--muted-2)}

/* shell */ @media(max-width:900px){
  /* Above the fixed nav rail (z-index 50) and below the toast (z-index 100), because a refused
     in-place action navigates and shows its words on the page that loads — a sheet covering that
     is how a refusal becomes silent. The rail is 66px + safe area, not the 52px of a tab's
     min-height: the glyph and the word stack to 57, plus 4px padding each side and the border.
     At 60 the sheet sat over the top 6px of the tabs and clipped the active one's marker (2026-10-26). */
  .roomsheet{position:fixed;left:0;right:0;bottom:calc(var(--nav-h) + env(safe-area-inset-bottom));
    z-index:70;margin:0;border-radius:var(--r-card) var(--r-card) 0 0;border-bottom:0;
    max-height:70vh;overflow-y:auto;-webkit-overflow-scrolling:touch;
    box-shadow:var(--shadow-sheet);padding:16px}
} /* end shell */

.roomstatusbtns{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin-bottom:var(--sp-3)}
.roomstatusbtn{display:inline-flex;align-items:center;gap:6px}
@container (max-width:600px){
  /* align-items comes with the direction, never without it. The row above says flex-start to
     top-align the floor label beside the grid; flipping to a column turns the cross axis
     horizontal and the very same word then means "shrink each child to its content and pack it
     left". .roomgrid's flex:1 is no help — flex sizes the main axis, which in a column is the
     height. So the grid was as wide as one cell and auto-fill resolved to its minimum: at 440px
     the grid measured 52px and drew 209 rooms in a single column down a 374px row — "so much
     white space" (the owner, 2026-09-23). Restoring stretch gives back the 374px and six
     columns. */
  .floorrow{flex-direction:column;align-items:stretch;gap:6px}
  .floorlabel{width:auto;padding-top:0}
  .roomgrid{grid-template-columns:repeat(auto-fill,minmax(52px,1fr))}
}

/* ---------- the rooms on Today (rooms-on-today, step 3; the Navigation mock) ----------
   The block is a container of its own ("rooms"), so what fits is asked of it and not of the window: the list stands beside the
   grid once the block is 760px wide, and before that it stands above it (the list first on a phone). A hotel of over a hundred
   rooms is drawn compact — the number and the colour, twenty to a row — and a white dot says a room needs something. */
.todayrooms{container:rooms/inline-size;margin:var(--sp-4) 0}
.todayrooms .gridhead{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2) var(--sp-4);margin-bottom:var(--sp-2)}
.todayrooms .gridhead h3{margin:0}
.todayrooms .gridhead .gridfresh{margin:0 0 0 auto}
/* The chips filter by what each cell says of itself, so a redraw of the cells keeps the filter. A room that is not shown is faint, not gone: the grid keeps its shape. */
.roomgridcard[data-filter=needs] .roomcell:not([data-need]),
.roomgridcard[data-filter=ready] .roomcell:not(.vr),
.roomgridcard[data-filter=notready] .roomcell:not(.vd,.vc,.od){opacity:.22}
.allrooms>summary{cursor:pointer;font-weight:600;font-size:var(--fs-3);color:var(--ink);padding:var(--sp-1) 0 var(--sp-2)}
.roomsbody{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--sp-3);align-items:start}
.roomsgrid,.roomsneeds{min-width:0}
.roomsneeds{order:-1}
@container rooms (min-width:760px){
  .roomsbody{grid-template-columns:minmax(0,1fr) 320px}
  .roomsneeds{order:1}   /* it comes first in the page for a phone; beside the grid it is the side, or the grid gets the 320px */
}
/* The list of what each room wants: a line per thing, urgent in the flag colour, each a link that opens the room's sheet in the grid. */
.roomneeds{padding:var(--sp-3)}
.roomneeds h3.sub{margin:0 0 var(--sp-2);display:flex;justify-content:space-between;align-items:center}
.roomneedlist{list-style:none;margin:0;padding:0;max-height:520px;overflow-y:auto}
.roomneed{display:grid;grid-template-columns:44px 20px minmax(0,1fr);gap:2px 8px;align-items:start;padding:8px 2px;border-top:1px solid var(--line-soft);color:var(--ink);text-decoration:none;font-size:var(--fs-2)}
.roomneed:hover{background:var(--ground)}
.roomneed .rn{font-family:var(--mono);font-weight:600}
.roomneed svg{width:16px;height:16px;margin-top:2px;color:var(--slate)}
.roomneed.urgent svg,.roomneed.urgent .what{color:var(--flag)}
.roomneed.urgent .what{font-weight:600}
.roomneed small{display:block;font-size:var(--fs-1);color:var(--muted);font-weight:400}
@container rooms (min-width:520px){
  .todayrooms.compact .roomgrid{grid-template-columns:repeat(20,minmax(0,1fr));gap:3px}
  .todayrooms.compact .roomcell{min-height:27px}
  .todayrooms.compact .roomcell .roomnum{font-size:var(--fs-0)}
  .todayrooms.compact .roomcell .roomcode,.todayrooms.compact .roomcell .roommark{display:none}
  .todayrooms.compact .floorlabel{width:44px;padding-top:6px}
  .todayrooms.compact .floorrow{padding:3px 0}
  .todayrooms.compact .roomcell[data-need]::after{content:"";position:absolute;top:2px;right:2px;width:6px;height:6px;border-radius:var(--r-round);background:var(--on-fill);box-shadow:0 0 0 1px var(--edge-strong)}
}
/* The desk's shift when the rooms lead: the card shrinks to one line — the shift, how far it is, the next line, the button. */
.card.lead[data-shiftline]{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-1) var(--sp-4);padding:var(--sp-3) var(--sp-4)}
.card.lead[data-shiftline] .meter,.card.lead[data-shiftline] .cardhint,.card.lead[data-shiftline] .stepslabel{display:none}
.card.lead[data-shiftline] .sub,.card.lead[data-shiftline] .leadline,.card.lead[data-shiftline] .nextsteps{margin:0}
.card.lead[data-shiftline] .nextsteps li:nth-child(n+2){display:none}
.card.lead[data-shiftline] .cardlinks{margin:0 0 0 auto}

/* ---------- housekeeper's phone: the shift bar, the room timer, the board rows ----------
   Flat by decision: status is a stripe on the row's left edge, never a filled cell; one accent. */
/* Not sticky: the layout's top bar already is, and a second sticky bar slid under it. */
.shiftbar{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  padding:10px 0 8px;margin:-10px 0 14px;border-bottom:1px solid var(--line)}
.shiftbar .who{font-family:var(--head);font-weight:700;font-size:var(--fs-4)}
.shiftbar .clock{margin-left:auto;font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:var(--fs-3);font-weight:600}
.shiftbar.over .clock{color:var(--flag)}
.track{height:3px;background:var(--line-soft);flex-basis:100%}
.track i{display:block;height:100%;background:var(--accent);max-width:100%}
.track i.over{background:var(--flag)}
td.over,.bignum.over{color:var(--flag)} td.under,.bignum.under{color:inherit}
.bigtimer{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:var(--fs-8);font-weight:600;letter-spacing:-.02em;line-height:1;text-align:center;margin:6px 0 2px}
.bigtimer.over{color:var(--flag)}
.hkrow{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);margin-bottom:var(--sp-2);background:var(--card);
  border:1px solid var(--line);border-left:4px solid var(--line);border-radius:var(--r-card);color:inherit;text-decoration:none}
a.hkrow:hover{border-color:var(--muted)}
.hkrow .num{font-family:var(--mono);font-weight:600;font-size:var(--fs-4);min-width:48px}
.hkrow .meta{flex:1;font-size:var(--fs-2);color:var(--muted)}
.hkrow .right{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:var(--fs-1);color:var(--muted);white-space:nowrap;text-align:right}
.chkline{margin:0;border-bottom:1px solid var(--line-soft)}
.chkline:last-of-type{border-bottom:0}
.chkline button{display:flex;gap:12px;align-items:flex-start;width:100%;min-height:48px;padding:10px 0;margin:0;
  background:none;border:0;text-align:left;font:inherit;color:inherit;cursor:pointer}
.chkline .mark{flex:none;width:30px;height:30px;border-radius:var(--r-input);border:1px solid var(--line);background:var(--card);
  font-family:var(--mono);font-size:var(--fs-3);line-height:28px;text-align:center;color:var(--verde)}
.chkline.on .mark{background:var(--verde);border-color:var(--verde);color:var(--on-fill)}
.chkline .words{flex:1;padding-top:4px}
.chkline .es{display:block;font-size:var(--fs-1);color:var(--muted);margin-top:2px}
.chkline.on .en{color:var(--muted-2)}
.inboxitem{display:flex;gap:var(--sp-2);align-items:center;padding:var(--sp-2) var(--sp-3);margin-bottom:var(--sp-1);background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);font-size:var(--fs-2)}
.inboxitem span{flex:1}
.inboxearlier{margin:0 0 var(--sp-2)}
.inboxearlier>summary{cursor:pointer;font-size:var(--fs-2);color:var(--muted-2);padding:var(--sp-1) 2px}
.inboxmore{margin:0 0 var(--sp-2);font-size:var(--fs-2)}
.reportrange{margin:0 0 var(--sp-3)}
.reportrange>summary{cursor:pointer;font-size:var(--fs-2);color:var(--muted-2)}
.closedlist{margin:0 0 var(--sp-3)}
.closedlist>summary{cursor:pointer;font-size:var(--fs-2);padding:var(--sp-1) 2px}
.closedrow{padding:var(--sp-2) var(--sp-3);border:1px solid var(--line);border-radius:var(--r-card);background:var(--card);margin:var(--sp-1) 0;font-size:var(--fs-2)}
.closedrow>summary{cursor:pointer}
.hkwrap{max-width:520px}

/* Read from across a room (the UI review, 2026-10-26): the rail's glyphs did not carry on a 1920
   screen. They are drawn at 20px and a firmer shade there. */
/* shell */ @media(min-width:901px){
  .glyph{opacity:.85}
} /* end shell */
/* A 1920 display left a third of the page empty beside the 1120px column. Above 1600 the column
   takes 1360px; prose keeps its own caps (.lede at 64ch). */
/* shell */ @media(min-width:1600px){.wrap{max-width:1360px}} /* end shell */

/* ---------- the uploader's experience (U-1, 2026-10-28) ---------- */
/* The picker's label is a sentence, not a field name: .fld's 10px capitals would wrap it into a block. */
.uplabel{display:block;font-size:var(--fs-2);margin:0 0 var(--sp-2)}
/* One photo's line: its word, what it became, what needs doing, and "Show" opening the upright picture in place. */
.photo figcaption>span{display:block;margin-top:4px}
.photo .photoacts{display:flex;flex-wrap:wrap;gap:var(--sp-2);align-items:flex-start}
.photo details.show img,.review-board details.show img{height:auto;max-height:none;object-fit:contain;margin-top:6px;width:100%;border-radius:var(--r-sm)}
/* A photo's Show opens it over the page, as large as the screen allows: in its card it was no
   bigger than the thumbnail, and looked like a button that did nothing (the owner, 28 Oct 2026).
   A tap on the picture, on Show, or Escape closes it (site.js). */
.photo details.show[open] img{position:fixed;inset:0;margin:auto;z-index:60;width:auto;height:auto;max-width:96vw;max-height:94vh;background:var(--card);box-shadow:0 0 0 100vmax var(--scrim);cursor:zoom-out}
.photo details.show[open]>summary{position:fixed;top:12px;right:12px;z-index:61;background:var(--card)}
details.show>summary{list-style:none;cursor:pointer}
details.show>summary::-webkit-details-marker{display:none}
.photoways{display:flex;flex-wrap:wrap;gap:var(--sp-2);align-items:center;margin:0 0 var(--sp-2)}
.setaside>summary{cursor:pointer;font-weight:600;color:var(--muted)}
/* Busy: the words already say it; this only stops a second press reading as possible. */
label.busy,.btn[aria-disabled=true]{opacity:.7;pointer-events:none}
/* A row being typed into on a phone: the bottom nav steps aside for the keyboard (site.js sets body.typing). */
/* shell */ @media(max-width:900px){body.typing .rail{display:none}} /* end shell */
/* A narrow column: the strip of cards becomes a list, one 44px line a photo with a 44px thumbnail. */
@container (max-width:600px){
  .photos{flex-direction:column;gap:0;overflow:visible;padding-bottom:0}
  .photo{flex:none;display:grid;grid-template-columns:44px 1fr;column-gap:10px;align-items:start;min-height:var(--hit);
    padding:6px 0 6px 8px;border:0;border-radius:0;border-left:3px solid var(--verde);border-bottom:1px solid var(--line-soft)}
  .photo.waiting{border-left-color:var(--amber)} .photo.failed{border-left-color:var(--flag)}
  .photo>img.thumb,.photo>.doc{width:44px;height:44px;padding:0;font-size:var(--fs-0);overflow:hidden;word-break:break-all}
  .photo figcaption{margin:0;display:flex;flex-wrap:wrap;gap:4px 8px;align-items:center;min-height:var(--hit)}
  .photo figcaption>span{display:inline-flex;align-items:center;flex-wrap:wrap;gap:6px;margin:0}
  .photo details.show[open]{flex-basis:100%}
  .photo .btn.sm,.photoways .btn.sm,.setaside .btn.sm,details.show>summary.btn,.setaside>summary,.photoneeds a{min-height:var(--hit);display:inline-flex;align-items:center}
}

/* ==================== UI redesign, one section a step, each filled by its own step ==================== */

/* ---------- step 4: the nav: one list per role, icons, phone tabs, the More sheet ---------- */
/* Nothing here: step 4 rewrote the rail's own rules where they were (.rail, .glyph, .moresheet, the
   900px block), so the nav is read in one place. */
/* (end of step 4) */

/* ---------- step 5: Today: the lead card, quick actions, Needs you ---------- */
/* One column on a phone (lead, quick actions, then Needs you); beside each other (a .split, the list a
   fixed 360px) once the column holds both and 560px for the lead. Inside the 1120px reading width: Today
   is not a wide page. The rank is a stripe, not a fill, so the housekeeper's page stays least colour. */
.today .card.lead{margin-bottom:var(--sp-4)}
.card.lead .cardhint{font-size:var(--fs-2);margin:0 0 var(--sp-4)}
.cardlinks{display:flex;gap:var(--sp-2);flex-wrap:wrap;margin-top:var(--sp-3)}
.card.lead .cardlinks{margin-top:var(--sp-4)}
.nextsteps{margin:0 0 var(--sp-2)}
.nextsteps ol{margin:0;padding:0;list-style:none;counter-reset:step}
.nextsteps li{counter-increment:step;border-top:1px solid var(--line-soft)}
.nextsteps li:first-child{border-top:0}
.nextsteps a{display:flex;gap:var(--sp-3);align-items:baseline;padding:var(--sp-2) 0;color:var(--ink);text-decoration:none;font-size:var(--fs-3)}
.nextsteps a::before{content:counter(step);font-family:var(--mono);font-size:var(--fs-1);color:var(--accent-ink);min-width:1.2em}
.nextsteps a:hover{color:var(--slate);text-decoration:underline}
.needhead{font-family:var(--head);font-weight:700;font-size:var(--fs-3);margin:0;line-height:1.35}
.needs>h3.sub{margin-bottom:var(--sp-2)}
.needgroup{margin:0 0 var(--sp-4)}
.needrank{display:flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-1);font-weight:600;color:var(--muted);margin:0 0 var(--sp-2)}
.needrank.urgent{color:var(--flag)}
.needrank.soon{color:var(--amber-ink)}
.needcount{font-family:var(--sans);font-variant-numeric:tabular-nums;font-weight:500;color:var(--muted)}
.need{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);
  padding:var(--sp-3) var(--sp-4);margin-bottom:var(--sp-2)}
.need.urgent{border-color:var(--flag-line)}
.need.soon{border-color:var(--amber-line)}
.need .eyebrow{margin-bottom:var(--sp-1)}
.need .cardhint{margin:var(--sp-1) 0 0;font-size:var(--fs-2)}
.need .brief{margin-top:var(--sp-2)}
.need .cardfoot{margin-top:var(--sp-2)}
.needsnone{margin:0 0 var(--sp-4)}
/* The managers' Today (2026-11-02, the TodayManager mock): the day with its freshness and three small
   actions, a verdict, two money figures, four tiles, two lines, then "Needs you" one line each. One anatomy
   for every figure: label, value, delta, time frame. Every rule asks the column it sits in. */
.pagehead{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--sp-3) var(--sp-4);margin:0 0 var(--sp-4)}
.pagehead h2.sec{margin:0}
.pagehead h2.sec+.lede{margin:2px 0 0;max-width:none;font-variant-numeric:tabular-nums}
.pagehead .lede b{color:var(--ink);font-weight:600}
.pagehead .actions{margin-left:auto;display:flex;flex-wrap:wrap;gap:var(--sp-2)}
.pagehead .actions .btn{display:inline-flex;align-items:center;gap:6px}
.pagehead .actions .navicon{width:16px;height:16px}
@container (max-width:600px){
  .pagehead .actions{margin-left:0;width:100%}
  .pagehead .actions .btn{flex:1 1 0;justify-content:center;padding-inline:var(--sp-2)}
}
.moneyhead{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2) var(--sp-3);margin:0 0 var(--sp-3)}
.moneyhead .hint{font-size:var(--fs-2)}
.moneyhead .to{margin-left:auto;font-size:var(--fs-2)}
@container (max-width:600px){.moneyhead .to{margin-left:0}}
.verdict{display:inline-flex;align-items:center;gap:var(--sp-2);font-weight:700;font-size:var(--fs-3);line-height:1.3;
  padding:6px 14px 6px 10px;border-radius:var(--r-pill);border:1px solid}
.verdict .navicon{width:18px;height:18px;flex:none}
.verdict.bad{background:var(--flag-soft);color:var(--flag-deep);border-color:var(--flag-line)}
.verdict.ok{background:var(--verde-soft);color:var(--verde-deep);border-color:var(--verde-line)}
.verdict.under{background:var(--accent-soft);color:var(--accent-ink);border-color:var(--accent)}
/* The report's three tabs (Day report, Performance, Labor): where you are is sky. */
.reporttabs{display:flex;flex-wrap:wrap;gap:var(--sp-1) var(--sp-4);margin:0 0 var(--sp-3);border-bottom:1px solid var(--line)}
.reporttabs a{padding:var(--sp-2) 0;margin-bottom:-1px;border-bottom:2px solid transparent;color:var(--muted);text-decoration:none;font-weight:600}
.reporttabs a[aria-current="page"]{color:var(--ink);border-bottom-color:var(--accent)}
/* A day's ± drawn either side of a centre line; its length and start are data-w and data-left. */
.dbar{position:relative;display:block;width:120px;height:10px;background:var(--line-soft);border-radius:var(--r-pill)}
.dbar i{position:absolute;top:0;height:100%;background:var(--muted-2)}
.dbar i.over{background:var(--flag)}
.dbar i.under{background:var(--accent)}
.dbar b{position:absolute;left:50%;top:-2px;bottom:-2px;width:1px;background:var(--ink)}
/* Where a day went: the worked minutes in one bar, each part a share. */
.whereday{display:flex;height:12px;border-radius:var(--r-pill);overflow:hidden;background:var(--line-soft)}
.whereday i,.wherekey i{display:block;height:100%}
.wherekey i{display:inline-block;width:10px;height:10px;margin-right:6px;border-radius:var(--r-xs)}
.seg-rooms{background:var(--blue)}
.seg-reclean{background:var(--flag)}
.seg-duties{background:var(--accent)}
.seg-outside{background:var(--line)}
/* The reason under a person on the day report. */
.whyrow{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2) var(--sp-3)}
/* Simple or Advanced over the report (Q101): a segmented switch; the one you are on is filled. */
.reporthead{display:flex;justify-content:flex-end;margin:0 0 var(--sp-3)}
.modeseg{display:inline-flex;border:1px solid var(--line);border-radius:var(--r-input);overflow:hidden;background:var(--card)}
.modeseg a{padding:6px 14px;font-size:var(--fs-2);font-weight:600;color:var(--muted);text-decoration:none}
.modeseg a+a{border-left:1px solid var(--line)}
.modeseg a[aria-current="page"]{background:var(--blue);color:var(--on-fill)}
/* Simple (the owner's design, the LaborVariance mock): flat, one accent, status as a thin bar or a dot. */
.s-hero{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:var(--sp-3);margin:0 0 var(--sp-5)}
.s-hcard{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);padding:var(--sp-3) var(--sp-4);display:flex;flex-direction:column;gap:2px;min-width:0}
.s-hcard.lead{box-shadow:inset 0 3px 0 var(--blue)}
.s-hcard .h-label{font-size:var(--fs-2);font-weight:600}
.s-hcard .h-value{font-size:var(--fs-6);font-weight:700;line-height:1.15;font-variant-numeric:tabular-nums}
.s-hcard .h-value small{font-size:var(--fs-3);font-weight:500;color:var(--muted);margin-left:4px}
.s-hcard .h-foot{font-size:var(--fs-2)}
.s-hcard .h-time{font-size:var(--fs-1);color:var(--muted);margin-top:auto;padding-top:var(--sp-1)}
.trend{font-weight:600;white-space:nowrap}
.trend.good{color:var(--verde-deep)}
.trend.bad{color:var(--flag-deep)}
.trend.flat{color:var(--muted);font-weight:500}
.s-sec{display:flex;justify-content:space-between;align-items:baseline;flex-wrap:wrap;gap:var(--sp-2);margin:0 0 var(--sp-2)}
.s-sec h3{font-size:var(--fs-4);margin:0}
.s-people{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card)}
.s-prow{display:grid;grid-template-columns:minmax(150px,1.2fr) 2.4fr 84px 124px;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-4);
  border-top:1px solid var(--line-soft);color:var(--ink);text-decoration:none}
.s-prow:first-child{border-top:0}
.s-prow:hover{background:var(--blue-soft)}
.s-prow[aria-current="true"]{background:var(--accent-soft)}
.s-pwho{min-width:0}
.s-pwho b{display:block;font-size:var(--fs-3);font-weight:600}
.s-pwho span{font-size:var(--fs-1);color:var(--muted)}
.s-track{position:relative;display:block;height:6px;background:var(--line-soft);border-radius:var(--r-xs)}
.s-track .fill{position:absolute;left:0;top:0;bottom:0;border-radius:var(--r-xs)}
.s-track .fill.ok,.s-legend i.ok{background:var(--verde)}
.s-track .fill.slow,.s-legend i.slow{background:var(--flag)}
.s-track .fill.fast,.s-legend i.fast{background:var(--accent)}
.s-track .goal{position:absolute;top:-5px;bottom:-5px;width:2px;background:var(--ink)}
.s-track .goal::after{content:attr(data-l);position:absolute;top:-17px;left:50%;transform:translateX(-50%);font-size:var(--fs-0);font-weight:600;color:var(--muted);white-space:nowrap}
.s-pnum{font-size:var(--fs-5);font-weight:700;font-variant-numeric:tabular-nums;text-align:right;line-height:1.1}
.s-pnum small{display:block;font-size:var(--fs-1);font-weight:500;color:var(--muted)}
.s-pstat{display:flex;align-items:center;gap:6px;font-size:var(--fs-2);font-weight:600;white-space:nowrap}
.s-pstat .dot{width:8px;height:8px;border-radius:var(--r-round);flex:0 0 8px}
.s-pstat.ok{color:var(--verde-deep)}
.s-pstat.ok .dot{background:var(--verde)}
.s-pstat.slow{color:var(--flag-deep)}
.s-pstat.slow .dot{background:var(--flag)}
.s-pstat.fast{color:var(--accent-ink)}
.s-pstat.fast .dot{background:var(--accent)}
.s-legend{display:flex;flex-wrap:wrap;gap:4px var(--sp-4);font-size:var(--fs-1);color:var(--muted);margin-top:var(--sp-2)}
.s-legend i{display:inline-block;width:8px;height:8px;border-radius:var(--r-round);margin-right:5px;vertical-align:0}
.s-nudge{margin-top:var(--sp-4);display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:var(--sp-3);background:var(--card);
  border:1px solid var(--line);border-radius:var(--r-card);padding:var(--sp-3) var(--sp-4)}
.s-nudge.act{border-color:var(--flag-line)}
.s-nudge p{font-size:var(--fs-2);color:var(--muted)}
.s-nudge p b{color:var(--flag-deep)}
@container (max-width:600px){
  .s-prow{grid-template-columns:1fr auto;row-gap:var(--sp-3)}
  .s-prow .s-track{grid-column:1 / -1;order:3;margin-top:14px}
  .s-prow .s-pstat{grid-column:1 / -1;order:4}
}
.sub{display:block;font-size:var(--fs-1);color:var(--muted)}
.kpis{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--sp-3);margin:0 0 var(--sp-4)}
.figs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-3);margin:0 0 var(--sp-4)}
@container (min-width:560px){
  .kpis{grid-template-columns:repeat(2,minmax(0,1fr))}
  .figs{grid-template-columns:repeat(4,minmax(0,1fr))}
}
.kpi{position:relative;background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);
  padding:var(--sp-3) var(--sp-4);display:flex;flex-direction:column;gap:2px;min-width:0}
.kpi.risk{border-color:var(--flag-line)}
.k-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-2)}
.k-label{font-size:var(--fs-2);font-weight:600;color:var(--ink);text-decoration:none;line-height:1.35}
a.k-label:hover{text-decoration:underline}
.k-body{display:flex;align-items:baseline;flex-wrap:wrap;gap:0 var(--sp-2);margin-top:2px}
.k-value{font-size:var(--fs-7);font-weight:700;line-height:1.1;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.k-value.bad{color:var(--flag)}
.k-value .of{font-size:var(--fs-3);font-weight:500;color:var(--muted);letter-spacing:0}
.k-delta{margin:0;font-size:var(--fs-2);color:var(--ink);display:inline-flex;align-items:center;gap:4px}
.k-delta.bad{color:var(--flag-deep);font-weight:600}
.k-delta .navicon,.k-time .navicon,.k-time .pill .navicon{width:15px;height:15px;flex:none}
.k-note{margin:0;font-size:var(--fs-1);color:var(--muted)}
.k-foot{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2);margin-top:auto;padding-top:var(--sp-2)}
.k-foot .btn{margin-left:auto}
.k-time{margin:0;font-size:var(--fs-1);color:var(--muted);font-variant-numeric:tabular-nums;display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}
.k-time .pill{display:inline-flex;align-items:center;gap:4px;font-weight:600}
/* The definition behind an info sign: a <details> drawing its own marker (excluded from the chevron rule). */
.kinfo{flex:none;position:static}
.kinfo>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;
  margin:-4px -6px 0 0;border-radius:var(--r-round);color:var(--muted-2)}
.kinfo>summary::-webkit-details-marker{display:none}
.kinfo>summary:hover,.kinfo[open]>summary{background:var(--line-soft);color:var(--ink)}
.kinfo>summary .navicon{width:16px;height:16px}
.kdef{font-size:var(--fs-1);color:var(--slate);background:var(--ground);border-radius:var(--r-input);
  padding:var(--sp-2) var(--sp-3);margin:var(--sp-2) 0 0;position:absolute;left:var(--sp-3);right:var(--sp-3);z-index:5;
  box-shadow:var(--shadow-raised)}
/* A tile: the label stretched over the whole tile, so the tile is one link; the info sign sits above it. */
.fig{padding:var(--sp-3)}
.fig .k-head{display:block;padding-right:22px}
.fig .kinfo>summary{position:absolute;top:10px;right:10px;margin:0;z-index:2}
.fig .k-value{font-size:var(--fs-6)}
.fig .k-label::after{content:"";position:absolute;inset:0;border-radius:var(--r-card)}
.fig .k-label:focus-visible{outline:none}
.fig:has(.k-label:focus-visible){outline:var(--focus-w) solid var(--focus);outline-offset:var(--focus-off)}
.fig:hover{border-color:var(--blue);background:var(--blue-soft)}
.fig .k-time{margin-top:auto;padding-top:var(--sp-1);white-space:nowrap}
/* Stale: older than the shift it is shown in. Muted, a clock, and the words. */
.stale .k-value,.stale .k-time{color:var(--muted-2)}
/* Shifts to review: two lines and a button. The desk shift: one status line with its meter. */
.tline{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2) var(--sp-4);background:var(--card);border:1px solid var(--line);
  border-radius:var(--r-card);padding:var(--sp-3) var(--sp-4);margin:0 0 var(--sp-3)}
.tline .l-text{flex:1 1 260px;min-width:0}
.tline .l-head{margin:0;font-weight:700;font-size:var(--fs-3)}
.tline .l-sub{margin:0;font-size:var(--fs-2);color:var(--muted)}
.tline .l-sub a{font-weight:600}
.tline.quiet{background:none;border-style:dashed;padding:var(--sp-2) var(--sp-4)}
.tline.desk .meter{flex:1 0 100%;margin-top:-2px}
.tline.desk .l-head{font-variant-numeric:tabular-nums}
/* Needs you on a manager's page: one ruled line per item, a pill, the sentence, who and when, one link. */
.needlist{list-style:none;margin:0;padding:0;background:var(--card);border:1px solid var(--line);border-radius:var(--r-card)}
.needline{display:grid;grid-template-columns:auto minmax(0,1fr);gap:2px var(--sp-2);padding:var(--sp-2) var(--sp-3);
  border-top:1px solid var(--line-soft);align-items:baseline}
.needline:first-child{border-top:0}
.needline>.pill{grid-row:1;min-width:46px;text-align:center}
.needline .n-text{font-size:var(--fs-2);line-height:1.4}
.needline .n-who{grid-column:2;font-size:var(--fs-1);color:var(--muted);display:flex;flex-wrap:wrap;gap:0 var(--sp-2);justify-content:space-between}
.needline .n-who a{font-weight:600}
@media(pointer:coarse){
  .needs .inboxitem .btn,.cardlinks .btn,.pagehead .actions .btn,.k-foot .btn,.tline .btn{min-height:var(--hit);display:inline-flex;align-items:center}
  .needline .n-who a,.moneyhead .to a,.tline .l-sub a{display:inline-flex;align-items:center;min-height:var(--hit)}
  .kinfo>summary{width:44px;height:44px;margin:-12px -14px -8px 0}
  .nextsteps a{min-height:var(--hit);align-items:center}
}
/* (end of step 5) */

/* ---------- step 6: her board: Next room, the summary, the rows, Found item as a tab ---------- */
/* Two tabs with no script: a radio each, visually hidden but focusable, and the panels are their
   later siblings. The board shows unless Found item is checked. */
.mbtabs{position:relative}
.mbtabs>.mbtab-in{position:absolute;top:0;left:0;opacity:0;width:1px;height:1px;margin:0;pointer-events:none}
.mbtabstrip{display:flex;gap:0;margin:0 0 var(--sp-4);border-bottom:1px solid var(--line)}
.mbtab{flex:1;text-align:center;padding:var(--sp-2) var(--sp-2);min-height:var(--hit);display:flex;align-items:center;justify-content:center;
  font-size:var(--fs-2);font-weight:600;color:var(--muted);cursor:pointer;border-bottom:3px solid transparent;margin-bottom:-1px}
#mbtab-board:checked~.mbtabstrip .mbtab-board,#mbtab-found:checked~.mbtabstrip .mbtab-found{color:var(--ink);border-bottom-color:var(--accent)}
#mbtab-board:focus-visible~.mbtabstrip .mbtab-board,#mbtab-found:focus-visible~.mbtabstrip .mbtab-found{outline:var(--focus-w) solid var(--focus);outline-offset:-2px}
.mbpanel-found{display:none}
#mbtab-found:checked~.mbpanel-found{display:block}
#mbtab-found:checked~.mbpanel-board{display:none}
/* The card: the room to go to now. Status is the stripe; the one fill is the button. */
/* The room in hand is where she is: a sky edge all round, not a stripe. */
.mbnext{border-color:var(--accent);border-width:2px;box-shadow:none;padding:var(--sp-4)}
.mbnext.mbdone{border-color:var(--verde);box-shadow:none}
.mbnexthead{display:flex;align-items:baseline;gap:var(--sp-3);flex-wrap:wrap}
.mbnextnum{font-family:var(--mono);font-weight:600;font-size:var(--fs-6);line-height:1.1}
.mbnextname{font-weight:600;font-size:var(--fs-5);line-height:1.2}
.mbnexttype{flex:1;font-size:var(--fs-2);color:var(--muted)}
.mbnextflags{display:flex;flex-direction:column;gap:2px;margin:var(--sp-2) 0 0}
.mbnext form{margin:0}
.mbgo{display:flex;align-items:center;justify-content:center;width:100%;height:50px;margin-top:var(--sp-3);
  font-size:var(--fs-3);text-decoration:none;color:var(--on-fill)}
.mbgohint{margin:var(--sp-2) 0 0;text-align:center}
/* The day in three figures, mono. */
/* The same figure line as .statgrid (track F, round two): rules between, Public Sans tabular, label under. */
.mbfigs{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;margin:0 0 var(--sp-2);align-items:start}
.mbfigs>*{min-width:0;text-align:left;padding:var(--sp-1) var(--sp-4);border-left:1px solid var(--line-soft)}
.mbfigs>:first-child{border-left:0;padding-left:0}
.mbbig{display:block;font-family:var(--sans);font-variant-numeric:tabular-nums;font-weight:600;font-size:var(--fs-5);line-height:1.1;white-space:nowrap}
.mblbl{display:block;font-size:var(--fs-1);font-weight:500;color:var(--muted);margin-top:var(--sp-1)}
.mbcount{margin:0;font-size:var(--fs-2)}
.mbcount strong{font-weight:600}
.mbfig{font-family:var(--mono);font-variant-numeric:tabular-nums}
.mbhead{margin-top:var(--sp-4)}
/* A row: number, the clean and one flag, the paper's code. */
.mbrow{display:flex;align-items:center;gap:var(--sp-3);min-height:52px;padding:var(--sp-2) var(--sp-3);margin-bottom:var(--sp-2);
  background:var(--card);border:1px solid var(--line);border-left:4px solid var(--line);border-radius:var(--r-card);color:inherit;text-decoration:none}
a.mbrow:hover{border-color:var(--muted)}
.mbrow.held{opacity:.6}
.mbnum{font-family:var(--mono);font-weight:600;font-size:var(--fs-4);min-width:48px}
.mbname{font-weight:600;font-size:var(--fs-3);min-width:48px}
.mbmid{flex:1;min-width:0;display:flex;flex-direction:column}
.mbtype{font-size:var(--fs-2);color:var(--ink)}
.mbcode{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:var(--fs-2);color:var(--muted);white-space:nowrap;text-align:right}
/* The card's right corner (2026-11-01): the paper's code with the room's own clock under it. */
.mbnextright{display:flex;flex-direction:column;align-items:flex-end;gap:2px;margin-left:auto;align-self:flex-start}
.mbroomclock{font-family:var(--mono);font-variant-numeric:tabular-nums;font-weight:600;font-size:var(--fs-5);line-height:1;white-space:nowrap}
.mbroomclock.quiet{color:var(--muted);font-weight:500}
.mbroomclock.over{color:var(--flag)}
/* The day's topic on the start-of-day banner (2026-11-01): a label over the hotel's own words. */
.mbtopic{margin:0 0 var(--sp-3);font-size:var(--fs-3);line-height:1.35}
.mbtopic .mblbl{display:block;margin-bottom:2px}
/* The two confirmations on her board (2026-11-01): the fold opens its question under the button, full width. */
.mbdayfold{display:block}
.mbdayfold[open]>summary{background:var(--flag-soft)}
.mbconfirm{margin-top:var(--sp-3)}
.mbflag{display:flex;align-items:baseline;gap:6px;font-size:var(--fs-1);color:var(--muted);min-width:0}
.mbrow .mbflag>span:first-of-type{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mbdot{flex:none;width:7px;height:7px;border-radius:var(--r-round);background:var(--muted-2);align-self:center}
.mbflag.now{color:var(--accent-ink);font-weight:600}.mbflag.now .mbdot{background:var(--accent)}
.mbflag.urgent{color:var(--flag);font-weight:600}.mbflag.urgent .mbdot{background:var(--flag)}
/* (end of step 6) */

/* ---------- step 7: the desk's checklist: one status line, hand-in pinned ---------- */
/* Sticky under the top bar (2026-11-01): the count and the meter stay in sight down a 36-line list.
   --top-h is the bar's height where the bar is sticky and 0 where it scrolls away (the phone),
   set by the page's script; the bar's menus open over it (the bar is z 55, under the photo lightbox's 60), so z 30. */
.statusline{position:sticky;top:var(--top-h,0px);z-index:30;background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);
  padding:var(--sp-2) var(--sp-4) var(--sp-3);margin-bottom:var(--sp-4);box-shadow:var(--shadow-soft)}
.statusline .sl-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-1) var(--sp-3);margin-bottom:var(--sp-2)}
.statusline .sl-count{font-size:var(--fs-3)}
.statusline .sl-who{margin-left:auto;color:var(--muted)}
.statusline .sl-note{margin:var(--sp-2) 0 0;color:var(--muted)}
.meter.thin{height:4px}
@container (max-width:600px){.statusline .sl-who{margin-left:0;flex-basis:100%}}

/* The hand-in bar. Sticky, not fixed: it is the last block of the page, so at the end of the
   list it sits in its own place and covers no line. */
.handin{position:sticky;bottom:0;z-index:40;display:flex;flex-wrap:wrap;align-items:center;
  justify-content:space-between;gap:var(--sp-2) var(--sp-4);background:var(--card);
  border:1px solid var(--line);border-radius:var(--r-card);padding:var(--sp-3) var(--sp-4);
  box-shadow:var(--shadow-bar);margin-bottom:var(--sp-4)}
.handin .sub{margin:0;font-size:var(--fs-3)}
.handin .hint{margin:var(--sp-1) 0 0}
.handin-text{flex:1 1 260px;min-width:0}
.handin-act{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2)}
.handin-act a.pill{text-decoration:none}
/* shell */ @media(max-width:900px){
  .handin{bottom:calc(var(--nav-h) + env(safe-area-inset-bottom));max-height:40vh;overflow-y:auto;
    padding:var(--sp-2) var(--sp-3)}
  .handin .hint{display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
  /* The phone keeps the bar to its name and its buttons: the sentence is the desktop's (2026-11-01). */
  .handin .handin-why{display:none}
  .handin-text{flex-basis:100%}
  .handin-act{width:100%}
} /* end shell */
@media(pointer:coarse){.handin-act a.pill{display:inline-flex;align-items:center;min-height:var(--hit)}}
/* (end of step 7) */

/* ---------- step 8: tables that stack into rows in a narrow column ---------- */
/* Calls, Flag, Ledger, Work orders, Found items: a table that opts in with table.stack. In a
   column of 600px or less the head goes and each row is a card of two columns, every cell under its own data-label
   (the board's pattern, .boardrows above, copied not shared). The first cell leads on a line of
   its own; .prose cells (free text) and .sact (the row's button) take the full width; .sh keeps
   a first cell to half a line; a cell with data-label="" gets no label. Only the boxes move: the
   cells' markup, forms and posts are the desktop's. */
@container (max-width:600px){
  table.stack,table.stack tbody{display:block}
  table.stack thead{display:none}
  table.stack tr{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
    border:0;border-bottom:1px solid var(--line-soft);border-radius:0;margin:0;background:transparent}
  table.stack tr:last-child{border-bottom:0}
  table.stack td.rep{display:none}
  table.stack td:first-child{font-weight:600}
  /* min-width:0 beats ".tblwrap td.prose" (22ch); !important beats ".tblwrap td.r" (nowrap under 900px)
     and the time cells' .nowrap. */
  table.stack td{display:block;min-width:0;border:0;padding:var(--sp-1) var(--sp-2);text-align:left;
    white-space:normal!important;overflow-wrap:anywhere}
  table.stack td:first-child,table.stack td.prose,table.stack td.sact{grid-column:1/-1}
  table.stack td.sh{grid-column:auto}
  table.stack td.sact{border-top:1px solid var(--line-soft)}
  table.stack td:empty{display:none}
  table.stack td[data-label]:not([data-label=""])::before{content:attr(data-label);display:block;
    margin-bottom:2px;font-size:var(--fs-0);font-weight:500;color:var(--muted)}
  table.stack td.sact .btn{min-height:var(--hit);display:inline-flex;align-items:center;justify-content:center}
}
/* (end of step 8) */

/* ---------- step 9: her room: Ready and the timer pinned, the actions named ---------- */
/* The timer's words, where the timer card was; its digits are in the bar. */
.roomclock{margin:0 0 var(--sp-3)}
/* Ready and the clock. On a desktop it holds to the foot of the column while the list is longer
   than the screen; on a phone it is fixed above the bottom nav (below). The height is fixed and
   nothing in it can grow — both button lines are single lines, the words under the digits swap by
   [hidden] — so a tick that changes them cannot move a pixel of the page (site.js). z 60: over the
   page, under the room sheet (70) and the toast (100). */
.roombar{position:sticky;bottom:var(--sp-3);z-index:60;display:flex;align-items:center;gap:var(--sp-3);
  height:64px;padding:var(--sp-2) var(--sp-3);margin:0 0 var(--sp-4);background:var(--card);
  border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden}
/* The ticked share, along the bar's top edge: the count itself stays in the checklist's head (#tickCount). */
.roombar .rbtrack{position:absolute;left:0;right:0;top:0;height:3px;background:var(--line-soft)}
.roombar .rbtrack i{display:block;height:100%;max-width:100%;background:var(--accent)}
.roombar .rbclock{flex:none;display:flex;flex-direction:column;justify-content:center;min-width:92px}
/* The one display size off the scale (46px) is the duty page's; in the bar the digits are a figure, --fs-6. */
.roombar .bigtimer{font-size:var(--fs-6);margin:0;text-align:left}
.roombar .rbleft{font-size:var(--fs-1);line-height:1.3;color:var(--muted);white-space:nowrap;margin-top:2px}
.roombar .rbleft .n{font-family:var(--mono);font-variant-numeric:tabular-nums}
.roombar .rbready{flex:1;min-width:0;margin:0}
.roombar .btn{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;
  height:46px;min-height:0;padding:0 var(--sp-3);line-height:1.25}
.roombar .btn .en,.roombar .btn .es{display:block;max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.roombar .btn .en{font-size:var(--fs-2)}
.roombar .btn .es{font-size:var(--fs-1);font-weight:500}
/* shell */ @media(max-width:900px){
  .roombar{position:fixed;left:0;right:0;bottom:calc(var(--nav-h) + env(safe-area-inset-bottom));margin:0;
    padding:var(--sp-2) var(--sp-4);border-width:1px 0 0;border-radius:0}
  /* The list's last line, and the actions under it, are never under the bar. */
  .hkwrap.withbar{padding-bottom:calc(64px + var(--sp-4))}
  /* The nav's own Más sheet rises from the same edge, inside the rail's z 50: the bar steps out of its way. */
  body:has(.moretab[open]) .roombar{visibility:hidden}
  /* A note being typed: the keyboard and the box get the screen. */
  .hkwrap:has(.more :is(input:not([type]),input[type=text],select):focus) .roombar{visibility:hidden}
  /* The toast stands on the bar here, not on the nav, or its six seconds cover Ready. */
  html:has(.roombar) .toast{bottom:calc(var(--nav-h) + 64px + env(safe-area-inset-bottom) + var(--sp-3))}
} /* end shell */
/* Without script a tick lands on #line-{key}: clear of the sticky top bar, and of the pinned bar when focus moves. */
html:has(.chkline){scroll-padding-top:80px}
/* shell */ @media(max-width:900px){html:has(.chkline){scroll-padding-top:140px;scroll-padding-bottom:calc(var(--nav-h) + 64px + env(safe-area-inset-bottom))}} /* end shell */

/* Everything that is not the clean, each under its own name (the design's two-by-two). A name is a
   button; its form opens under it across the full width, one at a time (name="roomact"). */
.more .acts{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-2)}
.more details.sub{margin:0;min-width:0}
.more details.sub[open]{grid-column:1/-1}
.more details.sub>summary{list-style:none;display:flex;flex-direction:column;justify-content:center;height:100%;
  min-height:56px;padding:var(--sp-2) var(--sp-3);border:1px solid var(--line);border-radius:var(--r-input);
  background:var(--card);font-size:var(--fs-2);font-weight:600;line-height:1.3;cursor:pointer}
.more details.sub>summary::-webkit-details-marker{display:none}
.more details.sub>summary .hint{display:block;font-weight:500}
.more details.sub[open]>summary{border-color:var(--muted);background:var(--ground);height:auto}
.more details.sub>form{padding:var(--sp-3) 0 var(--sp-2)}
.more .actnow{margin-top:var(--sp-2)}
.more .actnow .btn{width:100%}
/* (end of step 9) */

/* ---------- step 10: no inline style a view could name ---------- */
/* Every style="" a view wrote is one of these classes. A utility is one declaration, named by its
   property and its pixels (mt-6 is margin-top:6px, m-0 the whole box at 0; mt-n4 is -4px), and the
   same pixels as the inline style it replaced: snapping them to --sp-* would have moved every page
   in one commit nobody could review. Each is !important because an inline style outweighed every
   selector and these must too — the box at 0 comes before its sides, so "m-0 mt-6" is margin:6px 0 0.
   Names with a dash are utilities; a component's name has none. What may still be inline is
   ArchitectureTests.InlineStyles: a value the model computes (a width, a stripe's colour), or one a
   script moves. */
.btncell{display:flex;align-items:flex-end}  /* a button in a .logrow: bottom-aligned because the grid stretched the cell */
.offscreen{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}  /* the form's default submit, out of sight */
.nowrap{white-space:nowrap}  /* not !important, though a stacked table's cell (step 8) would win either way */
/* Margin */
.m-0{margin:0!important}
.mb-2{margin-bottom:2px!important}
.mb-4{margin-bottom:4px!important}
.mb-6{margin-bottom:6px!important}
.mb-8{margin-bottom:8px!important}
.mb-10{margin-bottom:10px!important}
.mb-12{margin-bottom:12px!important}
.mb-14{margin-bottom:14px!important}
.mb-16{margin-bottom:16px!important}
.mb-18{margin-bottom:18px!important}
.mb-22{margin-bottom:22px!important}
.ml-6{margin-left:6px!important}
.ml-10{margin-left:10px!important}
.ml-30{margin-left:30px!important}
.mr-14{margin-right:14px!important}
.mt-n4{margin-top:-4px!important}
.mt-0{margin-top:0!important}
.mt-2{margin-top:2px!important}
.mt-4{margin-top:4px!important}
.mt-6{margin-top:6px!important}
.mt-8{margin-top:8px!important}
.mt-10{margin-top:10px!important}
.mt-12{margin-top:12px!important}
.mt-14{margin-top:14px!important}
.mt-16{margin-top:16px!important}
.mt-18{margin-top:18px!important}
.mt-20{margin-top:20px!important}
/* Padding */
.p-0{padding:0!important}
.pb-12{padding-bottom:12px!important}
.pt-0{padding-top:0!important}
.pt-2{padding-top:2px!important}
.pt-10{padding-top:10px!important}
.px-4{padding-left:4px!important;padding-right:4px!important}
.py-2{padding-top:2px!important;padding-bottom:2px!important}
.py-6{padding-top:6px!important;padding-bottom:6px!important}
.py-7{padding-top:7px!important;padding-bottom:7px!important}
.py-8{padding-top:8px!important;padding-bottom:8px!important}
.py-10{padding-top:10px!important;padding-bottom:10px!important}
.py-14{padding-top:14px!important;padding-bottom:14px!important}
/* Display and flex */
.ai-base{align-items:baseline!important}
.ai-center{align-items:center!important}
.ai-end{align-items:flex-end!important}
.ai-start{align-items:flex-start!important}
.ai-stretch{align-items:stretch!important}
.as-center{align-self:center!important}
.d-block{display:block!important}
.d-flex{display:flex!important}
.d-iflex{display:inline-flex!important}
.d-inline{display:inline!important}
.d-none{display:none!important}
.f-col{flex-direction:column!important}
.f-wrap{flex-wrap:wrap!important}
.flex-1{flex:1!important}
.gap-4{gap:4px!important}
.gap-5{gap:5px!important}
.gap-6{gap:6px!important}
.gap-8{gap:8px!important}
.gap-10{gap:10px!important}
.gap-12{gap:12px!important}
.gap-14{gap:14px!important}
.jc-between{justify-content:space-between!important}
.jc-center{justify-content:center!important}
.jc-end{justify-content:flex-end!important}
/* Size */
.h-48{height:48px!important}
.maxh-320{max-height:320px!important}
.maxh-420{max-height:420px!important}
.maxw-280{max-width:280px!important}
.maxw-320{max-width:320px!important}
.maxw-560{max-width:560px!important}
.maxw-full{max-width:100%!important}
.minh-40{min-height:40px!important}
.minh-56{min-height:56px!important}
.minh-80{min-height:80px!important}
.minh-88{min-height:88px!important}
.minw-160{min-width:160px!important}
.minw-180{min-width:180px!important}
.minw-200{min-width:200px!important}
.minw-220{min-width:220px!important}
.minw-240{min-width:240px!important}
.w-44{width:44px!important}
.w-48{width:48px!important}
.w-62{width:62px!important}
.w-64{width:64px!important}
.w-72{width:72px!important}
.w-90{width:90px!important}
.w-96{width:96px!important}
.w-110{width:110px!important}
.w-120{width:120px!important}
.w-140{width:140px!important}
.w-auto{width:auto!important}
.w-full{width:100%!important}
/* Text */
.c-accentink{color:var(--accent-ink)!important}
.c-amberink{color:var(--amber-ink)!important}
.c-flag{color:var(--flag)!important}
.c-inherit{color:inherit!important}
.c-ink{color:var(--ink)!important}
.c-muted{color:var(--muted)!important}
.c-muted2{color:var(--muted-2)!important}
.c-verde{color:var(--verde)!important}
.cur-def{cursor:default!important}
.cur-ptr{cursor:pointer!important}
.ff-inherit{font-family:inherit!important}
.fs-1{font-size:var(--fs-1)!important}
.fs-3{font-size:var(--fs-3)!important}
.fs-4{font-size:var(--fs-4)!important}
.fw-6{font-weight:600!important}
.mono{font-family:var(--mono)!important}
.ta-center{text-align:center!important}
.ta-right{text-align:right!important}
/* Borders */
.b-line{border:1px solid var(--line)!important}
.bt-0{border-top:0!important}
.bt-line{border-top:1px solid var(--line)!important}
.fit-cover{object-fit:cover!important}
.ov-auto{overflow:auto!important}
.r-4{border-radius:var(--r-sm)!important}
.r-6{border-radius:var(--r-input)!important}
.span-all{grid-column:1 / -1!important}
/* After the utilities, so a d-flex or d-block on an element a script hides loses to [hidden], as the
   inline display did. An author display rule beats the browser's own [hidden]; without this a hidden
   button shows on every phone. */
[hidden]{display:none!important}
/* (end of step 10) */

/* ---------- de-template, 2026-10-31: one section per track, each track writes only in its own ---------- */
/* (track A: the shell and what every page shares) */
/* Browser surfaces. accent-color is --verde: the product already uses verde for "done", and a ticked box is that. */
::selection{background:var(--accent-soft);color:var(--ink)}
input[type=checkbox],input[type=radio],input[type=range],progress{accent-color:var(--verde)}
.railnav,.daylist,.tblwrap,.moresheet,.photos{scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.railnav,.moresheet{scrollbar-color:var(--veil-5) transparent}
.railnav::-webkit-scrollbar,.daylist::-webkit-scrollbar,.tblwrap::-webkit-scrollbar,.moresheet::-webkit-scrollbar,.photos::-webkit-scrollbar{width:8px;height:8px}
.railnav::-webkit-scrollbar-thumb,.moresheet::-webkit-scrollbar-thumb{background:var(--veil-5);border-radius:var(--r-sm)}
.daylist::-webkit-scrollbar-thumb,.tblwrap::-webkit-scrollbar-thumb,.photos::-webkit-scrollbar-thumb{background:var(--line);border-radius:var(--r-sm)}
.railnav::-webkit-scrollbar-track,.daylist::-webkit-scrollbar-track,.tblwrap::-webkit-scrollbar-track,.moresheet::-webkit-scrollbar-track,.photos::-webkit-scrollbar-track{background:transparent}
/* The native "Choose files" button reads as a ghost button, on every page without a markup change. */
input[type=file]::file-selector-button{background:var(--card);border:1px solid var(--line);border-radius:var(--r-input);
  color:var(--ink);font:inherit;font-weight:600;font-size:var(--fs-1);padding:var(--sp-1) var(--sp-3);margin-right:var(--sp-3);cursor:pointer}
input[type=file]::file-selector-button:hover{background:var(--ground)}
/* Figures line up in a column. */
td.r,th.r,.numlbl,.bignum,.pill{font-variant-numeric:tabular-nums}
/* A details' native triangle becomes one small chevron, for the summaries that style nothing of their
   own; the ones that draw their own marker (edit lists, sheet groups) or are buttons are left alone. */
details:not(.edititem,.sheetgroup,.navmenu,.sheetsetup,.show,.setaside,.dayfold,.kinfo,.more details.sub)>summary:not(.btn){list-style:none}
details:not(.edititem,.sheetgroup,.navmenu,.sheetsetup,.show,.setaside,.dayfold,.kinfo,.more details.sub)>summary:not(.btn)::-webkit-details-marker{display:none}
details:not(.edititem,.sheetgroup,.navmenu,.sheetsetup,.show,.setaside,.dayfold,.kinfo,.more details.sub)>summary:not(.btn)::before{content:"";display:inline-block;
  width:6px;height:6px;margin:0 var(--sp-2) 2px 2px;border:solid var(--muted-2);border-width:0 1.5px 1.5px 0;transform:rotate(-45deg)}
details[open]:not(.edititem,.sheetgroup,.navmenu,.sheetsetup,.show,.setaside,.dayfold,.kinfo,.more details.sub)>summary:not(.btn)::before{transform:rotate(45deg);margin-bottom:4px}
/* (end of track A) */
/* (track B: housekeeping's desktop pages) */
/* The report's summary strip: one ruled line of anchors, as the paper's total line, not nine pills. */
.reportstrip{display:flex;flex-wrap:wrap;gap:var(--sp-1) var(--sp-5);margin:0 0 var(--sp-3);padding:var(--sp-2) 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.reportstrip .chip{display:inline-block;padding:0;border:0;border-radius:0;background:transparent;font-family:var(--sans);font-size:var(--fs-2);color:var(--ink);text-decoration:none}
.reportstrip a.chip{text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:3px}
.reportstrip a.chip:hover{text-decoration-color:var(--ink)}
.reportstrip .chip.none{color:var(--muted-2)}
.reportstrip .chip.act{font-weight:600;color:var(--flag)}
.reportstrip .chip.mpr{font-weight:600}
/* How the day goes: one line under the lede, the steps one click down. */
details.stepsdone#how{margin:var(--sp-2) 0 var(--sp-3)}
/* Teams: a fold, not a card holding a hint. */
details.teamsfold{margin:0 0 var(--sp-3)}
details.teamsfold>summary{cursor:pointer;color:var(--muted);font-size:var(--fs-2)}
/* (end of track B) */
/* (track C: the records pages) */
/* A figure that is bad and non-zero: text in the flag colour, never an inline style. */
.fig-bad{color:var(--flag)}

/* The coverage roster: a ruled grid like the paper. The cell is the fill; the name is the only
   thing in it. State is the fill and the legend; the words stay in the title. */
.covgrid td.ctr{padding:0;border:1px solid var(--line-soft)}
.covgrid .cov{display:flex;align-items:center;justify-content:center;min-height:40px;margin:0;
  border:0;border-radius:0;padding:5px 6px;transition:none}
.covgrid a.cov:hover{transform:none;filter:brightness(.96)}
.covgrid .cov.soon{background:transparent;border:0}

/* Audit trail, grouped by day: one date heading, then the times. */
.dayhd{font-family:var(--head);font-size:var(--fs-4);font-weight:700;margin:var(--sp-5) 0 var(--sp-1);
  padding-bottom:var(--sp-1);border-bottom:1px solid var(--line)}

/* (end of track C) */
/* (track D: Today, her board, the log, found items, calls, the checklist) */
/* Today: the lead is an ordinary card, not a framed box; its first line is its heading. */
.card.primary{border:1px solid var(--line);padding:var(--sp-4) var(--sp-5)}
.card.primary .sub{font-size:var(--fs-3);margin-bottom:var(--sp-1)}
.card.lead .leadline{margin:0 0 var(--sp-3);font-size:var(--fs-3);font-weight:600}
.need .leadline{margin:var(--sp-1) 0 0;font-weight:600;font-size:var(--fs-2)}
.card.lead .meter{height:4px;margin:0 0 var(--sp-3)}
.stepslabel{margin:0 0 var(--sp-1);font-size:var(--fs-1);font-weight:600;color:var(--muted)}
/* The quick actions: one ruled list, and one ruled row of up to three once Today's own column
   (the .split's main side, a container) is 560px wide. The column, not the window: "Needs you" takes
   360px beside it, and a laptop's row went to three columns of a few letters each (2026-10-31). */
.quickrow{display:block;background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;margin-bottom:var(--sp-4)}
.quick{display:grid;grid-template-columns:20px minmax(0,1fr);gap:var(--sp-1) var(--sp-3);align-items:center;
  text-decoration:none;color:var(--ink);background:none;border:0;border-top:1px solid var(--line-soft);border-radius:0;padding:var(--sp-3) var(--sp-4);transition:none}
.quick:first-child{border-top:0}
/* Only where a pointer hovers: on a phone the shade stuck to the last row touched. */
@media(hover:hover){.quick:hover{background:var(--line-soft)}}
.quick:active{background:var(--line-soft)}
.quick .navicon{grid-row:1/3;color:var(--ink)}
.quick .q-title{margin-top:0;font-size:var(--fs-2)}
@container (min-width:560px){
  .quickrow{display:grid;grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr)}
  .quick{border-top:0;border-left:1px solid var(--line-soft)}
  .quick:first-child{border-left:0}
}
/* Her board: a section is one sheet of ruled rows; the row's own stripe stays. */
h3.mbhead{margin:var(--sp-5) 0 var(--sp-2);padding-top:var(--sp-3);border-top:1px solid var(--line);
  font-size:var(--fs-2);font-weight:600;color:var(--ink)}
.mbsheet{border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;background:var(--card)}
.mbsheet .mbrow{margin:0;border-radius:0;border-width:0;border-top:1px solid var(--line-soft);border-left:4px solid var(--line)}
.mbsheet .mbrow:first-child{border-top-width:0}
.mbsheet a.mbrow:hover{background:var(--line-soft)}
.mbfigs.two{grid-template-columns:repeat(2,minmax(0,1fr))}
.mbfigs.four{grid-template-columns:repeat(2,minmax(0,1fr));margin:0}
@container (min-width:601px){.mbfigs.four{grid-template-columns:repeat(4,minmax(0,1fr))}}
.mbbig.over,.mbbig.bad,.bignum.bad{color:var(--flag)}.mbbig.under{color:inherit}
/* Her figures in a narrow column: two a row, the figure a size down. After every .mbfigs and .mbbig rule,
   or source order hands the win back to the three-column rule (it did until 2026-11-01: the phone showed
   three columns, and the day's clock, "8:44:31" from 2026-11-01, broke across two lines in its third). */
@container (max-width:600px){.mbbig{font-size:var(--fs-4)}
  .mbfigs,.mbfigs.two,.mbfigs.four{grid-template-columns:repeat(2,minmax(0,1fr));row-gap:var(--sp-3)}
  .mbfigs>:nth-child(odd){border-left:0;padding-left:0}}
.shiftbar .clock .hint{font-family:var(--sans)}
.mefacts{display:grid;grid-template-columns:auto 1fr;gap:var(--sp-2) var(--sp-4);margin:0;border-top:1px solid var(--line-soft);padding-top:var(--sp-2)}
.mefacts dt{color:var(--muted)}.mefacts dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}
/* The checklist: a done line is ticked and initialled, not struck out; the note is a small word. */
.checklist .chk input:checked~.lbl .title{text-decoration:none}
/* The compact list (2026-11-01, the ChecklistCompact mock): what is left is the top of the list
   and the done lines sit under a "Done" rule at the bottom, one row each — the tick, the title
   in the quiet colour, who and when on the right — with the steps, the note's word and the
   figures folded away until the title is tapped (.open). The required marker is a small pill on
   the title line rather than a line of its own. */
.req{display:inline-block;margin-left:var(--sp-2);font-size:var(--fs-0);font-weight:600;color:var(--amber-ink);background:var(--amber-soft);
  border-radius:var(--r-pill);padding:1px 8px;vertical-align:2px;white-space:nowrap}
.checklist .byline{display:none}
.clrow.done .chk{padding:5px var(--sp-1);align-items:center}
.clrow.done .chk input{margin-top:0}
.clrow.done .lbl{display:flex;align-items:center;gap:var(--sp-3)}
.clrow.done .lbl .title{flex:1;min-width:0;font-size:var(--fs-2);cursor:pointer}
.clrow.done .lbl .note,.clrow.done .req,.clrow.done .itemnote:not([open]),.clrow.done .countrow,.clrow.done:not(.open) .paperpack{display:none}
.clrow.done .byline{display:block;margin:0;white-space:nowrap;color:var(--muted-2);font-variant-numeric:tabular-nums}
.countsum{display:none;padding:0 4px 8px 34px;font-size:var(--fs-1);color:var(--muted);font-variant-numeric:tabular-nums}
.countsum b{color:var(--ink);font-weight:600}
.clrow.done .countsum{display:block}
.clrow.done.open .chk{padding:9px var(--sp-1);align-items:flex-start}
.clrow.done.open .lbl{display:block}
.clrow.done.open .lbl .note{display:block}
.clrow.done.open .countrow{display:grid}
.clrow.done.open .itemnote:not([open]){display:block}
.clrow.done.open .countsum{display:none}
.clrow.done.open .byline{margin-top:var(--sp-1);color:var(--verde)}
/* The tick lands first, then the line leaves for the rule — so the eye sees what it did. */
.clrow.leaving{transition:opacity .35s ease;opacity:.45}
.donehd{display:flex;align-items:baseline;gap:var(--sp-2);margin-top:var(--sp-4);padding:var(--sp-3) var(--sp-1) var(--sp-1);
  border-top:2px solid var(--line);font-weight:700;font-size:var(--fs-2);color:var(--muted)}
.donehd span{font-weight:500;font-variant-numeric:tabular-nums;color:var(--muted-2)}
.donehd[hidden]{display:none}
/* In a narrow column the name and time go under the title, at the right: beside it they left the
   title 25px and a word a line (measured at 360, 2026-11-01). */
@container (max-width:600px){
  .clrow.done .lbl{flex-wrap:wrap;gap:0 var(--sp-3)}
  .clrow.done .lbl .title{flex-basis:100%}
  .clrow.done .byline{margin-left:auto;font-size:var(--fs-0)}
}
.itemnote summary{cursor:pointer;font-size:var(--fs-1);list-style:none;text-align:right;margin:0 0 4px}
.itemnote summary::-webkit-details-marker{display:none}
.itemnote summary::marker{content:""}
.itemnote summary:hover{text-decoration:underline}
.hkwrap>.installhint{border-top:1px solid var(--line-soft);padding-top:var(--sp-3);margin-top:var(--sp-4)}
/* (end of track D) */
/* (track E: the admin and system pages, sign-in, the inbox) */
/* A table on a ruled section, not a card: the heading carries a rule, the table sits under it. */
section.ruled{margin:0 0 var(--sp-5)}
section.ruled>h3.sub,section.ruled>.spread>h3.sub{margin:0 0 var(--sp-3);padding-bottom:var(--sp-2);border-bottom:2px solid var(--line)}
section.ruled>.spread{gap:var(--sp-3);align-items:flex-start}
section.ruled>.spread>h3.sub{flex:1}
td.emptyrow{color:var(--muted-2)}
/* A state that is not an exception is plain muted text, not a pill. */
.tag{font-size:var(--fs-1);color:var(--muted);margin-left:var(--sp-2);font-weight:500}
.backlink{margin:calc(-1 * var(--sp-3)) 0 var(--sp-4)}
.roleline{display:flex;align-items:baseline;gap:var(--sp-2);margin:0 0 var(--sp-1)}
/* The company's admins with no role at the hotel, one line above the staff table (2026-11-01). */
.adminsline{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2) var(--sp-4);margin:0 0 var(--sp-3);padding:var(--sp-2) var(--sp-3);
  background:var(--ground);border:1px solid var(--line-soft);border-radius:var(--r-card);font-size:var(--fs-2)}
.acctfold>summary{cursor:pointer;font-size:var(--fs-1);color:var(--muted)}
.acctfold[open]>summary{margin-bottom:var(--sp-2)}
@container (max-width:600px){
  .acctfold>summary{min-height:var(--hit);display:flex;align-items:center}
}
/* The sign-in card: an ink band in the rail's brand look over a white form. */
.authband{background:var(--rail-bg);color:var(--on-fill);font-family:var(--head);font-weight:700;font-size:var(--fs-5);letter-spacing:.02em;
  line-height:1.1;padding:20px 24px}
.authbody{padding:var(--sp-5)}
/* The two legal pages: prose at a reading measure inside the sign-in card, which is wider for them; the links to them
   stand under the card when signed out and in the person menu when signed in. */
.legal{max-width:68ch;font-size:var(--fs-2)}
.legal ul{margin:0 0 var(--sp-4);padding-left:var(--sp-5)}
.legal li{margin:0 0 var(--sp-2)}
.legal h3.sub{margin:var(--sp-4) 0 var(--sp-2)}
.authcard:has(.legal){max-width:760px}
.authfoot{margin:var(--sp-3) 0 0;text-align:center;font-size:var(--fs-1);color:var(--muted)}
.plegal{margin:0;padding:var(--sp-2) 10px 0;font-size:var(--fs-1);color:var(--muted)}
.authcard .installhint{margin-top:var(--sp-5);padding-top:var(--sp-4);border-top:1px solid var(--line)}
/* A PIN: figures, so mono, tabular and spaced like the digits on a keypad. */
.txt.pin{font-family:var(--mono);font-variant-numeric:tabular-nums;letter-spacing:.3em;width:10ch;max-width:100%}
/* The inbox: one frame of ruled rows, the time first in mono, OK small. The time stays after the
   words in the markup (the cast and the tests read it there) and moves in front by order. */
/* The alerts card reads as a setting, not a banner: on the wide Today its one button ran 1,340px across the window. */
.phonealerts{max-width:560px}
/* One card family (the redesign run, 2026-11-05): the inbox was the one square box on Today, beside cards of --r-card. */
.inbox{border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;background:var(--card);margin-bottom:var(--sp-2)}
.inbox .inboxitem{border:0;border-top:1px solid var(--line-soft);border-radius:0;margin:0;background:transparent;gap:var(--sp-3)}
.inbox>.inboxitem:first-child{border-top:0}
.inbox .inboxitem>span{display:contents}
.inboxitem.nudged,.inbox .inboxitem.nudged{background:var(--amber-soft);border-color:var(--amber-line);flex-wrap:wrap}
.bell{position:relative;display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:var(--hit);color:var(--rail-text)}
.countbadge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;border-radius:var(--r-pill);background:var(--amber-ink);color:var(--on-fill);font-size:var(--fs-0);font-weight:600;line-height:1;margin-left:var(--sp-1)}
.countbadge[hidden]{display:none}
.bell .countbadge{position:absolute;top:4px;right:2px;margin-left:0}
/* Her board's asks, above the room in hand: amber, as everything waiting on someone is. */
.mbasks .inbox{border-color:var(--amber-line);background:var(--amber-soft)}
.mbasks .inbox .inboxitem>span>a{font-weight:600;color:var(--amber-ink)}
/* The bell's list: under the bell, its right edge the bell's; a card asking again is amber. */
.bellmenu{position:relative}
.bellmenu .menu{left:auto;right:0}
.belllist .hint{margin:0;padding:var(--sp-1) 10px var(--sp-2)}
.belllist .mi.asking .navlabel{color:var(--amber-ink)}
.belltoday{border-top:1px solid var(--line-soft);border-radius:0;margin-top:var(--sp-1)}
.inboxacts{display:flex;flex-wrap:wrap;gap:var(--sp-1);margin-top:var(--sp-1);flex-basis:100%}
.inbox .inboxitem>span>.hint{order:-1;flex:0 0 auto;min-width:7ch;font-family:var(--mono);font-variant-numeric:tabular-nums;color:var(--muted-2)}
.inbox .inboxitem>span>a{flex:1}
.inbox .inboxitem>form{margin-left:auto}
/* A card with answers takes two lines: the time, the words and OK, then the answers. Their row asks for the whole width, and in a row that could not wrap
   the words were squeezed to one per line at 901px (seen in a browser, 2026-11-05). */
.inbox .inboxitem:has(.inboxacts){flex-wrap:wrap}
.inbox .inboxitem>span>.inboxacts{order:1}
/* A phone column: the time over the words, the OK after them, not a 110px column of both (2026-11-02). */
@container (max-width:600px){
  .inbox .inboxitem{flex-wrap:wrap;align-items:flex-start;row-gap:0}
  .inbox .inboxitem>span>.hint{flex-basis:100%}
  .inbox .inboxitem>span>a{min-width:0;overflow-wrap:anywhere}
}
.inbox .inboxearlier{margin:0;border-top:1px solid var(--line-soft)}
.inbox .inboxearlier>summary{padding:var(--sp-2) var(--sp-3)}
.inbox>form{padding:var(--sp-2) var(--sp-3);margin:0;border-top:1px solid var(--line-soft)}
/* (end of track E) */
/* (track F: round two, shared) */
/* shell */ @media(max-width:900px){
  /* One page, one tab: a full-width block says nothing. */
  .navsolo .rail{display:none}
  .navsolo{padding-bottom:0}
} /* end shell */
/* A room tile is a link but reads as a tile: no underline between the number and the code. */
.roomcell,.roomcell:hover,.roomcell:focus,.roomcell *{text-decoration:none}
.roomcell:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
/* A page head is h2.sec, then an optional .lede; with no lede the next block still gets the gap. */
h2.sec+.lede{margin-top:calc(-1 * var(--sp-4) + 4px)}
/* (end of track F) */
/* (track G: round two, front office and records) */
/* The audit trail's own list. It was a `.daylist`, the board review's scroller, and inherited a card,
   an overflow and 72px of blank under every time on a phone. The 72px time column is a desktop one. */
@container (min-width:601px){.auditday .evtime{flex:0 0 72px}}
/* The shift log: search and day pick are one bar. */
.datenav{display:flex;flex-wrap:wrap;gap:var(--sp-2);align-items:center}
/* The date box stands in a row of small buttons: their height, not a form field's (it stood 14px over them). The chips under the bar keep a gap. */
.datenav .txt{padding-block:var(--sp-1)}
.datenav+.chiprow{margin-top:var(--sp-2)}
.datenav-day{min-width:7.5em;text-align:center}
.logbar>.datenav{margin-top:var(--sp-3);padding-top:var(--sp-3);border-top:1px solid var(--line-soft)}
/* Found items: the room select and the photo input need their own width, not a fifth of the row. */
@container (min-width:601px){
  .foundrow{grid-template-columns:220px minmax(0,1fr) minmax(0,1fr)}
  .foundrow .foundphoto{grid-column:1 / span 2}
}
.foundrow input[type=file]{width:100%;min-width:0}
/* A field that only shows a value (the checklist's department) reads as a field, not as an input. */
.logrow input.txt[readonly]{background:var(--line-soft);color:var(--muted);cursor:default}
/* The checklist line's note: its summary rides the right end of the item's title line instead of
   taking a row of its own (the last text line until 2026-11-01). Open (a required item left undone,
   or being written) it is in the flow. */
.clrow:not(:has(.paperpack)) .itemnote:not([open])>summary{position:absolute;right:0;top:13px;margin:0;padding:4px 0 4px var(--sp-3);line-height:1.3}
.clrow:not(.done):not(:has(.paperpack)):has(.itemnote:not([open])) .chk .lbl{padding-right:4em}
@container (max-width:600px){.clrow:not(:has(.paperpack)) .itemnote:not([open])>summary{top:2px;min-height:var(--hit);display:inline-flex;align-items:center}}
/* (end of track G) */
/* (track H: round two, housekeeping) */
/* Boards, "Housekeepers today": one line per person on a phone (name, floors, board), not a stacked card. */
@container (max-width:600px){
  #people table.stack tr{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:var(--sp-3);
    border:0;border-bottom:1px solid var(--line-soft);border-radius:0;margin:0;background:transparent}
  #people table.stack td{display:inline;padding:var(--sp-1) 0}
  #people table.stack td:first-child{flex:0 0 100%}
  #people table.stack td::before{content:none!important}
}
/* Housekeeping report, discrepancies: one card, each open item ruled off from the last. */
.dsccard .dsc{padding:var(--sp-3) 0;border-top:1px solid var(--line-soft)}
.dsccard .dsc:first-child{border-top:0;padding-top:0}
.dsccard .dsc:last-child{padding-bottom:0}
.dsccard>.closedlist{margin-top:var(--sp-2)}
/* (end of track H) */

/* (track S: off-nav sweep) */
.sheethead>.spread>div>h3.sub:first-child{margin-bottom:var(--sp-1)}
h2.sec>.hint{font-weight:500}
/* (end of track S) */

/* ---------- blue, white and one sky (2026-10-31, DECISIONS.md § Blue, white and one sky) ---------- */
/* The phone's current tab: white words on the bar and a sky rule along its top edge. The brass
   fill it replaces was white on brass at 3.95:1 and the shape of the page's buttons (question 34). */
/* shell */ @media(max-width:900px){
  .railbtn[aria-current="page"]{background:var(--accent-on-rail);color:var(--on-fill);border-radius:0;box-shadow:inset 0 3px 0 var(--accent);font-weight:700}
  .railbtn[aria-current="page"] .glyph{color:var(--accent)}
} /* end shell */
/* You are here, said in sky everywhere it applies (the owner, 2026-10-31: "a clear sign").
   The rail's current page is a white sheet with a sky icon and heavier words; the phone's current
   tab is tinted sky with a sky rule on its top edge and a sky icon; the More sheet's current item
   the same; the room in hand on her board is a 2px sky frame and its row on the list a sky wash;
   on the room page, the next unticked line is washed in sky with a sky box, so the eye lands on
   what to do now. Nothing here is a button's colour: sky never means "press me". */
.mbnext .mbnextnum{color:var(--ink)}
.mbsheet .mbrow:has(.mbflag.now){background:var(--accent-soft)}
.chkline:not(.on):not(.chkline:not(.on) ~ .chkline){background:var(--accent-soft);border-radius:var(--r-input);
  box-shadow:0 0 0 6px var(--accent-soft)}
.chkline:not(.on):not(.chkline:not(.on) ~ .chkline) .mark{border:2px solid var(--accent)}
/* A score under the standard is short of it, not on its way: amber, not the progress sky. */
.meter.short span{background:var(--amber)}
/* (end of blue, white and one sky) */


/* (maintenance: assets) The Assets tab of the Maintenance mock. A card per asset, its last figures as a
   ruled list, a sparkline per reading drawn from the model's own coordinates: the range a neutral band,
   the line the accent, a reading outside the range a red point. Red marks a problem, amber a log owed. */
.assetcard h3{margin:0 0 var(--sp-1);font-size:var(--fs-3)}
.assetcard.risk{border-color:var(--flag-line)}
.assetcard .where{font-size:var(--fs-1);color:var(--muted);margin:0 0 var(--sp-2)}
.mlist{list-style:none;margin:0;padding:0;font-size:var(--fs-2)}
.mlist li{display:flex;justify-content:space-between;gap:var(--sp-2);padding:3px 0;border-top:1px solid var(--line-soft)}
.mlist li:first-child{border-top:0}
.mlist .v{font-variant-numeric:tabular-nums;font-weight:600;text-align:right}
.mlist .v.bad{color:var(--flag-deep)}
.mlist .v.miss{color:var(--amber-ink)}
.unit{font-size:var(--fs-1);color:var(--muted);font-weight:500}
.spark{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--sp-2)}
.sp{display:grid;grid-template-columns:minmax(120px,1fr) auto;gap:var(--sp-1) var(--sp-3);align-items:center;padding:var(--sp-2) 0;border-top:1px solid var(--line-soft)}
.sp:first-child{border-top:0}
.sp .nm{font-weight:600;font-size:var(--fs-2)}
.sp .last{font-size:var(--fs-1);color:var(--muted);font-variant-numeric:tabular-nums}
.sp .last b{color:var(--ink)}
.sp .last b.bad{color:var(--flag-deep)}
.sp svg{width:100%;max-width:360px;height:40px;display:block;grid-column:1/-1}
.spark-band{fill:var(--line-soft)}
.spark-line{fill:none;stroke:var(--accent);stroke-width:2;stroke-linejoin:round;stroke-linecap:round}
.spark-dot{fill:var(--flag);stroke:var(--card);stroke-width:2}
.assettrail{list-style:none;margin:0;padding:0;font-size:var(--fs-2)}
.assettrail li{padding:var(--sp-1) 0;border-top:1px solid var(--line-soft)}
.assettrail li:first-child{border-top:0}
.assettrail li.bad{color:var(--flag-deep)}
/* (end of maintenance: assets) */
/* Values the model computes, as attribute rules, so no style="" is needed (the CSP has no 'unsafe-inline').
   A row's stripe is one of the colour tokens MyBoardRow.StripeVar returns; after a.mbrow:hover so a hover keeps it.
   A meter's fill starts empty: page.js sets the width from data-w, so without script a bar reads as 0, not full. */
a.mbrow[data-stripe="--accent"]{border-left-color:var(--accent)}
a.mbrow[data-stripe="--gold"]{border-left-color:var(--gold)}
a.mbrow[data-stripe="--verde"]{border-left-color:var(--verde)}
a.mbrow[data-stripe="--amber"]{border-left-color:var(--amber)}
a.mbrow[data-stripe="--flag"]{border-left-color:var(--flag)}
a.mbrow[data-stripe="--muted-2"]{border-left-color:var(--muted-2)}
a.mbrow[data-stripe="--line"]{border-left-color:var(--line)}
.bignum[data-ink="--flag"]{color:var(--flag)}
.bignum[data-ink="--ink"]{color:var(--ink)}
.meter span[data-w],.rbtrack i[data-w]{width:0}
