/* =====================================================================
   AREMIS - Aero UI design system
   Glassmorphic surfaces, layered 3D depth, gradient mesh background.
   Light + dark theme, fully responsive (desktop sidebar / mobile tab bar).
   ===================================================================== */

:root {
  --primary: #2563eb;
  --primary-600: #1d4ed8;
  --primary-300: #93c5fd;
  --accent: #06b6d4;
  --accent-600: #0891b2;

  --success: #22c55e;
  --warning: #f59e0b;
  --danger: #ef4444;
  --purple: #a855f7;
  --slate: #64748b;

  --bg: #eef3fb;
  --bg-2: #dfe9f8;
  --surface: rgba(255, 255, 255, 0.72);
  --surface-solid: #ffffff;
  --surface-2: rgba(255, 255, 255, 0.5);
  --border: rgba(255, 255, 255, 0.75);
  --border-2: rgba(15, 23, 42, 0.08);

  --text: #0f172a;
  --text-2: #475569;
  /* Was #94a3b8, which on this background is a contrast ratio of 2.3:1.
     WCAG AA asks for 4.5:1 for text this size, and --text-3 is the colour of
     nearly every secondary line in the system: the timestamp under a message,
     the room type, the "last seen", the labels on the tab bar. It is the
     colour you read most and it was the hardest to read - in an engineering
     corridor, on a five-year-old screen, in daylight through a window.
     #5b6b82 is 4.9:1 and still clearly a step back from --text-2 at 6.8, so
     the hierarchy survives; it just stops being decorative. */
  --text-3: #5b6b82;
  /* referenced by .chat-photo and .pick-btn:hover and never defined, so both
     resolved to nothing - a transparent placeholder behind a loading
     photograph, and a hover state that did not change on hover */
  --surface-3: rgba(15, 23, 42, 0.06);

  --radius: 18px;
  --radius-sm: 12px;
  --radius-lg: 26px;

  --shadow-1: 0 1px 2px rgba(15, 23, 42, .06), 0 4px 12px rgba(15, 23, 42, .06);
  --shadow-2: 0 2px 4px rgba(15, 23, 42, .06), 0 12px 28px rgba(15, 23, 42, .10);
  --shadow-3: 0 8px 16px rgba(15, 23, 42, .08), 0 24px 56px rgba(15, 23, 42, .16);
  --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, .85), inset 0 -1px 0 rgba(15, 23, 42, .04);
  --glow: 0 0 0 4px rgba(37, 99, 235, .14);

  --sidebar-w: 268px;
  --header-h: 68px;

  /* Rounder, and a shade smaller. ui-rounded picks up SF Pro Rounded on
     Apple hardware; Nunito is the web fallback and is rounded by design.
     The whole interface steps down about 7%, which on a phone is the
     difference between a job card that fits and one that does not. */
  --font: 'Nunito', ui-rounded, 'SF Pro Rounded', -apple-system, BlinkMacSystemFont,
          'Segoe UI Variable Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --fs: 13px;

  /* Selected navigation is green, not blue. Blue is the brand and it was
     doing two jobs at once - "this is AREMIS" and "you are here" - which is
     why the sidebar read as a wall of blue whenever anything was open. */
  --nav-on-1: #34d399;
  --nav-on-2: #059669;
  --nav-on-glow: rgba(16, 185, 129, .34);
}

html[data-theme="dark"] {
  --bg: #070c17;
  --bg-2: #0d1526;
  --surface: rgba(23, 33, 54, 0.66);
  --surface-solid: #131c2f;
  --surface-2: rgba(30, 41, 66, 0.5);
  --border: rgba(255, 255, 255, 0.09);
  --border-2: rgba(255, 255, 255, 0.06);
  --text: #e8eefc;
  --text-2: #a3b0c9;
  /* 3.9:1 against the dark card, also under AA - see the note above */
  --text-3: #8794ad;
  --surface-3: rgba(255, 255, 255, 0.07);
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 12px rgba(0, 0, 0, .32);
  --shadow-2: 0 2px 6px rgba(0, 0, 0, .45), 0 14px 34px rgba(0, 0, 0, .45);
  --shadow-3: 0 10px 24px rgba(0, 0, 0, .5), 0 30px 70px rgba(0, 0, 0, .6);
  --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, .07), inset 0 -1px 0 rgba(0, 0, 0, .3);
}

/* ---------------------------------------------------------------------
   Where there is no backdrop-filter.
   Twenty-one rules in this file lean on backdrop-filter for legibility -
   the top bar, the drawer, cards, dialogs, the chat dock. Chrome has had it
   since 76; the WebView on the Android 5 and 6 handsets this app has to run
   on has not, and neither does Firefox with it turned off. On those, every
   one of those surfaces falls back to whatever alpha it was given - and text
   sitting on a 50%-transparent card over a gradient is not a style choice,
   it is unreadable.
   So: if the browser cannot blur, it gets solid surfaces instead. Nobody
   loses any information; they lose an effect they could never see anyway.
   --------------------------------------------------------------------- */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  :root {
    --surface: #ffffff;
    --surface-2: #f4f7fc;
    --border: rgba(15, 23, 42, 0.10);
  }
  html[data-theme="dark"] {
    --surface: #172136;
    --surface-2: #1e2942;
  }
}

* { box-sizing: border-box; }
html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  /* another step down, from 13.5. A rounded face reads a shade larger than
     a grotesque at the same size, so this lands about where 13.5 Inter did
     while fitting more on a phone. Still well above the 12px that starts to
     strain in a plant room. */
  font-size: var(--fs);
  line-height: 1.52;
  letter-spacing: -.09px;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ------------------------- gradient mesh backdrop ------------------- */
.aero-bg {
  position: fixed; inset: 0; z-index: -2;
  background:
    radial-gradient(1100px 700px at 8% -10%, rgba(6, 182, 212, .30), transparent 60%),
    radial-gradient(1000px 620px at 100% 0%, rgba(37, 99, 235, .28), transparent 58%),
    radial-gradient(900px 620px at 60% 110%, rgba(168, 85, 247, .20), transparent 60%),
    linear-gradient(160deg, var(--bg) 0%, var(--bg-2) 100%);
}
.aero-bg::after {
  content: ''; position: absolute; inset: 0;
  background-image:
    radial-gradient(rgba(255,255,255,.5) 1px, transparent 1px);
  background-size: 26px 26px;
  opacity: .18; mix-blend-mode: overlay;
}
html[data-theme="dark"] .aero-bg::after { opacity: .05; }

.aero-orb {
  position: fixed; border-radius: 50%; filter: blur(46px); z-index: -1;
  opacity: .5; pointer-events: none; animation: float 18s ease-in-out infinite;
}
.aero-orb.o1 { width: 340px; height: 340px; top: -80px; right: 6%;
  background: radial-gradient(circle at 30% 30%, #67e8f9, #0891b2); }
.aero-orb.o2 { width: 260px; height: 260px; bottom: 4%; left: -60px; animation-delay: -7s;
  background: radial-gradient(circle at 30% 30%, #c4b5fd, #7c3aed); }
/* a third, slower orb low on the right: the background never quite repeats,
   which is what stops a glass interface reading as flat wallpaper */
.aero-orb.o3 { width: 300px; height: 300px; bottom: -90px; right: 14%; animation-delay: -13s;
  animation-duration: 26s; opacity: .38;
  background: radial-gradient(circle at 35% 35%, #86efac, #0d9488); }
html[data-theme="dark"] .aero-orb { opacity: .34; }
@keyframes float {
  0%,100% { transform: translate3d(0,0,0) scale(1); }
  50% { transform: translate3d(-24px, 30px, 0) scale(1.06); }
}

/* ------------------------------- glass ------------------------------ */
.glass {
  background: var(--surface);
  backdrop-filter: blur(22px) saturate(180%);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-2), var(--shadow-inset);
  border-radius: var(--radius);
}
.glass-sm { border-radius: var(--radius-sm); box-shadow: var(--shadow-1), var(--shadow-inset); }

/* ------------------------------ layout ------------------------------ */
.app-shell { display: flex; min-height: 100vh; }

.sidebar {
  width: var(--sidebar-w); flex: 0 0 var(--sidebar-w);
  position: sticky; top: 0; height: 100vh;
  display: flex; flex-direction: column; gap: 8px;
  padding: 16px 12px; z-index: 40;
  /* a cold wash down the glass, so the sidebar sits behind the page rather
     than beside it - the one thing a flat panel never does */
  background:
    radial-gradient(115% 50% at 0% 0%, rgba(56,189,248,.15), transparent 60%),
    radial-gradient(90% 42% at 8% 100%, rgba(139,92,246,.12), transparent 64%),
    var(--surface);
  backdrop-filter: blur(26px) saturate(180%);
  -webkit-backdrop-filter: blur(26px) saturate(180%);
  border-right: 1px solid var(--border);
  box-shadow: 8px 0 30px rgba(15, 23, 42, .06);
}

/* the account row at the foot, given an edge of its own */
.acct-row { transition: background .16s ease, transform .16s ease; }
.acct-row:hover { background: var(--surface-2); transform: translateX(2px); }

.brand { display: flex; align-items: center; gap: 10px; padding: 6px 8px 2px; }
.brand img { height: 40px; width: auto; max-width: 190px; object-fit: contain;
  filter: drop-shadow(0 6px 14px rgba(37,99,235,.35)); }
.brand-fallback { font-weight: 800; letter-spacing: 3px; font-size: 22px;
  background: linear-gradient(135deg, var(--accent), var(--primary));
  -webkit-background-clip: text; background-clip: text; color: transparent; }

/* Emergency button - directly under the logo */
.emergency-btn {
  /* smaller than it was: it still has to be unmissable, but it was taking a
     third of the sidebar for a button most people press once a year */
  margin: 8px 10px 4px; padding: 8px 12px; border: none; cursor: pointer; width: calc(100% - 20px);
  border-radius: 13px; font-weight: 800; font-size: 11.5px; letter-spacing: 1.1px; color: #fff;
  background: linear-gradient(140deg, #ff5f6d 0%, #dc2626 55%, #991b1b 100%);
  box-shadow: 0 6px 16px rgba(220, 38, 38, .38), inset 0 1px 0 rgba(255,255,255,.45),
              inset 0 -2px 5px rgba(0,0,0,.22);
  display: flex; align-items: center; justify-content: center; gap: 8px;
  transition: transform .12s ease, box-shadow .2s ease;
  position: relative; overflow: hidden;
}
.emergency-btn::after {
  content: ''; position: absolute; inset: 0 0 55% 0;
  background: linear-gradient(180deg, rgba(255,255,255,.42), rgba(255,255,255,0));
  pointer-events: none;
}
.emergency-btn svg { width: 15px; height: 15px; }
.emergency-btn:hover { transform: translateY(-1px); box-shadow: 0 10px 22px rgba(220,38,38,.5), inset 0 1px 0 rgba(255,255,255,.5); }
.emergency-btn:active { transform: translateY(1px) scale(.99); }
.emergency-btn.armed { animation: pulseRed 1s infinite; }
@keyframes pulseRed {
  0%,100% { box-shadow: 0 0 0 0 rgba(239,68,68,.6), 0 8px 20px rgba(220,38,38,.42); }
  50% { box-shadow: 0 0 0 14px rgba(239,68,68,0), 0 8px 20px rgba(220,38,38,.42); }
}

.nav { flex: 1; overflow-y: auto; padding: 6px 2px 12px; display: flex; flex-direction: column; gap: 7px; }
.nav::-webkit-scrollbar { width: 6px; }
.nav::-webkit-scrollbar-track { background: transparent; }
.nav::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, var(--border), var(--border-2));
  border-radius: 3px;
}
.nav::-webkit-scrollbar-thumb:hover { background: var(--primary); }

/* A section heading is a rule with a word on it, not a word floating in
   space. The hairline is what turns three lists into three groups. */
.nav-section {
  display: flex; align-items: center; gap: 9px;
  font-size: 10px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--text-3); padding: 20px 12px 9px; user-select: none;
}
.nav-section span { flex: 0 0 auto; }
.nav-section::after {
  content: ''; flex: 1; height: 1px;
  background: linear-gradient(90deg, var(--text-3) 0%, var(--border) 45%, transparent 100%);
  opacity: .45;
}
.nav-section:first-child { padding-top: 6px; }

.nav-item {
  display: flex; align-items: center; gap: 12px; padding: 10px 13px 10px 10px;
  border-radius: 14px; color: var(--text-2); text-decoration: none;
  font-weight: 700; font-size: 13.4px; letter-spacing: -.15px;
  transition: color .16s ease, background .16s ease, box-shadow .2s ease, transform .16s ease;
  position: relative; border: 1px solid transparent; overflow: hidden;
}

/* the icon lives in a chip, so the column reads as a row of marks */
.nav-ico {
  flex: 0 0 30px; width: 30px; height: 30px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--surface-2); border: 1px solid var(--border-2);
  color: var(--text-3);
  transition: all .18s cubic-bezier(.2,.9,.3,1);
}
.nav-item svg { width: 17px; height: 17px; flex: 0 0 17px; }
.nav-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Hover has to be felt, not inferred.
   This changed the background to --surface-2 and the text to --text, which
   on the light theme is a couple of percent of luminance - on a phone in a
   corridor, or a monitor at an angle behind a reception desk, it read as
   nothing at all. The weight goes up as well as the colour, and the row
   moves a hair, so the answer to "is this the one I am about to press" is
   visible rather than deduced. */
.nav-item:hover {
  background: var(--surface-2);
  color: var(--text);
  font-weight: 800;
  border-color: var(--border-2);
  transform: translateX(2px);
  box-shadow: 0 2px 8px rgba(15, 23, 42, .07);
}
html[data-theme="dark"] .nav-item:hover {
  background: rgba(148, 163, 184, .13);
  box-shadow: 0 2px 8px rgba(0, 0, 0, .30);
}
/* the active row is already unmistakable - hover only lifts it slightly */
.nav-item.active:hover { transform: translateX(2px); font-weight: 800; }
.nav-item:hover .nav-ico {
  color: var(--nav-on-2); border-color: rgba(16,185,129,.34);
  background: rgba(16,185,129,.11); transform: translateY(-1px);
  box-shadow: 0 4px 10px rgba(16,185,129,.16);
}

/* the marker on the left is what the eye finds first when scanning back */
.nav-item::before {
  content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 0; border-radius: 0 3px 3px 0;
  background: linear-gradient(180deg, var(--nav-on-1), var(--nav-on-2));
  transition: height .22s cubic-bezier(.2,.9,.3,1);
}
.nav-item:hover::before { height: 18px; }

.nav-item.active {
  color: #fff; border-color: rgba(255,255,255,.24);
  background: linear-gradient(135deg, var(--nav-on-1) 0%, var(--nav-on-2) 100%);
  box-shadow: 0 8px 20px var(--nav-on-glow), inset 0 1px 0 rgba(255,255,255,.44);
  font-weight: 800;
}
.nav-item.active::before { height: 0; }
/* a highlight across the top edge - the glass reading the light */
.nav-item.active::after {
  content: ''; position: absolute; inset: 0 0 58% 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(255,255,255,.20), rgba(255,255,255,0));
}
.nav-item.active .nav-ico {
  background: rgba(255,255,255,.20); border-color: rgba(255,255,255,.34);
  color: #fff; box-shadow: inset 0 1px 0 rgba(255,255,255,.4);
}
.nav-item .badge { margin-left: auto; }

html[data-theme="dark"] .nav-ico { background: rgba(148,163,184,.10); border-color: rgba(148,163,184,.20); }
html[data-theme="dark"] .nav-item:hover .nav-ico { background: rgba(16,185,129,.16); border-color: rgba(16,185,129,.38); }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  /* iOS draws the web view UNDER the status bar and Dynamic Island, because
     index.html asks for viewport-fit=cover. Without this the hotel name sits
     behind the clock and the notification bell behind the battery - which is
     exactly what shipped, and only on iPhone. env() is 0 everywhere there is
     no notch, so desktop and Android are untouched. */
  height: calc(var(--header-h) + env(safe-area-inset-top));
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; gap: 12px;
  padding: env(safe-area-inset-top) 20px 0;
  background: var(--surface); backdrop-filter: blur(22px) saturate(180%);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  border-bottom: 1px solid var(--border);
}
.topbar h1 { font-size: 17.5px; margin: 0; font-weight: 750; letter-spacing: -.3px; }
.topbar .sub { font-size: 12px; color: var(--text-3); font-weight: 500; }
.topbar-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; }

