:root{
  /* Hotel Mastery Hub Professional Suite — design tokens per the
     platform-wide UI/UX spec (2026-07-28). These are the canonical
     names/values now; --gold/--ink/--off-white/--muted/--line/etc. stay
     as ALIASES pointing at the same values (same pattern this file
     already used for --black/--paper) so the hundred-plus existing
     rules below don't all need rewriting in one pass — new rules should
     reach for --hm-* directly. */
  --hm-gold:#B6960C; --hm-gold-hover:#CFB23A;
  --hm-black:#080808; --hm-charcoal:#171717;
  --hm-paper:#F7F5EF; --hm-cream:#F8F5F0; --hm-white:#FFFFFF;
  --hm-border:#E5DDD0; --hm-text:#1A1A1A; --hm-muted:#746D63;
  --hm-danger:#B64545; --hm-success:#397A4A; --hm-warning:#C27A20; --hm-info:#315F86;

  /* Aliases — old names, same values (a couple repointed slightly to
     the new palette: --line was #ddd8cd, now the spec's --hm-border;
     --danger/--success/--muted likewise). */
  --gold:var(--hm-gold);--gold2:var(--hm-gold-hover);--ink:var(--hm-text);
  --off-white:var(--hm-paper);--white:var(--hm-white);--gray:var(--hm-muted);
  --black:var(--hm-black);--paper:var(--hm-paper);--muted:var(--hm-muted);
  --line:var(--hm-border);--danger:var(--hm-danger);--success:var(--hm-success);
  --warning:var(--hm-warning);--info:var(--hm-info);--border:var(--hm-border);

  --radius:12px;--shadow:0 2px 10px rgba(0,0,0,.05);
  /* Georgia/serif reserved for major titles/report covers/SOP headings
     only, per spec — never forms, buttons, tables, filters, nav, or
     mobile controls. Body/UI stays a plain system sans throughout. */
  --font-heading:Georgia,'Times New Roman',serif;
  --font-body:system-ui,-apple-system,'Segoe UI',Inter,Arial,sans-serif;

  /* Department accents — the shared gold/typography/button system stays
     constant across every module; only this one hue changes per
     department. Housekeeping/Front Office already matched the platform
     spec exactly; Maintenance/Food & Beverage are now set to the spec's
     exact values (F&B moves from an earlier ad-hoc purple to the spec's
     #A65E2E — flag if that's not what's wanted, easy to revert). Finance/
     HR/Sales & Revenue/Executive are new — no module uses them yet, but
     the tokens exist ready for when one does. */
  --accent-housekeeping:#2F4B3E;
  --accent-maintenance:#6B2737;
  --accent-front-office:#B6960C;
  --accent-food-beverage:#A65E2E;
  --accent-finance:#1F4E79;
  --accent-hr:#2F6F73;
  --accent-sales:#5B3F8C;
  --accent-executive:#333333;

  /* Action TYPE colors — deliberately vivid/saturated (unlike the muted
     department tints above) so they read clearly as a distinct signal
     even against a light department-tinted row background. Shared here
     so the row's color bar and the "+ New Action" menu's swatches never
     drift out of sync with each other. */
  --type-internal:#5CB85C;      /* "Regular" — light green */
  --type-guest_request:#E53935; /* bright red */
  --type-pre_arrival:#FFC800;   /* vivid yellow */
}
*{box-sizing:border-box}
html,body{margin:0;min-height:100%;font-family:var(--font-body);background:var(--paper);color:var(--ink)}
button,input,select{font:inherit}
button{cursor:pointer}
.hidden{display:none!important}

