/* BesenPose app. Tokens and components from design/besenpose-app/rev-b.html: one chain of radii,
   each derived from the one inside it (inner radius + padding = outer radius), light and dark.
   The gap between two edges is padding + border (--bw), so the border is part of every derivation. */
/* registered so that JS reads it as plain px (app.js planRadius: plan.js draws the house's corner with it) */
@property --r-inplan { syntax: "<length>"; inherits: true; initial-value: 0px; }
:root {
  --bw: 1px;
  /* spacing: inside a group, between the items of a screen, before a new section */
  --gap-xs: 4px; --gap-s: 8px; --gap: 14px; --gap-l: 24px;
  --r-ctl: 12px; --pad-card: 14px; --pad-btn-sm: 12px; --h-btn-sm: 36px; --seg-pad: 3px; --h-tap: 44px;
  --mk: 12px;    /* a device marker, centred in a list row's icon tile; the carried chip derives its radius from it */
  --r-card: calc(var(--r-ctl) + var(--pad-card) + var(--bw));
  --gutter: 16px; --form-w: 480px; --page-w: 720px;
  /* the floating tab bar, the same as the Besendorf app's (design/RULES.md): fully rounded ends (radius = half its
     height) and a fully rounded current tab concentric with it; at most 600 px wide; on the safe area or --tab-inset
     above the bottom, whichever is more */
  --tab-inset: 12px; --tab-h: 66px; --tab-pad: 6px; --tab-w: min(calc(100vw - 2 * var(--tab-inset)), 600px);
  --tab-bottom: max(var(--tab-inset), env(safe-area-inset-bottom));
  --r-tabbar: calc(var(--tab-h) / 2); --r-tabitem: calc(var(--r-tabbar) - var(--tab-pad) - var(--bw));
  --r-tab: 32px;   /* the bars and cards of the dock above it (recording, update, leave question) */
  --rec-pad: 8px; --r-recitem: calc(var(--r-tab) - var(--rec-pad));
  --dock-pad: 10px; --r-dockitem: calc(var(--r-tab) - var(--dock-pad));   /* the dock's card: its buttons and chips sit --dock-pad inside its corner */
  --plan-pad: 10px; --r-inplan: calc(var(--r-card) - var(--plan-pad) - var(--bw));
  --sheet-inset: 8px; --r-sheet: 34px; --pad-sheet: 14px; --r-insheet: calc(var(--r-sheet) - var(--pad-sheet) - var(--bw));
  --inblock-pad: 12px; --r-inblockctl: calc(var(--r-insheet) - var(--inblock-pad));
  --h-lrow: 52px; --ic: 30px;   /* a list row's least height, the icon tile at its start */
  --r-mk: calc(var(--r-ctl) - (var(--ic) - var(--mk)) / 2);
  --avatar: 34px; --pad-person: 8px; --r-person: calc(var(--avatar) / 2 + var(--pad-person));
  --bg: #F4F2EE; --surface: #FFFFFF; --surface-2: #F0EEE9; --ink: #16171A; --ink-2: #55534F; --ink-3: #75726C; --line: #E2DED6; --glass: rgba(255,255,255,.82);
  --wallc: #CFCAC0; --floor: #FFFFFF; --fixf: #ECE9E2; --hatchfill: url(#hatch-l);
  --accent: #F29A2E; --accent-ink: #8F4B05; --on-accent: #1E1405; --accent-wash: rgba(242,154,46,.16);
  --act: #2F66D0; --act-wash: rgba(47,102,208,.16); --on-act: #FFFFFF;
  --good: #1B7A4A; --good-wash: rgba(27,122,74,.12); --bad: #C0362F; --bad-wash: rgba(192,54,47,.10); --hatch: rgba(22,23,26,.10);
  --sans: "Hanken Grotesk", -apple-system, "SF Pro Text", "Segoe UI", sans-serif;
  --display: "Bricolage Grotesque", "Hanken Grotesk", -apple-system, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, Menlo, monospace;
  color-scheme: light;
}
@media (prefers-color-scheme: dark) { :root {
  --bg: #0E1014; --surface: #181B21; --surface-2: #20242B; --ink: #ECEEF2; --ink-2: #AAB0BA; --ink-3: #868D98; --line: #2A2F38; --glass: rgba(24,27,33,.82);
  --wallc: #3A414C; --floor: #20242B; --fixf: #2B313B; --hatchfill: url(#hatch-d);
  --accent: #FFA23C; --accent-ink: #FFB766; --on-accent: #1E1405; --accent-wash: rgba(255,162,60,.15);
  --act: #7FA8FF; --act-wash: rgba(127,168,255,.18); --on-act: #0B1430;
  --good: #4CD48D; --good-wash: rgba(76,212,141,.13); --bad: #FF6E64; --bad-wash: rgba(255,110,100,.13); --hatch: rgba(236,238,242,.10);
  color-scheme: dark; } }
* { box-sizing: border-box; }
html, body { margin: 0; background: var(--bg); color: var(--ink); font: 15px/1.45 var(--sans); -webkit-font-smoothing: antialiased; height: 100%; }
/* springy scrolling everywhere (design/RULES.md): the page and every scroll view bounce; only chaining is stopped
   (overscroll-behavior: contain on the sheets), never the bounce itself */
button, input { font: inherit; color: inherit; }
/* The page never zooms, by pinch or by double tap: a pinch that touched a button, the sheet or the tab bar used to
   shrink the whole page (on House the map owns the gestures). touch-action narrows down the tree, so pan-x pan-y
   on the root leaves fingers only scrolling; app.js blocks Safari's gesture events too. */