.content { padding: 20px; flex: 1; }
.page-enter { animation: pageIn .32s cubic-bezier(.2,.7,.3,1); }
@keyframes pageIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ------------------------------ buttons ----------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 9px 16px; border-radius: 13px; border: 1px solid var(--border);
  background: var(--surface-solid); color: var(--text); font-weight: 650; font-size: 12.5px;
  cursor: pointer; font-family: inherit; transition: all .15s ease;
  box-shadow: var(--shadow-1), var(--shadow-inset); white-space: nowrap;
}
.btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-2); }
.btn:active { transform: translateY(0); }
.btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }
.btn svg { width: 16px; height: 16px; }
.btn-primary {
  color: #fff; border-color: transparent;
  background: linear-gradient(135deg, var(--accent) 0%, var(--primary) 100%);
  box-shadow: 0 6px 16px rgba(37,99,235,.34), inset 0 1px 0 rgba(255,255,255,.4);
}
.btn-danger { color: #fff; border-color: transparent;
  background: linear-gradient(135deg, #f87171, #dc2626);
  box-shadow: 0 6px 16px rgba(220,38,38,.34), inset 0 1px 0 rgba(255,255,255,.35); }
.btn-success { color: #fff; border-color: transparent;
  background: linear-gradient(135deg, #4ade80, #16a34a);
  box-shadow: 0 6px 16px rgba(22,163,74,.32), inset 0 1px 0 rgba(255,255,255,.35); }
.btn-warning { color: #fff; border-color: transparent;
  background: linear-gradient(135deg, #fbbf24, #d97706);
  box-shadow: 0 6px 16px rgba(217,119,6,.32), inset 0 1px 0 rgba(255,255,255,.35); }
.btn-ghost { background: transparent; box-shadow: none; border-color: var(--border-2); }
.btn-sm { padding: 6px 11px; font-size: 12.5px; border-radius: 10px; }
.btn-lg { padding: 12px 22px; font-size: 14px; border-radius: 15px; }
.btn-icon { padding: 8px; width: 35px; height: 35px; border-radius: 11px; }
/* 35px is fine for a mouse and small for a thumb. Rather than making every
   icon button bigger everywhere - which would push the toolbars around on
   the desktop screens people are happy with - they grow only where the
   input is a finger. */
@media (pointer: coarse) {
  .btn-icon { width: 40px; height: 40px; padding: 9px; }
}
.btn-block { width: 100%; }

/* ------------------------------- cards ------------------------------ */
.card {
  background: var(--surface); backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-2), var(--shadow-inset);
  padding: 16px; transition: transform .2s ease, box-shadow .2s ease;
  position: relative; isolation: isolate;
}
/* the sheen: a soft diagonal highlight across the top-left of every pane.
   It is what tells the eye "this is glass" rather than "this is a box", and
   it costs one pseudo-element rather than an image. */
.card::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  pointer-events: none; z-index: -1;
  background: linear-gradient(135deg, rgba(255,255,255,.55) 0%,
              rgba(255,255,255,.10) 32%, transparent 58%);
}
html[data-theme="dark"] .card::before {
  background: linear-gradient(135deg, rgba(255,255,255,.11) 0%,
              rgba(255,255,255,.03) 32%, transparent 58%);
}
/* a hairline of light along the top edge, the way a real pane catches a
   ceiling light */
.card::after {
  content: ''; position: absolute; left: 12%; right: 12%; top: 0; height: 1px;
  border-radius: 1px; pointer-events: none; z-index: -1;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.85), transparent);
}
html[data-theme="dark"] .card::after {
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.22), transparent);
}
.card-hover:hover { transform: translateY(-3px); box-shadow: var(--shadow-3); }
.card-title { font-size: 14px; font-weight: 700; margin: 0 0 2px; display: flex; align-items: center; gap: 8px; }
.card-sub { font-size: 12.5px; color: var(--text-3); margin-bottom: 14px; }
.card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 12px; }

.grid { display: grid; gap: 16px; }
.grid-2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0,1fr)); }
.grid-auto { grid-template-columns: repeat(auto-fill, minmax(272px, 1fr)); }

/* ------------------------------- stats ------------------------------ */
.stat {
  position: relative; overflow: hidden; padding: 16px 18px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-2), var(--shadow-inset);
  backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px) saturate(180%);
  transition: transform .2s ease, box-shadow .2s ease;
}
.stat:hover { transform: translateY(-3px); box-shadow: var(--shadow-3); }
.stat::before {
  content: ''; position: absolute; right: -28px; top: -28px; width: 96px; height: 96px;
  border-radius: 50%; opacity: .18; background: var(--_c, var(--primary));
}
.stat-label { font-size: 11.5px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--text-3); }
.stat-value { font-size: 27px; font-weight: 800; letter-spacing: -1px; line-height: 1.15; margin-top: 4px; }
.stat-foot { font-size: 12px; color: var(--text-2); margin-top: 3px; display: flex; align-items: center; gap: 6px; }
.stat-link { display: block; text-decoration: none; color: inherit; position: relative; }
.stat-link:active { transform: translateY(0) scale(.99); }
.stat-go { position: absolute; right: 12px; bottom: 10px; color: var(--text-3); opacity: .6; }
.stat-link:hover .stat-go { opacity: 1; color: var(--primary); transform: translateX(2px); }

