/* Event Desk: door mode. Standalone, one thumb, dark room, standing up.
   Spec: docs/event-desk-spec.md §6.1. Deliberately not sharing the dashboard's stylesheet:
   this page has to paint from cache with no network, so everything it needs is here or in the
   three hub files the service worker precaches with it.

   Hub migration Step 4 (2026-09-30): the page sits on the hub tokens (/assets/hub/tokens.css,
   both themes from the same daaily.theme key), Inter and hub.css. This file is the door's own
   layout on those tokens: the counts are KPI tiles, the capacity bar sits on the state tokens
   with a number, the search and the filter chips are the hub controls at the door's 44px, the
   party rows are 44px targets, the walk-in sheet is a hub bottom sheet, the undo bar and the
   toast are hub chrome. Every color is rgb(var(--token)); nothing here is light-only. */
:root{ --tap: 3.5rem; }
*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;background:rgb(var(--bg));color:rgb(var(--fg));
  font:1rem/1.45 var(--font-sans);
  -webkit-text-size-adjust:100%;overscroll-behavior-y:contain;
  height:100%;overflow:hidden;
}
/* One column, full height: header, search, list, action bar. The list is the only thing that
   scrolls, so the check-in buttons on the last visible row are never under the action bar, which
   is what a fixed bar over a scrolling page always does, and it hides the one control the row
   exists for.
   On #app and not on body: body's children are the sign-in gate and #app, so a flex column there
   makes the whole interface ONE flex item and the list grows to its full height again. */
#app{display:flex;flex-direction:column;height:100dvh;overflow:hidden}
#app.hide{display:none}
button,input,select{font:inherit;color:inherit}
button{cursor:pointer}
.hide{display:none!important}