html, body, a, button, input, select, label, .lrow, .sheet, .scr, .dock, .tabbar { touch-action: pan-x pan-y; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
[hidden] { display: none !important; }
p { margin: 0; }   /* spacing comes from the grids' gaps, never from paragraph margins */
[data-err]:empty, [data-userdetail]:empty { display: none; }   /* an empty slot (no error, nobody picked) takes no row and no gap */
#app { max-width: var(--page-w); margin: 0 auto; min-height: 100dvh; position: relative; }
/* the bottom padding clears the floating tab bar, plus a section's breathing room */
.scr { padding: calc(env(safe-area-inset-top) + 10px) var(--gutter) calc(var(--tab-h) + var(--tab-bottom) + var(--gap-l) + var(--dock-h, 0px)); display: grid; align-content: start; gap: var(--gap); }
.scr.noTabs { padding-bottom: calc(var(--gap-l) + env(safe-area-inset-bottom)); max-width: var(--form-w); margin-inline: auto; }
/* a section title sits closer to what it names than to what came before */
.scr > .t-sec, .sec > .t-sec { margin-top: calc(var(--gap-l) - var(--gap)); margin-bottom: calc(var(--gap-s) - var(--gap)); }
.sec { display: grid; gap: var(--gap); }
/* from 900 px desk.js draws the app (desk.css); the screens before it (the signed-out page, an error) stay in a wider column */
@media (min-width: 900px) { #app { max-width: 1100px; } }

.t-large { font: 750 30px/1.08 var(--display); letter-spacing: -.02em; }
.t-title { font: 650 20px/1.2 var(--display); letter-spacing: -.01em; }
.t-sec { font: 700 12px/1 var(--sans); letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.t-small { font: 500 13px/1.35 var(--sans); color: var(--ink-2); }
.hint { font: 500 12.5px/1.35 var(--sans); color: var(--ink-3); } .hint.bad { color: var(--bad); } .hint.good { color: var(--good); }
.mono { font-family: var(--mono); }
.row { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
/* a title row with its button stays on one line at every width and in every language */
.titlerow > .t-title, .titlerow > .btn { white-space: nowrap; }
.titlerow > .btn { flex: none; }

.btn { font: 650 16px/1.2 var(--sans); min-height: 50px; padding: var(--gap-xs) 18px; text-wrap: balance; border-radius: var(--r-ctl); border: 1px solid var(--line); background: var(--surface); color: var(--ink); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 8px; width: 100%; transition: background .12s, transform .06s; }
.btn svg { width: 20px; height: 20px; }
.btn > span { min-width: 0; text-align: start; }   /* a label that wraps stays one group with its icon */
.btn:active { transform: scale(.985); }
.btn.primary { background: var(--accent); border-color: transparent; color: var(--on-accent); }
.btn.danger { color: var(--bad); }
.btn.quiet { border-color: transparent; background: none; color: var(--accent-ink); min-height: 40px; }
.row > .btn.quiet:last-child { margin-inline-end: calc(-1 * var(--pad-btn-sm)); }   /* its label, not its tap area, lines up with the edge */
.btn.sm { min-height: var(--h-btn-sm); font-size: 14px; padding: 0 var(--pad-btn-sm); width: auto; }
/* small controls keep their look; an invisible box makes the tap area at least --h-tap in both directions */
.btn.sm, .btn.quiet, .iconbtn, .chip { position: relative; }
.btn.sm::after, .btn.quiet::after, .iconbtn::after, .chip::after { content: ""; position: absolute; inset: min(0px, calc((100% - var(--h-tap)) / 2)); }
.btn:disabled { background: var(--surface-2); color: var(--ink-3); border-color: var(--line); cursor: not-allowed; transform: none; }
/* a request on its way (app.js busyButton): the button keeps its look and size, its label gives way to a spinner */
[aria-busy="true"] { position: relative; color: transparent !important; cursor: progress; }
[aria-busy="true"].btn:disabled { background: var(--surface); border-color: var(--line); } [aria-busy="true"].btn.primary:disabled { background: var(--accent); border-color: transparent; }
[aria-busy="true"] > * { visibility: hidden; }
[aria-busy="true"]::before { content: ""; position: absolute; inset: 0; margin: auto; width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--spin, var(--ink-2)); border-right-color: transparent; animation: spin .7s linear infinite; }
.btn.primary { --spin: var(--on-accent); } .btn.danger, .iconbtn.danger { --spin: var(--bad); } .recbar, .reccard { --spin: var(--bg); }
@keyframes spin { to { rotate: 360deg; } }
@media (prefers-reduced-motion: reduce) { [aria-busy="true"]::before { animation-duration: 1.6s; } }
.field { display: grid; gap: 6px; } .field label { font: 600 13px var(--sans); color: var(--ink-2); }
.input { height: 50px; border-radius: var(--r-ctl); border: 1px solid var(--line); background: var(--surface); color: var(--ink); padding: 0 14px; font: 16px var(--sans); width: 100%; }
.input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-wash); }
.input[aria-invalid="true"] { border-color: var(--bad); box-shadow: 0 0 0 3px var(--bad-wash); }
.input.sm { height: 40px; font-size: 16px; }   /* 16px: smaller makes iPhone Safari zoom in on focus */
select.input { appearance: none; -webkit-appearance: none; padding-right: 40px; cursor: pointer; background: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%) calc(100% - 21px) 50% / 6px 6px no-repeat, linear-gradient(135deg, var(--ink-3) 50%, transparent 50%) calc(100% - 15px) 50% / 6px 6px no-repeat, var(--surface); }
.inblock .input { border-radius: var(--r-inblockctl); }
.seg { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; background: var(--surface-2); border-radius: var(--r-ctl); padding: var(--seg-pad); gap: var(--seg-pad); }
.seg button { font: 600 14px/1 var(--sans); color: var(--ink-2); background: none; border: 0; height: var(--h-tap); border-radius: calc(var(--r-ctl) - var(--seg-pad)); cursor: pointer; display: inline-flex; gap: 6px; align-items: center; justify-content: center; }
.seg button[aria-pressed="true"] { background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px rgba(0,0,0,.14); }
.seg .ct { font: 600 11px/1 var(--mono); background: var(--act); color: var(--on-act); border-radius: 99px; padding: 3px 6px; }
.card-p { background: var(--surface); border-radius: var(--r-card); padding: var(--pad-card); display: grid; gap: 12px; border: var(--bw) solid var(--line); }
.card-p.who { --avatar: 52px; border-radius: calc(var(--avatar) / 2 + var(--pad-card) + var(--bw)); }   /* the card's corner follows the avatar's circle */
/* the 30px icon tiles sit as far from the list's top and bottom as from its side (--pad-card inside the border),
   so the corner stays concentric with theirs: the row centres the tile, the list adds the rest */
.list { background: var(--surface); border-radius: var(--r-card); border: var(--bw) solid var(--line); padding: calc(var(--pad-card) - (var(--h-lrow) - var(--ic)) / 2) var(--pad-card); display: grid; }
/* the separator is drawn inside the row, so every row centres its icon in the full --h-lrow */
.lrow { display: flex; gap: 12px; align-items: center; min-height: var(--h-lrow); border: 0; box-shadow: inset 0 calc(-1 * var(--bw)) var(--line); background: none; color: inherit; text-align: left; width: 100%; padding: 6px 0; }
.lrow:last-child { box-shadow: none; } button.lrow, a.lrow { cursor: pointer; } a.lrow { text-decoration: none; }
/* the accounts list: its corners follow the first and last avatar, which sit as far from the top as from the side
   (the row's min-height already holds its padding, so only the centring gap comes off) */