.stat-icon {
  width: 40px; height: 40px; border-radius: 13px; display: grid; place-items: center; color: #fff;
  background: linear-gradient(135deg, var(--_c, var(--primary)), color-mix(in srgb, var(--_c, var(--primary)) 60%, #000));
  box-shadow: 0 6px 14px rgba(15,23,42,.2), inset 0 1px 0 rgba(255,255,255,.4);
}

/* ------------------------------ badges ------------------------------ */
.badge {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: 999px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .2px; white-space: nowrap;
  background: rgba(100,116,139,.14); color: var(--text-2); border: 1px solid rgba(100,116,139,.18);
}
.badge-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.badge.b-success { background: rgba(34,197,94,.15); color: #15803d; border-color: rgba(34,197,94,.28); }
.badge.b-warning { background: rgba(245,158,11,.16); color: #b45309; border-color: rgba(245,158,11,.3); }
.badge.b-danger  { background: rgba(239,68,68,.15); color: #b91c1c; border-color: rgba(239,68,68,.28); }
.badge.b-info    { background: rgba(37,99,235,.14); color: #1d4ed8; border-color: rgba(37,99,235,.26); }
.badge.b-purple  { background: rgba(168,85,247,.15); color: #7e22ce; border-color: rgba(168,85,247,.28); }
html[data-theme="dark"] .badge.b-success { color: #4ade80; }
html[data-theme="dark"] .badge.b-warning { color: #fbbf24; }
html[data-theme="dark"] .badge.b-danger { color: #f87171; }
html[data-theme="dark"] .badge.b-info { color: #93c5fd; }
html[data-theme="dark"] .badge.b-purple { color: #d8b4fe; }

.chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 999px;
  font-size: 12.5px; font-weight: 650; cursor: pointer; user-select: none;
  border: 1px solid var(--border-2); background: var(--surface-2); color: var(--text-2);
  transition: all .15s ease;
}
.chip:hover { background: var(--surface-solid); color: var(--text); }
.chip.active { background: linear-gradient(135deg, var(--accent), var(--primary)); color: #fff; border-color: transparent;
  box-shadow: 0 4px 12px rgba(37,99,235,.3); }
.chip-row { display: flex; gap: 8px; flex-wrap: wrap; }

/* ------------------------------ forms ------------------------------- */
.field { margin-bottom: 14px; }
.label { display: block; font-size: 12.5px; font-weight: 700; color: var(--text-2); margin-bottom: 6px; }
.input, .select, .textarea {
  width: 100%; padding: 10px 13px; border-radius: 13px; font-family: inherit; font-size: 14px;
  color: var(--text); background: var(--surface-solid);
  border: 1px solid var(--border-2); box-shadow: var(--shadow-inset);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.textarea { min-height: 92px; resize: vertical; }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--primary-300); box-shadow: var(--glow);
}
.input[type=color] { height: 44px; padding: 4px 6px; cursor: pointer; }
.input[type=file] { padding: 8px 10px; cursor: pointer; }
.select { appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; background-size: 15px; padding-right: 36px; }
.hint { font-size: 11.5px; color: var(--text-3); margin-top: 4px; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; }
.switch input { display: none; }
.switch .track {
  width: 46px; height: 26px; border-radius: 999px; position: relative; transition: background .2s ease;
  background: rgba(100,116,139,.3); box-shadow: inset 0 2px 5px rgba(0,0,0,.16);
}
.switch .track::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%;
  background: #fff; box-shadow: 0 2px 6px rgba(0,0,0,.28); transition: transform .2s cubic-bezier(.3,1.4,.5,1);
}
.switch input:checked + .track { background: linear-gradient(135deg, var(--accent), var(--primary)); }
.switch input:checked + .track::after { transform: translateX(20px); }

/* ------------------------------- table ------------------------------ */
.table-wrap { overflow-x: auto; border-radius: var(--radius); }
table.tbl { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13.5px; }
table.tbl th {
  text-align: left; padding: 11px 14px; font-size: 11.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .7px; color: var(--text-3); background: var(--surface-2);
  border-bottom: 1px solid var(--border-2); position: sticky; top: 0; backdrop-filter: blur(8px);
}
table.tbl td { padding: 11px 14px; border-bottom: 1px solid var(--border-2); vertical-align: middle; }
table.tbl tbody tr { transition: background .12s ease; }
table.tbl tbody tr:hover { background: var(--surface-2); }
table.tbl tbody tr:last-child td { border-bottom: none; }

/* --------------------------- room map grid -------------------------- */
.floor-block { margin-bottom: 22px; }
.floor-head { display: flex; align-items: center; gap: 10px; margin: 0 4px 12px; }
.floor-head h3 { margin: 0; font-size: 15px; font-weight: 750; }
.floor-line { flex: 1; height: 1px; background: linear-gradient(90deg, var(--border-2), transparent); }

.room-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(124px, 1fr)); gap: 12px; }
.room {
  position: relative; padding: 12px 12px 10px; border-radius: 16px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-solid);
  box-shadow: var(--shadow-1), var(--shadow-inset);
  transition: transform .16s cubic-bezier(.2,.8,.3,1), box-shadow .2s ease;
  overflow: hidden; min-height: 104px; display: flex; flex-direction: column;
}
.room::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 5px; background: var(--_c, var(--slate));
}
.room::after {
  content: ''; position: absolute; right: -26px; bottom: -26px; width: 74px; height: 74px; border-radius: 50%;
  background: var(--_c, var(--slate)); opacity: .1;
}
.room:hover { transform: translateY(-4px) scale(1.02); box-shadow: var(--shadow-3); }
.room-top { display: flex; align-items: flex-start; gap: 6px; }
.room-no { font-size: 15.5px; font-weight: 800; letter-spacing: -.4px; flex: 0 0 auto; }
.room-type { font-size: 10.5px; font-weight: 700; letter-spacing: .6px; color: var(--text-3); text-transform: uppercase; }
.room-status { font-size: 11px; font-weight: 700; color: var(--_c, var(--slate)); margin-top: auto; }
/* the badges sit beside the number, never over it */
.room-icons { margin-left: auto; display: flex; gap: 4px; align-items: center;
  flex-wrap: wrap; justify-content: flex-end; row-gap: 3px; min-width: 0; }
.room-pill { font-size: 9.5px; font-weight: 800; padding: 2px 6px; border-radius: 999px; color: #fff; }
.room-pill.vip { background: linear-gradient(135deg, #fbbf24, #d97706); box-shadow: 0 2px 6px rgba(217,119,6,.4); }
.room-pill.job { background: linear-gradient(135deg, #f87171, #dc2626); }
.room-pill.hk  { background: linear-gradient(135deg, #c084fc, #9333ea); }
.room-pill.lock { background: #0f172a; }
.room-pill.arr { background: linear-gradient(135deg, #38bdf8, #0284c7); }
.room-pill.dep { background: linear-gradient(135deg, #94a3b8, #475569); }
.room-pill svg { vertical-align: -1px; margin-right: 2px; }
.room.compact { min-height: 74px; padding: 9px 10px; }
.room.compact .room-no { font-size: 14px; }

/* a room with nothing for maintenance to do: quiet, so the ones that do
   need attention are the only colour on the screen */
.room.plain::before { background: var(--border-2); height: 3px; }
.room.plain::after { opacity: .05; }

/* the stay dates, straight from the PMS */
.room-dates {
  margin-top: 2px; font-size: 11px; font-weight: 700; color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.room-dates .arrow { opacity: .55; }
.room.arriving .room-dates { color: #0284c7; }
.room-pill.ooo { background: #64748b; }

/* ---- what the PMS files say about the room -------------------------
   has-guest : somebody is in the room right now  (gibyroom)
   is-vip    : that somebody is a VIP
   arriving  : booked to arrive today, not checked in yet (res_detail)   */
/* text-overflow: ellipsis on a flex CONTAINER does nothing - it applies to
   the box whose text is overflowing, and here the text is an anonymous flex
   item. That is why the names were being sliced off at the tile edge with no
   "..." to say so. The ellipsis belongs on .rg-name, and min-width:0 is what
   lets a flex item shrink below the width of its own content in the first
   place. */
.room-guest {
  display: flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 700;
  color: var(--text-2); overflow: hidden; white-space: nowrap;
}
.room-guest .rg-name {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.room-guest .rg-more { flex: 0 0 auto; color: var(--text-3); font-weight: 800; }
.room-guest svg { flex: 0 0 auto; opacity: .7; }
.room-guest.exp { color: #0284c7; }

.room.has-guest {
  border-color: #22c55e; border-width: 2px;
  box-shadow: var(--shadow-1), 0 0 0 2px rgba(34,197,94,.16);
}
.room.has-guest::after { opacity: .14; }
.room.has-guest .room-no::before {
  content: ''; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: #16a34a; margin-right: 6px; vertical-align: 2px;
  box-shadow: 0 0 0 3px rgba(34,197,94,.2);
}

.room.is-vip, .room.has-guest.is-vip {
  border-color: #d97706; border-width: 2px;
  box-shadow: var(--shadow-1), var(--shadow-inset), 0 0 0 2px rgba(217,119,6,.22);
  background-image: linear-gradient(135deg, rgba(251,191,36,.14), transparent 55%);
}
.room.is-vip .room-no::before { background: #d97706; box-shadow: 0 0 0 3px rgba(217,119,6,.2); }

.room.arriving {
  border-style: dashed; border-color: #0284c7; border-width: 2px;
  background-image: linear-gradient(135deg, rgba(56,189,248,.28), rgba(56,189,248,.06) 60%);
  box-shadow: var(--shadow-1), 0 0 0 3px rgba(2,132,199,.14);
}
/* the coloured bar across the top says "arriving" at a glance, even from
   the far side of the room map */
.room.arriving::before { background: #0284c7; height: 7px; }
.room.arriving::after { background: #0284c7; opacity: .16; }
.room.arriving .room-status { color: #0284c7; }
.room.arriving .room-no::before {
  content: ''; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: transparent; border: 2px solid #0284c7; margin-right: 6px; vertical-align: 2px;
  box-shadow: none;
}

/* ---- emergency: who to call, and the photo -------------------------- */
.em-groups { display: flex; flex-wrap: wrap; gap: 6px; }
.em-group {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  padding: 6px 11px 6px 8px; border-radius: 999px; font-size: 12px; font-weight: 700;
  background: var(--surface-2); border: 1.5px solid var(--border-2); color: var(--text-2);
  transition: all .14s ease; user-select: none;
}
.em-group input { display: none; }
.em-group .dot { width: 8px; height: 8px; border-radius: 50%; opacity: .45; }
.em-group.on {
  border-color: var(--danger); color: var(--danger);
  background: rgba(239, 68, 68, .08);
}
.em-group.on .dot { opacity: 1; }
.em-preview { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.em-preview img {
  width: 74px; height: 56px; object-fit: cover; border-radius: 10px;
  border: 1px solid var(--border-2);
}
.em-photo {
  width: 100%; max-height: 190px; object-fit: cover; border-radius: 13px;
  margin: 8px 0 4px; cursor: pointer; border: 2px solid rgba(255,255,255,.35);
}

/* ---- what maintenance is doing to the room -------------------------
   maint-req    : work has been asked for            - blue, steady
   under-maint  : the room is out of service now     - red, pulsing
   The pulse beats roughly once a second: fast enough to catch the eye
   from across the office, slow enough not to be irritating on a screen
   somebody has to work in front of all day. It also wins over the guest
   and VIP borders, because a room being worked on outranks who is in it. */
.room.maint-req {
  border-color: #2563eb; border-width: 2px;
  box-shadow: var(--shadow-1), 0 0 0 2px rgba(37, 99, 235, .16);
}
.room.maint-req::before { background: #2563eb; height: 6px; }
.room.maint-req .room-status { color: #2563eb; }

.room.under-maint,
.room.has-guest.under-maint,
.room.is-vip.under-maint {
  border-color: #dc2626; border-width: 2px;
  animation: roomAlarm 1.1s ease-in-out infinite;
}
.room.under-maint::before { background: #dc2626; height: 7px; }
.room.under-maint .room-status { color: #dc2626; font-weight: 800; }
.room.under-maint .room-no::before { background: #dc2626; box-shadow: 0 0 0 3px rgba(220,38,38,.25); }

@keyframes roomAlarm {
  0%, 100% { box-shadow: var(--shadow-1), 0 0 0 2px rgba(220, 38, 38, .18); border-color: #dc2626; }
  50%      { box-shadow: var(--shadow-2), 0 0 0 7px rgba(220, 38, 38, .30); border-color: #f87171; }
}

/* somebody who has asked their device to stop animating gets a solid ring
   instead - still the loudest thing on the map, just not moving */
@media (prefers-reduced-motion: reduce) {
  .room.under-maint { animation: none; box-shadow: var(--shadow-2), 0 0 0 5px rgba(220, 38, 38, .28); }
}

/* ---- the job filter -------------------------------------------------
   Comboboxes that combine, then one Search. Changing a box no longer fires
   a query, so three filters and a date range cost one round trip instead
   of five, and a half-set filter never runs. */
.job-filter { padding: 14px 16px; }
.filter-row { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.filter-search { position: relative; flex: 1 1 220px; min-width: 180px; }
.filter-search svg { position: absolute; left: 12px; top: 11px; color: var(--text-3); }
.filter-search .input { padding-left: 36px; }
.filter-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.filter-field > span {
  font-size: 10.5px; font-weight: 700; letter-spacing: .3px;
  color: var(--text-3); text-transform: uppercase;
}
.filter-field .select, .filter-field .input { min-width: 128px; }
.filter-check {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  padding: 8px 12px; border-radius: 11px; font-size: 12px; font-weight: 700;
  color: var(--text-2); background: var(--surface-2);
  border: 1.5px solid var(--border-2); user-select: none; height: 36px;
}
.filter-check input { accent-color: var(--primary); }
.filter-check:has(input:checked) { border-color: var(--primary); color: var(--primary); }
.filter-actions { display: flex; gap: 8px; margin-left: auto; align-items: flex-end; }
.filter-summary { min-height: 16px; }
/* the sub-line on a dashboard card is its own link */
.sub-link { text-decoration: none; cursor: pointer; }
.sub-link:hover { filter: brightness(1.12); text-decoration: underline; }

@media (max-width: 860px) {
  .job-filter { padding: 12px; }
  .filter-row { gap: 8px; }
  .filter-field { flex: 1 1 46%; }
  .filter-field .select, .filter-field .input { min-width: 0; width: 100%; }
  .filter-search { flex: 1 1 100%; }
  .filter-actions { margin-left: 0; width: 100%; }
  .filter-actions .btn { flex: 1; }
  /* the phone opens on a search box; everything else is behind Filter */
  .job-filter.collapsed .filter-adv { display: none; }
  .job-filter .filter-adv { animation: filterOpen .18s ease; }
  .job-filter > .filter-row:first-child .btn { flex: 0 0 auto; }
}
@keyframes filterOpen { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

/* ---- the asset card on a job detail --------------------------------
   The picture (or a placeholder) beside the name and code, not above it,
   so the card reads in one glance the way a label on the machine would. */
.asset-mini { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }
.asset-mini img, .asset-mini .ph {
  width: 58px; height: 58px; flex: 0 0 58px; border-radius: 13px;
  object-fit: cover; border: 1px solid var(--border-2);
}
.asset-mini img { cursor: pointer; }
.asset-mini .ph {
  display: grid; place-items: center; color: var(--text-3);
  background: var(--surface-2);
}

/* ---- dashboard ------------------------------------------------------ */
.dash-split { display: grid; grid-template-columns: 1.25fr .75fr; gap: 16px; align-items: start; }
.dash-split > * { min-width: 0; }

/* ---- job / asset detail -------------------------------------------
   Two columns on a desk, one on a phone. This used to be an inline style,
   which no media query can override, so on a phone the second column ran
   off the side of the screen and took the page with it. */
.detail-grid { display: grid; grid-template-columns: 1.4fr .9fr; gap: 16px; align-items: start; }
.detail-grid > * { min-width: 0; }

.area-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; }
.area-card {
  display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 16px; cursor: pointer;
  background: var(--surface-solid); border: 1px solid var(--border);
  box-shadow: var(--shadow-1), var(--shadow-inset); transition: transform .16s ease, box-shadow .2s ease;
}
.area-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-3); }
.area-icon { width: 42px; height: 42px; flex: 0 0 42px; border-radius: 14px; display: grid; place-items: center;
  color: #fff; font-weight: 800; font-size: 15px;
  box-shadow: 0 6px 14px rgba(15,23,42,.18), inset 0 1px 0 rgba(255,255,255,.4); }

/* --------------------- PMS strip above the map ----------------------
   Which system, whether it is running, how fresh it is, and what it found -
   all one rank of information, so all one line. The title used to sit above
   the On / synced pair as a two-line block with the counts centred against
   it, which left nothing aligned to anything.

   Two groups on that line - "is the link healthy" and "what it found" - kept
   apart by a wider column gap than the one inside each group. A drawn divider
   was tried first and is wrong: a flex row wraps wherever it runs out of
   width, so at some window sizes the hairline is the first thing on a new
   line, pointing at nothing. Spacing cannot do that.

   `row-gap` is what makes the wrapped state survive: on a phone this becomes
   two or three lines, and without it the badges collide vertically. */
.pms-strip { column-gap: 22px; row-gap: 8px; }
.pms-strip .pms-group { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
/* The title reads as a caption, not as a badge, so it keeps its own size and
   colour - it just stops being a block. */
.pms-strip .stat-label { line-height: 20px; white-space: nowrap; }

/* ------------------------ map search toolbar ------------------------ */
.map-tools { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.map-search { position: relative; flex: 1 1 280px; min-width: 220px; display: flex; align-items: center; }
.map-search > svg { position: absolute; left: 12px; color: var(--text-3); pointer-events: none; }
.map-search .input { padding-left: 38px; padding-right: 34px; }
/* The little x that clears the room search.
   It was about 22px square. A fingertip is nearer 45, so clearing the search
   was two or three attempts, each one of which puts the cursor back in the
   field and reopens the keyboard. The button still LOOKS the same size - it
   has to, it sits inside the input - but ::after extends the area that
   actually responds to a touch out to 44px, centred on the icon. */
.map-search .ms-clear {
  position: absolute; right: 8px; border: 0; background: none; cursor: pointer;
  color: var(--text-3); display: grid; place-items: center; padding: 4px; border-radius: 8px;
}
.map-search .ms-clear::after {
  content: ''; position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
.map-search .ms-clear:hover { background: var(--surface-2); color: var(--text); }

/* ------------------------- department board ------------------------- */
.dept-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 14px; }
.dept-card { padding: 16px; border-radius: 18px; background: var(--surface-solid);
  border: 1px solid var(--border); box-shadow: var(--shadow-1), var(--shadow-inset);
  border-top: 4px solid var(--_g, var(--slate)); }
.dept-head { display: flex; align-items: center; gap: 10px; }
.dept-dot { width: 34px; height: 34px; border-radius: 12px; display: grid; place-items: center;
  color: #fff; font-weight: 800; font-size: 13px; background: var(--_g, var(--slate)); }
.dept-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 14px; }
.dept-stat { text-align: center; padding: 9px 4px; border-radius: 12px; background: var(--surface-2); }
.dept-stat b { display: block; font-size: 19px; font-weight: 800; line-height: 1.2; }
.dept-stat span { font-size: 10.5px; font-weight: 700; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .5px; }
.dept-stat.warn b { color: var(--warning); }
.dept-stat.bad b { color: var(--danger); }
.dept-stat.good b { color: var(--success); }
.dept-members { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.dept-member { display: flex; align-items: center; gap: 6px; padding: 4px 9px 4px 4px;
  border-radius: 999px; background: var(--surface-2); font-size: 11.5px; font-weight: 700; }
.dept-member .av { width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
  background: var(--_g, var(--slate)); color: #fff; font-size: 9.5px; font-weight: 800; }
.dept-member.secondary { opacity: .68; }

.legend { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: center; }
.legend-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-2); font-weight: 600; }
.legend-swatch { width: 13px; height: 13px; border-radius: 5px; box-shadow: inset 0 1px 0 rgba(255,255,255,.5); }
.legend-dot { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 11px; }
.legend-dot.guest { background: #16a34a; box-shadow: 0 0 0 3px rgba(34,197,94,.2); }
.legend-dot.vip { background: #d97706; box-shadow: 0 0 0 3px rgba(217,119,6,.2); }
.legend-dot.arr { background: transparent; border: 2px solid #0284c7; }
.legend-dot.dep { background: #94a3b8; }

/* ------------------------------ job card ---------------------------- */
.job-card {
  display: flex; gap: 13px; padding: 14px; border-radius: 16px; cursor: pointer;
  background: var(--surface-solid); border: 1px solid var(--border);
  box-shadow: var(--shadow-1), var(--shadow-inset);
  transition: transform .16s ease, box-shadow .2s ease; position: relative; overflow: hidden;
}
.job-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
.job-card::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--_c, var(--primary)); }
.job-thumb { width: 62px; height: 62px; flex: 0 0 62px; border-radius: 13px; object-fit: cover;
  background: var(--surface-2); box-shadow: var(--shadow-1); }
.job-thumb.ph { display: grid; place-items: center; color: var(--text-3); }
.job-body { min-width: 0; flex: 1; }
.job-title { font-weight: 700; font-size: 14px; margin-bottom: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.job-meta { font-size: 12px; color: var(--text-3); display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.job-foot { margin-top: 8px; display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }

.timer { font-variant-numeric: tabular-nums; font-weight: 750; font-size: 12.5px; }
.timer.ok { color: var(--success); }
.timer.warn { color: var(--warning); }
.timer.late { color: var(--danger); animation: blinkText 1.4s infinite; }
@keyframes blinkText { 50% { opacity: .42; } }

.progress { height: 6px; border-radius: 999px; background: rgba(100,116,139,.2); overflow: hidden; }
.progress > i { display: block; height: 100%; border-radius: 999px; transition: width .4s ease;
  background: linear-gradient(90deg, var(--accent), var(--primary)); }
.progress.warn > i { background: linear-gradient(90deg, #fbbf24, #d97706); }
.progress.late > i { background: linear-gradient(90deg, #f87171, #dc2626); }

/* --------------------- hierarchical job groups ---------------------- */
.jgroup {
  border: 1px solid var(--border); border-radius: 16px; overflow: hidden; margin-bottom: 10px;
  background: var(--surface); box-shadow: var(--shadow-1), var(--shadow-inset);
}
.jgroup-head {
  display: flex; align-items: center; gap: 8px; padding: 12px 13px; cursor: pointer;
  user-select: none; font-size: 13.5px;
}
.jgroup-head:active { background: var(--surface-2); }
.jgroup-caret { display: inline-flex; color: var(--text-3); transition: transform .2s ease; }
.jgroup.open .jgroup-caret { transform: rotate(90deg); }
.jgroup-title { font-weight: 750; }
.jgroup-sub { font-size: 11.5px; color: var(--text-3); }
.jgroup-body { display: none; padding: 0 9px 9px; }
.jgroup.open .jgroup-body { display: block; }
.jgroup-body .job-card { margin-bottom: 8px; }
.jgroup-body .job-card:last-child { margin-bottom: 0; }

.job-card.compact { padding: 11px 12px; }
.job-card.compact .job-title { font-size: 14.5px; font-weight: 800; }
.job-sub { font-size: 12.5px; color: var(--text-2); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.job-card.compact .job-foot { margin-top: 7px; }
.job-card.compact .progress { margin-top: 7px; height: 5px; }

/* ------------------------------ timeline ---------------------------- */
.timeline { position: relative; padding-left: 26px; }
.timeline::before { content: ''; position: absolute; left: 9px; top: 6px; bottom: 6px; width: 2px;
  background: linear-gradient(180deg, var(--primary), var(--accent), transparent); border-radius: 2px; }
.tl-item { position: relative; padding-bottom: 16px; }
.tl-item::before {
  content: ''; position: absolute; left: -21px; top: 4px; width: 12px; height: 12px; border-radius: 50%;
  background: var(--surface-solid); border: 2.5px solid var(--primary); box-shadow: 0 0 0 3px rgba(37,99,235,.14);
}
.tl-item.ev-done::before { border-color: var(--success); box-shadow: 0 0 0 3px rgba(34,197,94,.16); }
.tl-item.ev-escalated::before { border-color: var(--danger); box-shadow: 0 0 0 3px rgba(239,68,68,.18); }
.tl-item.ev-not_done::before { border-color: var(--warning); box-shadow: 0 0 0 3px rgba(245,158,11,.18); }
.tl-title { font-weight: 700; font-size: 13.5px; }
.tl-meta { font-size: 11.5px; color: var(--text-3); }
.tl-note { font-size: 13px; color: var(--text-2); margin-top: 3px; }

/* ------------------------------- modal ------------------------------ */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 200; display: grid; place-items: center; padding: 18px;
  background: rgba(8, 15, 30, .5); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  animation: fadeIn .18s ease;
}
@keyframes fadeIn { from { opacity: 0; } }
.modal {
  width: min(660px, 100%); max-height: 90vh; overflow: hidden; display: flex; flex-direction: column;
  background: var(--surface-solid); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3); animation: modalIn .26s cubic-bezier(.2,.9,.3,1);
}
.modal.wide { width: min(980px, 100%); }
.modal.narrow { width: min(440px, 100%); }
@keyframes modalIn { from { opacity: 0; transform: translateY(22px) scale(.97); } }
.modal-head { padding: 18px 20px 14px; border-bottom: 1px solid var(--border-2);
  display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.modal-head h3 { margin: 0; font-size: 17px; font-weight: 750; }
.modal-body { padding: 18px 20px; overflow-y: auto; }
.modal-foot { padding: 14px 20px; border-top: 1px solid var(--border-2);
  display: flex; gap: 9px; justify-content: flex-end; background: var(--surface-2); }

/* ---------------------------- context menu -------------------------- */
.ctx-menu {
  position: fixed; z-index: 300; min-width: 232px; padding: 7px; border-radius: 16px;
  background: var(--surface-solid); border: 1px solid var(--border); box-shadow: var(--shadow-3);
  animation: modalIn .16s ease;
}
.ctx-item { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border-radius: 11px;
  font-size: 13.5px; font-weight: 600; cursor: pointer; color: var(--text-2); }
.ctx-item:hover { background: var(--surface-2); color: var(--text); }
.ctx-item.danger { color: var(--danger); }
.ctx-sep { height: 1px; background: var(--border-2); margin: 5px 7px; }
.ctx-head { padding: 8px 11px 6px; font-size: 11px; font-weight: 800; letter-spacing: 1px;
  text-transform: uppercase; color: var(--text-3); }
.ctx-menu { max-height: calc(100vh - 24px); overflow: auto; }

/* guest card at the top of the room menu */
.ctx-guests { margin: 2px 4px 6px; display: flex; flex-direction: column; gap: 6px; }
.ctx-guest {
  padding: 9px 10px; border-radius: 12px; background: var(--surface-2);
  border-left: 3px solid #3b82f6;
}
.ctx-guest.expected { border-left-color: #38bdf8; border-left-style: dashed; }
.cg-name { display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 13px; font-weight: 800; color: var(--text); }
.cg-dates { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 5px;
  font-size: 11.5px; color: var(--text-2); font-weight: 600; }
.cg-dates span { display: inline-flex; align-items: center; gap: 4px; }
.cg-dates b { color: var(--text); font-weight: 800; }
.cg-meta { margin-top: 3px; font-size: 11px; color: var(--text-3); font-weight: 600;
  display: flex; align-items: center; gap: 4px; }
.raw-lines {
  margin: 8px 0 0; padding: 10px 12px; border-radius: 12px; overflow: auto;
  max-height: 260px; background: var(--surface-2); border: 1px solid var(--border-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px; line-height: 1.7; white-space: pre; color: var(--text-2);
}
.cg-more { font-size: 11px; color: var(--text-3); font-weight: 700; padding-left: 10px; }

/* ------------------------------ toasts ------------------------------ */
.toasts { position: fixed; top: 16px; right: 16px; z-index: 400; display: flex; flex-direction: column; gap: 9px;
  max-width: min(380px, calc(100vw - 32px)); }
.toast {
  display: flex; gap: 11px; padding: 13px 15px; border-radius: 15px; align-items: flex-start;
  background: var(--surface-solid); border: 1px solid var(--border); box-shadow: var(--shadow-3);
  animation: toastIn .3s cubic-bezier(.2,1.2,.4,1); position: relative; overflow: hidden;
}
@keyframes toastIn { from { opacity: 0; transform: translateX(40px); } }
.toast::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--primary); }
.toast.t-success::before { background: var(--success); }
.toast.t-error::before { background: var(--danger); }
.toast.t-warning::before { background: var(--warning); }
.toast-title { font-weight: 700; font-size: 13.5px; }
.toast-body { font-size: 12.5px; color: var(--text-2); }

/* ---------------------- emergency alert overlay --------------------- */
.emergency-overlay {
  position: fixed; inset: 0; z-index: 900; display: grid; place-items: center; padding: 20px;
  background: rgba(60, 0, 0, .55); backdrop-filter: blur(6px);
  animation: flashRed 1s steps(1) infinite;
}
@keyframes flashRed {
  0%, 49% { background: rgba(190, 18, 18, .62); box-shadow: inset 0 0 220px 70px rgba(239,68,68,.85); }
  50%, 100% { background: rgba(40, 0, 0, .58); box-shadow: inset 0 0 90px 20px rgba(239,68,68,.4); }
}
.emergency-card {
  width: min(520px, 100%); text-align: center; padding: 30px 26px; border-radius: 26px;
  background: var(--surface-solid); border: 3px solid #dc2626;
  box-shadow: 0 0 60px rgba(239,68,68,.7), var(--shadow-3);
  animation: shake .6s cubic-bezier(.36,.07,.19,.97) 2;
}
@keyframes shake {
  10%, 90% { transform: translateX(-2px); } 20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-7px); } 40%, 60% { transform: translateX(7px); }
}
.emergency-icon {
  width: 84px; height: 84px; margin: 0 auto 14px; border-radius: 50%; display: grid; place-items: center;
  background: linear-gradient(140deg, #ff6b6b, #dc2626); color: #fff;
  box-shadow: 0 0 0 10px rgba(239,68,68,.22), 0 12px 30px rgba(220,38,38,.5);
  animation: pulseRed 1s infinite;
}
.emergency-card h2 { margin: 0 0 6px; font-size: 27px; font-weight: 900; letter-spacing: 2px; color: #dc2626; }

/* ------------------------------ gallery ----------------------------- */
.photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 9px; }
.photo-grid img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 13px; cursor: pointer;
  box-shadow: var(--shadow-1); transition: transform .18s ease; }
.photo-grid img:hover { transform: scale(1.05); box-shadow: var(--shadow-2); }

.dropzone {
  border: 2px dashed var(--border-2); border-radius: 16px; padding: 20px; text-align: center;
  cursor: pointer; transition: all .18s ease; background: var(--surface-2); color: var(--text-3);
  font-size: 13px; font-weight: 600;
}
.dropzone:hover, .dropzone.drag { border-color: var(--primary); color: var(--primary); background: rgba(37,99,235,.06); }

/* ------------------------------- misc ------------------------------- */
.avatar {
  width: 36px; height: 36px; border-radius: 12px; display: grid; place-items: center; font-weight: 800;
  font-size: 13px; color: #fff; background: linear-gradient(135deg, var(--accent), var(--primary));
  box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,.35); flex: 0 0 36px;
}
/* A smaller avatar, for lists that are mostly text - the roster grid, the
   on-duty panel. Without this the 36px one overlapped the name beside it. */
.avatar.sm {
  width: 26px; height: 26px; flex: 0 0 26px; border-radius: 9px; font-size: 11px;
}
.flip-x svg { transform: scaleX(-1); }
.dot-live { width: 8px; height: 8px; border-radius: 50%; background: var(--success);
  box-shadow: 0 0 0 3px rgba(34,197,94,.22); animation: blinkText 2s infinite; }
.spinner { width: 22px; height: 22px; border-radius: 50%; border: 2.5px solid var(--border-2);
  border-top-color: var(--primary); animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.empty { text-align: center; padding: 44px 20px; color: var(--text-3); }
.empty svg { width: 46px; height: 46px; opacity: .4; margin-bottom: 10px; }
.skeleton { border-radius: 12px; background: linear-gradient(90deg, var(--surface-2) 25%, var(--border-2) 50%, var(--surface-2) 75%);
  background-size: 200% 100%; animation: shimmer 1.4s infinite; }
@keyframes shimmer { to { background-position: -200% 0; } }

.muted { color: var(--text-3); }
.small { font-size: 12px; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }
.flex { display: flex; } .items-center { align-items: center; } .gap-6 { gap: 6px; }
.gap-10 { gap: 10px; } .gap-16 { gap: 16px; } .ml-auto { margin-left: auto; }
.wrap { flex-wrap: wrap; } .col { flex-direction: column; }
.mt-8 { margin-top: 8px; } .mt-16 { margin-top: 16px; } .mb-12 { margin-bottom: 12px; } .mb-16 { margin-bottom: 16px; }
.text-right { text-align: right; } .center { text-align: center; }
.hidden { display: none !important; }

/* ------------------------------- login ------------------------------ */
.login-wrap { min-height: 100vh; display: grid; place-items: center; padding: 20px; }
.login-card {
  width: min(430px, 100%); padding: 34px 30px; border-radius: 28px; text-align: center;
  background: var(--surface); backdrop-filter: blur(26px) saturate(180%);
  -webkit-backdrop-filter: blur(26px) saturate(180%);
  border: 1px solid var(--border); box-shadow: var(--shadow-3), var(--shadow-inset);
  animation: modalIn .45s cubic-bezier(.2,.9,.3,1);
}
.login-card img { height: 74px; margin-bottom: 6px; filter: drop-shadow(0 10px 22px rgba(37,99,235,.35)); }
.login-card h1 { font-size: 22px; margin: 6px 0 2px; font-weight: 800; letter-spacing: -.4px; }

/* -------------------------- mobile tab bar -------------------------- */
.tabbar { display: none; }
.mobile-only { display: none; }

@media (max-width: 1024px) {
  .grid-4 { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .grid-3 { grid-template-columns: repeat(2, minmax(0,1fr)); }
}

@media (max-width: 860px) {
  /* Denser, calmer mobile typography: one step down and tighter line height,
     with the base size exposed as a variable so it is easy to tune. */
  :root { --header-h: 58px; --radius: 15px; --radius-sm: 11px; }
  body { font-size: 13.6px; line-height: 1.45; }
  .card { padding: 14px; }
  .card-title { font-size: 14px; }
  .card-sub { font-size: 11.5px; margin-bottom: 10px; }
  .stat { padding: 13px 14px; }
  .stat-label { font-size: 10.5px; letter-spacing: .6px; }
  .stat-value { font-size: 25px; }
  .stat-foot { font-size: 11px; }
  .stat-icon { width: 34px; height: 34px; border-radius: 11px; }
  .badge { font-size: 10.5px; padding: 2px 7px; }
  .chip { font-size: 12px; padding: 7px 12px; }
  .btn { padding: 10px 15px; }               /* keep touch targets big */
  .btn-sm { padding: 7px 11px; }
  .input, .select, .textarea { font-size: 16px; }   /* 16px stops iOS zooming in */
  .label { font-size: 12px; }
  .job-meta { font-size: 11.5px; gap: 8px; }
  .timer { font-size: 12px; }
  table.tbl { font-size: 12.5px; }
  table.tbl th, table.tbl td { padding: 9px 10px; }
  /* the dashboard's two side panels are noise on a phone */
  .mobile-hide { display: none !important; }
  /* the filter bar must not eat half the first screen */
  .content > .card:first-child { padding: 11px; }
  /* The map toolbar, on a phone.
     Each select carried an inline max-width:220px, so on a 390px screen the
     two of them took a line each with 150px of nothing beside them, and the
     legend below added four more lines. Between the header, the badges, the
     search box, the filters and the legend, the first actual ROOM was about
     1200px down - a full screen and a half of scrolling before the screen
     showed the thing it is for. Two across, tighter legend. */
  .map-tools .select {
    flex: 1 1 calc(50% - 5px); min-width: 0; max-width: none !important;
  }
  .map-tools { gap: 8px; }
  .legend { gap: 8px 14px; }
  .legend.mt-16 { margin-top: 12px; }
  .chip-row { gap: 6px; }
  .grid { gap: 12px; }
  .mb-16 { margin-bottom: 12px; }
  /* .topbar h1 was set here AND again forty lines down in this same media
     block, at two different sizes. The later one won and this one had never
     done anything since the day it was written. One rule now. */
  .topbar .sub { font-size: 11px; }
  .job-card { padding: 12px; }
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0; transform: translateX(-102%);
    transition: transform .28s cubic-bezier(.3,.9,.3,1); box-shadow: var(--shadow-3);
    width: min(300px, 86vw); flex-basis: min(300px, 86vw);
    padding-top: env(safe-area-inset-top);
    padding-bottom: max(16px, env(safe-area-inset-bottom));
  }
  /* above the tab bar (z-index 50) so the account row is always tappable */
  .sidebar.open { transform: none; z-index: 70; }
  /* One rule, not two.
     This was declared twice, three lines apart - z-index 65 and then z-index
     39 - and the second one won, so the scrim sat BELOW the tab bar at 50.
     I first wrote here that this meant you could tap the tab bar through the
     open drawer, and then checked: you could not. toggleSidebar() in app.js
     adds .hidden to the tab bar whenever the drawer opens, so nothing was
     ever reachable through the scrim and no user has ever hit this.
     It is still wrong, and worth one rule instead of two: the stacking now
     says what the behaviour is rather than relying on a line of JavaScript
     somewhere else to cover for it. If that line is ever changed - and
     hiding the navigation to open the navigation is the sort of thing that
     does get changed - the CSS underneath it is now correct. */
  .sidebar-scrim {
    position: fixed; inset: 0; z-index: 65;
    background: rgba(8,15,30,.45); backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
  }
  .content { padding: 12px 11px calc(78px + env(safe-area-inset-bottom)); }
  .topbar { padding: env(safe-area-inset-top) 13px 0; }
  .topbar h1 { font-size: 16px; }   /* the only rule for this in this block */
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .grid-auto { grid-template-columns: 1fr; }
  .form-row { grid-template-columns: 1fr; }
  .room-grid { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 9px; }
  .area-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .mobile-only { display: block; }
  .desktop-only { display: none !important; }
  .modal { border-radius: 22px; }
  .modal.wide { width: 100%; }

  .tabbar {
    display: flex; position: fixed; left: 7px; right: 7px; z-index: 50;
    bottom: calc(7px + env(safe-area-inset-bottom));
    padding: 4px 3px; border-radius: 19px; justify-content: space-around; align-items: center;
    /* Opaque, with the blur as decoration rather than as the thing doing
       the work.
       This was rgba(255,255,255,.72) and a 24px backdrop blur, which is
       lovely where backdrop-filter exists. Where it does not - and the
       Android WebView on a phone old enough to still be in a housekeeping
       trolley is exactly where it does not - all that is left is a panel
       that is 28% transparent, with room numbers and job cards scrolling
       visibly underneath the navigation. The screenshot of this screen has
       "10104 10105 10106" legible straight through the tab bar.
       So the base is near-solid and the blur only deepens it. */
    background: rgba(255, 255, 255, 0.97);
    backdrop-filter: blur(24px) saturate(180%);
    -webkit-backdrop-filter: blur(24px) saturate(180%);
    border: 1px solid var(--border); box-shadow: var(--shadow-3), var(--shadow-inset);
  }
  html[data-theme="dark"] .tabbar { background: rgba(19, 28, 47, 0.97); }
  .tab {
    flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center;
    gap: 2px; padding: 6px 2px;
    /* 8.2px. That is the primary navigation of the whole application,
       set smaller than the legal small print on a bottle of aspirin. Ten is
       still compact - the label ellipses if a translation is long, which is
       what .tab span below is for - and it is the difference between reading
       the word and recognising the shape of it. */
    border-radius: 13px; font-size: 10px; font-weight: 800; color: var(--text-3);
    text-decoration: none; transition: all .16s ease; position: relative;
    letter-spacing: 0;
  }
  .tab span {
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .tab svg { width: 17px; height: 17px; flex: 0 0 17px; }
  .tab.active { color: #fff; background: linear-gradient(135deg, var(--nav-on-1), var(--nav-on-2));
    box-shadow: 0 4px 12px var(--nav-on-glow); }
  .tab .tab-badge { position: absolute; top: 3px; right: calc(50% - 18px); min-width: 15px; height: 15px;
    border-radius: 999px; background: var(--danger); color: #fff; font-size: 10px; font-weight: 800;
    display: grid; place-items: center; padding: 0 3px; }
  /* one column, and nothing may push the page sideways */
  .detail-grid { grid-template-columns: 1fr; gap: 12px; }
  .dash-split { grid-template-columns: 1fr; gap: 12px; }
  /* A technician opens the dashboard to see what they have to do, not how
     many rooms the hotel has. On a phone My tasks comes first and the
     counters follow it. */
  .dash-root { display: flex; flex-direction: column; }
  .dash-root > .dash-split { order: -1; margin-bottom: 16px; }
  .content, .detail-grid, .card { max-width: 100%; }
  .card { overflow-x: hidden; }
  .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  img, video, canvas { max-width: 100%; }
  .toasts { top: auto; bottom: 78px; left: 12px; right: 12px; max-width: none; }
  /* leave room for the tab bar so the last menu entry is always reachable */
  .ctx-menu { max-height: calc(100vh - 100px); }
  .cg-dates { font-size: 12px; }
}

@media print {
  .sidebar, .topbar, .tabbar, .toasts, .emergency-btn { display: none !important; }
  .content { padding: 0; }
  body { background: #fff; }
}

/* =====================================================================
   CHANGE HISTORY
   ===================================================================== */
.hist-list { display: flex; flex-direction: column; gap: 10px; }
.hist-row {
  display: flex; align-items: flex-start; gap: 12px;
  background: var(--surface); backdrop-filter: blur(18px) saturate(170%);
  -webkit-backdrop-filter: blur(18px) saturate(170%);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-1); padding: 12px 14px;
}
.hist-row.undone { opacity: .58; }
.hist-dot {
  width: 9px; height: 9px; border-radius: 999px; margin-top: 7px; flex: 0 0 9px;
  background: var(--slate);
}
.hist-dot.b-success { background: var(--success); }
.hist-dot.b-danger { background: var(--danger); }
.hist-dot.b-info { background: var(--accent); }
.hist-main { min-width: 0; flex: 1; }
.hist-act { flex: 0 0 auto; }
.mt-4 { margin-top: 4px; }

/* =====================================================================
   CHAT
   ===================================================================== */
.chat-badge {
  min-width: 17px; height: 17px; border-radius: 999px; background: var(--danger);
  color: #fff; font-size: 9.5px; font-weight: 800; display: grid; place-items: center;
  padding: 0 4px; line-height: 1;
}
.chat-badge.hidden { display: none; }

.chat-fab {
  /* phones only - on a desktop the chat lives in the top bar */
  display: none;
  position: fixed; right: 18px; bottom: 18px; z-index: 60;
  width: 54px; height: 54px; border-radius: 18px; border: 1px solid var(--border);
  background: linear-gradient(135deg, var(--accent), var(--primary));
  color: #fff; place-items: center; cursor: pointer;
  box-shadow: 0 10px 28px rgba(37, 99, 235, .42); transition: transform .16s ease;
}
.chat-fab:hover { transform: translateY(-2px) scale(1.03); }
.chat-fab:active { transform: scale(.96); }

.chat-dock {
  position: fixed; right: 18px; bottom: 84px; z-index: 61;
  width: 372px; max-width: calc(100vw - 24px);
  height: min(560px, calc(100vh - 140px));
  display: none; flex-direction: column; overflow: hidden;
  background: var(--surface-solid); border: 1px solid var(--border-2);
  border-radius: var(--radius); box-shadow: var(--shadow-3);
}
.chat-dock.show { display: flex; animation: chatIn .18s ease; }
@keyframes chatIn { from { opacity: 0; transform: translateY(14px) scale(.98); } to { opacity: 1; transform: none; } }

.chat-head {
  display: flex; align-items: center; gap: 8px; padding: 10px 10px 10px 12px;
  border-bottom: 1px solid var(--border-2);
  background: linear-gradient(135deg, rgba(37, 99, 235, .10), rgba(6, 182, 212, .08));
}
.chat-head-ic { color: var(--primary); display: grid; place-items: center; }
.chat-head #chatBack svg { transform: rotate(180deg); }
.chat-title { font-weight: 800; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-sub { font-size: 11px; color: var(--text-3); }
.chat-body { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; }

/* ---- channel list */
.chat-channels { padding: 8px; display: flex; flex-direction: column; gap: 3px; }
.chat-ch {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer; padding: 9px 10px;
  border-radius: 13px; color: var(--text); transition: background .14s ease;
}
.chat-ch:hover { background: var(--surface-2); }
.chat-ch-ic { width: 34px; height: 34px; flex: 0 0 34px; border-radius: 11px; display: grid; place-items: center; }
.chat-ch-main { min-width: 0; flex: 1; }
.chat-ch-name { display: block; font-weight: 700; font-size: 13px; }
.chat-ch-last {
  display: block; font-size: 11.5px; color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-ch-meta { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex: 0 0 auto; }

/* ---- thread */
.chat-thread { padding: 12px 12px 4px; display: flex; flex-direction: column; gap: 3px; }
.chat-day { text-align: center; margin: 10px 0 6px; }
.chat-day span {
  font-size: 10.5px; font-weight: 700; color: var(--text-3);
  background: var(--surface-2); padding: 3px 10px; border-radius: 999px;
}
.chat-msg { display: flex; align-items: flex-end; gap: 7px; margin-top: 7px; }
.chat-msg.stacked { margin-top: 2px; padding-left: 33px; }
.chat-msg.mine { flex-direction: row-reverse; padding-left: 0; padding-right: 0; }
.chat-av {
  width: 26px; height: 26px; flex: 0 0 26px; border-radius: 9px; color: #fff;
  display: grid; place-items: center; font-size: 11px; font-weight: 800;
}
.chat-bub {
  max-width: 78%; padding: 7px 11px 5px; border-radius: 14px;
  background: var(--surface-2); border: 1px solid var(--border-2);
}
.chat-msg.mine .chat-bub {
  background: linear-gradient(135deg, var(--primary), var(--primary-600));
  color: #fff; border-color: transparent;
}
.chat-who { font-size: 10.5px; font-weight: 800; color: var(--primary); margin-bottom: 2px; }
.chat-text { font-size: 13px; line-height: 1.45; word-wrap: break-word; overflow-wrap: anywhere; }
.chat-time {
  font-size: 10px; opacity: .7; text-align: right; margin-top: 3px;
  display: flex; align-items: center; justify-content: flex-end; gap: 6px;
}
.chat-link { display: inline-block; font-size: 11px; font-weight: 700; margin-top: 3px; }

/* ---- has it been seen?
   Two ticks and a word. The ticks alone are a convention people have learned
   from other apps, and the word is for everybody who has not. */
.chat-rcpt { display: inline-flex; align-items: center; gap: 3px; font-weight: 700; opacity: .85; }
.chat-rcpt svg { width: 13px; height: 13px; }
.chat-msg.mine .chat-rcpt.read { opacity: 1; color: #bbf7d0; }

/* ---- a photograph in a bubble */
.chat-photo {
  display: block; max-width: 100%; width: 220px; height: auto;
  border-radius: 11px; margin: 2px 0 4px; cursor: zoom-in;
  background: var(--surface-3);
}
.chat-bub.photo-only { padding: 5px 5px 3px; }
.chat-bub.photo-only .chat-photo { margin-bottom: 2px; }

/* the one chosen but not yet sent */
.chat-pending {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  border-top: 1px solid var(--border-2); background: var(--surface-2);
}
.chat-pending img { width: 44px; height: 44px; object-fit: cover; border-radius: 10px; flex: 0 0 44px; }
.chat-pending-meta { min-width: 0; flex: 1; display: flex; flex-direction: column; }
.chat-pending-meta b { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- "there is a new one below you"
   So that scrolling up to read something is never punished by being dragged
   back down, and never punished by missing what arrived either. */
.chat-newpill {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: 76px; z-index: 3;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border: 0; border-radius: 999px; cursor: pointer;
  background: var(--primary); color: #fff; font-size: 12px; font-weight: 700;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .22);
}
.chat-newpill svg { transform: rotate(90deg); width: 15px; height: 15px; }
.chat-newpill.hidden { display: none; }

/* ---- composer
   The buttons are 42px because a thumb is about that wide. They were the
   default icon size, which is fine with a mouse and a nuisance on a phone. */
.chat-compose {
  display: flex; align-items: flex-end; gap: 8px; padding: 9px 10px;
  border-top: 1px solid var(--border-2); background: var(--surface-2);
}
.chat-compose textarea {
  flex: 1; resize: none; min-height: 42px; max-height: 120px; line-height: 1.4; padding: 11px 12px;
}
.chat-compose button { flex: 0 0 auto; }
.chat-cbtn { width: 42px; height: 42px; border-radius: 13px; }
.chat-cbtn svg { width: 21px; height: 21px; }

/* The picture button. It was a ghost button holding a thin outline, which at
   this size read as an empty box rather than as anything you could press. */
.chat-attach {
  background: linear-gradient(135deg, rgba(37, 99, 235, .13), rgba(6, 182, 212, .13));
  border: 1px solid var(--border-2); color: var(--primary);
}
.chat-attach:hover { background: linear-gradient(135deg, rgba(37, 99, 235, .2), rgba(6, 182, 212, .2)); }
.chat-attach:active { transform: scale(.94); }
.chat-attach svg { width: 22px; height: 22px; stroke-width: 1.9; }

/* take one, or choose one */
.pick-src { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.pick-btn {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 22px 12px; border-radius: 16px; cursor: pointer;
  border: 1px solid var(--border-2); background: var(--surface-2); color: var(--text);
}
.pick-btn b { font-size: 13px; }
.pick-btn svg { color: var(--primary); }
.pick-btn:hover { background: var(--surface-3); border-color: var(--primary); }
.pick-btn:active { transform: scale(.97); }

/* ---- header buttons, same reasoning */
.chat-hbtn { width: 40px; height: 40px; border-radius: 12px; }
.chat-hbtn svg { width: 20px; height: 20px; }
.chat-head-ic svg { width: 20px; height: 20px; }

.spinner-sm { width: 16px; height: 16px; border-width: 2px; }

/* ---- new direct message picker */
.dm-list { max-height: 46vh; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.dm-row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer; padding: 8px 10px;
  border-radius: 12px; color: var(--text);
}
.dm-row:hover { background: var(--surface-2); }

@media (max-width: 900px) {
  .chat-fab { display: grid; bottom: 86px; right: 14px; width: 50px; height: 50px; }
  .chat-dock {
    right: 0; left: 0; bottom: 0; width: auto; max-width: none;
    height: 84vh; border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }
  body.chat-open .tabbar { display: none; }
  .hist-row { flex-wrap: wrap; }
  .hist-act { width: 100%; }
  .hist-act .btn { width: 100%; }
}

/* ===================================================================== */
/*  MODULE 10 - CHECKLISTS AND PREVENTIVE MAINTENANCE                    */
/*  Filled in on a phone, in a plant room, one hand on a torch. Targets  */
/*  are big, the answer is two taps, and the round never scrolls         */
/*  sideways.                                                            */
/* ===================================================================== */

/* ---- period tabs (Day / Week / Month / Year, and the round's own tabs) */
.pmm-tabs {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 5px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-1), var(--shadow-inset);
  backdrop-filter: blur(18px) saturate(180%); -webkit-backdrop-filter: blur(18px) saturate(180%);
}
.pmm-tab {
  padding: 7px 15px; border-radius: 999px; font-size: 12.5px; font-weight: 700;
  color: var(--text-2); text-decoration: none; transition: all .18s ease;
  display: inline-flex; align-items: center; gap: 6px;
}
.pmm-tab:hover { background: var(--surface-2); color: var(--text); }
.pmm-tab.on {
  background: linear-gradient(160deg, var(--primary), var(--primary-2, var(--primary)));
  color: #fff; box-shadow: 0 4px 12px rgba(37,99,235,.32);
}
.pmm-tab .pill {
  font-size: 10.5px; padding: 1px 7px; border-radius: 999px;
  background: rgba(255,255,255,.22); font-weight: 800;
}
.pmm-tab:not(.on) .pill { background: var(--surface-2); color: var(--text-3); }
.pmm-window { margin-left: auto; padding-right: 10px; font-size: 11.5px; color: var(--text-3); }

/* ---- the faults strip */
.pmm-faults {
  display: flex; align-items: center; gap: 10px; padding: 11px 15px;
  border-left: 3px solid #f59e0b; font-size: 13px; color: var(--text-2);
}
.pmm-faults svg { color: #f59e0b; flex: 0 0 auto; }
.pmm-fault { color: #dc2626; font-weight: 700; }
html[data-theme="dark"] .pmm-fault { color: #f87171; }
.pmm-warn { color: #b45309; font-weight: 600; }
html[data-theme="dark"] .pmm-warn { color: #fbbf24; }

/* ---- the round list */
.pmm-list { display: flex; flex-direction: column; gap: 7px; }
.pmm-row {
  display: flex; align-items: center; gap: 12px; padding: 11px 14px;
  border-radius: 14px; text-decoration: none; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--border-2);
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.pmm-row:hover {
  transform: translateX(2px); border-color: var(--primary);
  box-shadow: 0 6px 16px rgba(15,23,42,.10);
}
.pmm-row.late { border-left: 3px solid #ef4444; }
.pmm-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.pmm-row-sub { font-size: 11.5px; color: var(--text-3); }
.pmm-row-prog { display: flex; align-items: center; gap: 8px; flex: 0 0 190px; }
.pmm-row-end { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; color: var(--text-3); }

/* ---- the progress bar */
.pmm-bar {
  flex: 1; height: 7px; min-width: 70px; border-radius: 999px; overflow: hidden;
  background: var(--border-2); box-shadow: inset 0 1px 2px rgba(15,23,42,.14);
}
.pmm-bar i {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, #22c55e, #16a34a);
  box-shadow: 0 0 8px rgba(34,197,94,.45); transition: width .4s ease;
}
.pmm-pct { font-size: 11.5px; font-weight: 800; color: var(--text-2); min-width: 34px; }

/* ---- the round header */
.pmm-head.finalized { border-left: 3px solid #16a34a; }
.pmm-progress { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.pmm-frozen, .pmm-late-note {
  display: flex; align-items: center; gap: 7px; margin-top: 12px;
  padding: 9px 13px; border-radius: 12px; font-size: 12.5px;
}
.pmm-frozen { background: rgba(22,163,74,.10); color: #15803d; border: 1px solid rgba(22,163,74,.22); }
.pmm-late-note { background: rgba(239,68,68,.10); color: #b91c1c; border: 1px solid rgba(239,68,68,.22); }
html[data-theme="dark"] .pmm-frozen { color: #4ade80; }
html[data-theme="dark"] .pmm-late-note { color: #fca5a5; }

/* ---- the checkpoint list */
.pmm-cps { display: flex; flex-direction: column; gap: 6px; }
.pmm-cp {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  padding: 11px 13px; border-radius: 13px; cursor: pointer; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--border-2);
  transition: all .16s ease;
}
.pmm-cp:hover { border-color: var(--primary); transform: translateX(2px); }
.pmm-cp-tick {
  flex: 0 0 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  border: 2px solid var(--border); color: transparent;
}
.pmm-cp.done .pmm-cp-tick { background: #16a34a; border-color: #16a34a; color: #fff; }
.pmm-cp.skipped .pmm-cp-tick { background: var(--text-3); border-color: var(--text-3); color: #fff; }
.pmm-cp.done { opacity: .78; }
.pmm-cp-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.pmm-cp-sub { font-size: 11px; color: var(--text-3); }

/* ---- documentation, remarks, last revision */
.pmm-docs { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.pmm-doc {
  display: flex; align-items: center; gap: 9px; padding: 10px 13px;
  border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border-2);
  color: var(--text); text-decoration: none;
}
.pmm-doc:hover { border-color: var(--primary); }
.pmm-prev-faults { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.pmm-prev-fault {
  display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px;
  border-radius: 12px; background: rgba(239,68,68,.07); border: 1px solid rgba(239,68,68,.16);
}
.pmm-prev-fault img { width: 46px; height: 46px; border-radius: 9px; object-fit: cover; flex: 0 0 auto; }
.pmm-prev-fault .ph {
  width: 46px; height: 46px; border-radius: 9px; display: grid; place-items: center;
  background: rgba(239,68,68,.12); color: #dc2626; flex: 0 0 auto;
}

/* ---- the checkpoint sheet: what an inspector fills in */
.pmm-sheet-head {
  display: flex; align-items: center; gap: 8px; padding-bottom: 10px;
  border-bottom: 1px solid var(--border-2); margin-bottom: 12px;
}
.pmm-asset, .pmm-prev-line {
  display: flex; align-items: center; gap: 9px; padding: 9px 12px;
  border-radius: 12px; margin-bottom: 10px; font-size: 12.5px;
  background: var(--surface-2); border: 1px solid var(--border-2); color: var(--text-2);
}
.pmm-items { display: flex; flex-direction: column; gap: 10px; }
.pmm-item {
  padding: 12px 13px; border-radius: 14px;
  background: var(--surface-2); border: 1px solid var(--border-2);
  transition: border-color .18s ease, background .18s ease;
}
.pmm-item.bad { border-color: rgba(239,68,68,.45); background: rgba(239,68,68,.06); }
.pmm-item-head { font-size: 13.5px; margin-bottom: 9px; }
.pmm-item-head .req { color: #ef4444; }
.pmm-item-ctl { display: flex; align-items: center; gap: 8px; }
.pmm-unit { font-size: 12px; color: var(--text-3); font-weight: 700; }
.pmm-item-extra { display: flex; align-items: center; gap: 8px; margin-top: 9px; }
.pmm-item-extra .input { flex: 1; }
.pmm-photo-btn { flex: 0 0 auto; cursor: pointer; }
.pmm-item-photo { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.pmm-item-photo:empty { display: none; }
.pmm-item-photo img { width: 62px; height: 62px; border-radius: 10px; object-fit: cover; }

/* the Ok / Not Ok / N/A control - the two taps that matter */
.pmm-toggle { display: flex; gap: 7px; width: 100%; }
.pmm-toggle button {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 11px 10px; border-radius: 12px; cursor: pointer; font-weight: 700; font-size: 13px;
  background: rgba(148,163,184,.12); border: 1.5px solid rgba(100,116,139,.34);
  color: var(--text-2); transition: all .16s ease;
}
html[data-theme="dark"] .pmm-toggle button {
  background: rgba(148,163,184,.10); border-color: rgba(148,163,184,.30);
}
.pmm-toggle button:disabled { cursor: default; opacity: .55; }
.pmm-toggle button:not(:disabled):hover { border-color: var(--primary); background: rgba(37,99,235,.10); }
.pmm-toggle .ok.on {
  background: linear-gradient(160deg,#22c55e,#16a34a); border-color: #16a34a; color: #fff;
  box-shadow: 0 4px 12px rgba(34,197,94,.34);
}
.pmm-toggle .bad.on {
  background: linear-gradient(160deg,#ef4444,#dc2626); border-color: #dc2626; color: #fff;
  box-shadow: 0 4px 12px rgba(239,68,68,.34);
}
.pmm-toggle .na.on { background: var(--text-3); border-color: var(--text-3); color: #fff; }

/* a multi-select is a list, not a dropdown - lose the chevron */
.select[multiple] { background-image: none; padding-right: 12px; height: auto; }

/* ---- the target picker preview */
.pmm-target { margin-bottom: 6px; }
.pmm-preview { min-height: 22px; margin-bottom: 12px; }
.pmm-preview-in {
  display: inline-flex; align-items: center; gap: 7px; padding: 6px 12px;
  border-radius: 999px; font-size: 12.5px;
  background: rgba(37,99,235,.10); border: 1px solid rgba(37,99,235,.22); color: var(--text-2);
}

/* ---- the checklist builder */
.pmm-build-title {
  margin: 18px 0 8px; font-size: 13px; font-weight: 800; letter-spacing: .3px;
  text-transform: uppercase; color: var(--text-3);
}
.pmm-build-head, .pmm-build-row {
  display: grid; gap: 7px; align-items: center;
  grid-template-columns: 22px minmax(140px,2fr) minmax(100px,1.4fr) 130px 78px minmax(110px,1.4fr) 46px 38px;
}
.pmm-build-head { grid-template-columns: 22px minmax(140px,2fr) minmax(100px,1.4fr) 130px 78px minmax(110px,1.4fr) 46px 38px;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-3);
  padding: 0 2px 5px; }
.pmm-build-head span:first-child { grid-column: 2; }
.pmm-build-row { margin-bottom: 6px; }
.pmm-build-row .pmm-build-h { color: var(--text-3); cursor: grab; }
.pmm-build-row .input, .pmm-build-row .select { padding: 8px 10px; font-size: 12.5px; }
.pmm-doc-row {
  display: flex; align-items: center; gap: 9px; padding: 8px 11px; margin-bottom: 5px;
  border-radius: 11px; background: var(--surface-2); border: 1px solid var(--border-2); font-size: 12.5px;
}
.pmm-doc-row a { color: var(--primary); text-decoration: none; }

/* ---- small utilities this module needs */
.field.grow { flex: 1 1 180px; }
.switch.nowrap { white-space: nowrap; flex: 0 0 auto; }
.input.narrow { max-width: 80px; }
.mt-10 { margin-top: 10px; }

/* ---- phone: the whole point is that it works on one */
@media (max-width: 900px) {
  .pmm-tabs { overflow-x: auto; flex-wrap: nowrap; }
  .pmm-tab { flex: 0 0 auto; padding: 7px 13px; }
  .pmm-window { display: none; }
  .pmm-row { flex-wrap: wrap; gap: 7px; }
  .pmm-row-prog { flex: 1 1 100%; order: 3; }
  .pmm-row-end { order: 2; }
  .pmm-item-extra { flex-wrap: wrap; }
  .pmm-item-extra .input { flex: 1 1 100%; }
  .pmm-toggle button { padding: 13px 8px; font-size: 13.5px; }
  .pmm-build-head { display: none; }
  .pmm-build-row {
    grid-template-columns: 1fr 1fr; padding: 10px; margin-bottom: 9px;
    border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border-2);
  }
  .pmm-build-row .pmm-build-h { display: none; }
  .pmm-build-row .input[data-f="label"] { grid-column: 1 / -1; }
  .pmm-build-row .input[data-f="expects"] { grid-column: 1 / -1; }
  .input.narrow { max-width: none; }
}

/* ---- preparing: the diary, not the queue -------------------------- */
.pmm-cards { display: grid; gap: 14px; grid-template-columns: repeat(5, minmax(0, 1fr)); }
@media (max-width: 1400px) { .pmm-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 780px)  { .pmm-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.badge.b-prep {
  background: rgba(139,92,246,.15); color: #6d28d9; border-color: rgba(139,92,246,.3);
}
html[data-theme="dark"] .badge.b-prep { color: #c4b5fd; }

.pmm-nextup {
  display: flex; align-items: center; gap: 10px; padding: 11px 15px; font-size: 13px;
  border-left: 3px solid #8b5cf6; color: var(--text-2);
}
.pmm-nextup svg { color: #8b5cf6; flex: 0 0 auto; }

/* a preparing row has no progress bar, because there is no progress yet */
.pmm-row.prep {
  border-left: 3px solid #8b5cf6;
  background: linear-gradient(100deg, rgba(139,92,246,.08), var(--surface-2) 55%);
}
.pmm-row.prep:hover { border-color: #8b5cf6; }
.pmm-when { flex-direction: column; align-items: flex-end; gap: 1px; }
.pmm-when-date { font-size: 12.5px; font-weight: 700; color: var(--text); }
.pmm-when-rel { font-size: 11px; color: #7c3aed; font-weight: 700; }
html[data-theme="dark"] .pmm-when-rel { color: #c4b5fd; }

/* ---- the room scope picker ---------------------------------------- */
.pmm-scope { display: flex; gap: 7px; flex-wrap: wrap; }
.pmm-scope-btn {
  display: inline-flex; align-items: center; gap: 7px; padding: 9px 14px;
  border-radius: 12px; cursor: pointer; font-weight: 700; font-size: 12.5px;
  background: rgba(148,163,184,.12); border: 1.5px solid rgba(100,116,139,.3);
  color: var(--text-2); transition: all .16s ease;
}
.pmm-scope-btn:hover { border-color: var(--primary); background: rgba(37,99,235,.10); color: var(--text); }
.pmm-scope-btn.on {
  background: linear-gradient(150deg, var(--accent), var(--primary));
  border-color: transparent; color: #fff;
  box-shadow: 0 5px 14px rgba(37,99,235,.34), inset 0 1px 0 rgba(255,255,255,.35);
}
html[data-theme="dark"] .pmm-scope-btn { background: rgba(148,163,184,.10); border-color: rgba(148,163,184,.28); }

.pmm-roomtools { display: flex; gap: 8px; align-items: center; margin-bottom: 7px; }
.pmm-roomtools .input { flex: 1; }
.pmm-roomlist { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }
.pmm-roomlist option { padding: 3px 6px; }

@media (max-width: 900px) {
  .pmm-when { align-items: flex-start; }
  .pmm-scope-btn { flex: 1 1 calc(50% - 4px); justify-content: center; }
  .pmm-roomtools { flex-wrap: wrap; }
  .pmm-roomtools .input { flex: 1 1 100%; }
}

/* ---- a round that has not happened yet ----------------------------- */
.prep-head { border-left: 3px solid #8b5cf6; }
.prep-when {
  display: flex; align-items: center; gap: 14px; margin-top: 14px;
  padding: 13px 16px; border-radius: 14px;
  background: linear-gradient(100deg, rgba(139,92,246,.12), rgba(139,92,246,.04));
  border: 1px solid rgba(139,92,246,.24);
}
.prep-when-main { display: flex; align-items: center; gap: 11px; flex: 1; }
.prep-when-main svg { color: #7c3aed; flex: 0 0 auto; }
.prep-when-label {
  font-size: 10.5px; font-weight: 800; letter-spacing: 1.1px;
  text-transform: uppercase; color: var(--text-3);
}
.prep-when-date { font-size: 17px; font-weight: 800; letter-spacing: -.3px; }
.prep-when-rel {
  font-size: 13px; font-weight: 800; color: #6d28d9;
  padding: 6px 13px; border-radius: 999px; background: rgba(139,92,246,.16);
}
html[data-theme="dark"] .prep-when-rel { color: #c4b5fd; }

.pmm-locked {
  display: flex; align-items: flex-start; gap: 9px; margin-top: 12px;
  padding: 11px 14px; border-radius: 12px; font-size: 12.5px;
  background: var(--surface-2); border: 1px solid var(--border-2); color: var(--text-2);
}
.pmm-locked svg { flex: 0 0 auto; margin-top: 1px; color: var(--text-3); }

.prep-actions {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 13px; border-top: 1px dashed var(--border);
}
.prep-actions .muted { flex: 1; min-width: 200px; }

.prep-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 11px; }
.prep-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 11px; border-radius: 999px; font-size: 12px; font-weight: 600;
  background: var(--surface-2); border: 1px solid var(--border-2); color: var(--text-2);
}
.prep-chip.more { background: rgba(139,92,246,.14); border-color: rgba(139,92,246,.26); font-weight: 800; }

.prep-items { display: flex; flex-direction: column; gap: 5px; margin-top: 11px; }
.prep-item {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px;
  border-radius: 11px; font-size: 13px;
  background: var(--surface-2); border: 1px solid var(--border-2);
}
.prep-item .n {
  flex: 0 0 22px; height: 22px; border-radius: 7px; display: grid; place-items: center;
  font-size: 11px; font-weight: 800; color: var(--text-3);
  background: var(--surface); border: 1px solid var(--border-2);
}
.prep-item > span:nth-child(2) { flex: 1; min-width: 0; }

.prep-meta {
  display: flex; gap: 18px; flex-wrap: wrap; margin-top: 13px; padding-top: 12px;
  border-top: 1px solid var(--border-2); font-size: 12.5px; color: var(--text-2);
}

/* ---- walked before its date, and saying so -------------------------- */
.early-warn {
  display: flex; align-items: flex-start; gap: 12px; padding: 14px;
  border-radius: 14px; font-size: 13.5px;
  background: rgba(245,158,11,.12); border: 1px solid rgba(245,158,11,.32); color: var(--text);
}
.early-warn svg { color: #d97706; flex: 0 0 auto; margin-top: 1px; }

.pmm-early-note {
  display: flex; align-items: flex-start; gap: 9px; margin-top: 12px;
  padding: 11px 14px; border-radius: 12px; font-size: 12.5px;
  background: rgba(245,158,11,.11); border: 1px solid rgba(245,158,11,.28); color: var(--text-2);
}
.pmm-early-note svg { color: #d97706; flex: 0 0 auto; margin-top: 2px; }
.pmm-early-why {
  margin: 5px 0 4px; padding: 7px 11px; border-radius: 9px;
  background: var(--surface); border-left: 2px solid #d97706;
  color: var(--text); font-style: italic;
}

@media (max-width: 900px) {
  .prep-when { flex-wrap: wrap; }
  .prep-when-rel { width: 100%; text-align: center; }
  .prep-actions .btn { width: 100%; }
  .prep-meta { gap: 8px; flex-direction: column; }
}

/* the line under the frequency tabs: what you are looking at, and what
   the Completed figure covers - so no number on the page is a guess */
.pmm-scopeline {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 9px 15px; border-radius: 13px; font-size: 12.5px; color: var(--text-2);
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-1), var(--shadow-inset);
}
.pmm-scopeline .muted { margin-left: auto; font-size: 11.5px; }
@media (max-width: 900px) {
  .pmm-scopeline { gap: 4px; }
  .pmm-scopeline .muted { margin-left: 0; }
}

/* ---- the header icons, made legible on a phone -------------------- */
/* They were 35px ghost buttons with a 17px line icon inside: on a 6-inch
   screen in daylight that reads as three empty circles. Each now has a
   tinted face of its own, so it is a button with a job rather than a mark. */
.topbar-actions .btn-icon {
  width: 38px; height: 38px; border-radius: 12px;
  background: var(--surface-2); border: 1px solid var(--border-2);
  color: var(--text-2);
}
.topbar-actions .btn-icon svg { width: 19px; height: 19px; stroke-width: 2.4; }
.topbar-actions .btn-icon:hover { border-color: currentColor; }
#btnLang span { font-size: 11.5px !important; letter-spacing: .4px; }

/* Each one carries its own colour. Six identical grey circles in a row are
   six things nobody can tell apart at arm's length in daylight; a green
   question mark, a violet moon and an amber bell are three things you can
   hit without looking. */
#btnHelp  { color: #047857; background: rgba(16,185,129,.16); border-color: rgba(16,185,129,.34); }
#btnLang  { color: #1e40af; background: rgba(37,99,235,.13);  border-color: rgba(37,99,235,.28); }
#btnTheme { color: #6d28d9; background: rgba(139,92,246,.15); border-color: rgba(139,92,246,.30); }
#btnChat  { color: #0e7490; background: rgba(6,182,212,.15);  border-color: rgba(6,182,212,.30); }
#btnBell  { color: #b45309; background: rgba(245,158,11,.17); border-color: rgba(245,158,11,.34); }
html[data-theme="dark"] #btnHelp  { color: #6ee7b7; }
html[data-theme="dark"] #btnLang  { color: #93c5fd; }
html[data-theme="dark"] #btnTheme { color: #c4b5fd; }
html[data-theme="dark"] #btnChat  { color: #67e8f9; }
html[data-theme="dark"] #btnBell  { color: #fbbf24; }

@media (max-width: 900px) {
  .topbar-actions { gap: 5px; }
  .topbar-actions .btn-icon { width: 36px; height: 36px; border-radius: 11px; padding: 6px; }
  .topbar-actions .btn-icon svg { width: 19px; height: 19px; stroke-width: 2.5; }
  /* the account button keeps its avatar, so it needs no tint of its own */
  #btnAccount { background: none; border-color: transparent; }
}
/* on a narrow phone the language toggle is the one that can go - it is in
   the account sheet as well */
@media (max-width: 400px) { #btnLang { display: none; } }

/* ===================================================================== */
/*  THE USER GUIDE, AS A SCREEN                                          */
/* ===================================================================== */
/* Contents down the side, the chapter beside it. The sidebar sticks while
   the chapter scrolls, because a manual you have to scroll back up to
   navigate is a manual nobody navigates. Below 900px it becomes a strip
   above the text - a phone has no room for two columns and the contents
   are still the first thing you want. */
.g-wrap { display: grid; grid-template-columns: 244px 1fr; gap: 16px; align-items: start; }
/* No inner scroll, and therefore no scrollbar.
   Eighteen chapters and five part headings come to about 700px, which fits
   the viewport on any ordinary screen - so the contents was given its own
   scroll region to solve a problem it does not have, and charged a permanent
   grey bar for it. Where the viewport IS too short, the panel stops sticking
   and scrolls with the page instead: everything stays reachable, and still
   nothing draws a scrollbar. */
.g-toc { position: sticky; top: 14px;
  background: var(--surface); border: 1px solid var(--border-2); border-radius: 16px;
  padding: 10px; }
@media (max-height: 820px) { .g-toc { position: static; } }
.g-part { font-size: 10px; font-weight: 800; letter-spacing: .7px; text-transform: uppercase;
  color: var(--primary); padding: 12px 8px 5px; }
.g-part:first-child { padding-top: 4px; }
.g-toc-item { display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left;
  background: none; border: 0; border-radius: 9px; padding: 6px 9px; cursor: pointer;
  font: inherit; font-size: 12.5px; color: var(--text-2); line-height: 1.35; }
.g-toc-item .n { color: var(--text-3); font-weight: 800; font-size: 11px; min-width: 14px; }
.g-toc-item:hover { background: var(--surface-2); color: var(--text); }
.g-toc-item.active { background: rgba(37,99,235,.12); color: var(--primary); font-weight: 700; }
.g-toc-item.active .n { color: var(--primary); }

.g-body { min-width: 0; }
.g-chapter { background: var(--surface); border: 1px solid var(--border-2);
  border-radius: 18px; padding: 22px 24px; }
.g-head { border-bottom: 2px solid var(--primary); padding-bottom: 14px; margin-bottom: 18px; }
.g-kicker { font-size: 10.5px; font-weight: 800; letter-spacing: 1px;
  text-transform: uppercase; color: var(--primary); }
.g-head h2 { font-size: 25px; letter-spacing: -.5px; margin: 4px 0 0; }
.g-intro { color: var(--text-2); margin: 10px 0 0; font-size: 14px; }
.g-fig { margin: 0 0 20px; }
.g-fig svg { width: 100%; height: auto; }
.g-fig figcaption { text-align: center; font-size: 11.5px; color: var(--text-3); margin-top: 6px; }

.g-sec { margin-bottom: 26px; scroll-margin-top: 16px; }
.g-sec h3 { font-size: 16px; margin: 0 0 8px; padding-left: 10px;
  border-left: 3px solid var(--primary); }
.g-sec p { margin: 0 0 8px; color: var(--text-2); font-size: 13.5px; line-height: 1.62; }

ol.g-steps { list-style: none; margin: 12px 0; padding: 0; counter-reset: gs; }
ol.g-steps li { counter-increment: gs; position: relative; padding-left: 32px;
  margin-bottom: 9px; font-size: 13.5px; line-height: 1.55; }
ol.g-steps li::before { content: counter(gs); position: absolute; left: 0; top: 0;
  width: 22px; height: 22px; border-radius: 50%; background: var(--primary); color: #fff;
  font-size: 11px; font-weight: 800; display: flex; align-items: center; justify-content: center; }
ol.g-steps li .sn { display: block; color: var(--text-3); font-size: 12.5px; margin-top: 2px; }

table.g-fields td.k { font-weight: 700; width: 32%; }
.g-perm { display: inline-flex; align-items: center; gap: 5px; margin-top: 8px;
  font-family: ui-monospace, 'DejaVu Sans Mono', monospace; font-size: 11.5px;
  color: var(--text-2); background: var(--surface-2); border: 1px solid var(--border-2);
  border-radius: 7px; padding: 3px 8px; }

.g-hit { display: block; width: 100%; text-align: left; background: none; border: 0;
  border-bottom: 1px solid var(--border-2); padding: 9px 4px; cursor: pointer; font: inherit; }
.g-hit:last-child { border-bottom: 0; }
.g-hit:hover { background: var(--surface-2); }
.g-hit-h { font-size: 13px; font-weight: 700; color: var(--text); }
.g-hit-s { font-size: 12px; color: var(--text-3); margin-top: 2px; line-height: 1.45; }

/* Where a search result landed. It fades rather than staying highlighted:
   the point is to catch the eye once, not to leave the page marked up. */
@keyframes gflash { 0%,70% { background: rgba(37,99,235,.13); } 100% { background: transparent; } }
.g-flash { animation: gflash 1.6s ease-out; border-radius: 10px; }

@media (max-width: 900px) {
  .g-wrap { grid-template-columns: 1fr; }
  .g-toc { position: static; max-height: 210px; }
  .g-chapter { padding: 16px 15px; border-radius: 14px; }
  .g-head h2 { font-size: 21px; }
}

/* Print: the contents, the search box and the chrome are not part of the
   book. Everything else is, and every chapter starts on a fresh sheet. */
@media print {
  .sidebar, .topbar, .tabbar, .g-toc, .g-bar, #gSearchOut { display: none !important; }
  .content, .g-body, .g-chapter { border: 0; padding: 0; background: #fff; }
  .g-chapter { page-break-before: always; }
  .g-sec { page-break-inside: avoid; }
}

/* ===================================================================== */
/*  THE GUIDE BEHIND THE QUESTION MARK                                   */
/* ===================================================================== */
/* The "?" that belongs to one control, sat beside its title.
   Deliberately quiet until wanted: at full strength, forty of them across
   the settings screen read as forty warnings. It comes up to full contrast
   on hover and on keyboard focus, and the touch target is padded out to 26px
   because the visible circle is 18 and a fingertip is nearer 45. */
.help-dot {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; flex: 0 0 18px; margin-left: 7px; padding: 0;
  border-radius: 50%; border: 1px solid rgba(100,116,139,.35);
  background: transparent; color: var(--text-3);
  font-size: 11px; font-weight: 800; line-height: 1; cursor: pointer;
  position: relative; vertical-align: middle;
  transition: color .15s, border-color .15s, background .15s;
}
.help-dot::after {                 /* the invisible part a thumb actually hits */
  content: ''; position: absolute; top: -6px; right: -6px; bottom: -6px; left: -6px;
}
.help-dot:hover, .help-dot:focus-visible {
  color: var(--primary); border-color: var(--primary);
  background: rgba(37,99,235,.1); outline: none;
}
html[data-theme="dark"] .help-dot { border-color: rgba(148,163,184,.34); }
.card-title .help-dot { margin-left: 8px; }

.help-body { max-height: 66vh; overflow-y: auto; padding-right: 4px; }
/* The list of per-control topics at the foot of a page guide. Every topic is
   reachable from here, which is what makes "every function has a ?" true even
   on a toolbar with nowhere to hang one. */
.help-index { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border-2); }
.help-chips { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 8px; }
.chip-sm { padding: 5px 11px; font-size: 12px; font-weight: 600; }
.help-lead {
  margin: 0 0 16px; padding: 12px 15px; border-radius: 13px; font-size: 13.5px;
  background: rgba(37,99,235,.09); border: 1px solid rgba(37,99,235,.2); color: var(--text);
}
.help-sec { margin-bottom: 15px; }
.help-sec h4 {
  margin: 0 0 5px; font-size: 13px; font-weight: 800; color: var(--text);
  display: flex; align-items: center; gap: 7px;
}
.help-sec h4::before {
  content: ''; width: 4px; height: 14px; border-radius: 2px; flex: 0 0 4px;
  background: linear-gradient(180deg, var(--nav-on-1), var(--nav-on-2));
}
.help-sec p { margin: 0; color: var(--text-2); font-size: 13px; line-height: 1.6; }
.help-sec ul { margin: 6px 0 0; padding-left: 20px; color: var(--text-2); font-size: 13px; }
.help-sec li { margin-bottom: 3px; }
.help-tips {
  margin-top: 18px; padding: 13px 15px; border-radius: 13px;
  background: rgba(245,158,11,.1); border: 1px solid rgba(245,158,11,.26);
}
.help-tips h4 {
  margin: 0 0 7px; font-size: 11.5px; font-weight: 800; letter-spacing: .5px;
  text-transform: uppercase; color: #b45309; display: flex; align-items: center; gap: 6px;
}
html[data-theme="dark"] .help-tips h4 { color: #fbbf24; }
.help-tips ul { margin: 0; padding-left: 19px; font-size: 12.5px; color: var(--text-2); }
.help-tips li { margin-bottom: 5px; }

/* ===================================================================== */
/*  WHO IS ON THIS                                                       */
/* ===================================================================== */
.team-card .card-sub { margin-bottom: 12px; }
.team-list { display: flex; flex-direction: column; gap: 7px; }
.team-row {
  display: flex; align-items: flex-start; gap: 11px; padding: 11px 13px;
  border-radius: 13px; background: var(--surface-2); border: 1px solid var(--border-2);
}
.team-row.faded { opacity: .55; }
.team-av {
  flex: 0 0 32px; width: 32px; height: 32px; border-radius: 11px; display: grid;
  place-items: center; font-weight: 800; font-size: 13px; color: #fff;
  background: linear-gradient(135deg, var(--accent), var(--primary));
}
.team-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.team-sub { font-size: 11.5px; color: var(--text-3); }
.team-note {
  margin-top: 5px; padding: 6px 10px; border-radius: 9px; font-size: 12.5px;
  background: var(--surface); border-left: 2px solid var(--nav-on-2); color: var(--text-2);
}
.team-reason {
  margin-top: 4px; font-size: 12px; font-style: italic; color: var(--text-3);
}
.team-end { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; flex: 0 0 auto; }
.team-actions { display: flex; gap: 5px; }

.ask-list { max-height: 42vh; overflow-y: auto; display: flex; flex-direction: column; gap: 5px; }
.ask-row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 9px 12px; border-radius: 12px; cursor: pointer; color: var(--text);
  background: var(--surface-2); border: 1.5px solid var(--border-2); transition: all .15s ease;
}
.ask-row:hover:not([disabled]) { border-color: var(--nav-on-2); }
.ask-row.on {
  background: rgba(16,185,129,.12); border-color: var(--nav-on-2);
}
.ask-row[disabled] { opacity: .5; cursor: default; }
.ask-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.ask-tick { opacity: 0; color: var(--nav-on-2); flex: 0 0 auto; }
.ask-row.on .ask-tick { opacity: 1; }

/* ===================================================================== */
/*  TWO-FACTOR                                                           */
/* ===================================================================== */
.tfa-steps { display: flex; flex-direction: column; gap: 16px; }
.tfa-step { display: flex; gap: 13px; align-items: flex-start; }
.tfa-step .n {
  flex: 0 0 26px; width: 26px; height: 26px; border-radius: 50%; display: grid;
  place-items: center; font-weight: 800; font-size: 12.5px; color: #fff;
  background: linear-gradient(135deg, var(--nav-on-1), var(--nav-on-2));
}
.tfa-step > div { flex: 1; min-width: 0; }
.tfa-step > div > b { display: block; margin-bottom: 3px; font-size: 13.5px; }
.tfa-qr {
  margin: 10px 0; padding: 12px; border-radius: 15px; width: fit-content;
  background: #fff; border: 1px solid var(--border-2); box-shadow: var(--shadow-1);
}
.tfa-qr svg { display: block; width: 190px; height: 190px; }
.tfa-secret { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.tfa-secret code {
  font-family: ui-monospace, Menlo, monospace; font-size: 13px; letter-spacing: 1.2px;
  padding: 6px 11px; border-radius: 9px; user-select: all;
  background: var(--surface-2); border: 1px solid var(--border-2);
}
.input.tfa-code {
  font-family: ui-monospace, Menlo, monospace; font-size: 24px; letter-spacing: 9px;
  text-align: center; font-weight: 800; max-width: 210px; margin-top: 8px;
}
.tfa-done {
  display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 14px;
  background: rgba(16,185,129,.12); border: 1px solid rgba(16,185,129,.3);
}
.tfa-done svg { color: var(--nav-on-2); flex: 0 0 auto; }
.tfa-codes {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 7px; margin: 14px 0;
}
.tfa-codes code {
  font-family: ui-monospace, Menlo, monospace; font-size: 13.5px; text-align: center;
  padding: 8px; border-radius: 9px; letter-spacing: .6px; user-select: all;
  background: var(--surface-2); border: 1px solid var(--border-2);
}

/* ===================================================================== */
/*  BACKUPS                                                              */
/* ===================================================================== */
.bk-meta {
  display: flex; gap: 20px; flex-wrap: wrap; margin: 13px 0;
  padding: 11px 14px; border-radius: 12px; font-size: 12.5px; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border-2);
}
.bk-sched {
  display: flex; align-items: center; gap: 11px; flex-wrap: wrap;
  padding-top: 12px; border-top: 1px dashed var(--border);
}
.bk-sched .muted { flex: 1; min-width: 170px; }
.nowrap { white-space: nowrap; }

@media (max-width: 900px) {
  .team-row { flex-wrap: wrap; }
  .team-end { width: 100%; }
  .tfa-codes { grid-template-columns: 1fr; }
  .bk-meta { flex-direction: column; gap: 5px; }
  .bk-sched { flex-direction: column; align-items: stretch; }
  .help-body { max-height: 72vh; }
}

/* every zoomable image, whatever draws it */
[data-zoom] { cursor: zoom-in; }

/* =====================================================================
   THE DUTY ROSTER
   A roster is a spreadsheet and pretending otherwise helps nobody: people
   down the side, days across the top, one code per cell. Fourteen columns
   have to fit a phone, so the cells are small, the name column is sticky,
   and the grid scrolls sideways under a header that does not.
   ===================================================================== */
.roster-wrap { overflow: auto; max-height: calc(100vh - 320px); }
.roster-tbl { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12.5px; }
.roster-tbl th, .roster-tbl td { border-bottom: 1px solid var(--border-2); padding: 0; }

/* the name column stays put while the fortnight scrolls past it - without
   this you are looking at a row of codes with no idea whose row it is */
.roster-tbl .rt-name {
  position: sticky; left: 0; z-index: 2;
  background: var(--surface-solid); min-width: 168px; max-width: 168px;
  padding: 7px 10px; text-align: left;
}
.roster-tbl thead th {
  position: sticky; top: 0; z-index: 3;
  background: var(--surface-solid); padding: 6px 2px; text-align: center;
  font-size: 11px; font-weight: 800; color: var(--text-2);
}
.roster-tbl thead .rt-name { z-index: 4; }
.rt-wd { font-size: 10.5px; color: var(--text-3); font-weight: 700; }
.rt-dn { font-size: 13px; font-weight: 800; }
.rt-weekend { background: var(--surface-2); }
.rt-today { color: var(--primary); }
.rt-today .rt-dn { position: relative; }
.rt-today .rt-dn::after {
  content: ''; position: absolute; left: 50%; bottom: -3px; transform: translateX(-50%);
  width: 16px; height: 2px; border-radius: 2px; background: var(--primary);
}
.rt-person { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.rt-cell {
  min-width: 44px; height: 42px; text-align: center; cursor: pointer;
  border-left: 1px solid var(--border-2); transition: background .12s ease;
  vertical-align: middle;
}
.rt-cell.we { background: var(--surface-2); }
.rt-cell.today { box-shadow: inset 0 0 0 1px var(--primary-300); }
.rt-cell:hover { background: var(--surface-3); }
.rt-cell:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
/* a working day carries its colour; a day off is flat and grey, because the
   whole point of the grid is seeing at a glance who is actually in */
.rt-cell.on { background: color-mix(in srgb, var(--_d) 16%, transparent); }
.rt-cell.on b { color: var(--_d); font-size: 12.5px; font-weight: 800; display: block; }
.rt-cell.off b { color: var(--text-3); font-size: 12px; font-weight: 800; display: block; }
.rt-hrs { font-size: 10px; color: var(--text-3); font-weight: 700; display: block; }
.rt-sum {
  min-width: 44px; text-align: center; font-weight: 800; color: var(--text-2);
  border-left: 1px solid var(--border-2); font-size: 12px;
}
.rt-plus1 { font-style: normal; font-size: 9.5px; opacity: .8; }

/* where color-mix is not available - the same old WebViews that have no
   backdrop-filter - a flat tint rather than nothing at all */
@supports not (background: color-mix(in srgb, red 10%, transparent)) {
  .rt-cell.on { background: var(--surface-2); }
  .rt-cell.on b { color: var(--text); }
}

.roster-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center; }
.rl-item {
  display: inline-flex; align-items: center; gap: 6px; font-size: 12px;
  padding: 4px 8px; border-radius: 999px;
}
.rl-item.pick { cursor: pointer; border: 1px solid var(--border-2); }
.rl-item.pick:hover { border-color: var(--primary); background: var(--surface-2); }
.rl-dot { width: 9px; height: 9px; border-radius: 999px; flex: 0 0 9px; }

/* ---- the cell editor: duty codes as buttons, not a dropdown.
   Six codes in a dropdown is two taps and a scroll; six buttons is one tap,
   which matters when somebody is filling in a fortnight. */
.duty-pick { display: flex; flex-wrap: wrap; gap: 8px; }
.duty-opt {
  flex: 1 1 92px; min-width: 92px; padding: 9px 8px; border-radius: 12px;
  border: 1px solid var(--border-2); background: var(--surface-2); cursor: pointer;
  text-align: left; font-family: inherit; color: var(--text);
}
.duty-opt b { display: block; font-size: 14px; font-weight: 800; color: var(--_d); }
.duty-opt span { display: block; font-size: 11px; color: var(--text-3); }
.duty-opt.active {
  border-color: var(--_d); background: color-mix(in srgb, var(--_d) 14%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--_d) 18%, transparent);
}
.duty-opt.shift b { color: var(--text); font-size: 13px; }
@supports not (background: color-mix(in srgb, red 10%, transparent)) {
  .duty-opt.active { border-color: var(--primary); background: var(--surface-3); }
}

.fill-people { max-height: 210px; overflow: auto; border: 1px solid var(--border-2);
  border-radius: 12px; padding: 8px 10px; }
.fill-row { display: flex; align-items: center; gap: 9px; padding: 5px 0; font-size: 13px; cursor: pointer; }
.fill-days { display: flex; flex-wrap: wrap; gap: 6px; }
.fill-day {
  flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 6px 9px; border-radius: 10px; border: 1px solid var(--border-2);
  cursor: pointer; font-size: 11px; text-align: center; min-width: 46px;
}
.fill-day.we { background: var(--surface-2); }
.fill-day:has(input:checked) { border-color: var(--primary); background: var(--surface-3); }
.switch-row { display: flex; align-items: center; gap: 9px; cursor: pointer; font-size: 13.5px; }

.callout {
  display: flex; align-items: flex-start; gap: 9px; padding: 10px 12px;
  border-radius: 12px; background: var(--surface-2); font-size: 12.5px;
  border: 1px solid var(--border-2); color: var(--text-2);
}
.callout.ok { background: rgba(34, 197, 94, .12); border-color: rgba(34, 197, 94, .3); color: var(--text); }
.callout.warn { background: rgba(245, 158, 11, .12); border-color: rgba(245, 158, 11, .35); color: var(--text); }

/* ---- the chip beside the bell */
.duty-chip { width: auto !important; min-width: 44px; padding: 0 9px !important; }
.duty-code { font-size: 11.5px; font-weight: 800; letter-spacing: .3px; }
.duty-chip.is-on { color: #15803d; background: rgba(34, 197, 94, .14); }
.duty-chip.is-off { color: #b45309; background: rgba(245, 158, 11, .16); }
html[data-theme="dark"] .duty-chip.is-on { color: #86efac; }
html[data-theme="dark"] .duty-chip.is-off { color: #fcd34d; }
.duty-held {
  position: absolute; top: 3px; right: 1px; min-width: 15px; height: 15px;
  border-radius: 999px; background: var(--danger); color: #fff;
  font-size: 10px; font-weight: 800; display: grid; place-items: center; padding: 0 3px;
}

@media (max-width: 860px) {
  .roster-tbl .rt-name { min-width: 124px; max-width: 124px; padding: 6px 7px; }
  .rt-cell { min-width: 38px; height: 40px; }
  .roster-wrap { max-height: calc(100vh - 300px); }
}

/* ---- the connection chip.
   Invisible while everything works: a green tick that is always green is a
   green tick nobody reads, and then it is not read on the morning it turns
   red. Its presence IS the message, so it only appears when something is
   wrong - and it pulses, because a static red dot in a toolbar of coloured
   buttons disappears into the row. */
.net-chip { width: auto !important; min-width: 40px; padding: 0 9px !important; position: relative; }
.net-chip.is-offline { color: #b45309; background: rgba(245, 158, 11, .16); }
.net-chip.is-noserver { color: #b91c1c; background: rgba(239, 68, 68, .15); }
html[data-theme="dark"] .net-chip.is-offline { color: #fcd34d; }
html[data-theme="dark"] .net-chip.is-noserver { color: #fca5a5; }
.net-pulse {
  position: absolute; top: 5px; right: 5px; width: 7px; height: 7px; border-radius: 999px;
  background: currentColor; animation: netPulse 1.6s ease-in-out infinite;
}
@keyframes netPulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) { .net-pulse { animation: none; } }

/* ---- the estate status block in Settings */
.callout.warn #estateStart { margin-top: 6px; }