/* LOGIN — split screen, dark brand panel + light form panel */
.login-screen{min-height:100vh;display:grid;grid-template-columns:minmax(320px,44%) 1fr;background:#090909}
.login-brand{position:relative;display:flex;flex-direction:column;justify-content:center;padding:48px;
  background:linear-gradient(145deg,#050505,#171717);border-right:1px solid rgba(182,150,12,.35);overflow:hidden}
.login-brand:after{content:"";position:absolute;width:460px;height:460px;border:1px solid rgba(182,150,12,.18);
  border-radius:50%;right:-220px;bottom:-180px;box-shadow:0 0 0 80px rgba(182,150,12,.04),0 0 0 160px rgba(182,150,12,.025)}
/* The real logo, dark-panel variant (hm-logo-horizontal-dark.png —
   "HOTEL" recolored white, background made transparent instead of the
   opaque white it shipped with; see STATUS.md's Brand assets section
   for why a separate file exists instead of just this one recolored via
   CSS filters). Replaces the old plain-text "Hotel Mastery Hub" eyebrow
   line the logo now visually covers itself. Wide variant gets its own
   width since a horizontal lockup's aspect ratio needs a wider, shorter
   box than the stacked one this was first built for. */
.login-brand-logo{width:200px;height:auto;display:block;margin-bottom:6px}
.login-brand-logo-wide{width:260px}
.login-brand h1{font-family:var(--font-heading);color:#fff;font-size:38px;line-height:1.1;margin:14px 0 14px;font-weight:500}
.login-brand p{color:#c9c9c9;font-size:16px;line-height:1.6;margin:0;max-width:440px}
.login-card-wrap{display:grid;place-items:center;padding:32px;background:var(--paper)}
.login-card{width:min(440px,100%);background:#fff;border:1px solid #e2ded4;border-radius:18px;padding:34px;box-shadow:var(--shadow)}
.login-card h2{font-family:var(--font-heading);font-size:28px;margin:0 0 6px}
.login-card .sub{color:#666;margin:0 0 24px}
label{display:block;font-size:12px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;margin:14px 0 6px}
/* select never had its own rule, so every dropdown in the app fell back
   to the bare native control — no border-radius, no padding, no shadow —
   while its sibling text inputs got the full soft treatment below. Same
   class of gap as the textarea fix noted just below: folding select into
   the shared rule (rather than a new near-duplicate one) is what keeps
   every field in a form looking like one family instead of drifting. The
   resting shadow is what gives fields the "high-end" lift the flat
   1px-border look was missing; focus keeps its existing gold ring. */
input,textarea,select{width:100%;border:1px solid #cfc9bc;border-radius:9px;padding:12px 13px;background:#fff;outline:none;font-family:inherit;font-size:14px;box-shadow:0 1px 2px rgba(20,15,5,.05);transition:border-color .15s,box-shadow .15s}
input:focus,textarea:focus,select:focus{border-color:var(--gold);box-shadow:0 0 0 3px rgba(182,150,12,.13)}
/* No rule targeted textarea at all before this, so every textarea in
   the app (SOP Centre's step fields, first exposed it) fell back to the
   browser's native ~2-row box instead of matching input's styling —
   min-height keeps a textarea usable even at a small `rows` value. */
textarea{min-height:64px;resize:vertical;line-height:1.5}
/* The rule above is meant for text/date/number fields — applied by tag
   with no type selector, it was also stretching every checkbox in the
   app to full row width (border/padding included), leaving only a tiny
   native tick in the corner of a huge invisible box and shoving
   whatever sits next to it (a checklist label's text, "Repeats", each
   weekday picker) far away instead of directly beside it. Checkboxes
   opt back out here, once, rather than in every component that happens
   to use one. */
input[type="checkbox"]{width:auto;padding:0;border-radius:3px;box-shadow:none}
.primary{width:100%;margin-top:22px;border:1px solid var(--gold);background:var(--gold);color:#080808;
  border-radius:9px;padding:12px 16px;font-weight:900;letter-spacing:.03em}
.primary:hover{background:var(--gold2)}
.error{background:#fff0f0;color:#7e171c;border-left:4px solid var(--danger);padding:10px 12px;margin-top:14px;
  border-radius:4px;font-size:13px}
.hint{color:#888;font-size:12px;margin-top:16px;line-height:1.5}

/* APP SHELL — dark sidebar + light workspace.
   #app is a plain 2-column, 1-row grid: #nav in column 1, #mainColumn
   (topbar + demo banner + page content, stacked via flex) in column 2.
   Keeping topbar/pageHost as SEPARATE grid-column:2 items (the previous
   shape) each created their own implicit row, which stretched row 1 to
   nav's full content height and left a large blank gap in column 2 below
   the 70px topbar — nav's own height then measured only that one
   oversized row, not the page's actual full height. Wrapping them in one
   flex column avoids implicit-row sizing entirely, which also sidesteps
   a real CSS Grid gotcha: grid-row's negative line indices (e.g. "1/-1")
   only resolve against an EXPLICIT grid-template-rows — with none
   defined here, "-1" silently failed to span past row 1. */
#app{display:grid;grid-template-columns:250px 1fr;min-height:100vh;transition:grid-template-columns .15s ease}
#nav{background:#0b0b0b;border-right:1px solid #252525;padding:0;display:flex;flex-direction:column}
#mainColumn{grid-column:2;display:flex;flex-direction:column;min-width:0}
.side-brand{height:78px;display:flex;align-items:center;justify-content:space-between;padding:0 14px 0 20px;
  border-bottom:3px solid var(--gold);color:#fff}
.side-brand-text{font-family:var(--font-heading);font-size:17px;font-weight:600;display:flex;flex-direction:column;
  justify-content:center;white-space:nowrap;overflow:hidden}
.side-brand-text span{color:var(--gold);font-family:system-ui;font-size:9px;letter-spacing:.16em;
  text-transform:uppercase;font-weight:900;margin-top:3px}
/* Collapsible desktop sidebar (spec section 4) — expanded ~250-260px,
   collapsed ~76px icon-only with tooltips (native title attr) instead
   of labels. Deliberately scoped above the mobile breakpoint: mobile's
   sidebar is already a slide-out drawer with its own separate pattern,
   not this one. */
.nav-collapse-btn{background:transparent;border:1px solid #333;color:#c9c9c9;border-radius:6px;
  width:26px;height:26px;flex-shrink:0;cursor:pointer;font-size:13px;line-height:1}
.nav-collapse-btn:hover{background:#171717;color:#fff}
@media(min-width:821px){
  #app.nav-collapsed{grid-template-columns:76px 1fr}
  #app.nav-collapsed .side-brand-text{width:0;opacity:0}
  #app.nav-collapsed .side-brand{padding:0 12px;justify-content:center}
  #app.nav-collapsed .nav-collapse-btn{transform:rotate(180deg)}
  #app.nav-collapsed .nav-group-toggle{justify-content:center;padding:11px 0}
  #app.nav-collapsed .nav-group-toggle>span:first-child{gap:0}
  #app.nav-collapsed .nav-group-toggle-label,
  #app.nav-collapsed .nav-chevron,
  #app.nav-collapsed .nav-submenu{display:none}
  #app.nav-collapsed .nav-icon{margin:0}
}
.nav-list{padding:10px 10px;flex:1;overflow-y:auto}
.nav-group{margin:2px 0;border-radius:9px;overflow:hidden}
.nav-group-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:11px 12px;background:transparent;border:0;color:#c9c9c9;font:inherit;font-weight:700;
  text-align:left;cursor:pointer;border-radius:8px}
.nav-group-toggle:hover{background:#171717;color:#fff}
.nav-group-toggle>span:first-child{display:flex;align-items:center;gap:9px}
.nav-icon{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;opacity:.9;flex-shrink:0}
.nav-icon svg{display:block}
.nav-chevron{transition:transform .15s ease;opacity:.7;font-size:12px}
.nav-group.open .nav-chevron{transform:rotate(180deg)}
.nav-submenu{display:none;padding:2px 0 6px 30px}
.nav-group.open .nav-submenu{display:block}
.nav-btn{display:block;width:100%;text-align:left;padding:9px 11px;margin-bottom:2px;background:transparent;
  border:0;border-left:2px solid transparent;color:#c9c9c9;border-radius:7px;font-weight:600;font-size:.92rem}
.nav-btn:hover{background:#171717;color:#fff}
.nav-btn.active{background:rgba(182,150,12,.18);color:var(--gold);border-left-color:var(--gold)}
.nav-btn-inactive{opacity:.55}
.nav-btn-inactive::after{content:" (inactive)";font-size:11px;font-style:italic}

/* Top bar — dark, gold bottom border, matching the Housekeeping Daily
   Operations tool's own header exactly (the named design benchmark).
   Was a plain white bar; every sub-component below is re-tinted for a
   dark background as part of the same change (property switcher,
   search, notif bell, user menu, logout, hamburger). */
#topbar{background:var(--hm-black);border-bottom:2px solid var(--hm-gold);height:76px;display:flex;
  align-items:center;gap:14px;padding:0 24px;position:sticky;top:0;z-index:20}

/* Header brand — desktop shows the full horizontal logo (icon + wordmark
   + gold subtitle are already baked into that one image); mobile swaps
   to hm-icon.png alone (icon only, no text) — simplified from an
   earlier monogram+"HMH"-text pass per direct feedback ("on mobile use
   just icon"). Toggled by the same max-width:820px breakpoint every
   other responsive rule in this file already keys off. */
.header-brand{display:flex;align-items:center;gap:8px;flex-shrink:0}
.header-logo-full{height:32px;display:block;width:auto}
.header-logo-mono{height:28px;display:none;width:auto}

/* Hamburger — desktop hidden; mobile-only alternate way to open the same
   nav drawer the bottom "More" tab already opens (openMobileNav()) — a
   top-corner hamburger is the more conventional spot to expect it, per
   brand-asset header-layout spec. */
.hamburger-btn{display:none;border:0;background:transparent;color:#fff;padding:6px;flex-shrink:0}

/* Re-tinted for the dark #topbar (was styled for a white bar) — subtle
   translucent white surfaces read as "on dark chrome" without needing a
   second full color system just for the header. */
.property-switcher{flex-shrink:0;max-width:180px;padding:8px 10px;border:1px solid rgba(255,255,255,.18);border-radius:8px;
  background:rgba(255,255,255,.06);font-weight:700;font-size:13px;color:#fff}

.search-zone{position:relative;flex:1;min-width:0;max-width:480px;display:flex;align-items:center;gap:8px;
  background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.14);border-radius:9px;padding:0 12px;height:38px}
.search-zone:focus-within{border-color:var(--hm-gold);box-shadow:0 0 0 2px var(--hm-gold)}
.search-zone svg{flex-shrink:0;color:#a89f8f}
.search-zone input{flex:1;min-width:0;border:0;background:transparent;font-size:13px;outline:none;color:#fff}
.search-zone input::placeholder{color:#9b9284}
.search-clear{border:0;background:transparent;font-size:16px;color:#a89f8f;cursor:pointer;line-height:1;padding:2px 4px}
.search-results{position:absolute;top:44px;left:0;right:0;background:#fff;border:1px solid var(--line);
  border-radius:10px;box-shadow:var(--shadow);max-height:320px;overflow-y:auto;z-index:30}
.search-result-item{display:block;width:100%;text-align:left;padding:9px 12px;border:0;background:transparent;
  font-size:13px;cursor:pointer;border-bottom:1px solid #f0ede5;color:var(--hm-text)}
.search-result-item:last-child{border-bottom:0}
.search-result-item:hover{background:#f5f3ee}
.search-result-kind{display:inline-block;font-size:9px;text-transform:uppercase;letter-spacing:.06em;
  color:#8a8070;margin-right:6px}
.search-empty{padding:12px;font-size:12px;color:#8a8070}

.notif-bell{position:relative;flex-shrink:0;border:1px solid rgba(255,255,255,.18);background:rgba(255,255,255,.06);border-radius:8px;
  width:38px;height:38px;display:grid;place-items:center;color:#fff;cursor:pointer}
.notif-count{position:absolute;top:-5px;right:-5px;background:var(--danger);color:#fff;font-size:10px;
  font-weight:800;border-radius:999px;min-width:16px;height:16px;display:grid;place-items:center;padding:0 3px}

/* Timesheet — header clock in/out control, visible for every role */
.clock-widget{flex-shrink:0}
.clock-btn{display:flex;align-items:center;gap:7px;border-radius:8px;padding:9px 14px;font-weight:800;font-size:13px;border:1px solid transparent}
.clock-icon{display:inline-flex;width:16px;height:16px;flex-shrink:0}
.clock-icon svg{width:100%;height:100%}
.clock-btn.clock-in{background:var(--success);border-color:var(--success);color:#fff}
.clock-btn.clock-in:hover{opacity:.9}
.clock-btn.clock-out{background:#fff;border-color:var(--danger);color:var(--danger)}
.clock-btn.clock-out:hover{background:#fff5f5}
.clock-elapsed{font-weight:700;opacity:.85;font-size:12px}
.btn-sm{border:1px solid #d8d4cb;background:#fff;border-radius:6px;padding:6px 10px;font:700 12px var(--font-body);cursor:pointer}
.btn-sm:hover{background:#f5f3ee}
.btn-pick-up{background:var(--gold);border-color:var(--gold);color:#111}
.btn-pick-up:hover{background:var(--gold2)}
/* .btn-sec/.btn-primary/.btn-danger never set their own font-size —
   with `button{font:inherit}` above, that meant each one's actual
   rendered text size was whatever its container happened to cascade
   down (16px in an unstyled panel, something else nested in a table or
   .hint), not a deliberate value. Every button in the shared system now
   fixes its own type explicitly so it looks the same everywhere. */
.btn-sec{border:1px solid #d8d4cb;background:#fff;border-radius:9px;padding:11px 18px;font:700 14px var(--font-body);color:#333;cursor:pointer}
.btn-sec:hover{background:#f5f3ee}
/* Used across the app (SOP Centre delete/remove buttons, etc.) but
   never had a rule of its own — rendered as a raw unstyled native
   button (grey 3D bevel, square corners, tiny padding) next to
   everything else. */
.btn-danger{border:1px solid var(--hm-danger);background:#fff;border-radius:9px;padding:11px 18px;font:700 14px var(--font-body);color:var(--hm-danger);cursor:pointer}
.btn-danger:hover{background:color-mix(in srgb,var(--hm-danger) 8%,#fff)}

/* In-app confirm modal — replaces window.confirm() for anything clicked
   often (clock in/out, unapprove): a native dialog is exactly what people
   learn to blow through with reflexive Enter/click all day. */
.confirm-overlay{position:fixed;inset:0;background:rgba(8,8,8,.5);z-index:100;
  display:flex;align-items:center;justify-content:center;padding:20px}
/* No max-height/overflow at all before this, so any modal taller than
   the viewport (a long Edit form, e.g.) simply overflowed off both
   edges of the screen with no way to scroll to the top OR the Save
   button — confirmed live, not just a wide-monitor edge case. The
   overlay's own flex-center + 20px padding already reserves the
   headroom; this just stops the modal from exceeding it. */
.confirm-modal{background:#fff;border-radius:14px;padding:22px;max-width:360px;width:100%;
  max-height:calc(100vh - 40px);overflow-y:auto;
  box-shadow:0 20px 50px rgba(0,0,0,.25)}
.confirm-modal p{margin:0 0 18px;font-size:15px;line-height:1.5;color:var(--ink)}
.confirm-modal-actions{display:flex;gap:10px;justify-content:flex-end}
.confirm-modal-actions button{margin-top:0}
/* Common Area rule modal gets a soft gold wash so it visually reads as
   a different context from the guest Rule Library's plain-white modal
   at a glance — direct feedback: "put it in different color background
   so it does not get overlooked." Border uses the same gold, just
   opaque, so it doesn't disappear against the tint. */
.confirm-modal-common-area{background:color-mix(in srgb,var(--gold) 9%,#fff);
  border:1px solid color-mix(in srgb,var(--gold) 45%,#fff)}

.user-menu{display:flex;align-items:center;gap:10px;border:1px solid rgba(255,255,255,.18);background:rgba(255,255,255,.06);border-radius:10px;
  padding:6px 12px 6px 7px;flex-shrink:0;color:#fff}
.avatar{width:34px;height:34px;border-radius:50%;background:#111;color:var(--gold);display:grid;
  place-items:center;font-weight:900;font-size:13px}
.logout-btn{border:1px solid rgba(255,255,255,.18);background:rgba(255,255,255,.06);color:#fff;border-radius:8px;padding:9px 12px;font-weight:800;font-size:13px;flex-shrink:0}
.logout-btn:hover{background:rgba(255,255,255,.12)}

#pageHost{padding:28px 30px}

.demo-banner{background:#FBF0E0;color:#7a4a12;border-bottom:1px solid #E8C98A;
  font-size:12.5px;font-weight:700;text-align:center;padding:8px 16px}

/* Mobile bottom nav — hidden on desktop */
#mobileBottomNav{display:none}
#navBackdrop{display:none}

@media(max-width:820px){
  .login-screen{grid-template-columns:1fr}
  .login-brand{min-height:200px;padding:24px}
  .login-brand h1{font-size:28px}
  #app{grid-template-columns:1fr}
  #nav{position:fixed;left:-280px;top:0;bottom:0;width:260px;z-index:40;transition:left .2s ease;
    box-shadow:0 0 0 9999px rgba(0,0,0,0);flex-direction:column}
  #nav.mobile-open{left:0}
  #navBackdrop.show{display:block;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:35}
  #mainColumn{grid-column:1}
  /* Seven flex-shrink:0 controls (brand, switcher, notif, clock, user,
     logout, hamburger) plus search never fit a real phone width in one
     row — wrap rather than silently clip/scroll anything off-screen.
     Search takes its own full row since it's the most flexible, least
     urgent piece to lose first. */
  #topbar{padding:8px 12px;gap:8px;flex-wrap:wrap;height:auto}
  .header-logo-full{display:none}
  .header-logo-mono{display:block}
  .hamburger-btn{display:flex;align-items:center;margin-left:auto;order:4}
  .property-switcher{max-width:110px;font-size:12px}
  .search-zone{max-width:none;order:5;flex-basis:100%}
  .search-zone input::placeholder{font-size:12px}
  .user-menu{padding:5px 10px 5px 5px}
  .user-menu>div{display:none} /* name/role — avatar alone is enough once space is this tight */
  #pageHost{padding:16px;padding-bottom:82px} /* clear the bottom nav */

  #mobileBottomNav{display:flex;position:fixed;left:0;right:0;bottom:0;height:64px;background:#0b0b0b;
    border-top:1px solid #252525;z-index:20}
  .mnav-btn{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
    border:0;background:transparent;color:#c9c9c9;font-size:10px;font-weight:700}
  .mnav-btn.active{color:var(--gold)}
}
.panel{max-width:680px;background:#fff;border:1px solid var(--line);border-radius:var(--radius);
  padding:22px;box-shadow:0 4px 14px rgba(0,0,0,.04)}
.panel h2{font-family:var(--font-heading);font-size:26px;margin:0 0 4px}
.panel label{margin-top:16px}
/* Same gold wash as .confirm-modal-common-area, applied to the Common
   Area Cleaning Schedule section itself (Service Setup) so it reads as
   its own distinct zone against the guest Rule Library above it, not
   just inside its own modal — same direct feedback, applied at both
   the section and the modal level. */
.common-area-panel{background:color-mix(in srgb,var(--gold) 7%,#fff);
  border:1px solid color-mix(in srgb,var(--gold) 30%,#fff);border-radius:var(--radius);
  padding:18px 20px;margin-top:32px}
.common-area-panel h4{margin-top:0 !important}

/* PAGE HEADER — one shared shape for every module's title block (spec:
   module label, title, short description, one primary action, filters
   kept in their OWN row below, never mixed into this one). Title +
   description already existed everywhere as a plain <h2>+.hint pair;
   this wraps that same content consistently rather than replacing it,
   and adds the small uppercase module-label "eyebrow" line the spec
   asks for, which nothing had before. */
.page-header{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap;margin-bottom:18px}
.page-header-eyebrow{font-size:11px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--hm-muted);margin:0 0 4px}
.page-header-titlewrap{min-width:0}
.page-header h2{font-family:var(--font-heading);font-size:26px;margin:0 0 4px}
.page-header-desc{margin:0;color:var(--hm-muted);font-size:13px;max-width:640px;line-height:1.5}
.page-header-actions{display:flex;gap:8px;flex-wrap:wrap;flex-shrink:0}
@media(max-width:820px){.page-header{flex-direction:column}.page-header-actions{width:100%}}

/* STATUS / DAY-MODE BADGE — one shared shape replacing several ad-hoc
   inline-styled spans (Assignment Sheet's/Room Board's day-mode badge,
   Actions' priority meta) that each hand-rolled their own background/
   color/padding. Tone maps straight onto the token set (success/warning/
   danger/info/neutral) so a badge's color always means the same thing
   everywhere it appears. */
.badge{display:inline-block;font-size:10px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  padding:3px 9px;border-radius:4px;white-space:nowrap}
.badge-success{background:color-mix(in srgb,var(--hm-success) 16%,#fff);color:var(--hm-success)}
.badge-warning{background:color-mix(in srgb,var(--hm-warning) 16%,#fff);color:var(--hm-warning)}
.badge-danger{background:color-mix(in srgb,var(--hm-danger) 16%,#fff);color:var(--hm-danger)}
.badge-info{background:color-mix(in srgb,var(--hm-info) 16%,#fff);color:var(--hm-info)}
.badge-neutral{background:#F0EBE3;color:var(--hm-muted)}
.badge-gold{background:color-mix(in srgb,var(--hm-gold) 18%,#fff);color:#8a7209}

/* METRIC CARD (KPI box) — .kpi-box/.kpi-label/.kpi-val/.kpi-sub are
   used identically across Shift History, Productivity, and Room Board,
   but had NO shared definition anywhere in this file — every one was
   rendering as bare unstyled text with no card at all, just whatever
   inline color: override that render happened to set. One real
   definition here, matching the same card look as .panel (spec's
   MetricCard: label, large value, supporting detail). */
.kpi-box{background:#fff;border:1px solid var(--hm-border);border-radius:var(--radius);padding:14px 16px}
.kpi-label{font-size:10px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--hm-muted);margin-bottom:6px}
.kpi-val{font-size:22px;font-weight:800;font-family:var(--font-heading);color:var(--hm-text);line-height:1.2}
.kpi-sub{font-size:11.5px;color:var(--hm-muted);margin-top:2px}

/* Dashboard's KPI rows — same .kpi-box card, just laid out in a
   responsive grid instead of the flex strips other screens use. */
.dash-kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;margin-top:8px}
.dash-alerts{display:flex;flex-direction:column;gap:6px;margin-top:8px}
.dash-alert-item{padding:8px 12px;font-size:12px;text-align:left}

/* TOOL CARD — the dashboard's module-launch tile, deliberately distinct
   from the compact, information-dense OPERATIONAL cards used for rooms/
   actions/staff (spec section 9): larger, simpler, one description, one
   live summary line, one primary action. */
.tool-card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin-top:8px}
.tool-card{background:#fff;border:1px solid var(--hm-border);border-left:4px solid var(--tool-card-accent,var(--hm-gold));
  border-radius:var(--radius);padding:18px 20px;display:flex;flex-direction:column;gap:6px;box-shadow:var(--shadow)}
.tool-card-icon{width:34px;height:34px;display:flex;align-items:center;justify-content:center;color:var(--tool-card-accent,var(--hm-gold))}
.tool-card-icon svg{width:24px;height:24px}
.tool-card-title{font-family:var(--font-heading);font-weight:700;font-size:16px;color:var(--hm-text);margin:0}
.tool-card-desc{font-size:12.5px;color:var(--hm-muted);margin:0;line-height:1.4}
.tool-card-summary{font-size:12.5px;color:var(--hm-text);font-weight:600;margin-top:2px}
.tool-card-summary.is-muted{color:var(--hm-muted);font-weight:400;font-style:italic}
.tool-card-action{margin-top:10px;background:none;border:none;padding:0;color:var(--tool-card-accent,var(--hm-gold));
  font-weight:800;font-size:13px;cursor:pointer;text-align:left}
.tool-card-action:hover{text-decoration:underline}

.btn-primary{margin-top:18px;padding:11px 18px;background:var(--gold);border:1px solid var(--gold);
  color:#111;font:900 14px var(--font-body);border-radius:9px;cursor:pointer}
.btn-primary:hover{background:var(--gold2)}

/* VIEW/EDIT TOGGLE (spec section 14) — protected setup screens default
   to a clean read-only view; Edit unlocks fields; Save/Cancel stay
   visible while editing, with a banner making the mode unmistakable. */
.ve-toolbar{display:flex;align-items:center;justify-content:flex-end;gap:12px;margin-bottom:12px}
.ve-toolbar-edit{justify-content:space-between;background:color-mix(in srgb,var(--hm-gold) 10%,#fff);
  border:1px solid var(--hm-gold);border-radius:var(--radius);padding:10px 14px}
.ve-banner{font-size:12.5px;font-weight:700;color:#7a6207}
.ve-actions{display:flex;gap:8px}
.ve-actions .btn-primary{margin-top:0}
.ve-error{color:var(--hm-danger);font-size:12.5px;margin:6px 0 0}
/* Read-only inputs keep the same box shape (no layout shift switching
   modes) but visually recede — muted background, no pointer cursor. */
.data-table td input:disabled,.data-table td select:disabled,
.form-grid input:disabled,.form-grid select:disabled{
  background:var(--hm-paper);color:var(--hm-muted);cursor:default;border-color:#ece8df}

/* HELP & VIDEO (spec section 18) — three tiers: a compact hover
   tooltip, an expandable panel for longer guidance, and a video modal/
   Watch button. See js/lib/help.js for the no-video-yet "coming soon"
   state the Watch button renders until real footage exists. */
.info-tip{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:50%;
  background:var(--hm-paper);border:1px solid var(--hm-border);color:var(--hm-muted);font-size:11px;font-weight:800;
  cursor:help;position:relative;vertical-align:middle;margin-left:4px;line-height:1}
.info-tip:hover .info-tip-bubble,.info-tip:focus .info-tip-bubble,.info-tip:focus-visible .info-tip-bubble{
  opacity:1;visibility:visible;transform:translateX(-50%) translateY(0)}
.info-tip-bubble{position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%) translateY(4px);
  width:220px;background:var(--hm-black);color:#fff;font-size:12px;font-weight:400;line-height:1.4;
  padding:8px 10px;border-radius:8px;opacity:0;visibility:hidden;transition:opacity .15s,transform .15s;z-index:50;text-align:left}

/* Tier 1b — a real clickable "?" (not a hover bubble, see help.js
   showInfoPopup) for guidance that needs to survive living inside a
   scrollable modal. Solid-gold circle, same proportions as the vendor
   Housekeeping tool's own .info-btn, confirmed against its actual CSS
   rather than guessed. */
.info-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:18px;height:18px;
  border-radius:50%;border:none;background:var(--hm-gold);color:#1A1A1A;font-size:11px;font-weight:700;
  cursor:pointer;vertical-align:middle;margin-left:4px;padding:0;line-height:1}
.info-btn:hover,.info-btn:focus-visible{background:var(--hm-gold-hover,var(--hm-gold))}

.explain-panel{margin-top:8px}
.explain-panel summary{cursor:pointer;font-size:12.5px;font-weight:700;color:var(--hm-info);list-style:none}
.explain-panel summary::-webkit-details-marker{display:none}
.explain-panel summary::before{content:"+ "}
.explain-panel[open] summary::before{content:"– "}
.explain-panel-body{font-size:12.5px;color:var(--hm-muted);margin-top:6px;line-height:1.5;max-width:640px}

.watch-btn{display:inline-flex;align-items:center;gap:6px;background:none;border:1px solid var(--hm-border);
  border-radius:8px;padding:6px 12px;font-size:12.5px;font-weight:700;color:var(--hm-text);cursor:pointer}
.watch-btn:hover:not(:disabled){background:var(--hm-paper)}
.watch-btn:disabled{color:var(--hm-muted);cursor:default;opacity:.7}

/* EMPTY STATE (spec section 16) — icon, title, short explanation, one
   clear next action. Existing ad hoc "No X yet" text elsewhere in the
   app isn't broken and isn't being swept in one pass; this is the
   shared shape new/touched screens should reach for going forward. */
.empty-state{display:flex;flex-direction:column;align-items:center;text-align:center;gap:8px;
  padding:40px 20px;color:var(--hm-muted)}
.empty-state-icon{width:40px;height:40px;color:var(--hm-border)}
.empty-state-icon svg{width:100%;height:100%}
.empty-state-title{font-family:var(--font-heading);font-size:16px;font-weight:700;color:var(--hm-text)}
.empty-state-desc{font-size:13px;max-width:360px;line-height:1.5;margin:0}

/* SKELETON LOADER (spec section 16) — shown while data is in flight, a
   rough shape of what replaces it; never a full-screen spinner for
   normal in-page loading. */
@keyframes skeleton-shimmer{0%{background-position:-200px 0}100%{background-position:calc(200px + 100%) 0}}
.skeleton-row,.skeleton-card{position:relative;overflow:hidden;background:var(--hm-paper);border-radius:var(--radius);margin-bottom:10px}
.skeleton-row{height:44px}
.skeleton-card{height:100px}
.skeleton-shimmer{position:absolute;inset:0;
  background:linear-gradient(90deg,var(--hm-paper) 0,#eee8db 50px,var(--hm-paper) 100px);
  background-size:200px 100%;animation:skeleton-shimmer 1.2s ease-in-out infinite}

/* ERROR BANNER (spec section 16) — a friendly failure message, never
   the raw error object, with an optional retry action. */
.error-banner{background:color-mix(in srgb,var(--hm-danger) 8%,#fff);border:1px solid var(--hm-danger);
  border-radius:var(--radius);padding:14px 16px;margin:12px 0}
.error-banner p{margin:0 0 8px;color:var(--hm-danger);font-size:13px;font-weight:600}

.data-table{width:100%;border-collapse:collapse;margin-top:8px}
.data-table th,.data-table td{text-align:left;padding:11px 10px;border-bottom:1px solid #ece8df;font-size:14px}
.data-table th{font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:#777}

/* Timesheet filter bar */
.filter-bar{display:flex;align-items:flex-end;gap:14px;flex-wrap:wrap;margin:16px 0;padding:14px;
  background:#f5f3ee;border:1px solid var(--line);border-radius:10px}
.filter-bar label{margin-top:0;font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);
  display:flex;flex-direction:column;gap:4px;font-weight:800}
.filter-bar select,.filter-bar input{padding:7px 8px;border:1px solid var(--line);border-radius:6px;
  font-size:13px;font-weight:400;text-transform:none;letter-spacing:normal;color:var(--ink);background:#fff}
.filter-bar-actions{display:flex;gap:8px;margin-left:auto;align-self:flex-end}
.data-table td input,.data-table td select{width:100%;padding:7px 8px;border:1px solid var(--line);border-radius:6px;font-size:13px}

/* Tasks — department segmented control */
.tasks-segmented{display:flex;flex-wrap:wrap;gap:6px;margin:16px 0;padding:4px;
  background:#f5f3ee;border:1px solid var(--line);border-radius:10px;width:fit-content}
.tasks-seg-btn{border:0;background:transparent;padding:8px 14px;border-radius:7px;
  font-weight:700;font-size:13px;color:#555}
.tasks-seg-btn:hover{background:#fff}
.tasks-seg-btn.active{background:var(--gold);color:#111}
.tasks-seg-btn:disabled{color:#bbb;cursor:not-allowed}
.tasks-seg-btn:disabled:hover{background:transparent}

/* Actions — compact ROWS, not cards: tapping one opens a detail modal
   rather than showing everything inline, since a phone-sized screen
   full of expanded cards is exactly the "visual noise" housekeepers
   can't work with (direct user feedback after an earlier card-based
   pass).
   Two color signals, kept visually distinct on purpose (direct
   feedback: "that color code has to be separated with white stripe,
   otherwise colors will blend"):
     - Department fills the row as a light tint of its existing
       --accent-* var (which team owns this — the more constant fact,
       so it gets the bigger surface).
     - Type gets its own thicker bar down the left edge (internal now
       gets a real, if quiet, color too — not "no indicator" like the
       small-dot version this replaced).
     - A 3px WHITE gap sits between the type bar and the tinted body,
       via a second pseudo-element, so the two colors never touch. */
.action-rows{display:flex;flex-direction:column;gap:6px;margin-top:16px}
.action-row{position:relative;display:flex;align-items:center;gap:10px;
  border:1px solid var(--line);border-radius:8px;padding:10px 12px 10px 22px;cursor:pointer;overflow:hidden}
.action-row:hover{filter:brightness(0.98)}
.action-row:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
.action-row::before{content:'';position:absolute;left:0;top:0;bottom:0;width:9px}
.action-row::after{content:'';position:absolute;left:9px;top:0;bottom:0;width:3px;background:#fff}
.action-row.dept-housekeeping{background:color-mix(in srgb,var(--accent-housekeeping) 16%,#fff)}
.action-row.dept-front-office{background:color-mix(in srgb,var(--accent-front-office) 16%,#fff)}
.action-row.dept-maintenance{background:color-mix(in srgb,var(--accent-maintenance) 16%,#fff)}
.action-row.dept-food-beverage{background:color-mix(in srgb,var(--accent-food-beverage) 16%,#fff)}
.action-row.type-internal::before{background:var(--type-internal)}
.action-row.type-guest_request::before{background:var(--type-guest_request)}
.action-row.type-pre_arrival::before{background:var(--type-pre_arrival)}
.action-row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
/* Owner bubble + status used to be direct children of .action-row under
   justify-content:space-between, so their position drifted with how
   long that row's meta text happened to be — grouping them here and
   letting .action-row-main do all the stretching keeps the tail pinned
   to the same spot on every row. */
.action-row-tail{flex-shrink:0;display:flex;align-items:center;gap:8px}
.action-row-title{font-weight:700;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  display:flex;align-items:center;gap:6px}
.action-row-meta{font-size:11.5px;color:var(--muted)}
.action-row-status{flex-shrink:0;font-size:13px;font-weight:900;color:var(--success);width:16px;text-align:center}
/* Owner bubble — right-aligned, same avatar language as the header's
   .avatar: initials when assigned, a "?" (in the danger color, since it
   means "still needs assigning") when not. */
.action-row-owner-bubble{flex-shrink:0;width:26px;height:26px;border-radius:50%;display:grid;place-items:center;
  font-size:11px;font-weight:900;background:#171717;color:var(--gold)}
.action-row-owner-bubble.action-row-unassigned{background:var(--danger);color:#fff}
/* Completed-today rows stay in Active (per the same-day grace period)
   but read as "done" at a glance — greyed and struck through — and sort
   to the bottom rather than mixing in with what's still open. */
.action-row.done-today{opacity:.55}
.action-row.done-today .action-row-title{text-decoration:line-through}
.action-section-head{margin-top:24px;font-size:13px;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}

/* "+ New Action" — one button, three nested options, rather than a
   Type field inside a longer always-visible form (direct feedback:
   "create new action should be a button and options nested inside it"). */
.new-action-wrap{position:relative}
.new-action-menu{position:absolute;right:0;top:calc(100% + 6px);background:#fff;border:1px solid var(--line);
  border-radius:9px;box-shadow:var(--shadow);z-index:30;min-width:180px;overflow:hidden}
.new-action-menu button{display:flex;align-items:center;gap:9px;width:100%;text-align:left;padding:10px 14px;
  border:0;background:transparent;font-weight:700;font-size:13px;color:var(--ink)}
.new-action-menu button:hover{background:#f5f3ee}
.new-action-menu-dot{display:inline-block;width:11px;height:11px;border-radius:50%;flex-shrink:0}
.new-action-menu-dot.type-internal{background:var(--type-internal)}
.new-action-menu-dot.type-guest_request{background:var(--type-guest_request)}
.new-action-menu-dot.type-pre_arrival{background:var(--type-pre_arrival)}

/* Detail / create modals — same .confirm-overlay/.confirm-modal shell
   as Timesheet/Users & Roles, widened for forms and given a header row
   with a close button since these carry more content than a yes/no
   confirm. 560px, not 520 — confirmed live (DevTools computed layout)
   that a scrolling instance of this modal (.confirm-modal's
   overflow-y:auto kicking in on a tall form) loses ~20px of content
   width to its own scrollbar, which left .form-grid's two 220px
   minmax columns just ~2px short of fitting side by side and silently
   collapsing to one column — not a cache or viewport issue, an actual
   width shortfall only visible once the modal was actually tall
   enough to scroll. */
.confirm-modal-wide{max-width:560px}

/* SOP Centre — the two-panel library|editor layout and the two 4-column
   grids (APPLIES TO scope picker, Staff View meta strip) have a fixed
   intended column count (2 panels, 4 named categories), unlike the
   auto-fit galleries elsewhere in this file, so they need a real
   breakpoint rather than "however many fit" — direct report that the
   page was unreadable on a phone screen, confirmed from these three
   inline grids never having had one. Single breakpoint, matching the
   one already used everywhere else in this file (max-width:820px). */
.sop-layout{display:grid;grid-template-columns:minmax(260px,340px) minmax(0,1fr);gap:14px;align-items:start}
.sop-scope-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;padding:12px}
.sop-meta-strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr))}
@media(max-width:820px){
  .sop-layout{grid-template-columns:1fr}
  .sop-scope-grid,.sop-meta-strip{grid-template-columns:repeat(2,minmax(0,1fr))}
}
.modal-head{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;margin-bottom:14px}
.modal-close{border:0;background:transparent;font-size:22px;line-height:1;color:var(--muted);padding:0 4px}
.modal-close:hover{color:var(--ink)}
.detail-kv{width:100%;border-collapse:collapse;font-size:13px}
.detail-kv th{text-align:left;color:var(--muted);font-weight:700;padding:5px 10px 5px 0;white-space:nowrap;vertical-align:top}
.detail-kv td{padding:5px 0}
/* Direct feedback: the plain gold text link read as inert, not
   clickable — a hover/focus tint on top of the icon-badge redesign
   (tasks.js) makes the affordance unmistakable without a full border. */
.detail-sop-link:hover,.detail-sop-link:focus-visible{background:var(--hm-paper,#F8F5F0)}
.action-checklist{list-style:none;margin:14px 0 0;padding:0;font-size:13px}
.action-checklist li{margin:4px 0}
/* Overrides the global label{display:block} rule (meant for form
   fields stacked above their input) — here the checkbox and its text
   need to sit side by side on one line, not stack. */
.action-checklist li label{display:flex;align-items:center;gap:7px;margin:0;font-size:13px;
  font-weight:400;text-transform:none;letter-spacing:normal}
.action-checklist .chk-done{text-decoration:line-through;color:var(--muted)}

/* Users & Roles — active/inactive toggle switch */
.status-toggle{display:inline-flex;align-items:center;gap:8px;cursor:pointer;white-space:nowrap}
.status-toggle input{position:absolute;opacity:0;width:1px;height:1px}
.status-toggle-track{position:relative;width:34px;height:19px;border-radius:999px;background:#d8d4cb;
  transition:background .15s ease;flex-shrink:0}
.status-toggle.is-active .status-toggle-track{background:var(--success)}
.status-toggle-thumb{position:absolute;top:2px;left:2px;width:15px;height:15px;border-radius:50%;
  background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.25);transition:left .15s ease}
.status-toggle.is-active .status-toggle-thumb{left:17px}
.status-toggle-label{font-size:12px;font-weight:700;color:var(--muted)}
.status-toggle.is-active .status-toggle-label{color:var(--success)}
.status-toggle input:focus-visible~.status-toggle-track{outline:2px solid var(--gold);outline-offset:2px}

/* Timesheet — long-shift warning badge */
.long-shift-badge{display:inline-block;font-size:11px;font-weight:700;color:var(--danger);white-space:nowrap}

/* My Property → Setup */
.form-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:0 18px}
.add-btn{border:1px dashed #c9c2b2;background:transparent;border-radius:8px;padding:9px 14px;font-weight:700;font-size:13px;color:#555;width:100%}
.add-btn:hover{background:#f5f3ee}
.totals-bar{display:flex;gap:14px;margin:14px 0 18px}
.totals-bar>div{flex:1;background:#f5f3ee;border:1px solid var(--line);border-radius:10px;padding:12px 14px;text-align:center}
.totals-bar strong{display:block;font-size:22px;font-family:var(--font-heading)}
.totals-bar span{font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}

/* A second, conflicting @media(max-width:820px) block used to live here,
   duplicating the login/#app rules above and fighting the slide-out-drawer
   #nav rules with an unrelated "#nav as a fixed top bar" design that the
   JS never actually drove (wireMobileNav/openMobileNav only ever toggle
   .mobile-open, which only the block above understands). Since the two
   blocks have equal specificity, source order let this dead design
   silently win several properties (including #nav's z-index), which is
   exactly the kind of thing that can bury the header behind the nav on a
   real phone. Removed rather than merged — nothing here was reachable
   through the actual mobile-nav JS. */