.list[data-users] { --avatar: 38px; border-radius: calc(var(--avatar) / 2 + var(--pad-card) + var(--bw)); padding-block: calc(var(--pad-card) - (var(--h-lrow) - var(--avatar)) / 2); }
.lrow .ic { width: var(--ic); height: var(--ic); border-radius: var(--r-ctl); display: grid; place-items: center; background: var(--surface-2); color: var(--ink-2); flex: none; }
.lrow .ic svg { width: 18px; height: 18px; }
.lrow .tx { flex: 1; min-width: 0; display: grid; gap: 1px; }
.lrow .tx > * { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }   /* rows of one list are one height: one line each, the rest an ellipsis */
.lrow.msg .tx > * { white-space: normal; }   /* an error or a notice is said in full (a list's only row) */
.lrow .tx b { font: 600 15px/1.25 var(--sans); } .lrow .tx span { font: 500 13px/1.3 var(--sans); color: var(--ink-3); }
.lrow .end { color: var(--ink-3); font: 500 14px var(--sans); display: flex; align-items: center; gap: 6px; flex: none; }
.live { display: inline-flex; align-items: center; gap: 6px; font: 600 12.5px/1 var(--sans); color: var(--ink-2); background: var(--surface); border: 1px solid var(--line); padding: 7px 10px 7px 8px; border-radius: 99px; }
.live i { width: 8px; height: 8px; border-radius: 50%; background: var(--good); box-shadow: 0 0 0 3px var(--good-wash); }
.live.off i { background: var(--ink-3); box-shadow: none; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip { font: 600 13px/1 var(--sans); padding: 9px 12px; border-radius: var(--r-ctl); background: var(--surface-2); color: var(--ink); border: 1px solid transparent; cursor: pointer; display: inline-flex; gap: 6px; align-items: center; }
.chip[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-wash); color: var(--accent-ink); }
.chip.add { background: none; border-color: var(--line); color: var(--ink-2); }
.chip i { width: 8px; height: 8px; border-radius: 50%; background: var(--act); }
.pill { font: 650 12px/1 var(--sans); padding: 6px 9px; border-radius: 99px; display: inline-flex; gap: 5px; align-items: center; width: max-content; }
.pill.act { background: var(--act); color: var(--on-act); } .pill.recent { background: var(--act-wash); color: var(--ink); } .pill.quiet { background: var(--surface-2); color: var(--ink-2); } .pill.off { background: var(--hatch); color: var(--ink-2); }
.pill.home { background: var(--good-wash); color: var(--good); } .pill.away { background: var(--surface-2); color: var(--ink-3); } .pill.admin { background: var(--accent-wash); color: var(--accent-ink); } .pill.warn { background: var(--bad-wash); color: var(--bad); }
.people { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 8px; }
.person { display: grid; justify-items: start; gap: 8px; padding: var(--pad-person); border-radius: var(--r-person); background: var(--surface); border: 1px solid var(--line); }
.av { width: var(--avatar); height: var(--avatar); aspect-ratio: 1; border-radius: 50%; overflow: hidden; display: grid; place-items: center; font: 700 15px/1 var(--display); color: #fff; position: relative; flex: none; }
.av.away { filter: grayscale(1); opacity: .55; }
.av.big { font-size: 22px; }   /* the size is the card's --avatar (.card-p.who) */
.av img, .dme img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: inherit; object-fit: cover; }   /* same box, same radius */
.person b { font: 650 14.5px/1.1 var(--sans); padding-inline: 2px; } .person span { font: 500 12.5px/1.2 var(--sans); color: var(--ink-3); padding: 0 2px 2px; }
/* who is home (House): avatars side by side in a pill whose corner is concentric with the avatars' circle */
.homerow { --avatar: 26px; --pad-home: 4px; display: flex; align-items: center; gap: 8px; width: max-content; max-width: 100%;
  padding: var(--pad-home) 12px var(--pad-home) var(--pad-home); border: var(--bw) solid var(--line); background: var(--surface);
  border-radius: calc(var(--avatar) / 2 + var(--pad-home) + var(--bw)); }