/* ── header: the numbers, always visible ─────────────────────────────────────── */
.top{flex:0 0 auto;z-index:20;background:rgb(var(--bg-sidebar));border-bottom:1px solid rgb(var(--line));padding:.5rem .75rem .625rem;padding-top:calc(.5rem + env(safe-area-inset-top))}
.toprow{display:flex;align-items:center;gap:.625rem;margin-bottom:.5rem}
.ev{flex:1;min-width:0}
.ev b{display:block;font-size:.9375rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ev span{display:block;font-size:.75rem;line-height:1rem;color:rgb(var(--fg-muted));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* the sync chip: a pill whose words carry the state; the state token only tints it */
.sync{display:inline-flex;align-items:center;gap:.375rem;height:2.75rem;font:500 .75rem/1rem var(--font-sans);padding:0 .625rem;border-radius:var(--radius-full);border:1px solid rgb(var(--line));background:rgb(var(--surface));color:rgb(var(--fg-muted));white-space:nowrap}
.sync::before{content:"";width:.5rem;height:.5rem;border-radius:var(--radius-full);background:rgb(var(--fg-faint))}
.sync.ok{color:rgb(var(--success));border-color:rgb(var(--success) / .35);background:rgb(var(--success-subtle))}
.sync.ok::before{background:rgb(var(--success))}
.sync.pending{color:rgb(var(--warning));border-color:rgb(var(--warning) / .35);background:rgb(var(--warning-subtle))}
.sync.pending::before{background:rgb(var(--warning))}
.sync.off{color:rgb(var(--danger));border-color:rgb(var(--danger) / .35);background:rgb(var(--danger-subtle))}
.sync.off::before{background:rgb(var(--danger))}
.iconbtn{border:1px solid rgb(var(--line-strong));background:rgb(var(--surface));color:rgb(var(--fg-muted));border-radius:var(--radius-md);width:2.75rem;height:2.75rem;display:grid;place-items:center;flex:0 0 auto}
.iconbtn:hover{background:rgb(var(--surface-2));color:rgb(var(--fg))}
.themebtn{height:2.75rem;padding:0 .75rem;border:1px solid rgb(var(--line-strong));background:rgb(var(--surface));color:rgb(var(--fg-muted));border-radius:var(--radius-md);font:500 .8125rem/1.25rem var(--font-sans);flex:0 0 auto;white-space:nowrap}
.themebtn:hover{background:rgb(var(--surface-2));color:rgb(var(--fg))}

/* the live counts: three KPI tiles, the hub's .kpi-value (Inter 600, tabular) over its .stat-label
   (12px, sentence case), which is also what keeps "yet to arrive" whole at 360 */
.counts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.5rem}
.count{background:rgb(var(--surface));border:1px solid rgb(var(--line));border-radius:var(--radius-lg);padding:.5rem .625rem;min-width:0}
.count b{display:block}
.count span{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.count.inroom b{color:rgb(var(--success))}
.count.walk b{color:rgb(var(--info))}
/* the capacity meter: on the state tokens, and the number beside it says what the color says */
.cap{margin-top:.625rem;padding-bottom:.125rem}
.capbar{height:.5rem;border-radius:var(--radius-full);background:rgb(var(--surface-3));overflow:hidden}
.capbar i{display:block;width:0;height:100%;background:rgb(var(--success));border-radius:var(--radius-full);transition:width var(--duration-base)}
.capbar.warn i{background:rgb(var(--warning))} .capbar.full i{background:rgb(var(--danger))}
.caplab{display:flex;justify-content:space-between;font-size:.75rem;line-height:1rem;color:rgb(var(--fg-muted));margin-top:.25rem;font-variant-numeric:tabular-nums}
.capbar.warn + .caplab{color:rgb(var(--warning))} .capbar.full + .caplab{color:rgb(var(--danger))}

/* ── search: the hub search field at the door's height, and the filter chips ─── */
.searchwrap{flex:0 0 auto;z-index:15;padding:.625rem .75rem;background:rgb(var(--bg));border-bottom:1px solid rgb(var(--line))}
.searchbox{display:flex;gap:.5rem;align-items:center}
.searchbox .hub-search{max-width:none;flex:1 1 auto}
.searchbox .hub-search>.field{height:var(--tap);font-size:1.125rem;border-radius:var(--radius-lg)}
.searchbox .hub-search>.hub-search-icon{width:1.25rem;height:1.25rem;left:.875rem}
.searchbox .hub-search>.field{padding-left:2.5rem}
.searchbox .hub-search-clear{width:2.75rem;height:2.75rem;right:.375rem}
.searchbox .hub-search-clear svg{width:1.125rem;height:1.125rem}
.filters{display:flex;gap:.375rem;margin-top:.5rem;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.filters::-webkit-scrollbar{display:none}
.filters .hub-chip{flex:0 0 auto;height:2.75rem;min-height:2.75rem;padding:0 .875rem;font-size:.875rem;cursor:pointer}

/* ── the list ────────────────────────────────────────────────────────────────── */
.flagstrip{flex:0 0 auto;padding:.5rem .75rem 0}
.flagstrip[hidden]{display:none}
/* A flagged arrival: the designboom wash is the mark, the words say why. */
.flagalert{display:flex;align-items:center;gap:.625rem;background:rgb(var(--designboom-subtle));border:1px solid rgb(var(--line-strong));border-radius:var(--radius-lg);padding:.625rem .75rem;margin-bottom:.5rem;color:rgb(var(--fg))}
.flagalert .who{flex:1;min-width:0}
.flagalert b{display:block;font-size:.9375rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.flagalert span{display:block;font-size:.75rem;line-height:1rem;color:rgb(var(--fg-muted));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.flagalert .star{color:rgb(var(--fg));font-size:1.125rem;flex:0 0 auto}
.flagalert button{flex:0 0 auto;border:1px solid rgb(var(--line-strong));background:transparent;color:rgb(var(--fg-muted));border-radius:var(--radius-md);width:2.75rem;height:2.75rem;font-size:1rem}
main{flex:1 1 auto;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:.5rem .75rem .75rem;min-height:0}
.party{background:rgb(var(--surface));border:1px solid rgb(var(--line));border-radius:var(--radius-lg);margin-bottom:.5rem;overflow:hidden}
.party.allin{border-color:rgb(var(--success) / .4);background:rgb(var(--success-subtle))}
.party.some{border-color:rgb(var(--warning) / .4);background:rgb(var(--warning-subtle))}
.party.dupe{border-left:4px solid rgb(var(--danger))}
.party.flag{border-left:4px solid rgb(var(--designboom-solid));box-shadow:inset 4px 0 0 rgb(var(--line-strong) / .5)}
/* A walk-in the server refused. It stays on the list on purpose (the person IS in the room), so
   it has to read as unfinished business rather than as a normal row. */
.party.failed{border-left:4px solid rgb(var(--danger));background:rgb(var(--danger-subtle))}
.prow{display:flex;align-items:stretch;gap:0}
.pmain{flex:1;min-width:0;min-height:var(--tap);text-align:left;background:transparent;border:0;padding:.75rem .875rem;display:block;color:inherit}
.pname{font-size:1.0625rem;line-height:1.5rem;font-weight:600;display:flex;align-items:center;gap:.4375rem;flex-wrap:wrap}
.pname .star{color:rgb(var(--fg))}
.pmeta{display:block;font-size:.8125rem;line-height:1.125rem;color:rgb(var(--fg-muted));margin-top:.125rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.phint{display:block;font-size:.75rem;line-height:1rem;color:rgb(var(--fg-faint));margin-top:.25rem;white-space:normal}
.phint b{color:rgb(var(--fg-muted));font-weight:600}
/* the badges are hub pills: text on every one */
.badge{display:inline-flex;align-items:center;padding:.0625rem .5rem;border-radius:var(--radius-md);font:500 .6875rem/1rem var(--font-sans);background:rgb(var(--surface-2));color:rgb(var(--fg-muted));white-space:nowrap}
.badge.dupe{background:rgb(var(--danger-subtle));color:rgb(var(--danger))}
.badge.walk{background:rgb(var(--info-subtle));color:rgb(var(--info))}
.badge.wd{color:rgb(var(--fg-faint))}
.badge.failed{background:rgb(var(--danger-subtle));color:rgb(var(--danger));font-weight:600}
.pfail{padding:.6875rem .875rem;font-size:.8125rem;line-height:1.25rem;color:rgb(var(--danger))}
.pfail b{color:rgb(var(--fg-muted))}
.ptap{flex:0 0 6.5rem;min-height:var(--tap);border:0;border-left:1px solid rgb(var(--line));background:rgb(var(--surface-2));color:rgb(var(--fg-muted));display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.1875rem;font:600 .75rem/1.15 var(--font-sans);text-align:center;padding:.375rem .25rem;letter-spacing:.02em}
.ptap b{font:700 1.375rem/1 var(--font-sans);font-variant-numeric:tabular-nums;display:block;color:rgb(var(--fg))}
.party.allin .ptap b,.party.some .ptap b{color:inherit}
/* The wash under the tap column stays light enough that the small label keeps 4.5:1 on the
   party's own state wash in both themes (at .14 it fell to 4.3 in light). */
.party.allin .ptap{background:rgb(var(--success) / .08);color:rgb(var(--success))}
.party.some .ptap{background:rgb(var(--warning) / .08);color:rgb(var(--warning))}
.pexp{border-top:1px solid rgb(var(--line));padding:.375rem .75rem .75rem}
.seat{display:flex;align-items:center;gap:.625rem;padding:.5rem 0;border-bottom:1px solid rgb(var(--line))}
.seat:last-child{border-bottom:0}
.seatn{flex:0 0 1.375rem;font-size:.75rem;color:rgb(var(--fg-faint));font-variant-numeric:tabular-nums}
.seatbody{flex:1;min-width:0}
.seatbody input{width:100%;height:2.75rem;background:rgb(var(--surface));border:1px solid rgb(var(--line-strong));border-radius:var(--radius-md);padding:0 .625rem;font-size:1rem;color:rgb(var(--fg))}
.seatbody input::placeholder{color:rgb(var(--fg-faint))}
.seatbody input:focus{outline:none;border-color:rgb(var(--ring));box-shadow:0 0 0 1px rgb(var(--ring))}
.seatbody .two{display:flex;gap:.375rem;flex-wrap:wrap}
.seatbody .two input{flex:1 1 8rem;width:auto}
.seatname{font-size:.9375rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.seatsub{font-size:.75rem;line-height:1rem;color:rgb(var(--fg-faint))}
.seattap{flex:0 0 5.25rem;height:2.75rem;border-radius:var(--radius-md);border:1px solid rgb(var(--line-strong));background:rgb(var(--surface));color:rgb(var(--fg-muted));font:600 .8125rem/1.25rem var(--font-sans)}
.seattap.in{background:rgb(var(--success-subtle));border-color:rgb(var(--success) / .4);color:rgb(var(--success))}
.pacts{display:flex;gap:.5rem;margin-top:.625rem;flex-wrap:wrap}
.pacts button{min-height:2.75rem;border:1px solid rgb(var(--line-strong));background:rgb(var(--surface));color:rgb(var(--fg));border-radius:var(--radius-md);padding:0 .75rem;font:500 .875rem/1.25rem var(--font-sans)}
.pacts button:hover{background:rgb(var(--surface-2))}
/* the list's own empty and error states: the words first, what to do next under them */
.empty{text-align:center;color:rgb(var(--fg-muted));padding:2.75rem 1rem;font-size:.875rem;line-height:1.25rem}
.empty b{display:block;color:rgb(var(--fg));font-size:1rem;line-height:1.5rem;font-weight:600;margin-bottom:.375rem}

/* ── bottom bar + walk-in sheet ──────────────────────────────────────────────── */
.bottom{flex:0 0 auto;z-index:25;padding:.625rem .75rem;padding-bottom:calc(.625rem + env(safe-area-inset-bottom));background:rgb(var(--bg));border-top:1px solid rgb(var(--line));display:flex;gap:.5rem}
.bottom .btn{flex:1;height:var(--tap);border-radius:var(--radius-lg);font-size:.9375rem;font-weight:600}
/* the walk-in sheet: the hub bottom sheet (Hub.overlay.open on #walkSheet) at the door's sizes */
#walkSheet .hub-sheet-panel{max-height:92dvh}
#walkSheet .hub-ov-body{padding:1rem 1rem 0}
#walkSheet .lead{margin:0 0 1rem;color:rgb(var(--fg-muted));font-size:.875rem;line-height:1.25rem}
#walkSheet .field-opt{color:rgb(var(--fg-muted));font-weight:400}
/* the X is a 44px target at every width: the door is a touch device whatever its size */
#walkSheet .hub-modal-x{width:2.75rem;height:2.75rem;margin-right:-.75rem}
#walkSheet .f{margin-bottom:.75rem}
#walkSheet .f .field-label{margin-bottom:.375rem}
#walkSheet .f .field{height:3rem;font-size:1rem;border-radius:var(--radius-md)}
#walkSheet .hub-ov-foot .btn{flex:1;height:var(--tap);font-size:.9375rem;font-weight:600}
#walkSheet .hub-ov-foot .btn-primary{margin-left:0}
.sizepick{display:flex;gap:.375rem}
.sizepick button{flex:1;height:3rem;border-radius:var(--radius-md);border:1px solid rgb(var(--line-strong));background:rgb(var(--surface));color:rgb(var(--fg-muted));font:500 .9375rem/1.25rem var(--font-sans)}
.sizepick button[aria-pressed="true"],.sizepick button.on{background:rgb(var(--primary));border-color:rgb(var(--primary));color:rgb(var(--primary-fg))}
.sizepick button:focus-visible{outline:2px solid rgb(var(--ring));outline-offset:2px}

/* ── undo bar ────────────────────────────────────────────────────────────────── */
.undo{flex:0 0 auto;margin:0 .75rem .5rem;background:rgb(var(--surface));border:1px solid rgb(var(--line-strong));border-radius:var(--radius-lg);box-shadow:var(--shadow-md);padding:.5rem .5rem .5rem .875rem;display:flex;align-items:center;gap:.625rem}
.undo[hidden]{display:none}
.undo span{flex:1;font-size:.875rem;line-height:1.25rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.undo .btn{min-height:2.75rem}
/* The door's own toast is only the fallback for a page without hub.js (never the case once the
   worker has cached it); with the hub, toast() goes through window.toast. */
.toast{position:fixed;left:50%;transform:translateX(-50%);bottom:calc(6rem + env(safe-area-inset-bottom));z-index:var(--z-toast);background:rgb(var(--surface));border:1px solid rgb(var(--line));border-radius:var(--radius-lg);box-shadow:var(--shadow-lg);padding:.625rem 1rem;font-size:.875rem;max-width:88vw;text-align:center;opacity:0;transition:opacity var(--duration-fast);pointer-events:none}
.toast.show{opacity:1}
/* The hub toasts sit just above the action bar at every width, above the undo bar while it shows,
   and at the top while the walk-in sheet or a hub dialog is open (both rise from the bottom on a
   phone), so a toast never lands on a control the door is reaching for. */
.hub-toast-region{bottom:calc(5.5rem + env(safe-area-inset-bottom))}
body:has(#undo:not([hidden])) .hub-toast-region{bottom:calc(10rem + env(safe-area-inset-bottom))}
body:has(#walkSheet:not([hidden])) .hub-toast-region,
body:has(.hub-modal:not([hidden])) .hub-toast-region{top:calc(.75rem + env(safe-area-inset-top));bottom:auto}
/* The hub confirm (un-check-in, leaving with a queue) keeps 44px buttons above md too. */
.hub-dialog .hub-ov-foot .btn{min-height:2.75rem}

/* ── gate / boot ─────────────────────────────────────────────────────────────── */
.gate{position:fixed;inset:0;z-index:var(--z-modal);display:grid;place-items:center;background:rgb(var(--bg));padding:1.5rem;text-align:center}
.gate[hidden]{display:none}
.gatecard{max-width:21.25rem}
.gatecard h1{font:600 1.25rem/1.75rem var(--font-display);letter-spacing:-.02em;margin:0 0 .375rem}
.gatecard p{color:rgb(var(--fg-muted));font-size:.875rem;line-height:1.25rem;margin:0 0 1.125rem}
.gatecard .btn{height:var(--tap);padding:0 1.375rem;font-size:.9375rem;font-weight:600}
.gatecard .err{color:rgb(var(--danger));font-size:.8125rem;line-height:1.25rem;margin-top:.75rem;min-height:1.25rem}
.spin{width:1.625rem;height:1.625rem;border:3px solid rgb(var(--line));border-top-color:rgb(var(--fg));border-radius:var(--radius-full);animation:sp .8s linear infinite;margin:0 auto}
@keyframes sp{to{transform:rotate(360deg)}}

@media (min-width:51.25rem){
  /* `width:100%` is doing real work here, not padding the rule out.
     These are flex items of the #app column, and AN AUTO MARGIN ON THE CROSS AXIS TURNS OFF
     `align-items: stretch`. So `max-width` + auto margins alone made every one of them
     shrink-to-fit and then center: at 1100px the header came out 390px wide and the action bar
     208px, all narrower than the list, which is what "the top and bottom are narrow" was.
     width:100% restores the full width first, max-width caps it, and the auto margins center it. */
  .top,.searchwrap,.flagstrip,main,.undo,.bottom{width:100%;max-width:47.5rem;margin-left:auto;margin-right:auto}
  .undo{max-width:46rem}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