.homerow .avs { display: flex; flex: none; }
.homerow .av { font-size: 12px; box-shadow: 0 0 0 2px var(--surface); }
.homerow .av + .av { margin-left: -6px; }
.homerow .tx { font: 600 13.5px/1.2 var(--sans); color: var(--ink-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rm { cursor: pointer; } .rm > * { transition: fill .25s; }
.rm:focus-visible { outline: none; } .rm:focus-visible .zr { stroke: var(--accent); stroke-width: 8; }
.rm[aria-pressed="true"] .zr { stroke: var(--ink); stroke-width: 6; }
.spot { cursor: pointer; } .spot:focus-visible { outline: none; } .spot:focus-visible .sc, .spot[aria-pressed="true"] .sc { stroke: var(--accent); stroke-width: 9; }
.spot[data-draggable] { cursor: grab; }
.legend { display: flex; flex-wrap: wrap; gap: 12px; padding: 2px 4px 2px; font: 500 12px/1 var(--sans); color: var(--ink-3); }
.legend span { display: inline-flex; gap: 6px; align-items: center; } .legend i { width: 12px; height: 12px; border-radius: 4px; display: inline-block; }
.legend i.hx { background: repeating-linear-gradient(45deg, var(--floor) 0 3px, var(--wallc) 3px 5px); box-shadow: inset 0 0 0 1px var(--line); }
/* the room model's "how sure" tint (plan.js fillOf: the "now" colour at up to 40 %) */
.legend i.pg { width: 22px; background: linear-gradient(90deg, var(--floor), color-mix(in oklab, var(--act) 40%, var(--floor))); box-shadow: inset 0 0 0 1px var(--line); }
.legend i.sp { border-radius: 50%; background: var(--surface); box-shadow: inset 0 0 0 2px var(--ink-2); }
.legend i.ly { width: 11px; height: 11px; border-radius: 3px; background: var(--ink); }
.legend i.dv { width: 10px; height: 10px; border-radius: 3px; background: var(--surface); box-shadow: inset 0 0 0 2px var(--ink-2); }
.legend i.sn { width: 8px; height: 8px; border-radius: 2px; background: var(--accent); box-shadow: inset 0 0 0 1.5px var(--accent-ink); transform: rotate(45deg); margin: 0 2px; }
.chips.outside { align-items: center; padding: 0 4px; }
/* devices: the side panel next to the plan while placing (desktop only), the router's client list, and a
   device being carried onto the plan */
.devpanel { align-content: start; }
.devrow .tx { background: none; border: 0; padding: 0; text-align: left; cursor: pointer; }
.devrow .end { gap: var(--gap-xs); }
/* the row's buttons are icon tiles like the one at its start, so both share the list's corner centre */
.devrow .iconbtn { width: var(--ic); height: var(--ic); border-radius: var(--r-ctl); }
.devrow[data-carry] { cursor: grab; user-select: none; -webkit-user-select: none; }
.devrow[aria-selected="true"] .tx b { color: var(--accent-ink); }
.mk { width: var(--mk); height: var(--mk); border-radius: var(--r-mk); flex: none; display: inline-block; }
.mk.ly { background: var(--ink); } .mk.dv { background: var(--surface); box-shadow: inset 0 0 0 2px var(--ink-2); }
.mk.sn { width: 9px; height: 9px; border-radius: 2px; background: var(--accent); box-shadow: inset 0 0 0 1.5px var(--accent-ink); transform: rotate(45deg); margin: 0 2px; }
.iconbtn.sm { width: 32px; height: 32px; } .iconbtn.sm svg { width: 16px; height: 16px; }
.iconbtn.danger { color: var(--bad); } .iconbtn.back svg { transform: scaleX(-1); }
.list.insheet { --pad-card: var(--inblock-pad); border-radius: var(--r-insheet); max-height: 50dvh; overflow: auto; }
.list.insheet .lrow .ic { border-radius: calc(var(--r-insheet) - var(--pad-card) - var(--bw)); }
button.lrow:disabled { cursor: default; } button.lrow:disabled .tx b { color: var(--ink-3); }
/* The ring is a shadow, not a border, and the 14px line box is 1px taller than the 12px marker on each side:
   so the marker sits --carry-pad in from every edge and the chip's corner shares the marker's centre. */
.carry { --carry-pad: 9px; position: fixed; left: 0; top: 0; z-index: 70; pointer-events: none; display: inline-flex; align-items: center; gap: 8px; padding: calc(var(--carry-pad) - 1px) 12px calc(var(--carry-pad) - 1px) var(--carry-pad); border-radius: calc(var(--r-mk) + var(--carry-pad)); background: var(--surface); font: 600 14px/1 var(--sans); box-shadow: inset 0 0 0 1px var(--accent), 0 8px 24px rgba(0,0,0,.18); white-space: nowrap; }
body.carrying, body.carrying * { cursor: grabbing !important; }
.now { display: flex; gap: 12px; align-items: center; }
.now .pulse { width: 42px; height: 42px; border-radius: var(--r-ctl); background: var(--act); color: var(--on-act); display: grid; place-items: center; flex: none; }
.now .pulse svg { width: 22px; height: 22px; }
.now .tx { display: grid; gap: 2px; min-width: 0; } .now .tx b { font: 650 16px/1.25 var(--sans); } .now .tx span { font: 500 13px/1.3 var(--sans); color: var(--ink-3); }
.surerow { display: flex; align-items: center; gap: 10px; } .surerow .sure { flex: 1; } .surerow .mono { font: 600 13px/1 var(--mono); color: var(--ink-2); min-width: 4.5ch; text-align: right; font-variant-numeric: tabular-nums; }
.inblock .sure { background: var(--surface); }
.qline { display: flex; gap: 8px; align-items: baseline; } .qdot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--ink-3); transform: translateY(-1px); }
.qdot.home { background: var(--good); } .qdot.admin { background: var(--accent); } .qdot.warn { background: var(--bad); }
/* the model card's room list and button sit in the card's padding: their corner is the card's minus that padding */
.card-p > .list.inside, .card-p > .btn.sm:last-child { border-radius: calc(var(--r-card) - var(--pad-card) - var(--bw)); }
.sure { height: 6px; border-radius: 3px; background: var(--surface-2); overflow: hidden; } .sure i { display: block; height: 100%; background: var(--act); border-radius: 3px; transition: width .4s; }
.surerow { display: flex; align-items: center; gap: 10px; } .surerow .sure { flex: 1; } .surerow .pct { font: 600 12px/1 var(--mono); color: var(--ink-3); min-width: 4ch; text-align: right; font-variant-numeric: tabular-nums; }

.tabbar { position: fixed; left: 50%; transform: translateX(-50%); width: var(--tab-w); bottom: var(--tab-bottom); height: var(--tab-h); padding: var(--tab-pad); border-radius: var(--r-tabbar); background: var(--glass); backdrop-filter: blur(18px) saturate(1.4); -webkit-backdrop-filter: blur(18px) saturate(1.4); border: var(--bw) solid var(--line); display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 2px; box-shadow: 0 10px 30px rgba(0,0,0,.16); z-index: 20; }
.tab { border: 0; background: none; border-radius: var(--r-tabitem); display: grid; place-items: center; align-content: center; gap: 4px; font: 600 11px/1 var(--sans); color: var(--ink-2); cursor: pointer; }
.tab:hover { color: var(--ink); }
.kbd .tabbar, .kbd .tabfade { display: none; }
.tab svg { width: 23px; height: 23px; } .tab[aria-current="page"] { background: var(--accent-wash); color: var(--accent-ink); }

.scrim { touch-action: none; overscroll-behavior: contain; position: fixed; inset: 0; background: rgba(0,0,0,.28); z-index: 30; border: 0; cursor: pointer; }
.sheet { position: fixed; left: 50%; transform: translateX(-50%); width: calc(min(100vw, 720px) - 2 * var(--sheet-inset)); bottom: calc(var(--sheet-inset) + env(safe-area-inset-bottom)); border-radius: var(--r-sheet); background: var(--surface); border: var(--bw) solid var(--line); padding: var(--pad-sheet); display: grid; gap: 12px; z-index: 40; box-shadow: 0 -10px 40px rgba(0,0,0,.22); max-height: 90dvh; overflow: auto; overscroll-behavior: contain; }
html:has(.sheet), html:has(.sheet) body { overflow: hidden; }   /* the page behind a sheet never scrolls */
/* the grab floats over the top padding, so the header starts at the sheet's inset and its corner button can follow the curve */
.sheet .grab, .msheet .grab { position: absolute; top: 6px; left: 50%; translate: -50% 0; width: 38px; height: 5px; border-radius: 3px; background: var(--line); }
.sheet .hd, .msheet .hd { display: flex; align-items: center; gap: 10px; } .sheet .hd .t-title, .msheet .hd .t-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
/* the header's buttons: a circle of --r-insheet, so the one in the top corner is concentric with the sheet */
.sheet .hd > .iconbtn, .msheet .hd > .iconbtn { width: calc(2 * var(--r-insheet)); height: calc(2 * var(--r-insheet)); } .sheet .hd > .iconbtn:last-child, .msheet .hd > .iconbtn:last-child { align-self: start; }
/* a button in the sheet's bottom corners follows the sheet's curve */
.sheet > .btn:last-child, .sheet > .btns2:last-child > .btn, .sheet > form:last-child > .btn:last-child { border-radius: var(--r-insheet); }
.sheet > .btn.sm:last-child, .sheet > .btns2:last-child > .btn.sm { min-height: max(var(--h-tap), calc(2 * var(--r-insheet))); }   /* tall enough to hold that corner */
/* and one in a block's bottom corners follows the block's */
.inblock > .btns2:last-child > .btn, .inblock > .btn:last-child { border-radius: var(--r-inblockctl); }
.iconbtn { width: 36px; height: 36px; border-radius: 50%; border: 0; background: var(--surface-2); color: var(--ink-2); display: grid; place-items: center; cursor: pointer; flex: none; }
.iconbtn svg { width: 18px; height: 18px; }
.inblock { background: var(--surface-2); border-radius: var(--r-insheet); padding: var(--inblock-pad); display: grid; gap: var(--gap-s); }
.btns2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.tl-ax { display: flex; justify-content: space-between; font: 500 11px/1 var(--mono); color: var(--ink-3); }

.mark svg { width: 64px; height: 64px; }
.toast { position: fixed; left: 50%; bottom: calc(var(--tab-h) + var(--tab-bottom) + var(--gap) + var(--dock-h, 0px)); transform: translateX(-50%); background: var(--ink); color: var(--bg); font: 600 14px/1 var(--sans); padding: 12px 16px; border-radius: 14px; box-shadow: 0 10px 30px rgba(0,0,0,.25); z-index: 60; animation: toast 2.6s ease forwards; pointer-events: none; white-space: nowrap; max-width: 92vw; overflow: hidden; text-overflow: ellipsis; }
@keyframes toast { 0% { opacity: 0; translate: 0 6px; } 10%, 85% { opacity: 1; translate: 0 0; } 100% { opacity: 0; } }
.banner { display: flex; gap: 12px; align-items: flex-start; padding: var(--pad-card); border-radius: var(--r-card); background: var(--surface); border: var(--bw) solid var(--line); }
.banner .ic { width: 36px; height: 36px; border-radius: var(--r-ctl); display: grid; place-items: center; flex: none; background: var(--surface-2); color: var(--ink-2); }
.banner .ic.bad { background: var(--bad-wash); color: var(--bad); } .banner .ic.rec { background: var(--accent-wash); color: var(--accent-ink); } .banner .ic svg { width: 20px; height: 20px; }
.banner .btn.sm { padding-inline: var(--gap-s); white-space: nowrap; }   /* two side by side stay one line each in the narrow side column */
.banner .tx { display: grid; gap: var(--gap-xs); flex: 1; min-width: 0; } .banner .tx > .btns2 { margin-top: var(--gap-xs); } .banner b { font: 650 15px/1.3 var(--sans); } .banner p { margin: 0; font: 500 13.5px/1.4 var(--sans); color: var(--ink-2); }
.switch { width: 51px; height: 31px; border-radius: 99px; border: 0; background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line); position: relative; cursor: pointer; flex: none; transition: background .15s; }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 27px; height: 27px; border-radius: 50%; background: #fff; box-shadow: 0 2px 4px rgba(0,0,0,.25); transition: transform .15s; }
.switch[aria-checked="true"] { background: var(--good); box-shadow: none; } .switch[aria-checked="true"]::after { transform: translateX(20px); }

/* recording: the dock above the tab bar holds the update notice and the recording bar, same inset and width as the
   tab bar; app.js sets --dock-h to its height so the page, the plan and toasts leave room for it */
.dock { position: fixed; left: 50%; transform: translateX(-50%); width: var(--tab-w); bottom: calc(var(--tab-bottom) + var(--tab-h) + var(--gap-s)); display: grid; gap: var(--gap-s); z-index: 20; }
.dock:empty { display: none; }
/* the bar's buttons sit --rec-pad inside its corner: r-recitem = r-tab - rec-pad */
.recbar { height: 64px; padding: var(--rec-pad) var(--rec-pad) var(--rec-pad) 16px; border-radius: var(--r-tab); background: var(--ink); color: var(--bg); display: flex; align-items: center; gap: 10px; box-shadow: 0 10px 30px rgba(0,0,0,.25); }
.recdot { width: 12px; height: 12px; border-radius: 50%; background: var(--accent); flex: none; animation: recpulse 1.3s ease-in-out infinite; }
.recdot.sm { width: 8px; height: 8px; animation: none; display: inline-block; }
@keyframes recpulse { 0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent) 55%, transparent); } 60% { box-shadow: 0 0 0 7px transparent; } }
@media (prefers-reduced-motion: reduce) { .recdot { animation: none; } }
.recbar .tx { flex: 1; min-width: 0; display: grid; gap: 2px; }
.recbar .tx b { font: 650 14.5px/1.2 var(--sans); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.recbar .tx > span { font: 500 12px/1.2 var(--sans); opacity: .75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.recbar .mono { font: 600 14.5px/1 var(--mono); }
.rbtn { height: 48px; border-radius: var(--r-recitem); padding: 0 14px; font: 650 14px/1 var(--sans); background: color-mix(in oklab, var(--bg) 16%, transparent); color: var(--bg); border: 0; cursor: pointer; flex: none; display: inline-flex; align-items: center; gap: 6px; }
.rbtn svg, .lbtn svg { width: 16px; height: 16px; flex: none; }
.rbtn.stop { background: var(--accent); color: var(--on-accent); }
.rbtn:disabled { opacity: .4; cursor: default; }
/* the update notice: same corner; its icon tile sits rec-pad + border inside it */
.updbar { min-height: 64px; display: flex; align-items: center; gap: 12px; padding: var(--rec-pad) 16px var(--rec-pad) var(--rec-pad); border-radius: var(--r-tab); background: var(--surface); border: var(--bw) solid var(--accent); box-shadow: 0 10px 30px rgba(0,0,0,.16); }
.updbar .ic { width: calc(64px - 2 * var(--rec-pad) - 2 * var(--bw)); height: calc(64px - 2 * var(--rec-pad) - 2 * var(--bw)); border-radius: calc(var(--r-tab) - var(--rec-pad) - var(--bw)); background: var(--accent-wash); color: var(--accent-ink); display: grid; place-items: center; flex: none; }
.updbar .tx { flex: 1; min-width: 0; display: grid; gap: 2px; } .updbar .tx b { font: 650 14.5px/1.25 var(--sans); } .updbar .tx span { font: 500 12.5px/1.3 var(--sans); color: var(--ink-2); }
/* the app's own update (appUpdBar): the same padding on every side, so the button and the X at the edge share the bar's
   corner centre: their size is the icon's, their radius the bar's minus the padding and the border */
.updbar.appupd { --appupd-in: calc(64px - 2 * var(--rec-pad) - 2 * var(--bw)); padding: var(--rec-pad); gap: var(--rec-pad); }
.updbar.appupd .tx b { font-size: 14px; text-wrap: balance; }
.updbar.appupd .btn.sm, .updbar.appupd .iconbtn { min-height: var(--appupd-in); height: var(--appupd-in); border-radius: calc(var(--r-tab) - var(--rec-pad) - var(--bw)); text-decoration: none; }
.updbar.appupd .iconbtn { width: var(--appupd-in); }
/* the leave question: same corner as the bar; its three big buttons (Still here, Pause, Stop: the icon over the word)
   sit rec-pad + border inside it (concentric) */
.leavebar { display: grid; gap: var(--rec-pad); padding: var(--rec-pad); border-radius: var(--r-tab); background: var(--surface); border: var(--bw) solid var(--accent); box-shadow: 0 10px 30px rgba(0,0,0,.16); }
.leavebar .tx { display: grid; gap: 2px; padding: 8px 10px 0; } .leavebar .tx b { font: 650 15px/1.25 var(--sans); text-wrap: balance; } .leavebar .tx span { font: 500 12.5px/1.3 var(--sans); color: var(--ink-2); }
.leavebar .row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--rec-pad); }
.lbtn { display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; min-height: 60px; border-radius: calc(var(--r-tab) - var(--rec-pad) - var(--bw)); padding: 6px 8px; font: 650 13.5px/1.2 var(--sans); text-align: center; text-wrap: balance; background: var(--surface-2); color: var(--ink); border: 0; cursor: pointer; }
.lbtn svg { width: 18px; height: 18px; }
.lbtn.left { background: var(--accent); color: var(--on-accent); }
.lbtn:disabled { opacity: .5; cursor: default; }
/* the dock's card (app.js recCard): recording on the ink, paused, Switch and the favorites on the surface (opaque: the
   map's sheet runs behind it). Everything in it
   sits --dock-pad inside its corner (r-dockitem = r-tab - dock-pad); the light card's outline is a shadow, so no border
   joins the derivation. Its rows: the head (icon tile or dot, what and how long, Cancel), the buttons, the favorites. */
.reccard { display: grid; gap: var(--gap-s); padding: var(--dock-pad); border-radius: var(--r-tab); background: var(--ink); color: var(--bg); box-shadow: 0 10px 30px rgba(0,0,0,.25); }
.reccard.light { background: var(--surface); color: var(--ink); box-shadow: 0 0 0 var(--bw) var(--line), 0 10px 30px rgba(0,0,0,.14); }
.rchd { display: flex; align-items: center; gap: 10px; min-height: var(--h-tap); padding-inline-start: calc(var(--r-dockitem) - 6px); }   /* the dot sits at the curve's centre */
.rchd:has(> .rcic) { padding-inline-start: 0; }
.rchd .tx { flex: 1; min-width: 0; display: grid; gap: 2px; }
.rchd .tx b { font: 650 15px/1.2 var(--sans); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rchd .tx > span { font: 500 12.5px/1.25 var(--sans); opacity: .75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rchd > .mono { font: 600 15px/1 var(--mono); font-variant-numeric: tabular-nums; padding-inline-end: calc(var(--r-dockitem) - 8px); }
.rcic { width: var(--h-tap); height: var(--h-tap); border-radius: var(--r-dockitem); display: grid; place-items: center; flex: none; background: var(--accent-wash); color: var(--accent-ink); }
.rcic svg { width: 18px; height: 18px; }
.rcbtns { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: var(--gap-s); }
.reccard .rbtn { height: var(--h-tap); border-radius: var(--r-dockitem); justify-content: center; padding: 0 10px; min-width: 0; white-space: nowrap; }
.reccard.light .rbtn { background: var(--surface-2); color: var(--ink); }
.reccard.light .rbtn.stop { background: var(--accent); color: var(--on-accent); }
.rchd > .rbtn { flex: none; }
/* the favorites: chips (icon and short name) in a row that scrolls sideways, clipped to the chips' own corner */
.favrow { display: flex; gap: var(--gap-s); overflow-x: auto; border-radius: var(--r-dockitem); scrollbar-width: none; overscroll-behavior-x: contain; }
.favrow::-webkit-scrollbar { display: none; }
.fchip { flex: none; display: inline-flex; align-items: center; gap: 7px; height: var(--h-tap); padding: 0 16px 0 14px; border-radius: var(--r-dockitem); border: 0; font: 650 14px/1 var(--sans); cursor: pointer; white-space: nowrap;
  background: color-mix(in oklab, var(--bg) 16%, transparent); color: var(--bg); }
.fchip svg { width: 16px; height: 16px; flex: none; } .fchip .mk { flex: none; }
.reccard.light .fchip { background: var(--surface-2); color: var(--ink); }
.fchip[aria-pressed="true"], .reccard.light .fchip[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); }
.fchip:disabled { opacity: .45; cursor: default; }
/* the scrubber of "when": a range from 10 minutes back (left) to now (right), and the button that answers with it */
.scrub { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--gap-s); }
.scrub input[type="range"] { width: 100%; height: var(--h-tap); margin: 0; accent-color: var(--accent); cursor: pointer; touch-action: none; }
.scrub .btn, .scrub .rbtn { font-variant-numeric: tabular-nums; white-space: nowrap; }
.inblock > .scrub .btn { border-radius: var(--r-inblockctl); }   /* in the block's right corners */
.reccard .scrub { padding-inline-start: calc(var(--r-dockitem) - 12px); }
/* a room or spot sheet's actions: Record beside the star, "Nobody here" under them (its bar while it runs) */
.recmain { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--gap-s); } .recmain.one { grid-template-columns: 1fr; }
.favbtn { width: auto; } .favbtn[aria-pressed="true"] { color: var(--accent-ink); border-color: var(--accent); background: var(--accent-wash); }
.nobody .row b { font: 650 15px/1.25 var(--sans); } .nobody .mono { font: 600 14px/1 var(--mono); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.nbar { height: 8px; border-radius: 4px; background: var(--surface); overflow: hidden; }
.nbar i { display: block; height: 100%; border-radius: 4px; background: var(--good); transition: width 1s linear; }
.nobody > .btn.sm { justify-self: start; }
.legend i.em { background: color-mix(in oklab, var(--good) 24%, var(--floor)); box-shadow: inset 0 0 0 1px var(--line); }
/* the Stop sheet ("when"): Just now the largest, the other answers rows at least 56 px, "Don't remember" apart */
.btn.big { min-height: 64px; font-size: 18px; } .btn.big svg { width: 22px; height: 22px; }
.whenlist { --h-lrow: 56px; } .whenlist .lrow .tx b { font: 600 16px/1.25 var(--sans); font-variant-numeric: tabular-nums; }
.whenlist .lrow .tx b span { font: inherit; color: var(--ink-2); }
.sheet > .apart { margin-top: calc(var(--gap-l) - 12px); }
@media (prefers-reduced-motion: reduce) { .nbar i, .msmore > * { transition: none; } }
.pill.rec { background: var(--accent-wash); color: var(--accent-ink); } .pill.rec i { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.chip.recchip { cursor: default; background: var(--accent-wash); color: var(--accent-ink); }
.recarea { display: grid; gap: var(--gap-s); } .recwho { display: flex; align-items: center; gap: 8px; }
.mk.sp { border-radius: 50%; background: var(--surface); box-shadow: inset 0 0 0 2px var(--ink-2); }
.recrow .end { gap: var(--gap-xs); } .recrow.gone .tx b { color: var(--ink-3); text-decoration: line-through; }
/* a spot's model under its room in the Model card, and the legend's "how sure at a spot" (a spot filled by its live p) */
.lrow.sub { padding-inline-start: 14px; }
.legend i.spp { border-radius: 50%; background: linear-gradient(90deg, var(--surface), var(--act)); box-shadow: inset 0 0 0 1.5px var(--ink-2); }
/* the span set by hand (app.js spanEditor): the bar is a control in the block (--r-inblockctl). Its bands sit --span-pad
   inside it: what was pressed (the wash) and the 10 minutes either side an edge may move out to (hatched); the part
   kept sits --kept-pad inside those, so each corner is the one around it minus the gap between them */
.endedit { --span-pad: 2px; --kept-pad: 3px; --r-band: calc(var(--r-inblockctl) - var(--span-pad)); --r-kept: max(0px, calc(var(--r-band) - var(--kept-pad))); }
.endspan { position: relative; height: 30px; border-radius: var(--r-inblockctl); background: var(--surface); }
.endspan > i { position: absolute; top: var(--span-pad); bottom: var(--span-pad); }
.endspan .room, .endspan .pressed, .endspan .kept { left: calc(var(--span-pad) + (100% - 2 * var(--span-pad)) * var(--a, 0)); width: calc((100% - 2 * var(--span-pad)) * (var(--b, 1) - var(--a, 0))); min-width: 2px; border-radius: var(--r-band); }
.endspan .room { background: repeating-linear-gradient(45deg, var(--surface) 0 4px, var(--line) 4px 6px); }
.endspan .pressed { background: linear-gradient(var(--act-wash), var(--act-wash)), var(--surface); }
.endspan .kept { top: calc(var(--span-pad) + var(--kept-pad)); bottom: calc(var(--span-pad) + var(--kept-pad)); border-radius: var(--r-kept); background: var(--act); transition: left .15s, width .15s; }
.endspan .mark { top: -3px; bottom: -3px; left: calc(var(--span-pad) + (100% - 2 * var(--span-pad)) * var(--at, 0)); width: 3px; translate: -50% 0; border-radius: 1.5px; background: var(--accent); box-shadow: 0 0 0 1.5px var(--surface-2); }
/* scrubbing: a drag on the bar moves the nearer edge (app.js scrubTo). The bar takes the gesture (no scroll from it);
   its hit area reaches 8px past it, and a knob marks each edge of the kept part. No transition while dragging. */
.endspan { touch-action: none; cursor: ew-resize; user-select: none; -webkit-user-select: none; }
.endspan::after { content: ""; position: absolute; inset: -8px 0; }
.endspan .knob { top: 50%; left: calc(var(--span-pad) + (100% - 2 * var(--span-pad)) * var(--at, 0)); width: 16px; height: 16px; translate: -50% -50%; border-radius: 50%; background: var(--surface); border: 2px solid var(--act); box-shadow: 0 1px 3px rgba(0,0,0,.25); }
.endspan.scrub .kept { transition: none; }
.endspan.scrub .knob { scale: 1.2; }
@media (prefers-reduced-motion: reduce) { .endspan .kept { transition: none; } }
.spanax { display: grid; white-space: nowrap; letter-spacing: -.02em; grid-template-columns: calc(var(--m) * 100%) 1fr 1fr calc(var(--m) * 100%); font: 500 10px/1 var(--mono); color: var(--ink-3); }
.spanax span:nth-child(n+3) { text-align: right; }
.edgerow { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 10em); align-items: center; gap: var(--gap-s); }
.edgerow + .edgerow { margin-top: var(--gap-xs); }
.edgerow .nudges { grid-column: 1 / -1; }
.endedit .input { font-family: var(--mono); font-variant-numeric: tabular-nums; }
/* iPhone Safari draws time fields its own way (grey pill, centred, its own height): make them look like every other field */
.endedit input[type="time"] { -webkit-appearance: none; appearance: none; min-width: 0; display: flex; align-items: center; text-align: left; }
.endedit input[type="time"]::-webkit-date-and-time-value { text-align: left; margin: 0; }
.nudges { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--gap-s); }
.nudges .btn.sm { width: 100%; padding-inline: 4px; border-radius: var(--r-inblockctl); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* a text button inside a sentence (the leave question's "another time?") */
.lnk { border: 0; background: none; padding: 0; font: inherit; color: var(--accent-ink); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; position: relative; }
.lnk::after { content: ""; position: absolute; inset: -12px -6px; }

/* ---------- sheets move: they slide in, follow a drag (app.js sheetMove) and settle or fly off ---------- */
@keyframes sheetin { from { translate: 0 calc(100% + 24px); } }
@keyframes fadein { from { opacity: 0; } }
.sheet { animation: sheetin .34s cubic-bezier(.2, .8, .2, 1); } .scrim { animation: fadein .25s ease; }
.sheet.settle { transition: translate .28s cubic-bezier(.2, .8, .2, 1); } .scrim.out { opacity: 0; transition: opacity .26s; }
.sheet .grab, .sheet .hd { touch-action: none; }   /* the drag handles: a finger there moves the sheet, not its scroll */
.sheet .grab::after, .msheet .grab::after { content: ""; position: absolute; inset: -6px -40px -10px; }   /* a grab big enough to take */

/* ---------- the phone's House (app.js mapView, below 900 px): the plan is the screen ----------
   Layers: the map, the floating floor switch and live pill, the sheet (15), the tab bar's blur (18), the dock and
   the tab bar (20), sheets of their own (30, 40). */
html:has(.mapview), html:has(.mapview) body { overflow: hidden; height: 100%; }   /* the map owns the gestures; its sheet scrolls */
/* its padding is the safe areas, which app.js reads (safe()) */
.mapview { position: fixed; inset: 0; padding: env(safe-area-inset-top) 0 env(safe-area-inset-bottom); background: var(--bg); }
.map { position: absolute; inset: 0; overflow: hidden; touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; }
.mapin { position: absolute; transform-origin: 0 0; }
.mapin > svg { display: block; width: 100%; height: auto; }
.map.moving svg { cursor: crosshair; }
.map .spot[data-draggable] { touch-action: none; }
/* floating controls: glass on the map */
.maptop { position: absolute; z-index: 10; top: calc(env(safe-area-inset-top) + 10px); left: var(--gutter); right: var(--gutter); display: flex; justify-content: space-between; align-items: flex-start; gap: var(--gap-s); pointer-events: none; }
.maptop > * { pointer-events: auto; }
.maptop .seg, .maptop .live, .mapfit { background: color-mix(in oklab, var(--surface) 80%, transparent); -webkit-backdrop-filter: blur(16px) saturate(1.4); backdrop-filter: blur(16px) saturate(1.4); box-shadow: 0 0 0 var(--bw) var(--line), 0 6px 20px rgba(0, 0, 0, .12); }
.maptop .seg { flex: 0 1 auto; min-width: 0; }   /* its outline is a shadow, so its buttons' corner is r-ctl minus its padding only */
.maptop .seg button { padding-inline: 8px; white-space: nowrap; }
.maptop .seg button[aria-pressed="true"] { background: var(--surface); }
.mapbtns { display: grid; justify-items: end; gap: var(--gap-s); min-width: 0; }
.maptop .live > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.maptop .live { border: 0; height: var(--h-tap); white-space: nowrap; max-width: 44vw; min-width: 0; padding-inline: calc(var(--h-tap) / 2 - 4px) 16px; }   /* the dot sits at the pill end's centre */
.mapfit { width: var(--h-tap); height: var(--h-tap); color: var(--ink); }
.mapfit svg { width: 20px; height: 20px; }
/* the sheet: as wide as a sheet of its own, its bottom below the screen; app.js sets its height and where it stops */
.msheet { position: absolute; z-index: 15; top: 0; left: 0; right: 0; margin-inline: auto; width: calc(min(100vw, var(--page-w)) - 2 * var(--sheet-inset)); height: 100dvh; transform: translateY(100dvh);
  display: flex; flex-direction: column; background: var(--surface); border: var(--bw) solid var(--line); border-bottom: 0; border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  box-shadow: 0 -8px 30px rgba(0, 0, 0, .14); transition: transform .34s cubic-bezier(.2, .8, .2, 1); touch-action: none; }
.msheet.still, .msheet.drag { transition: none; }
.msbody { flex: 1; min-height: 0; overflow: hidden; display: grid; align-content: start; gap: 12px; padding: var(--pad-sheet) var(--pad-sheet) var(--ms-padb, 200px); overscroll-behavior: contain; }
.msbody:not(.scroll), .msbody:not(.scroll) * { touch-action: none; }   /* overflow hidden makes it a scroll container: its children need their own none, or a drag from a row pans and cancels */
.msbody.scroll { overflow-y: auto; touch-action: pan-y; }
.msmore { display: contents; }
/* collapsed, what lies below the summary line stays out of the strip between it and the dock's card (shown again as
   soon as a finger pulls the sheet) */
.msmore > * { transition: opacity .2s; } .msmore[inert] > * { opacity: 0; } .msheet.drag .msmore > * { opacity: 1; }
.msbody .grab, .msbody .mshd, .msbody .hd { touch-action: none; }
/* the summary line: the sheet's header, a tap opens it to half height */
.mssum { display: flex; align-items: center; width: 100%; min-height: var(--h-tap); margin-top: 2px; padding: 0 4px; border: 0; background: none; text-align: start; cursor: pointer; }
.mssum b { font: 650 17px/1.25 var(--display); letter-spacing: -.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mshd + .t-sec { margin-top: calc(var(--gap-l) - 12px); }
/* cards and lists in the sheet take the sheet's inner corner (r-insheet), their icon tiles that minus their padding */
.msbody .list, .msbody .card-p, .msbody .banner { --pad-card: var(--inblock-pad); border-radius: var(--r-insheet); }
.msbody .lrow .ic, .msbody .now .pulse, .msbody .banner .ic { border-radius: calc(var(--r-insheet) - var(--inblock-pad) - var(--bw)); }
.mapextra { display: grid; gap: var(--gap-s); } .mapextra .legend { padding-inline: 0; }
.lrow .ic.on { background: var(--act); color: var(--on-act); }
/* the tab bar blurs the map and the sheet behind it, fading out upward as in native apps */
.tabfade { position: absolute; z-index: 18; left: 0; right: 0; bottom: 0; height: calc(var(--tab-bottom) + var(--tab-h) + 36px); pointer-events: none;
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); -webkit-mask-image: linear-gradient(to top, #000 50%, transparent); mask-image: linear-gradient(to top, #000 50%, transparent); }
/* toasts on the map show above the sheet's visible part (app.js --ms-vis) */
body:has(.mapview) .toast { bottom: calc(var(--ms-vis, 0px) + var(--gap)); }
@media (prefers-reduced-motion: reduce) { .sheet, .scrim { animation: none; } .sheet.settle, .scrim.out, .msheet { transition: none; } }
