/* Yeti Ops — shared chrome.
   Theme carried from the Aquatics app so the two feel like one product:
   dark header bar, then a light tab strip whose active tab joins into the
   panel below. Tokens below are Aquatics' verbatim.

   Office/coordinator views. The field PWA (M5) gets its own much larger-target
   stylesheet; do not stretch this one to cover it. */

:root {
  --bg: #f6f7f9;
  --card: #ffffff;
  --ink: #1c2733;
  --muted: #64748b;
  --accent: #0f6fde;
  --ok: #12805c;
  --warn: #b45309;
  --bad: #b3261e;
  --border: #e2e8f0;
  --navy: #10314f;
  /* Theme tints (Sep 17 2026): the tint families the dark theme remaps.
     ink2 = secondary text, link = the in-tint blue, tint/tint2 = the
     gray fills, tintblue = the blue-washed fills. */
  --ink2: #334155;
  --link: #1d4ed8;
  --tint: #eef2f6;
  --tint2: #f8fafc;
  --tintblue: #f0f6ff;
  /* Schedule-grid cell states (Peter, Sep 17 2026: the grid read
     "funky and unclear" in dark while these stayed light). */
  --cell-on: #eefaf1;
  --cell-on-today: #e4f4ec;
  --cell-draft: #fbfdff;
  --cell-draft-line: #b6c8d8;
  --draft-word: rgba(71, 85, 105, .26);
  /* Headings/numbers that are navy INK in light mode (the count tiles,
     card titles, unit codes). Navy stays navy as a FILL (buttons, the
     header); as ink it must flip to light in the dark (Peter, Sep 17
     2026 night: "tiles and pills have text that is hard to read"). */
  --navyink: #10314f;
  --chart-top: #ffffff;
  color-scheme: light;
}

/* ==== DARK MODE (Peter, Sep 17 2026 - overnight staff asked) =========
   Switched per user from the user-name menu; 'auto' follows the
   device. Everything themed rides the variables above, so the two
   blocks below are the whole theme; status chips (green/amber/red
   tints) deliberately STAY light - colored labels with dark text read
   fine on a dark page, and their text colors are tuned to them. */
html[data-theme="dark"] {
  color-scheme: dark;
  --bg: #101823;
  --card: #182330;
  --ink: #dce5ee;
  --ink2: #c2cedb;
  --muted: #8fa3b8;
  --accent: #5aa2f0;
  --link: #8ab8ff;
  --border: #2c3b4c;
  --tint: #1c2836;
  --tint2: #161f2a;
  --tintblue: #1b2c42;
  --cell-on: #1b3226;
  --cell-on-today: #204030;
  --cell-draft: #1b2634;
  --cell-draft-line: #41586f;
  --draft-word: rgba(148, 163, 184, .3);
  --navyink: #d5e3f3;
  --chart-top: #1e2a38;
}
@media (prefers-color-scheme: dark) {
  html[data-theme="auto"] {
    color-scheme: dark;
    --bg: #101823;
    --card: #182330;
    --ink: #dce5ee;
    --ink2: #c2cedb;
    --muted: #8fa3b8;
    --accent: #5aa2f0;
    --link: #8ab8ff;
    --border: #2c3b4c;
    --tint: #1c2836;
    --tint2: #161f2a;
    --tintblue: #1b2c42;
    --cell-on: #1b3226;
    --cell-on-today: #204030;
    --cell-draft: #1b2634;
    --cell-draft-line: #41586f;
    --draft-word: rgba(148, 163, 184, .3);
  --navyink: #d5e3f3;
  --chart-top: #1e2a38;
  }
}

/* LIGHT ISLANDS: surfaces that keep a light background in dark mode
   (cream intake cards, amber notices, stale-packet reasons, in-house
   stripes) pin the light ink back locally, or their text washes out. */
html[data-theme="dark"] :is(.intakelane, .checkstrip, .notice,
    tr.inhouse, .packrow.needsmove, .pulsetable tr.pulsequiet,
    .packets tr.stalewhy) {
  --ink: #1c2733; --ink2: #334155; --muted: #64748b;
  --link: #1d4ed8; --accent: #0f6fde; --border: #e2e8f0;
  --card: #ffffff;              /* inner cards stay light too */
  color: var(--ink);            /* plain text inside re-resolves here */
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
  html[data-theme="auto"] :is(.intakelane, .checkstrip, .notice,
      tr.inhouse, .packrow.needsmove, .pulsetable tr.pulsequiet,
      .packets tr.stalewhy) {
    --ink: #1c2733; --ink2: #334155; --muted: #64748b;
    --link: #1d4ed8; --accent: #0f6fde; --border: #e2e8f0;
    --card: #ffffff;
    color: var(--ink);
    color-scheme: light;
  }
}

/* STATUS PILLS in the dark (Peter, Sep 17 2026: the light chips "hurt
   the eyes... blue light" against the dark page). Muted low-luminance
   fills with soft ink - still five clearly different families. Flashes
   are pills at paragraph size, so they ride the same palette. */
html[data-theme="dark"] :is(.pill.ok, .pill.live, .pill.status-done,
    .flash.ok) { background: #17342a; color: #7bd2ab;
  border-color: #23553f; }
html[data-theme="dark"] :is(.pill.warn, .pill.warnpill, .pill.dry,
    .pill.status-new) { background: #38290f; color: #e3b26b; }
html[data-theme="dark"] :is(.pill.bad, .pill.err, .pill.flagged,
    .pill.kind-broken, .flash.error) { background: #3d1e1b;
  color: #f19a92; border-color: #66312c; }
html[data-theme="dark"] :is(.pill.info, .pill.respill,
    .pill.kind-question, .pill.status-looking) { background: #1c2f4d;
  color: #94bdf7; }
html[data-theme="dark"] .pill.respill:hover { background: #254068; }
html[data-theme="dark"] :is(.pill.purple, .pill.ai, .pill.kind-idea) {
  background: #2b2450; color: #bda8f7; }
html[data-theme="dark"] .wl-card.wl-warn { background: #38290f; border-color: #8a5a12; }
html[data-theme="dark"] .wl-card.wl-b2b { background: #3a2312; border-color: #9a4f12; }
html[data-theme="dark"] .dispatchchip.alarm { background: #3d1e1b; }
html[data-theme="dark"] .card.unitcard.alarm { background: #2a1917; }
html[data-theme="dark"] .wlchart .wl-occ { fill: #86d9b2; }
html[data-theme="dark"] .wlchart :is(.wl-ihy, .wl-ih, .wl-dot) { fill: #5fc48f; stroke: #5fc48f; }
html[data-theme="dark"] .wlchart .wl-ih { fill: none; }
html[data-theme="dark"] .wlchart .wl-dot { fill: var(--card); }
@media (prefers-color-scheme: dark) {
  html[data-theme="auto"] :is(.pill.ok, .pill.live, .pill.status-done,
      .flash.ok) { background: #17342a; color: #7bd2ab;
    border-color: #23553f; }
  html[data-theme="auto"] :is(.pill.warn, .pill.warnpill, .pill.dry,
      .pill.status-new) { background: #38290f; color: #e3b26b; }
  html[data-theme="auto"] :is(.pill.bad, .pill.err, .pill.flagged,
      .pill.kind-broken, .flash.error) { background: #3d1e1b;
    color: #f19a92; border-color: #66312c; }
  html[data-theme="auto"] :is(.pill.info, .pill.respill,
      .pill.kind-question, .pill.status-looking) { background: #1c2f4d;
    color: #94bdf7; }
  html[data-theme="auto"] .pill.respill:hover { background: #254068; }
  html[data-theme="auto"] .wl-card.wl-warn { background: #38290f; border-color: #8a5a12; }
  html[data-theme="auto"] .wl-card.wl-b2b { background: #3a2312; border-color: #9a4f12; }
  html[data-theme="auto"] .dispatchchip.alarm { background: #3d1e1b; }
  html[data-theme="auto"] .card.unitcard.alarm { background: #2a1917; }
  html[data-theme="auto"] .wlchart .wl-occ { fill: #86d9b2; }
  html[data-theme="auto"] .wlchart :is(.wl-ihy, .wl-ih, .wl-dot) { fill: #5fc48f; stroke: #5fc48f; }
  html[data-theme="auto"] .wlchart .wl-ih { fill: none; }
  html[data-theme="auto"] .wlchart .wl-dot { fill: var(--card); }
  html[data-theme="auto"] :is(.pill.purple, .pill.ai, .pill.kind-idea) {
    background: #2b2450; color: #bda8f7; }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.45 system-ui, "Segoe UI", sans-serif;
  background: var(--bg);
  color: var(--ink);
}

/* --- dark header bar -------------------------------------------------- */
header {
  background: var(--navy);
  color: #fff;
  padding: 12px 16px;
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
}
/* Height comes from Settings -> Branding via a style attribute; width
   follows the aspect ratio so a wordmark is not squashed. */
header img.logo { width: auto; align-self: center; }
header h1 { font-size: 18px; margin: 0; }
header .sub { color: #9fb8d0; font-size: 12px; }
header .spacer { margin-left: auto; }
header .tools { display: flex; align-items: center; gap: 8px; align-self: center; }
header a.tool, header button.tool {
  background: #1d4e7e;
  color: #fff;
  border: 0;
  border-radius: 6px;
  padding: 7px 12px;
  font-size: 13px;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
header a.tool:hover, header button.tool:hover { background: #2a6198; }
header select.tool {
  background: #1d4e7e;
  color: #fff;
  border: 0;
  border-radius: 6px;
  padding: 7px 10px;
  font-size: 13px;
  cursor: pointer;
}

/* --- light tab strip -------------------------------------------------- */
nav.tabs {
  display: flex;
  gap: 4px;
  padding: 8px 12px 0;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
}
nav.tabs a {
  position: relative;   /* anchors the floating check pill */
  border: 1px solid var(--border);
  border-bottom: none;
  background: var(--tint);
  padding: 9px 14px;
  border-radius: 8px 8px 0 0;
  cursor: pointer;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
  text-decoration: none;
}
nav.tabs a.active { background: var(--card); color: var(--ink); }
nav.tabs a:hover { color: var(--ink); }

main { padding: 14px 12px 70px; max-width: 1100px; margin: 0 auto; }

h2 { font-size: 16px; margin: 4px 0 10px; }
h3 { font-size: 15px; margin: 14px 0 6px; }
.note, .muted { color: var(--muted); font-size: 13px; }
.small { font-size: 13px; }
.nowrap { white-space: nowrap; }

/* --- cards ------------------------------------------------------------ */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  margin-bottom: 14px;
}
/* A stale record should look stale before anyone opens it. */
.card.stale { border-left: 4px solid var(--warn); }
.card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.card-head h2, .card-head h3 { margin: 0; font-size: 16px; color: var(--navyink); }
.card-head h3 a { color: var(--navyink); text-decoration: none; }
.card-head h3 a:hover { text-decoration: underline; }
.card p.title { margin: 6px 0 4px; font-weight: 600; }

/* Radar's header line: building, then what it is, then when (Chie, Aug 30
   2026). The title carries the weight because it is the thing being read
   across the page; the when is quieter but NOT muted grey - a date somebody
   has to act on is not decoration. The dates and the times each hold together
   on one line, so a phone breaks BETWEEN them rather than inside "10a - 12p"
   (the times box is free text and can be any length). */
.card-head .cardtitle { font-size: 16px; font-weight: 600; color: var(--navyink); }
.card-head .cardwhen { font-size: 13px; color: var(--ink2); }
.card-head .cardwhen .whendates,
.card-head .cardwhen .whentimes { white-space: nowrap; }
.card-head .cardwhen .whentimes { margin-left: 6px; }

/* --- pills ------------------------------------------------------------ */
.pill {
  display: inline-block;
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 12px;
  font-weight: 700;
  background: var(--tint);
  color: var(--muted);
}
.pill.ok, .pill.live { background: #d9f2e5; color: var(--ok); }
.pill.warn, .pill.warnpill, .pill.dry { background: #fdeeda; color: var(--warn); }
.pill.bad, .pill.err { background: #fbe2e0; color: var(--bad); }
.pill.info, .pill.respill { background: #dbeafe; color: var(--link); text-decoration: none; }
.pill.respill:hover { background: #bfdbfe; }
.pill.purple, .pill.ai { background: #ede9fe; color: #6d28d9; }

/* --- tables ----------------------------------------------------------- */
table { border-collapse: collapse; width: 100%; font-size: 14px; background: var(--card); }
th, td {
  text-align: left;
  padding: 7px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
th {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--muted);
}
tbody tr:last-child td { border-bottom: 0; }
.tblscroll, table {
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}
td.body { max-width: 420px; overflow-wrap: anywhere; font-size: 12px; color: var(--muted); }
td.actions { white-space: nowrap; }
tr.inhouse td { background: #fff7ed; }
tr.me td { background: var(--tint2); }

/* --- counts strip ----------------------------------------------------- */
.counts { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.count {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 16px;
  min-width: 96px;
}
.count b { display: block; font-size: 24px; color: var(--navyink); line-height: 1.1; }
.count span { font-size: 12px; color: var(--muted); }
.count.warn b { color: var(--bad); }
.count.bad b { color: var(--bad); }
.count.bad { border-color: var(--bad); }

/* --- toolbar ---------------------------------------------------------- */
.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.toolbar form.row { margin: 0; }
a.btn {
  padding: 9px 14px;
  background: var(--accent);
  color: #fff;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}
a.btn:hover { background: #0c5cba; }

/* --- phases ----------------------------------------------------------- */
ul.phases { list-style: none; margin: 8px 0 0; padding: 0; }
ul.phases li { padding: 4px 0; border-top: 1px solid var(--tint2); font-size: 14px; }
ul.phases li:first-child { border-top: 0; }
.guest {
  margin-top: 3px;
  font-size: 13px;
  color: var(--ink2);
  background: var(--bg);
  border-left: 3px solid var(--border);
  padding: 4px 8px;
  border-radius: 0 4px 4px 0;
}

/* --- at-risk chips ---------------------------------------------------- */
.chips { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  background: #fdeeda;
  border: 1px solid #f6d8a8;
  color: var(--warn);
  border-radius: 999px;
  padding: 3px 6px 3px 12px;
  font-size: 13px;
  font-weight: 600;
}

/* --- notices and flashes ---------------------------------------------- */
.notice {
  background: #fdeeda;
  border: 1px solid #f6d8a8;
  color: var(--warn);
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 14px;
}
.flash { padding: 10px 14px; border-radius: 8px; font-size: 14px; margin-bottom: 14px; }
.flash.ok { background: #d9f2e5; border: 1px solid #a7e0c6; color: var(--ok); }
.flash.error { background: #fbe2e0; border: 1px solid #f4b8b3; color: var(--bad); }
/* Inline test verdicts (integrations tab): block so a verbatim error
   wraps under its button instead of stretching a nowrap cell. */
.testres { display: block; max-width: 340px; white-space: normal;
           font-size: 13px; margin-top: 4px; }
.testres.ok { color: var(--ok); }
.testres.bad { color: var(--bad); }

/* Tile popovers (Peter, Sep 9): unit warnings and WO notes in a small
   floating box with an X in the corner. */
.tipopen { cursor: pointer; }
.tipfloat {
  position: absolute; z-index: 300; width: 320px; max-width: 92vw;
  background: var(--card); border: 1px solid #cbd5e1; border-radius: 10px;
  box-shadow: 0 8px 24px rgba(16, 49, 79, .18); padding: 12px 14px;
  font-size: 14px;
}
.tipfloat .tipclose {
  position: absolute; top: 4px; right: 8px; border: 0; background: none;
  font-size: 20px; line-height: 1; cursor: pointer; color: var(--muted);
}
.tipfloat .tipline { display: block; margin: 2px 12px 2px 0; white-space: pre-line; }
.tipfloat .tipform { margin-top: 8px; display: grid; gap: 6px; }
.tipfloat .tipform textarea { width: 100%; box-sizing: border-box; }

/* The crew's cleaning order on assigned chips (Peter, Sep 9; same day:
   "reduce the size... do not put it in the pill. use 1. 2. 3.") -
   plain small text, no badge. */
.chipprio { font-size: 12px; font-weight: 700; color: var(--muted); }

/* The routines page (Peter, Sep 9): the stable key as a quiet chip, and
   the per-routine expander. */
.routineid {
  font-size: 11px; font-weight: 400; color: var(--muted);
  background: var(--tint); border-radius: 4px; padding: 1px 6px;
  margin-left: 6px; vertical-align: 2px;
}
.cadence input[type="number"] { width: 70px; }
.routineruns { margin-top: 6px; }
.routineruns summary { cursor: pointer; }
.routineruns table td { padding: 2px 10px 2px 0; }

/* --- Yeti Home (Peter, Sep 17 2026) ------------------------------------- */
.homequote { max-width: 860px; margin: 18px auto 10px; background: var(--card);
             border: 1px solid var(--border); border-radius: 16px;
             padding: 28px 34px 22px; position: relative; }
.homequote .quotemark { position: absolute; top: 4px; left: 18px; font-size: 72px;
                        line-height: 1; color: var(--accent); opacity: .25; }
.quotetext { margin: 6px 0 12px; font-size: 26px; line-height: 1.35;
             font-weight: 600; color: var(--navyink); }
.quoteby { font-size: 15px; color: var(--ink2); }
.quotedate { margin-top: 4px; }
.quoteacts { display: flex; gap: 14px; align-items: center; flex-wrap: wrap;
             margin: 18px 0 8px; }
.thumbbtn { font: inherit; font-size: 18px; padding: 6px 14px; border-radius: 999px;
            border: 1px solid var(--border); background: var(--tint); color: var(--ink);
            cursor: pointer; }
.thumbbtn.on { border-color: var(--accent); background: var(--tintblue); }
.thumbbtn:hover { background: var(--tintblue); }
.quotecomments { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 12px; }
.quotecomments h3 { margin: 0 0 8px; font-size: 14px; }
.commentlist { list-style: none; padding: 0; margin: 0 0 10px; display: flex;
               flex-direction: column; gap: 8px; }
.commentlist li { background: var(--tint2); border-radius: 8px; padding: 6px 10px; }
.commenttext { margin-top: 2px; }
.homeyesterday { max-width: 860px; margin: 10px auto 0; }
@media (max-width: 720px) { .quotetext { font-size: 21px; } .homequote { padding: 20px 18px 16px; } }

/* --- Radar coverages (Peter, Sep 17 2026) ------------------------------ */
.viacov { display: flex; flex-wrap: wrap; gap: 6px 14px; padding: 4px 14px 8px;
          font-size: 13px; }
.viacov a { color: var(--ink2); text-decoration: none; }
.viacov a:hover { text-decoration: underline; }
.covdistricts { margin: 8px 0 14px; }

/* --- the Notes pill (Juan, Sep 17 2026) -------------------------------- */
.notethumb { width: 84px; height: 63px; object-fit: cover; border-radius: 6px;
             border: 1px solid var(--border); display: block; }
.notestable .notecell { max-width: 460px; }
.notestable audio { height: 30px; margin-top: 4px; max-width: 260px; }
.notesadd { align-items: flex-start; gap: 8px; flex-wrap: wrap; }
.notesadd textarea { flex: 1 1 280px; min-width: 200px; }
.notesadd .notesfiles { display: inline-flex; flex-direction: column; gap: 2px; color: var(--muted); }
.saybar { display: flex; gap: 6px; margin-top: 4px; flex-wrap: wrap; }
.saybtn { cursor: pointer; font: inherit; font-size: 12px; line-height: 1.4;
          border: 1px solid var(--border); background: var(--tint); color: var(--ink); }
.saybtn:hover { background: var(--tintblue); }
.saybtn.speaking { border-color: var(--accent); color: var(--accent); }
.notes-toggle { cursor: pointer; font: inherit; font-size: 12px; line-height: 1.4; }
.notes-toggle.open { outline: 2px solid var(--accent); }
.newtab { margin-left: 6px; text-decoration: none; color: var(--muted); font-size: 13px; }
.newtab:hover { color: var(--accent); }
.reprow td { background: var(--tint2); padding: 8px 14px 10px 40px; }
.replist { display: flex; flex-direction: column; gap: 8px; }
.repline { display: flex; gap: 12px; align-items: flex-start; flex-wrap: wrap; }
.repline .repbody { flex: 1 1 320px; min-width: 240px; }

/* --- the recognition feed (#83) ---------------------------------------- */
/* The pill's unseen count: loud enough to notice, gone once read. */
.recogbadge {
  display: inline-block; min-width: 16px; text-align: center;
  background: #e8b93c; color: #1c2733; border-radius: 999px;
  font-size: 11px; font-weight: 800; padding: 0 5px; margin-left: 4px;
}
/* On the ribbon pill the badge sits ON the pill's corner and the pill
   itself glows while anything is unseen (staff feedback via Peter, Sep
   17 2026: nobody noticed the count beside it). recogbadge.js keeps it
   live without a reload and adds .fresh when a NEW one lands, which
   pulses a few times, then rests. */
header .recogpill { position: relative; }
header .recogpill .recogbadge { position: absolute; top: -7px; right: -9px;
  margin: 0; line-height: 16px; box-shadow: 0 0 0 2px #10314f; }
header .recogpill.hasnew b { border-color: #e8b93c;
  box-shadow: 0 0 0 1px rgba(232, 185, 60, .45); color: #fff; }
@media (prefers-reduced-motion: no-preference) {
  header .recogpill .recogbadge.fresh { animation: recogpulse 1.4s ease-out 4; }
  @keyframes recogpulse {
    0%   { box-shadow: 0 0 0 2px #10314f, 0 0 0 2px rgba(232, 185, 60, .9); }
    70%  { box-shadow: 0 0 0 2px #10314f, 0 0 0 12px rgba(232, 185, 60, 0); }
    100% { box-shadow: 0 0 0 2px #10314f, 0 0 0 0 rgba(232, 185, 60, 0); }
  }
}
.recogfeed { max-width: 720px; }
.recogcard {
  background: var(--card); border: 1px solid var(--border); border-radius: 10px;
  padding: 12px 14px; margin-bottom: 10px;
}
.recogcard .recoghead { display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; }
.recogcard .recogmsg { margin: 8px 0 6px; }
.recogcard .recogfoot { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.recogpager { margin: 14px 0; align-items: center; }
.recogtags { margin: 8px 0; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
/* Row, explicitly: .creddlg label is column-flex and would stack the
   checkbox above its own text. */
.creddlg label.recogtag, .recogtag {
  display: inline-flex; flex-direction: row; align-items: center;
  gap: 4px; border: 1px solid var(--border); border-radius: 999px;
  padding: 2px 10px; font-size: 13px; cursor: pointer;
}
.recogtag:has(input:checked) { background: #d9e9fb; border-color: #9ec5ef; }
/* On the page beside the feed (Peter, Sep 9), not in the send dialog. */
.recoglayout { display: flex; gap: 18px; flex-wrap: wrap; align-items: flex-start; }
.recoglayout .recogfeed { flex: 1 1 480px; }
.recogleaders {
  flex: 0 1 240px; background: var(--card); border: 1px solid var(--border);
  border-radius: 10px; padding: 10px 14px;
}
.recogleaders h4 { margin: 0 0 6px; font-size: 13px; color: var(--muted); }
.recogleaders ol { margin: 0; padding-left: 22px; font-size: 14px; }
.recogleaders li { padding: 2px 0; }
.recogleaders li b { margin-left: 6px; }

/* --- forms ------------------------------------------------------------ */
form.inline { display: inline; margin: 0; }
form.row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  margin: 10px 0 18px;
}
form.row .wide { min-width: 320px; }
select, input[type="email"], input[type="text"], input[type="password"],
input[type="date"], input[type="number"], input[type="datetime-local"] {
  padding: 9px 10px;
  border: 1px solid #cbd5e1;
  border-radius: 8px;
  font-size: 15px;
  background: var(--card);
  color: var(--ink);
}
button {
  padding: 9px 14px;
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
}
button:hover { background: #0c5cba; }
button.linkish {
  background: none;
  color: var(--accent);
  padding: 0 6px;
  font-weight: 400;
  font-size: 13px;
  text-decoration: underline;
}
button.linkish:hover { background: none; color: #0c5cba; }
button.linkish.danger { color: var(--bad); }

details.addbox {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  margin: 18px 0;
}
details.addbox summary { cursor: pointer; font-weight: 600; color: var(--navyink); }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
  margin: 14px 0;
}
.grid label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: var(--ink2);
  font-weight: 600;
}
.grid label.wide { grid-column: 1 / -1; }
.grid label.check { flex-direction: row; align-items: center; gap: 8px; font-size: 14px; font-weight: 400; }
/* Fields the parser could not determine — never silently accepted. */
.grid label.flagged input, .grid label.flagged select {
  border-color: #d97706;
  background: #fffbeb;
}
.grid label.flagged { color: var(--warn); }

fieldset.phasebox {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 14px 14px;
  margin: 12px 0;
  background: var(--card);
}
fieldset.phasebox legend { font-weight: 700; color: var(--navyink); padding: 0 6px; }

textarea {
  width: 100%;
  padding: 10px;
  border: 1px solid #cbd5e1;
  border-radius: 8px;
  font: 14px/1.45 ui-monospace, "SF Mono", Consolas, monospace;
  background: var(--card);
  color: var(--ink);
  resize: vertical;
}
input.wide { min-width: 320px; flex: 1; }

.actionbar { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; margin: 14px 0; }
.actionbar form.row { margin: 0; }

pre.raw {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px;
  overflow-x: auto;
  font-size: 13px;
  white-space: pre-wrap;
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

footer.buildstamp {
  max-width: 1100px;
  margin: 30px auto 20px;
  padding: 0 12px;
  color: #94a3b8;
  font-size: 12px;
}

/* --- sign-in page ----------------------------------------------------- */
body.auth {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}
.box {
  background: var(--card);
  border: 1px solid var(--border);
  padding: 38px 42px;
  border-radius: 14px;
  min-width: 320px;
  max-width: 90vw;
  box-shadow: 0 2px 12px rgba(16, 49, 79, .08);
  text-align: center;
}
.box h1 { font-size: 26px; margin: 0 0 8px; color: var(--navyink); }
.box .sub { color: var(--ink2); font-size: 15px; margin-bottom: 16px; }
.box .sub.info { margin-top: 12px; margin-bottom: 0; }
.box input { width: 100%; }
.box button { width: 100%; margin-top: 16px; padding: 12px; font-size: 16px; }
.box img.logo { width: auto; }
a.oauth {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  margin-top: 4px;
  padding: 12px;
  border: 1px solid #cbd5e1;
  border-radius: 8px;
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
  background: var(--card);
}
.div {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #94a3b8;
  font-size: 12px;
  margin: 18px 0 4px;
}
.div::before, .div::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.box .err { color: var(--bad); font-size: 14px; margin-top: 10px; background: none; padding: 0; }

@media (max-width: 640px) {
  body { font-size: 16px; }
  header h1 { font-size: 16px; }
  form.row .wide, input.wide { min-width: 0; width: 100%; }
  .pill { font-size: 13px; }
}

/* --- guest notification ----------------------------------------------- */
.notifyform { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin: 0; }
.notifyform select, .notifyform input { font-size: 13px; padding: 6px 8px; }
.notifyform input { min-width: 150px; flex: 1; }
.notifyform button { padding: 6px 12px; font-size: 13px; }
.buildingpick { margin: 0 0 14px; }
.buildinggrid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 4px 12px; margin: 10px 0 14px; max-height: 260px; overflow-y: auto;
}
.buildinggrid label.check {
  display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 400;
}

/* --- reservations inline on a board card ------------------------------ */
.restable { margin-top: 10px; font-size: 13px; }
.restable th { font-size: 10px; }
.restable td { padding: 5px 8px; vertical-align: middle; }
.restable td b { font-weight: 700; }
.restable .pill { font-size: 11px; padding: 1px 7px; margin-left: 4px; }
/* :not(.btn): this rule is for bare links; it used to out-specify a.btn and
   paint Contact Guest's text accent-on-accent (Peter, Aug 26 2026). */
.restable a.small:not(.btn) { margin-left: 8px; color: var(--accent); }
.restable a.btn.small { margin-left: 8px; }
/* A10: a unit somebody marked unaffected, shown only on request - dimmed,
   with its undo, never silently gone. */
.restable tr.unaffected td { opacity: .5; }
.restable .notifyform select { font-size: 12px; padding: 4px 6px; }
.restable .notifyform button { padding: 4px 10px; font-size: 12px; }

/* Fixed column widths: the action control must start at the same x on every
   row. With auto-layout the browser sizes columns to their longest value, so
   the Mark-notified buttons drifted from card to card. */
.restable { table-layout: fixed; }
.restable col.c-unit  { width: 15%; }
.restable col.c-guest { width: 26%; }
.restable col.c-stay  { width: 26%; }
.restable col.c-act   { width: 33%; }
.restable.wide col.c-unit  { width: 14%; }
.restable.wide col.c-guest { width: 22%; }
.restable.wide col.c-stay  { width: 20%; }
.restable.wide col.c-flags { width: 14%; }
.restable.wide col.c-act   { width: 30%; }
.clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.restable .notifyform { flex-wrap: nowrap; }
.restable .notifyform select { flex: 1; min-width: 0; }
.restable .notifyform button { flex: 0 0 auto; }

/* The filter's apply control is a button, not a text link: it sits in a row
   of four selects and read as unfinished styled as a link. */
.toolbar .filterbtn { padding: 9px 16px; }

/* The bulk-dismiss tick column (Peter, Sep 7 2026) stays a sliver. */
.restable col.c-sel   { width: 30px; }
/* The OBVIOUS bulk bar on affected-guest lists (Peter, Sep 7 2026):
   big ticks, live counts in the buttons, unmissable blue. */
.bulkbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
           margin: 8px 0; padding: 8px 12px; border: 1px solid #93c5fd;
           background: var(--tintblue); border-radius: 10px; }
.bulkbar .check { font-weight: 600; display: inline-flex;
                  align-items: center; gap: 6px; }
input.bulkrow, .bulkbar .bulkall { width: 17px; height: 17px;
                                   accent-color: var(--accent);
                                   vertical-align: -3px; cursor: pointer; }
/* Reservation number sits beside the unit and is the way into Track. */
.restable col.c-unit  { width: 13%; }
.restable col.c-res   { width: 10%; }
.restable col.c-guest { width: 23%; }
.restable col.c-stay  { width: 22%; }
.restable col.c-act   { width: 32%; }
.restable.wide col.c-unit  { width: 13%; }
.restable.wide col.c-res   { width: 9%; }
.restable.wide col.c-guest { width: 19%; }
.restable.wide col.c-stay  { width: 18%; }
.restable.wide col.c-flags { width: 12%; }
.restable.wide col.c-act   { width: 29%; }

/* --- routines page ---------------------------------------------------- */
.runline { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 8px; }
.runline .btn.small { padding: 5px 12px; font-size: 13px; margin-left: auto; }

/* Role control sits inline in a table cell. */
form.row.tight { margin: 0; gap: 4px; }
form.row.tight select { padding: 4px 6px; font-size: 13px; }
/* The staff dropdown is a normal select; the search sits on its own line
   above it so the row below stays a single tidy line of controls. */
#stafflist { min-width: 340px; max-width: 520px; }
.searchline { display: block; width: 100%; max-width: 520px; margin-bottom: 8px; }
input[type="search"] {
  padding: 9px 10px; border: 1px solid #cbd5e1; border-radius: 8px;
  font-size: 15px; background: var(--card); color: var(--ink);
}

/* --- where you are ---------------------------------------------------- */
header h1 { font-size: 21px; font-weight: 800; letter-spacing: -0.01em; }
header .sub { color: #7d9cba; font-size: 12px; }

/* Settings is a different place, and should look like one: a lighter bar and
   a labelled way back, so nobody edits configuration thinking they are doing
   their daily work. */
body.in-settings header { background: #0b2438; border-bottom: 3px solid var(--accent); }
nav.tabs a.backout {
  background: transparent; border-color: transparent;
  color: var(--accent); font-weight: 700;
}
nav.tabs a.backout:hover { background: var(--tint); color: #0c5cba; }

/* Profile fields carry a hint under each control. */
.grid label span.muted { font-weight: 400; line-height: 1.35; }

/* --- header wordmark -------------------------------------------------- */
header h1 { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
header h1 .brandname { font-size: 21px; font-weight: 800; letter-spacing: -0.01em; color: #fff; }
/* A red dot in front of the brand name on every screen (Matt, Sep 21 2026).
   It replaces the blue Settings-only dot: one dot, one colour, everywhere -
   Settings still stands out by its lighter bar and accent border. */
header h1 .branddot {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  background: #e5484d; flex: none; align-self: center;
}
header h1 .brandsep { color: #5f83a5; font-weight: 400; }
header h1 .where { font-size: 19px; font-weight: 600; color: #cfe2f6; }
body.in-settings header h1 .where { color: #9fd0ff; }

/* --- logo preview in Settings ----------------------------------------- */
.logopreview { display: flex; gap: 14px; flex-wrap: wrap; margin: 12px 0 16px; }
.logopreview .swatch {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 16px 24px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--card); min-width: 180px; justify-content: center;
}
.logopreview .swatch.dark { background: var(--navy); border-color: var(--navy); }
.logopreview .swatch.dark .muted { color: #9fb8d0; }
input[type="file"] {
  padding: 8px; border: 1px solid #cbd5e1; border-radius: 8px;
  font-size: 14px; background: var(--card);
}

/* --- modules not built yet -------------------------------------------- */
/* A tab that leads somewhere unfinished should look different from one that
   leads to working software. */
nav.tabs a.soon { color: #94a3b8; background: #f4f6f9; border-style: dashed; }
nav.tabs a.soon:hover { color: var(--muted); }
nav.tabs a.soon.active {
  background: var(--card); color: var(--ink); border-style: solid;
}
.card.comingsoon { border-left: 4px solid #cbd5e1; }

/* --- tab icons -------------------------------------------------------- */
nav.tabs a { display: inline-flex; align-items: center; gap: 7px; }
.ticon { flex: 0 0 auto; }
/* An unbuilt module's icon fades with its label rather than staying vivid,
   so the whole tab reads as one state. */
nav.tabs a.soon .ticon { opacity: .65; }
nav.tabs a.active .ticon { opacity: 1; color: var(--accent); }
h2 .ticon { vertical-align: -3px; margin-right: 2px; }
td .ticon { vertical-align: -3px; opacity: .7; }

/* --- desk arrivals ---------------------------------------------------- */
.card.arrival { padding: 12px 14px; }
.card.arrival.done { opacity: .68; border-left: 4px solid var(--ok); }
.arrival-body { display: flex; gap: 18px; flex-wrap: wrap; align-items: flex-start; margin-top: 8px; }
.guestcol { flex: 1 1 280px; min-width: 0; }
.stagecol { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* Arrival tiles, regularized (Peter, Sep 6 2026: "each reservation tile
   looks messy... all reservation tiles look the same as I scroll").
   Identity left, flags grouped right, actions in two right-aligned rows,
   and every free-text field truncates instead of reflowing the card. */
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
            display: inline-block; vertical-align: bottom; max-width: 100%; }
.card.arrival .card-head { row-gap: 6px; flex-wrap: nowrap; align-items: flex-start; }
.arrival-id { display: inline-flex; align-items: center; gap: 8px;
              min-width: 0; flex: 0 1 auto; }
.arrival-id h3 { white-space: nowrap; }
.arrival-id .bldg { max-width: 200px; }
.arrival-id .cleaner { max-width: 170px; }
.arrival-flags { display: inline-flex; align-items: center; gap: 4px 6px;
                 flex-wrap: wrap; justify-content: flex-end;
                 margin-left: auto; flex: 1 1 auto; min-width: 0; }
.card.arrival .pill { white-space: nowrap; }
.card.arrival .arrival-body { display: grid;
                              grid-template-columns: minmax(0, 1fr) auto;
                              gap: 8px 18px; align-items: start; }
.guestcol .guestname { display: block; max-width: 100%; }
.guestcol .chan { max-width: 220px; }
.guestcol .small { overflow-wrap: anywhere; }
.card.arrival .stagecol { display: flex; flex-direction: column;
                          align-items: flex-end; gap: 6px; }
.stagecol .actrow { display: flex; align-items: center; gap: 8px;
                    flex-wrap: wrap; justify-content: flex-end; }
.stagecol .actrow:empty { display: none; }
.stacked { display: inline-flex; flex-direction: column;
           align-items: flex-end; gap: 2px; }
.worow .wotitle { max-width: 320px; }
.arrivalnote { overflow-wrap: anywhere; }
@media (max-width: 760px) {
  .card.arrival .card-head { flex-wrap: wrap; }
  .arrival-flags { justify-content: flex-start; margin-left: 0; }
  .card.arrival .arrival-body { grid-template-columns: 1fr; }
  .card.arrival .stagecol { align-items: flex-start; }
  .stagecol .actrow { justify-content: flex-start; }
}
.stagebtn {
  background: var(--tint); color: var(--muted); border: 1px solid var(--border);
  padding: 6px 12px; font-size: 13px; font-weight: 600;
}
.stagebtn:hover { background: var(--border); color: var(--ink); }
.stagebtn.on { background: #d9f2e5; color: var(--ok); border-color: #a7e0c6; }
.stagebtn.on:hover { background: #c7ebd8; }
.stagebtn.remake { background: #fde8e6; color: var(--bad); border-color: #f2b8b3; }
.stagebtn.remake:hover { background: #f9d6d2; }

/* --- the final contact call dialog (B11) ------------------------------
   The spreadsheet rebuilt every morning, as a page: the questions that come
   up, the building issues from Radar, and the call history underneath. */
.callissue {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 12px; padding: 10px 12px; margin: 8px 0; border-radius: 9px;
  border: 1px solid var(--border); border-left-width: 4px;
}
.callissue.sev-unit_unusable { border-left-color: var(--bad); }
.callissue.sev-amenity_down { border-left-color: var(--warn); }
.callissue.sev-annoyance { border-left-color: var(--muted); }
.callissue-tick { white-space: nowrap; font-size: 13px; color: var(--ink); }

/* The building-issues pill and its hover popup (Karly, Aug 29 2026). The
   count rides the arrivals card and the call dialog's header; the detail
   only appears when someone asks for it, so a board of twenty arrivals does
   not become twenty paragraphs.

   CSS-only, no JS: :hover for a mouse, :focus-within for a keyboard, and a
   tap focuses the span on a touch screen. Hidden with display:none rather
   than opacity so it cannot be read by a screen reader out of context, and
   so it never widens the page - the 375px overflow test watches for that. */
.issuepill { position: relative; display: inline-block; cursor: help; }
.issuepill .pill { cursor: help; }
.issuepop {
  display: none;
  position: absolute;
  z-index: 800;
  top: calc(100% + 6px);
  left: 0;
  width: max-content;
  max-width: min(360px, calc(100vw - 32px));
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(16, 49, 79, .25);
  padding: 8px 10px;
  font-size: 13px;
  text-align: left;
  white-space: normal;
}
.issuepill:hover .issuepop,
.issuepill:focus .issuepop,
.issuepill:focus-within .issuepop { display: block; }
.issuepop-item { padding: 4px 0 4px 8px; border-left: 3px solid var(--border); }
.issuepop-item + .issuepop-item { margin-top: 6px; border-top: 1px solid var(--border); }
.issuepop-item.sev-unit_unusable { border-left-color: var(--bad); }
.issuepop-item.sev-amenity_down { border-left-color: var(--warn); }
.issuepop-item.sev-annoyance { border-left-color: var(--muted); }
.callform label { display: block; margin-bottom: 10px; font-size: 13px; color: var(--muted); }
.callform select, .callform input, .callform textarea {
  display: block; width: 100%; margin-top: 3px;
}
.callgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
}
.callactions { display: flex; align-items: center; gap: 14px; }
.callpast { padding: 10px 14px; }

/* --- open work orders on arrivals (B7) --------------------------------- */
.wodetails { margin-top: 8px; font-size: 13px; }
.wodetails summary { cursor: pointer; color: var(--muted); }
.worow {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 0; border-top: 1px dashed var(--border); font-size: 13px;
}
.worow form select { font-size: 12px; padding: 2px 4px; }

/* --- the key packet queue (B9) ----------------------------------------
   A table you work straight down while cutting keys. Remakes first, and
   loudly: a wrong packet in the drawer is worse than a missing one. */
.packets {
  width: 100%; border-collapse: collapse; margin-bottom: 20px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 9px; overflow: hidden; font-size: 14px;
}
.packets th {
  text-align: left; font-size: 11px; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted); padding: 8px 10px;
  border-bottom: 1px solid var(--border); background: var(--bg);
}
.packets td { padding: 8px 10px; border-bottom: 1px solid var(--border); }
/* Shift day view (Peter, Sep 2 2026): everyone is on the ONE list — the
   not-working rows sit quiet so the working half reads at a glance. */
.packets tr.dimrow td { opacity: .62; }
.packets tr:last-child td { border-bottom: 0; }
.packets tr.done td { opacity: .55; }
.packets td .muted.small { display: block; }
.packets .packact { text-align: right; white-space: nowrap; }
.packets tr.stalewhy td {
  padding-top: 0; border-top: 0; background: #fff7f6;
}

/* --- the key checkout log (M3) ------------------------------------------
   Same table as the packet queue - it is worked the same way - plus the one
   thing the paper sheet could never show: an overdue row that looks overdue
   from across the room. */
.packets tr.overdue td { background: #fff7f6; }
form.keyout {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px; align-items: end;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 9px; padding: 12px 14px; margin-bottom: 20px;
}
form.keyout label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; font-weight: 600; color: var(--muted);
}
.packets.remake { border-color: #f2b8b3; }
h2.bad-text { color: var(--bad); }
.arrivalnote { margin: 8px 0 0; padding-left: 10px; border-left: 3px solid var(--border); }

/* --- profile menu ----------------------------------------------------- */
header a.tool.iconly { padding: 7px 9px; }
.usermenu, .tourmenu { position: relative; }
.usermenu > summary, .tourmenu > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: inline-flex; align-items: center; gap: 6px;
}
.usermenu > summary::-webkit-details-marker, .tourmenu > summary::-webkit-details-marker { display: none; }
.usermenu[open] > summary, .tourmenu[open] > summary { background: #2a6198; }
.usermenu-panel {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  min-width: 210px; background: var(--card); color: var(--ink);
  border: 1px solid var(--border); border-radius: 10px; padding: 6px;
  box-shadow: 0 6px 20px rgba(16, 49, 79, .18);
}
.usermenu-panel a {
  display: block; padding: 9px 12px; border-radius: 7px;
  color: var(--ink); text-decoration: none; font-size: 14px;
}
.usermenu-panel a:hover { background: var(--bg); }
.usermenu-panel .who {
  display: block; padding: 4px 12px 8px; color: var(--muted); font-size: 12px;
  border-bottom: 1px solid var(--border); margin-bottom: 6px;
}
/* Sign out sits at the bottom, separated - it is not a navigation choice. */
.usermenu-panel a.signout { color: var(--bad); }
.usermenu-panel a.signout:hover { background: #fbe2e0; }

/* --- active tab icon: colour and motion -------------------------------
   Only the ACTIVE tab animates. Motion everywhere is noise; motion on the one
   thing you are looking at reads as "this is live". Every animation is inside
   the icon's own coordinate system, so nothing reflows. */
nav.tabs a.active .ticon { color: var(--accent); }
nav.tabs a.active .ticon g { transform-origin: 12px 12px; }

/* The radar sweep goes round, because that is what a radar does. */
nav.tabs a.active .ticon .sweep { animation: yeti-sweep 2.6s linear infinite; }
@keyframes yeti-sweep { to { transform: rotate(360deg); } }

/* The rest are small and slow: a nod, not a dance. */
nav.tabs a.active .ticon .swing { animation: yeti-swing 1.9s ease-in-out infinite; }
@keyframes yeti-swing {
  0%, 100% { transform: rotate(-7deg); }
  50%      { transform: rotate(7deg); }
}
nav.tabs a.active .ticon .ring { animation: yeti-ring 2.4s ease-in-out infinite; }
@keyframes yeti-ring {
  0%, 70%, 100% { transform: rotate(0deg); }
  78%           { transform: rotate(9deg); }
  86%           { transform: rotate(-9deg); }
  94%           { transform: rotate(4deg); }
}
nav.tabs a.active .ticon .turn { animation: yeti-turn 2.8s ease-in-out infinite; }
@keyframes yeti-turn {
  0%, 55%, 100% { transform: rotate(0deg); }
  75%           { transform: rotate(-28deg); }
}
nav.tabs a.active .ticon .drip { animation: yeti-drip 2.2s ease-in-out infinite; }
@keyframes yeti-drip {
  0%, 100% { transform: translateY(0) scale(1); }
  50%      { transform: translateY(-1.2px) scale(1.06); }
}
/* The Depot sheet feeds out of the printer, because that is the job. */
nav.tabs a.active .ticon .feed { animation: yeti-feed 2.4s ease-in-out infinite; }
@keyframes yeti-feed {
  0%, 15%  { transform: translateY(-3.5px); }
  55%, 100% { transform: translateY(0); }
}
nav.tabs a.active .ticon .bob { animation: yeti-bob 2.2s ease-in-out infinite; }
@keyframes yeti-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-1.4px); }
}

/* Someone who has asked their system for less motion gets the colour and none
   of the movement. */
@media (prefers-reduced-motion: reduce) {
  nav.tabs a.active .ticon g { animation: none !important; }
}

/* Quick controls inside the profile menu. */
.usermenu-panel .menuform {
  margin: 0; padding: 6px 12px 10px; border-bottom: 1px solid var(--border);
  margin-bottom: 6px;
}
.usermenu-panel .menuform label {
  display: block; font-size: 12px; color: var(--muted); margin-bottom: 4px;
}
.usermenu-panel .menuform select { width: 100%; font-size: 14px; padding: 6px 8px; }

/* --- translated user content ------------------------------------------
   A translation is always labelled and the original is always reachable.
   Deliberately quiet: this appears on every note, and a loud badge on every
   row would make a bilingual board look broken rather than normal. */
details.translated { display: inline; }
details.translated summary {
  display: inline;
  cursor: pointer;
  font-size: 11px;
  color: var(--muted);
  margin-left: 6px;
}
details.translated summary::marker { content: ""; }
details.translated summary:hover { color: var(--accent); }
details.translated .original {
  margin-top: 4px;
  padding: 6px 9px;
  background: var(--bg);
  border-left: 3px solid var(--border);
  border-radius: 0 4px 4px 0;
  font-size: 13px;
  color: var(--ink2);
}

/* --- Radar's own tabs --------------------------------------------------
   A second level below the module strip. Deliberately lighter than the module
   tabs above it: this is "which view of Radar", not "which module". */
.subnav { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; }
.subnav a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
}
.subnav a:hover { color: var(--ink); border-color: #cbd5e1; }
.subnav a.active {
  background: var(--navy);
  border-color: var(--navy);
  color: #fff;
}
.subnav a.active .pill { background: rgba(255, 255, 255, .22); color: #fff; }
/* Still-in-development marks (Peter, Aug 31 2026, revised same day: the
   word DEV goes RED and the main module tabs wear marks too). Dimming is
   done with color, not opacity, so the red mark keeps full strength. */
.subnav a.wip { color: var(--muted); font-style: italic; }
.subnav a.wip.active { color: #fff; }
sup.wipmark {
  font-size: 8px; font-style: normal; font-weight: 800; color: #dc2626;
  text-transform: uppercase; letter-spacing: .04em; margin-left: 2px;
}
/* Live tabs wear a green check - "go use it". Main strip and subnavs. */
.tabs a .modlive, .subnav a .modlive {
  color: #16a34a; font-weight: 800; margin-left: 3px; }
/* Partly live: the caution sign - live areas inside, DEV areas inside. */
.tabs a .modcaution { color: #d97706; margin-left: 3px; }
/* On the MAIN tabs the marks float ABOVE the label (Peter, Sep 7 2026:
   less width on laptops - same float as the checks pill, which sits
   top-right; these sit top-left). Subnav pills keep them inline. */
nav.tabs a .modlive, nav.tabs a .modcaution, nav.tabs a sup.wipmark {
  position: absolute; top: -7px; left: 10px; margin-left: 0; z-index: 1;
  background: var(--bg); border-radius: 6px; padding: 0 3px;
  line-height: 1.3; font-size: 11px;
}
nav.tabs a sup.wipmark { font-size: 8px; line-height: 1.6; }
/* The call button says its logging is manual, in a small line below. */
.callcta { display: inline-flex; flex-direction: column; align-items: center;
  gap: 1px; vertical-align: middle; }
.callcta .callnote { font-size: 10px; line-height: 1; }

/* The two halves of a consolidated tab (Peter, Aug 26 2026): one segmented
   control under the subnav, not another row of tabs. */
.viewtoggle {
  display: inline-flex; margin: 0 0 14px;
  border: 1px solid var(--border); border-radius: 999px;
  overflow: hidden; background: var(--card);
}
.viewtoggle a {
  padding: 5px 14px; font-size: 13px; font-weight: 600;
  color: var(--muted); text-decoration: none;
}
.viewtoggle a.active { background: var(--navy); color: #fff; }
.viewtoggle a:not(.active):hover { color: var(--ink); }

/* Settings -> Schedule (P2c(i)): the week grid, and the called-in-sick
   checkboxes that ARE the morning's gesture. */
.schedgrid td.schedcell { min-width: 148px; }
.schedgrid .schedcell input[type="time"] {
  width: 100%; padding: 3px 6px; font-size: 12px; margin: 1px 0;
  border: 1px solid var(--border); border-radius: 6px;
}
.schedgrid .schedcell.on { background: var(--cell-on); }
/* S2 drafts (Peter, Sep 3 2026: the crosshatch died): a big grey DRAFT
   lies diagonally across the whole cell, translucent so the hours and
   buttons underneath stay readable AND clickable (pointer-events). The
   word comes from the td's data-dw so it speaks the reader's language. */
.schedgrid .schedcell.draftcell { background: var(--cell-draft);
  outline: 1px dashed var(--cell-draft-line); outline-offset: -3px; }
.schedgrid .schedcell.draftcell::after {
  content: attr(data-dw); position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  transform: rotate(-22deg); pointer-events: none;
  font-weight: 900; font-size: 19px; letter-spacing: 2px;
  color: var(--draft-word); text-transform: uppercase;
  overflow: hidden; white-space: nowrap;
}
.toolbar .primarybtn { background: var(--navy); border-color: var(--navy);
  color: #fff; }

/* Approved PTO: greyed, inputs gone, unschedulable (Peter, 2026-08-27). */
.schedgrid .schedcell.ptoday { background: var(--tint2); color: var(--muted); }
.schedgrid .sickbtn { font-size: 11px; padding: 0 2px; display: block;
  color: var(--muted); }
.schedgrid .schedcell:hover .sickbtn { color: var(--ink); }
#sickdlg { border: 1px solid var(--border); border-radius: 10px;
  padding: 18px 20px; min-width: 300px; }
#sickdlg::backdrop { background: rgba(16, 49, 79, .35); }
#sickdlg h3 { margin: 0 0 10px; }
#sickdlg label { display: flex; flex-direction: column; gap: 4px;
  margin-bottom: 12px; font-size: 13px; }

/* Settings -> Integrations (Aug 30 2026): stored keys in full on a
   super-only screen, each edited through its own popup; the endpoints
   block lines up as one labels column beside one inputs column. */
.credval { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas,
  monospace; font-size: 12px; color: var(--ink2); display: block;
  max-width: 460px; max-height: 66px; overflow: auto;
  word-break: break-all; white-space: pre-wrap; }
.credline { display: flex; gap: 8px; align-items: baseline;
  flex-wrap: wrap; margin: 2px 0; }
.credline > .muted:first-child { min-width: 110px; }
.creddlg { border: 1px solid var(--border); border-radius: 10px;
  padding: 18px 20px; width: min(560px, 92vw); }
.creddlg::backdrop { background: rgba(16, 49, 79, .35); }
.creddlg h3 { margin: 0 0 10px; }
.creddlg label { display: flex; flex-direction: column; gap: 4px;
  margin-bottom: 6px; font-size: 13px; font-weight: 600; }
.creddlg textarea { font-family: ui-monospace, SFMono-Regular, Menlo,
  Consolas, monospace; font-size: 12px; width: 100%; }
.kvgrid { display: grid; grid-template-columns: max-content minmax(0, 1fr);
  gap: 8px 14px; align-items: center; margin: 14px 0; max-width: 780px; }
.kvgrid label { font-size: 13px; font-weight: 600; color: var(--ink2); }
.kvgrid input { width: 100%; }
.schedgrid th.todaycol, .schedgrid td.todaycol { background: var(--tintblue); }
.schedgrid td.todaycol.on { background: var(--cell-on-today); }
.sicklist { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
button.sickchip {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--card); color: var(--ink);
  border: 1px solid var(--border); border-radius: 999px;
  padding: 6px 14px; font-size: 13px; font-weight: 600;
}
button.sickchip:hover { background: #fde8e6; border-color: #f2b8b3;
  /* Pinned dark: the hover tint stays light in dark mode too. */
  color: #1c2733; }
/* .tickbox, not .box: the login card's generic .box rule (320px min-width,
   38px padding) swallowed the little checkbox square the moment the page
   moved out of the Settings shell (2026-08-27). */
button.sickchip .tickbox {
  width: 14px; height: 14px; border: 2px solid var(--muted);
  border-radius: 4px; background: var(--card); flex: none;
}
/* A name marked out is struck through wherever it appears, never hidden. */
.memberout, .memberout b { text-decoration: line-through; opacity: .6; }

/* Count tiles that link somewhere keep the tile look, not a link look. */
a.count { display: block; text-decoration: none; }
a.count:hover { border-color: var(--accent); }
/* The tile you are currently filtered to (Peter, Aug 28 2026: every count
   is now the filter it counts). */
a.count.on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }

/* The clickable brand in the dark bar. */
header a.home { text-decoration: none; color: inherit; display: inline-flex; }
header a.home:hover { opacity: .85; }
header h1 a.brandname { color: inherit; text-decoration: none; }

.latebanner {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.latebanner span { font-size: 13px; }
.latebanner .btn { margin-left: auto; }

/* --- move queue / late booking cards ----------------------------------- */
.card.move.done, .card.late.done { opacity: .62; }
.card.move .card-head h3, .card.late .card-head h3 { font-size: 15px; }
.moveline {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
  margin: 6px 0;
  font-size: 14px;
}
form.moveform { margin: 8px 0 0; }
form.moveform input { min-width: 150px; }

/* --- early check-in sell view -----------------------------------------
   The left edge carries the clean signal, because that is what the sale
   turns on: a coloured stripe reads down a list far faster than a pill in
   each header does. */
.card.eci { border-left: 4px solid var(--border); }
.card.eci.conf-green { border-left-color: var(--ok); }
.card.eci.conf-amber { border-left-color: var(--warn); }
.card.eci.conf-blocked { border-left-color: #cbd5e1; opacity: .72; }
.offerline {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin: 6px 0;
  font-size: 14px;
}

/* --- reservation change feed ------------------------------------------- */
.card.change { border-left: 4px solid var(--accent); }
.card.change.urgent { border-left-color: var(--bad); }
.card.change.done { opacity: .6; border-left-color: var(--border); }
.changeline {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 8px 0;
  font-size: 15px;
}
.changeline .was { text-decoration: line-through; color: var(--muted); }
.changeline .now { font-weight: 700; color: var(--ink); }
.changeline .arrow { color: var(--muted); }

/* Booking type. Reads as metadata, not as a status - it sits inside the muted
   guest cell, so it must not shout louder than the notification control. */
.pill.typepill { font-weight: 600; font-size: 11px; }

/* A Shift group (#15) rides a name the same size as its department pill,
   in the purple that means "a set somebody named" rather than a status. */
.pill.grouppill { font-weight: 600; font-size: 11px; }
.teamcard.inactiverow { opacity: .6; }

/* --- Yeti Limpia: the unit status board --------------------------------
   The left edge carries the priority, because the order IS the instruction:
   back-to-backs first, then sold early check-ins (Peter, Aug 12 2026). A
   coordinator scanning down the board should be able to see where the urgent
   work stops without reading a word. */
.card.unitcard { border-left: 4px solid var(--border); padding: 12px 14px; }
.card.unitcard.prio-0 { border-left-color: var(--bad); }
.card.unitcard.prio-1 { border-left-color: var(--warn); }
.card.unitcard.prio-2 { border-left-color: var(--accent); }
.card.unitcard.ready  { opacity: .74; }

/* "Ours" marks a state a person set, as opposed to one Track reported. Quiet
   on purpose - it appears on every unit somebody has touched. */
.pill.ours { background: var(--border); color: var(--muted); font-size: 10px; }

.turnline {
  display: flex; gap: 16px; flex-wrap: wrap; align-items: center;
  margin: 8px 0 4px; font-size: 14px;
}
.turnline .leg { display: inline-flex; align-items: center; gap: 6px; }
.turnline .leg b { font-weight: 700; color: var(--muted); font-size: 12px;
                   text-transform: uppercase; letter-spacing: .03em; }
.turnline .leg.empty { font-size: 13px; }

.planline {
  display: flex; gap: 14px; flex-wrap: wrap; align-items: center;
  margin: 4px 0; font-size: 14px;
}
.planline .eta.late b, .late { color: var(--bad); }

/* One tap per state, no menu to open first. The active state is the same
   green as a completed arrival stage, so the two boards read alike. */
.statusrow { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0 4px; }
.statusrow form { margin: 0; }
.statusrow .stagebtn { padding: 6px 11px; }

form.planform { margin: 4px 0 0; }
form.planform input[name="cleaner"] { min-width: 170px; }
form.planform input[type="time"] { width: 120px; }

details.unitnote { margin-top: 6px; }
details.unitnote summary {
  cursor: pointer; font-size: 12px; color: var(--muted); list-style: none;
}
details.unitnote summary::-webkit-details-marker { display: none; }
details.unitnote summary:hover { color: var(--accent); }
details.unitnote form { margin-top: 6px; }
details.unitnote input[name="note"] { min-width: 260px; }

/* --- the turns matrix -------------------------------------------------- */
table.turns td { vertical-align: top; }
table.turns tr.hasconflict { background: #fff7f6; }
table.turns tr.prio-0 td:first-child { box-shadow: inset 3px 0 0 var(--bad); }
table.turns tr.prio-1 td:first-child { box-shadow: inset 3px 0 0 var(--warn); }

/* --- the exception report ---------------------------------------------- */
.card.exception { border-left: 4px solid var(--bad); }
.card.exception table { margin-top: 8px; }

/* What a change means for a clean, said plainly above the diff. */
p.meaning { margin: 6px 0 2px; font-size: 14px; font-weight: 600;
            color: var(--navyink); }

/* --- the day being worked ---------------------------------------------
   At the top, next to the numbers, because the numbers are about that day.
   It used to sit at the bottom of the page (Karly, Aug 24 2026). */
.dayline {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 12px; font-size: 16px;
}
.dayline form { margin: 0; }
.dayline .btn.small { padding: 5px 12px; font-size: 13px; }
.daynav {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--card);
  color: var(--muted); text-decoration: none; font-size: 16px; line-height: 1;
}
.daynav:hover { color: var(--ink); border-color: #cbd5e1; }

/* Two small smooth charts on the day line, thirty days out (Peter, Aug 25
   2026): % occupancy, and the flow - check-ins, departures, back-to-backs
   (B21). Replaced the row of per-day tiles, then the full-width chart. */
.minicharts {
  display: flex; align-items: center;
  /* Close up to the RIGHT of the date element (Peter, Aug 25 2026) - in
     flex flow next to the arrows, not pushed to the far edge. */
  min-width: 0; flex: 0 1 auto;
}
/* Flexible, not fixed: a fixed-width chart overflows a 375px phone, and a
   board that scrolls sideways is a board coordinators stop using. */
.minichart { flex: 0 1 324px; min-width: 170px; }
/* Jake, Aug 27 2026: numbers on the chart. The axis text names the scale;
   a day column tints on hover and its title carries every number at once. */
.wc-axis { font-size: 8.5px; fill: var(--muted); }
.wc-daycol { fill: transparent; }
.wc-daycol:hover { fill: rgba(15, 111, 222, .10); }
.minichart svg {
  display: block; width: 100%; height: 58px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 7px;
}
.wc-line { fill: none; stroke-width: 1.6; stroke-linejoin: round; }
.wc-grid { stroke: var(--border); stroke-width: 1; }
path.wc-occupying { stroke: var(--ok); }
path.wc-arrivals { stroke: var(--accent); }
path.wc-departures { stroke: var(--muted); }
path.wc-turns { stroke: var(--bad); }
/* Invisible hover targets carrying the day + value in a <title>. */
.wc-spot { fill: transparent; }
.wc-caption {
  display: flex; gap: 6px; align-items: center; margin-top: 2px;
  font-size: 10.5px; color: var(--muted); justify-content: center;
}
.wc-caption b { color: var(--ink); }
.wc-swatch {
  display: inline-block; width: 10px; height: 3px; border-radius: 2px;
}
i.wc-swatch.wc-occupying { background: var(--ok); }
i.wc-swatch.wc-arrivals { background: var(--accent); }
i.wc-swatch.wc-departures { background: var(--muted); }
i.wc-swatch.wc-turns { background: var(--bad); }

/* A queue heading with its action on the far side (Peter, Aug 25 2026:
   print labels sits opposite "Office check-in"). */
.qhead {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
}
.qhead h2 { margin-bottom: 6px; }

/* Config lives behind a small gear on the right of the pill row (Peter,
   Aug 25 2026: Limpia's Teams), not as a pill among the views. */
.subnav a.subgear {
  /* Bare gear, right beside the last pill (Peter, Aug 25 2026) - no pill
     chrome around it and not pushed to the far edge. */
  padding: 6px 4px; display: inline-flex; align-items: center;
  border: 0; background: none; color: var(--muted);
}
.subnav a.subgear:hover, .subnav a.subgear.active { color: var(--ink); }

/* A count that is zero stays on screen and goes quiet, rather than
   disappearing and making the tab strip jump. */
.subnav .pill.zero { background: transparent; color: inherit; opacity: .45; }

/* --- editing a project -------------------------------------------------
   Quiet on the board and plain on the project page: a correction is routine,
   not an event. There was no way to do it at all before Aug 24 2026. */
.card-head .spacer { flex: 1; }
a.editlink { font-size: 12px; color: var(--muted); text-decoration: none; }
a.editlink:hover { color: var(--accent); text-decoration: underline; }
.card.phaseedit { border-left: 4px solid var(--accent); margin-bottom: 10px; }
.card.phaseedit .grid { margin: 0; }

/* A way out that is not as loud as the way forward: leaving without saving is
   the safe action, so it should not compete with Save. */
.btn.ghost {
  background: var(--card); color: var(--muted);
  border: 1px solid var(--border);
}
.btn.ghost:hover { color: var(--ink); border-color: #cbd5e1; background: var(--bg); }

/* --- Radar, grouped by building ---------------------------------------
   The header is the whole answer when the building is closed, so it carries
   the counts and the worst severity. Collapsed means NOT RENDERED - see the
   comment in index.html - so this is styling a real boundary, not a toggle. */
.buildinggroup { margin-bottom: 10px; }
.buildinghead {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 14px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--card);
  text-decoration: none; color: var(--ink); font-size: 15px;
}
.buildinghead:hover { border-color: var(--accent); }
.buildinggroup.open > .buildinghead {
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
  border-color: var(--navy);
}
.buildinggroup.sev-unit_unusable > .buildinghead { box-shadow: inset 3px 0 0 var(--bad); }
.buildinggroup.sev-amenity_down  > .buildinghead { box-shadow: inset 3px 0 0 var(--warn); }
.buildinghead .twist {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 4px; background: var(--bg);
  color: var(--muted); font-weight: 700; line-height: 1;
}
.buildinggroup.open > .card { border-radius: 0; margin-bottom: 0; }
.buildinggroup.open > .card:last-of-type {
  border-bottom-left-radius: 10px; border-bottom-right-radius: 10px;
  margin-bottom: 0;
}

/* How current the board is, in the bar, on every screen. Quiet by design:
   it is a reassurance you glance at, not a thing to read. */
header .stamp {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: #b8cee2; margin-right: 4px; white-space: nowrap;
}
header .stamp b { color: #e6eef6; font-weight: 600; }
header .stamp .sep { opacity: .5; }
/* The stamp is a LINK now - clicking it opens /refreshes, the breakdown of
   which parts of Track refreshed when and what every other feed last did. */
header a.stamp { text-decoration: none; }
header a.stamp:hover { color: #e6eef6; text-decoration: underline; }
@media (max-width: 720px) { header .stamp { display: none; } }

/* The sky in the ribbon (Peter, Sep 2 2026; compact Sep 6: one glyph and
   the temperature — a click opens today's numbers, one more the full
   forecast panel). Hidden a step earlier than the stamp: the forecast is
   a glance, the sync stamp is trust. */
header .weatherstamp { cursor: pointer; }
header .weatherstamp .wxi { font-size: 14px; line-height: 1; }
header .weatherstamp:hover b { text-decoration: underline; }
@media (max-width: 900px) { header .weatherstamp { display: none; } }

/* The forecast panel: a dusk-sky sheet of per-day glass cards. The stamp
   opens it DIRECTLY (Peter, Sep 7: no popover between). */
.wxmodal { position: fixed; inset: 0; z-index: 220;
           background: rgba(2, 6, 23, .55); overflow-y: auto;
           display: flex; align-items: flex-start; justify-content: center;
           padding: 6vh 16px 16px; }
.wxmodal[hidden] { display: none; }
.wxsheet { position: relative; width: 100%; max-width: 880px;
           border-radius: 20px; padding: 24px 26px 26px; color: #f2f7ff;
           background: linear-gradient(168deg, #0b1f4b, #16418c 45%,
                                       #2f6fd0 82%, #6ba7ec);
           box-shadow: 0 24px 60px rgba(2, 6, 23, .55); }
.wxhead { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
          margin: 0 56px 18px 0; }
.wxi-big { font-size: 52px; line-height: 1; }
.wxhead-now b { display: block; font-size: 40px; font-weight: 800;
                line-height: 1.05; }
.wxhead-now span { opacity: .85; font-size: 14px; }
.wxplace { margin-left: auto; text-align: right; opacity: .8;
           font-size: 13px; text-transform: uppercase;
           letter-spacing: .06em; }
.wxdays { display: grid; gap: 10px;
          grid-template-columns: repeat(auto-fit, minmax(102px, 1fr)); }
.wxday { display: flex; flex-direction: column; align-items: center;
         gap: 6px; text-align: center; border-radius: 14px;
         padding: 12px 10px; background: rgba(255, 255, 255, .10);
         border: 1px solid rgba(255, 255, 255, .16);
         transition: transform .15s ease, background .15s ease; }
.wxday:hover { background: rgba(255, 255, 255, .17);
               transform: translateY(-2px); }
.wxd-name { font-size: 12px; font-weight: 700; text-transform: uppercase;
            letter-spacing: .05em; opacity: .9; }
.wxd-icon { font-size: 30px; line-height: 1; }
.wxd-short { font-size: 12px; opacity: .85; min-height: 28px; }
.wxd-range { display: flex; align-items: center; gap: 6px; width: 100%; }
.wxd-lo, .wxd-hi { font-size: 13px; font-weight: 700; min-width: 24px; }
.wxd-lo { opacity: .75; }
.wxd-bar { position: relative; flex: 1; height: 5px; border-radius: 3px;
           background: rgba(255, 255, 255, .16); }
.wxd-bar i { position: absolute; top: 0; bottom: 0; border-radius: 3px;
             background: linear-gradient(90deg, #7dd3fc, #fbbf24); }
.wxd-precip { font-size: 12px; color: #bfe3ff; min-height: 16px; }
@media (max-width: 640px) {
  .wxdays { grid-template-columns: repeat(2, 1fr); }
  .wxplace { margin-left: 0; text-align: left; }
}

/* The big X (Peter, Sep 6 2026): one obvious way back to the app, on the
   forecast panel and on the workload chart page alike. */
.bigx { position: absolute; top: 12px; right: 14px; width: 52px;
        height: 52px; border: 0; border-radius: 50%; cursor: pointer;
        background: rgba(255, 255, 255, .14); color: #fff; font-size: 34px;
        line-height: 1; display: inline-flex; align-items: center;
        justify-content: center; }
.bigx:hover { background: rgba(255, 255, 255, .26); }
a.bigx-page { position: static; width: 46px; height: 46px;
              background: var(--card); color: var(--ink2); border: 1px solid #cbd5e1;
              font-size: 30px; text-decoration: none; margin-left: auto;
              box-shadow: 0 1px 3px rgba(15, 23, 42, .08); }
a.bigx-page:hover { background: var(--tint2); color: #0f172a; }
.wl-toolbar { display: flex; align-items: center;
              justify-content: space-between; gap: 10px; }

/* An edited-but-unsaved POST form lights its save button (dirtymark.js). */
button.unsaved, input[type=submit].unsaved {
  box-shadow: 0 0 0 2px #f59e0b !important;
  animation: unsavedpulse 1.6s ease-in-out infinite;
}
@keyframes unsavedpulse {
  50% { box-shadow: 0 0 0 5px rgba(245, 158, 11, .35); }
}
@media (prefers-reduced-motion: reduce) {
  button.unsaved, input[type=submit].unsaved { animation: none; }
}

/* The training hat is a details-menu now (replay + the self-serve mute);
   it borrows the usermenu dress via the .tourmenu selectors above. */

/* Quick shifts (Peter, Sep 2 2026): draggable chips above the schedule
   grid. Armed = the click-to-stamp mode; the eraser wears the warn tone. */
.presetbar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
             margin: 8px 0; }
.preset { cursor: grab; border: 1px solid var(--border);
          background: var(--tintblue); font-weight: 700; }
.preset:active { cursor: grabbing; }
.preset.armed { outline: 2px solid #0f6fde; background: #dbeafe; }
.preset.eraser { background: #fff6de; }
.presetmanage { margin-left: 8px; }
.presetmanage[open] { flex-basis: 100%; }
/* Per-cell quick marks (Peter, Sep 3 2026): Day off + Sick as REAL small
   buttons, bottom-right of every square. They replaced the x and the
   one-by-one exceptions form. */
.schedcell { position: relative; }
.schedcell .cellacts { display: flex; gap: 4px; justify-content: flex-end;
                       /* breathing room off the time inputs so a tap for
                          the inputs never lands on a mark button */
                       margin-top: 10px; }
.schedcell .cellact { border: 1px solid var(--border); background: var(--tint);
                      color: var(--muted); border-radius: 5px;
                      padding: 1px 7px; font-size: 11px; cursor: pointer; }
.schedcell .cellact:hover { color: var(--ink); background: var(--border); }
/* Clear is a small red x in the cell's lower-right corner (Peter,
   Sep 5 2026), living in the right gutter below the On Call pill. Same
   title, same JS hook - only the clothes changed. */
.schedcell .cellclear { position: absolute; right: 2px; bottom: 1px;
  border: 0; background: none; color: #b91c1c; font-size: 11px;
  font-weight: 700; line-height: 1; padding: 2px 4px; cursor: pointer; }
.schedcell .cellclear:hover { color: #7f1d1d; }
/* The line BETWEEN people reads at a glance now (Peter, Sep 5 2026:
   "make the row lines a little darker... hard to see"). */
.schedgrid tbody td { border-bottom: 1px solid #9fb2c2; }
/* And the native time control stops hogging the row: less padding, and
   the gap between the AM/PM half and the clock icon collapses - the
   space the On Call pill needed. */
.schedcell input[type="time"] { padding: 3px 2px; }
.schedcell input[type="time"]::-webkit-calendar-picker-indicator {
  margin-inline-start: 0; padding: 0; }

/* Radar email intake (Peter, Sep 5 2026): the drafts lane at the top. */
.intakelane { border: 1px solid #f2d9a0; background: #fdf6e3;
              border-radius: 10px; padding: 10px 14px; margin: 10px 0; }
.intakelane h3 { margin: 0 0 8px; font-size: 14px; color: #7a5a10; }
.intakerow { display: flex; gap: 12px; align-items: flex-start;
             justify-content: space-between; padding: 8px 0;
             border-top: 1px solid #efe1bf; }
.intakerow:first-of-type { border-top: 0; }
.intakemain { flex: 1; min-width: 0; font-size: 14px; }
.intakemain .pill { margin-right: 6px; }
.intakeacts { display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
              justify-content: flex-end; }
.intakeacts form { display: inline-flex; gap: 6px; }

/* Company Directory (Peter, Sep 5 2026): the ribbon pill and the page. */
header .dirstamp b { border: 1px solid #3d5f80; border-radius: 999px;
                     padding: 1px 9px; }
header .dirstamp:hover b { background: #1f4468; }
.dirlines { display: flex; flex-wrap: wrap; gap: 14px; margin: 8px 0 14px; }
.dirgroup { border: 1px solid var(--border); border-radius: 10px;
            padding: 8px 12px; background: var(--tint2); min-width: 220px; }
.dirgroup h3 { margin: 0 0 6px; font-size: 13px; color: var(--navyink); }
.dirline { display: flex; gap: 8px; align-items: center; font-size: 13px;
           padding: 2px 0; }
.dirline .dirlabel { color: var(--muted); }
.dirtable td { vertical-align: middle; }

/* Daily checkout checks (Peter, Sep 5 2026): the strip above dispatch,
   and the count pill the Limpia tab wears while any are open. */
.checkstrip { border: 1px solid #f2d9a0; background: #fdf6e3;
              border-radius: 10px; padding: 10px 14px; margin: 10px 0; }
.checkstrip h3 { margin: 0 0 8px; font-size: 14px; color: #7a5a10; }
.checkstrip h3 .small { font-weight: 400; margin-left: 8px; }
.checkrow { display: flex; flex-wrap: wrap; gap: 8px; }
.checkitem { display: inline-flex; align-items: center; gap: 8px;
             border: 1px solid #e7d199; background: var(--card); border-radius: 8px;
             padding: 4px 10px; font-size: 13px; }
.checkitem .checkname { font-weight: 600; }
.checkitem.donecheck { opacity: .62; }
.checkitem.donecheck .checkname { text-decoration: line-through; }
/* The pill floats ABOVE the tab label (Peter, Sep 6 2026: laptops - the
   tab must not widen). The nav's top padding is the space it floats in. */
.tabs .checkpill { position: absolute; top: -7px; right: 10px; z-index: 1;
                   background: #b45309; color: #fff; border-radius: 999px;
                   font-size: 10px; font-weight: 800; padding: 1px 7px;
                   line-height: 1.4; white-space: nowrap;
                   box-shadow: 0 0 0 2px var(--bg); }

/* Overnight on-call (Peter, Sep 3 2026): the pill straddling the border
   between a day and the next - the night keyed by the day it starts. */
/* The cells reserve gutters under the boundary pill (Peter, Sep 5
   2026: "the on call button blocks the clock icon") - the pill is ~48px
   wide and straddles the border, so the cell it belongs to keeps 36px
   clear on its right and EVERY cell keeps 17px clear on its left for
   the neighbour's pill. Inputs are width:100%, so padding is the law. */
.schedgrid .schedcell { padding-right: 36px; padding-left: 17px; }
.schedcell .ocbtn { position: absolute; right: -15px; top: 34%; z-index: 7;
                    border: 1px solid var(--border); background: var(--card);
                    color: var(--muted); border-radius: 999px;
                    font-size: 9px; font-weight: 800; padding: 2px 5px;
                    line-height: 1; cursor: pointer; white-space: nowrap; }
.schedcell .ocbtn:hover { color: var(--ink); }
.schedcell .ocbtn.on { background: #312e81; border-color: #312e81;
                       color: #fff; }
.schedcell span.ocbtn { cursor: default; }

/* The floating Save (Peter, Sep 3 2026, second cut): sticky INSIDE the
   schedule column - rides the viewport bottom while the grid scrolls,
   settles at the grid's bottom right at the end. Never position:fixed:
   that covered the feedback button. pointer-events keeps the empty strip
   left of the button click-through to the rows behind it. */
.schedsavewrap { position: sticky; bottom: 16px; z-index: 30;
                 display: flex; justify-content: flex-end;
                 margin-top: 8px; pointer-events: none; }
.schedsave { pointer-events: auto;
             background: #0f6fde; color: #fff; border: 0;
             border-radius: 8px; padding: 10px 22px; font-weight: 800;
             font-size: 14px; cursor: pointer;
             box-shadow: 0 4px 14px rgba(15, 23, 42, .3); }
.schedsave:hover { background: #0c5cb8; }

/* /refreshes: the description row under each feed reads as a caption. */
.refreshfeeds tr.feedwhy td { padding-top: 0; border-top: 0; }

/* --- job-role chips and the assign boards (Peter, Aug 25 2026) --------- */
.jobchips, .chippick {
  display: flex; gap: 6px; flex-wrap: wrap; align-items: center;
}
.chippick { margin: 10px 0; }
.jobchip input { position: absolute; opacity: 0; pointer-events: none; }
.jobchip span {
  display: inline-block; border-radius: 999px; padding: 3px 11px;
  font-size: 12.5px; font-weight: 600; cursor: pointer;
  background: var(--tint); color: var(--muted);
  border: 1px solid var(--border); user-select: none;
}
.jobchip input:checked + span {
  background: #dbeafe; color: var(--link); border-color: #93c5fd;
}
.jobchip input:focus-visible + span { outline: 2px solid var(--accent); }
.chipadd {
  border: 1px dashed var(--border); border-radius: 999px;
  padding: 3px 11px; font-size: 12.5px; width: 150px;
}
input.teamname {
  font-size: 15px; font-weight: 700; padding: 6px 10px;
  border: 1px solid var(--border); border-radius: 8px; min-width: 220px;
}
.teamcard .btn.small { margin-top: 6px; }

/* The Jobs column: pills of what is selected, edited through a small
   multi-select dropdown (Peter, Aug 25 2026). */
.jobpick { position: relative; display: inline-block; }
.jobpick summary {
  list-style: none; cursor: pointer; display: inline-flex;
  align-items: center; gap: 4px; flex-wrap: wrap;
}
.jobpick summary::-webkit-details-marker { display: none; }
.jobpick .caret { color: var(--muted); font-size: 11px; }
.jobmenu {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 20;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 8px; box-shadow: 0 6px 18px rgba(16, 49, 79, .14);
  padding: 8px 10px; min-width: 190px; display: flex;
  flex-direction: column; gap: 6px; font-size: 13px;
}
.jobmenu label {
  display: flex; align-items: center; gap: 7px; cursor: pointer;
  white-space: nowrap;
}

/* The tray and the drop targets. Armed = tapped, for phones with no drag. */
.assigntray {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 10px; padding: 10px 14px; margin-bottom: 14px;
  position: sticky; top: 0; z-index: 5;
}
.assignchip {
  display: inline-flex; align-items: center; gap: 6px;
  border-radius: 999px; padding: 5px 13px; font-size: 13px;
  font-weight: 700; background: #dbeafe; color: var(--link);
  border: 1px solid #93c5fd; cursor: grab; user-select: none;
}
.assignchip.team { background: #ede9fe; color: #6d28d9; border-color: #c4b5fd; }
.assignchip b {
  background: var(--card); border-radius: 999px; padding: 0 7px; font-size: 11px;
}
.assignchip.armed { outline: 3px solid var(--accent); }
.assignchip.on { cursor: default; background: #d9f2e5; color: var(--ok); border-color: #a7e0c6; }
.droprow.dropready { border-color: var(--accent); box-shadow: 0 0 0 2px #bfdbfe; }
body.assign-armed .droprow { cursor: copy; }
.assignrow .card-head { row-gap: 6px; }

/* --- field reports on the coordinators' board (M5) --------------------- */
.fieldstrip {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: center;
  border-top: 1px dashed var(--border); margin-top: 8px; padding-top: 8px;
  font-size: 13px;
}
.fieldact { display: inline-flex; gap: 6px; align-items: center; }
.fieldstrip audio { height: 30px; max-width: 220px; }

/* The work order's media thread (Peter, Sep 5 2026): photos and voice
   notes whole and chronological, behind a summary so boards stay tight. */
.fieldthread { font-size: 13px; }
.fieldthread summary { cursor: pointer; color: var(--muted); }
.fieldlist { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.fieldlist li { display: flex; gap: 10px; align-items: flex-start; flex-wrap: wrap; }
.fieldlist audio { height: 30px; max-width: 240px; }
.fieldphoto { max-width: 140px; max-height: 110px; border-radius: 6px; border: 1px solid var(--border); display: block; }
.fieldwords { flex-basis: 100%; margin-left: 8px; white-space: pre-line; }
.dispatchchip .fieldthread { flex-basis: 100%; }

/* The Den (P6 KB core, Sep 5 2026): article shelf + rendered markdown. */
.kbcard h3 { margin: 0 0 4px; }
.kbcard .kbpreview { margin: 2px 0 4px; }
.kbarticle { max-width: 840px; }
.kbbody { line-height: 1.55; }
.kbbody h1, .kbbody h2, .kbbody h3 { margin: 18px 0 6px; }
.kbbody ul, .kbbody ol { margin: 6px 0; padding-left: 22px; }
.kbbody table { border-collapse: collapse; margin: 8px 0; }
.kbbody th, .kbbody td { border: 1px solid var(--border); padding: 4px 8px; }
.kbbody.original { border-left: 3px solid var(--border); padding-left: 10px; }
.kbform label { display: block; margin: 10px 0 4px; font-weight: 600; }
.kbform input[name=title], .kbform input[name=category],
.kbform textarea { width: 100%; font-weight: 400; }
.kbhistory { margin-top: 8px; }

/* Conduit checkout self-reports on the units board. */
.checkoutbanner { margin-bottom: 14px; display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
.checkoutitem { display: inline-flex; gap: 6px; align-items: center; font-size: 13px; }

/* The Limpia dispatch board: crew rows, cleans as blocks, drag to assign
   and reorder. Pool on top; armed crew head = tap-to-assign target. */
.dispatchpool { border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; margin-bottom: 12px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.dispatchpool .poolhead { flex-basis: 100%; display: flex; gap: 8px; align-items: baseline; }
/* The filter dropdown gets its OWN row ABOVE the sort pills (Peter,
   Sep 10: "Do not use them in the same row") - the pool is flex-wrap,
   so both must claim the full width. */
.dispatchpool .poolfilters { flex-basis: 100%; margin: 0; }
.dispatchpool .sortbarline { flex-basis: 100%; margin: 0 0 4px; }
.dispatchchip { display: inline-flex; gap: 6px; align-items: center; border: 1px solid var(--border); border-radius: 6px; padding: 4px 8px; font-size: 13px; cursor: grab; background: var(--card); }
.dispatchchip.prio-b2b { border-color: var(--bad); }
.dispatchchip.prio-eci { border-color: var(--warn); }
.dispatchrowcard { padding: 8px 12px;
  /* The crew's own color (Juan, Sep 8): a stable hue per team/person,
     worn as the left edge so crews separate at a glance. */
  border-left: 5px solid var(--crew, transparent); }
.dispatchhead { display: flex; gap: 8px; align-items: baseline; cursor: pointer; }
.dispatchhead h3 { margin: 0; font-size: 15px; }
.dispatchhead.armed { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.dispatchrow { display: flex; gap: 6px; flex-wrap: wrap; min-height: 34px; padding: 6px 0 2px; }
.droptarget.dropready { outline: 2px dashed var(--accent); outline-offset: 2px; border-radius: 6px; }
body.assign-armed .dispatchpool .dispatchchip { cursor: pointer; }

/* Dispatch 2: the same board split-screen - people left, cleanings right,
   the pool sticky so it rides along while scrolling the people column. */
.dispatch2grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px; align-items: start; }
.dispatch2pool { position: sticky; top: 8px; max-height: calc(100vh - 16px); overflow-y: auto; align-content: flex-start; }
.dispatch2pool .dispatchchip { flex-basis: 100%; justify-content: flex-start; }
@media (max-width: 760px) { .dispatch2grid { grid-template-columns: minmax(0, 1fr); } .dispatch2pool { position: static; max-height: none; } }

/* A3: Radar projects that stop staff work, on Limpia and Wrench. */
.staffbanner { margin-bottom: 14px; display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
.staffitem { display: inline-flex; gap: 6px; align-items: center; font-size: 13px; flex-wrap: wrap; }

/* The phone-app install guide (Peter, Aug 25 2026). */
.fieldurl { font-size: 22px; letter-spacing: .3px; }
.helpgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; }
.helpgrid ol { padding-left: 20px; }
.helpgrid li { margin-bottom: 6px; }

/* The duplicate guard (Peter, Aug 27 2026): existing open issues, amber. */
.dupewarn { display: flex; flex-direction: column; gap: 2px; }
.card.dupecard { border-left: 4px solid var(--warn, #b45309); }

/* Juan's Limpia changes (2026-08-27). The status chart beside the units
   board: whole-inventory bars that refetch every minute (hskchart.js). */
.unitswrap { display: flex; gap: 14px; align-items: flex-start; }
.unitswrap .unitlist { flex: 1; min-width: 0; }
.hskchart { width: 240px; flex-shrink: 0; position: sticky; top: 8px;
  background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.chartline { display: grid; grid-template-columns: 82px 1fr 28px; gap: 6px; align-items: center; }
.chartlabel { color: var(--muted); }
.charttrack { background: var(--bg); border-radius: 4px; height: 14px; overflow: hidden; }
.chartbar { height: 100%; border-radius: 4px; min-width: 2px; transition: width .4s; }
.chartn { font-size: 13px; text-align: right; }
.chartbar.state-dirty { background: #e8b04b; }
.chartbar.state-in_progress { background: #6aa5e8; }
.chartbar.state-clean { background: #7fd0a8; }
.chartbar.state-inspected { background: #12805c; }
.chartbar.state-occupied { background: #94a3b8; }
.chartbar.state-blocked { background: #d06a63; }
.chartbar.state-unknown { background: #cbd5e1; }
/* Stacked on a phone - and align-items must flip to stretch: flex-start in
   a COLUMN flex sizes children to max-content, which let a wide unit card
   push the page sideways (caught by the 375px overflow test on CI). */
@media (max-width: 900px) { .unitswrap { flex-direction: column-reverse; align-items: stretch; } .hskchart { width: 100%; position: static; } }

/* Dispatch chip money + pool filters. Chips carry more now (pay, next
   reservation, owner/VIP), so their content wraps on a narrow phone
   instead of pushing the board sideways. */
.dispatchchip { flex-wrap: wrap; }
/* One clean per row inside a crew's box too (Peter, 2026-08-27): with
   pay, dates and pills on every chip, the inline flow read as a jumble.
   Same rule the pool already had - full-width chips, stacked in the
   crew's work order, details aligned to the right edge. */
.dispatchrow .dispatchchip { flex-basis: 100%; justify-content: flex-start; }
.dispatchrow .dispatchchip .muted, .dispatch2pool .dispatchchip .muted { margin-left: auto; }
/* The crew's name never wraps mid-name on a desk-size screen; on a phone
   the viewport wins - nowrap there pushed the whole page sideways. */
@media (min-width: 761px) { .dispatchhead h3 { white-space: nowrap; } }
.chippay { font-weight: 600; color: var(--ok); font-size: 13px; }
.poolfilters { margin-bottom: 8px; }
.poolfilters select { font-size: 13px; }

/* The Pulse report (Peter, Sep 9 2026): super-only activity rollup.
   Quiet-while-scheduled rows blush; the wide table scrolls inside its
   own box rather than the page. */
.pulsewrap { overflow-x: auto; }
.pulsetable { width: 100%; }
.pulsetable td, .pulsetable th { white-space: nowrap; }
.pulsetable tr.pulsequiet td { background: #fff7ed; }
/* v2 (#105): department chips, and the per-day 24-hour strip - the
   scheduled window outlined, hours with any event filled. */
.pulsechips { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0 12px; }
.pulsechips .pill { text-decoration: none; }
.pulseperson summary { cursor: pointer; display: flex; gap: 6px;
  align-items: center; list-style: none; }
.pulseperson summary::-webkit-details-marker { display: none; }
.pulsestrips { margin: 6px 0 2px; display: grid; gap: 2px; }
.pulsestripline { display: flex; gap: 8px; align-items: center; }
.pulsestripline > .muted.small { width: 48px; text-align: right; }
.pulsestrip { display: inline-flex; gap: 1px; }
.pulsestrip i { width: 9px; height: 12px; background: #eef2f7;
  border-radius: 2px; }
.pulsestrip i.sch { outline: 1px solid #94a3b8; outline-offset: -1px; }
.pulsestrip i.hit { background: var(--accent); opacity: .7; }
.pulsestrip i.sch.hit { opacity: 1; }

/* Bodega crew headings: centered, a notch larger - the "Dania
   Rodriguez / 4 clean(s)" line only (Peter, Sep 9 2026). */
.card-head.bodegahead { justify-content: center; text-align: center; }
.card-head.bodegahead h3 { font-size: 19px; }
.card-head.bodegahead .muted.small { font-size: 14px; }

/* The moved-bag banner (#108, made SUPER OBVIOUS Sep 9 night: the
   bodega works this page on PHONES) - every bag on the wrong shelf at
   the top, each with a thumb-sized button. The row itself blushes too
   and never dims with the packed rows. */
.movealert { background: #fef2f2; border: 2px solid #dc2626;
  border-radius: 12px; padding: 12px 14px; margin: 12px 0; }
.movealert .movetitle { display: block; color: #b91c1c;
  font-size: 18px; margin-bottom: 4px; }
.movealert .moveline { display: flex; gap: 10px; align-items: center;
  flex-wrap: wrap; padding: 10px 0; border-top: 1px solid #fecaca; }
.movealert .moveunit { font-size: 20px; font-weight: 800;
  white-space: nowrap; }
.movealert .movewho { font-size: 15px; min-width: 0; }
.movealert .movebtn { min-height: 44px; padding: 0 20px;
  margin-left: auto; font-size: 15px; font-weight: 700;
  background: #dc2626; color: #fff; border: 0; border-radius: 10px;
  cursor: pointer; }
.movealert .movebtn:hover { background: #b91c1c; }
.packrow.needsmove { background: #fff7ed;
  border-left: 4px solid #dc2626; border-radius: 6px;
  padding-left: 8px; opacity: 1; }
@media (max-width: 760px) {
  .movealert .moveline { align-items: stretch; flex-direction: column; }
  .movealert .movebtn { margin-left: 0; width: 100%; }
}

/* Bodega pack rows (048) + the projection's inline demand bars. */
.packrow { display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding: 6px 0; border-top: 1px solid var(--border); }
.packrow:first-of-type { border-top: none; }
.packrow.ispacked { opacity: .65; }
.projbar { width: 110px; display: inline-block; vertical-align: middle; }
/* The projection page's day-off door (Peter, Sep 14 2026): the one
   schedule gesture Limpia allows - a compact per-day crew list with an
   Off/Restore pill per name. */
.offdoor summary { cursor: pointer; list-style: none; display: inline-block; }
.offdoor summary::-webkit-details-marker { display: none; }
.offdoor[open] .offlist { border: 1px solid var(--border); border-radius: 8px;
  padding: 6px 8px; margin-top: 4px; background: var(--card, #fff);
  min-width: 220px; }
.offline { display: flex; gap: 8px; align-items: center;
  justify-content: space-between; padding: 2px 0; }
.offline .strike { text-decoration: line-through; opacity: .6; }

/* The real packing lists + pull sheet (051), and the inspect verdict. */
.packitems { display: flex; gap: 6px 12px; flex-wrap: wrap; }
.packitem { white-space: nowrap; }
.packitem b { color: var(--navyink); }
.pullitem { font-size: 15px; padding: 2px 0; }
form.verdict { display: inline-flex; gap: 4px; }
form.verdict button.pill { border: 0; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; }

/* Dispatch alignment (Peter, 2026-08-27): stacked chips and crew tiles
   read as a table - fixed columns, money on the far right, time beside
   it. Each grid is per-element, so the columns must be FIXED widths to
   line up across elements. Phones fall back to the wrapping flow. */
/* Three fixed lines per tile (Peter, Sep 10: "the information is
   spilling over... make the work order tiles taller but keep them all
   consistent"): identity/pay, then the dates, then the pills - the
   dates line reserves its height even when empty so tiles align. */
.dispatchchip.chipgrid { display: grid;
  grid-template-columns: 142px minmax(0, 1fr) 52px 58px;
  gap: 2px 8px; align-items: center; min-height: 72px;
  align-content: start; }
.chipgrid .c-next { grid-column: 1 / -1; justify-self: start;
  min-height: 15px; }
.chipgrid .c-unitwo { display: flex; gap: 6px; align-items: baseline; white-space: nowrap; }
.chipgrid .c-outtype { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
/* Flags get the whole SECOND line - squeezed into a column they wrapped
   word-by-word into tall blobs. FIXED SLOTS inside it (Peter, Sep 9
   evening: "Pills and information should always be in the same place
   on the work order tile"): the state pill anchors the left, situation
   flags flow in the middle, and the Warnings/Notes doors pin to the
   right edge - the same spots on every tile as the eye scrolls down.
   Both dispatch boards share this. */
.dispatchchip .c-flags { grid-column: 1 / -1; flex-basis: 100%;
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 2px 6px; align-items: start; min-width: 0; }
.dispatchchip .c-flags:empty { display: none; }
.c-flags .f-state, .c-flags .f-mid {
  display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }
.c-flags .f-doors { display: flex; gap: 4px; align-items: center;
  justify-self: end; }
.chipgrid .pill { white-space: nowrap; }
.chipgrid .c-pay, .chipgrid .c-min { justify-self: end; white-space: nowrap; }
/* The inspect chip is flex: its dates line takes the whole row too. */
.dispatchchip:not(.chipgrid) { min-height: 64px; }
.dispatchchip:not(.chipgrid) .c-next { flex-basis: 100%; min-height: 15px; }
.dispatchhead.headgrid { display: grid;
  grid-template-columns: minmax(100px, max-content) 1fr 68px 64px 64px;
  gap: 2px 8px; align-items: center; }
.headgrid .c-crew { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.headgrid .c-cleans, .headgrid .c-time, .headgrid .c-money { justify-self: end; white-space: nowrap; }
@media (max-width: 760px) {
  .dispatchchip.chipgrid, .dispatchhead.headgrid { display: flex; flex-wrap: wrap; }
  .chipgrid .c-outtype, .headgrid .c-crew { overflow: visible; white-space: normal; }
}

/* The one-tap Assign menu (Peter, 2026-08-27), and the bodega's vertical
   packing lists in one canonical order. */
.assignmenu { position: relative; display: inline-block; }
.assignmenu summary { list-style: none; cursor: pointer; display: inline-block;
  padding: 6px 14px; border: 1px solid var(--accent); color: var(--accent);
  border-radius: 8px; font-size: 13px; font-weight: 700; }
.assignmenu[open] summary { background: var(--accent); color: #fff; }
.assignpanel { position: absolute; z-index: 30; margin-top: 4px; min-width: 280px;
  background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 8px 22px rgba(16, 49, 79, .18); padding: 6px;
  display: flex; flex-direction: column; gap: 2px; max-height: 320px; overflow-y: auto; }
.assignpanel form { display: block; }
button.assignopt { width: 100%; text-align: left; background: none; border: 0; color: var(--ink);
  border-radius: 6px; padding: 7px 10px; cursor: pointer; font: inherit;
  display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
button.assignopt:hover { background: var(--bg); }
.packitems { flex-direction: column; gap: 2px; flex-basis: 100%; }

/* NOT NORMAL (Peter, 2026-08-27): an early check-in sold on an unready
   back-to-back screams; once the unit is ready the alarm clears itself. */
.dispatchchip.alarm { border: 2px solid var(--bad); background: #fff1f0; }
.card.unitcard.alarm { border-color: var(--bad); background: #fff8f7; }

form.inline .dismissbtn { border: 0; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; }

/* The Wrench dispatch grid (v1): tech rows x day columns plus a leading
   backlog cell. One CSS grid so the cells line up when read down a day;
   horizontal scroll inside the grid, never the page. */
.mtnweek { display: grid;
  grid-template-columns: minmax(110px, max-content) minmax(120px, 1fr)
    repeat(var(--mtndays, 7), minmax(120px, 1fr));
  gap: 2px; margin-top: 12px; overflow-x: auto; }
.mtnhead { font-size: 12px; font-weight: 700; color: var(--muted);
  padding: 4px 6px; position: sticky; top: 0; background: var(--bg); }
.mtnhead.istoday { color: var(--accent); }
.mtntech { padding: 8px 6px; display: flex; flex-direction: column; gap: 2px; }
.mtncell { border: 1px solid var(--border); border-radius: 6px; padding: 4px;
  min-height: 44px; display: flex; flex-direction: column; gap: 4px;
  background: var(--card); }
.mtncell.istoday { background: var(--bg); }
.mtncell.backlogcell { border-style: dashed; }
.wochip { flex-wrap: wrap; }
.wochip.armed { outline: 2px solid var(--accent); outline-offset: 1px; }
@media (max-width: 760px) { .mtnweek {
  grid-template-columns: minmax(90px, max-content) repeat(calc(var(--mtndays, 7) + 1), minmax(110px, 1fr)); } }

.apptform { display: inline-flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.apptform input[type=datetime-local] { font: inherit; font-size: 12px; padding: 2px 4px; }

/* The WO detail page (W2a): the facts row and the activity thread. */
.worows { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; margin-top: 8px; font-size: 14px; }
ul.thread { list-style: none; margin: 10px 0 0; padding: 0; }
li.threadrow { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap;
  padding: 7px 0; border-top: 1px solid var(--tint2); font-size: 14px; }
li.threadrow:first-child { border-top: 0; }
input.grow { flex: 1 1 240px; min-width: 0; }
/* A pipeline stage already completed and passed (Peter, 2026-08-27). */
.stagebtn.done { opacity: .45; background: var(--tint); color: var(--muted); text-decoration: line-through; }

/* --- feedback widget (Peter, 2026-08-28) -------------------------------- */
/* The button floats over every signed-in page and PULSES until the person
   has used it once (the users row carries the stamp, so it settles per
   person, not per browser). After that it is a quiet round button that is
   still exactly where they left it. */

.fb-fab {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 900;
  width: 52px;
  height: 52px;
  padding: 0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Explicit, not inherited: the default button paints its text white on
     accent, and this one is an icon that has to read on both states. */
  background: var(--accent);
  color: #fff;
  box-shadow: 0 4px 14px rgba(16, 49, 79, .28);
}
.fb-fab:hover { background: #0c5cba; }

/* The throb, on at all times (Peter, Sep 18 2026: "very obvious that people
   should click on it"). The button itself glows in rhythm and casts two
   rings; nothing scales the button, so the target never moves under a
   cursor on its way to being clicked. */
.fb-throb { animation: fb-glow 1.6s ease-in-out infinite; }
.fb-throb::before, .fb-throb::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 3px solid var(--accent);
  animation: fb-ring 1.6s ease-out infinite;
}
.fb-throb::before { animation-delay: .8s; }
@keyframes fb-ring {
  0%   { transform: scale(1);   opacity: .9; }
  100% { transform: scale(1.9); opacity: 0; }
}
@keyframes fb-glow {
  0%, 100% { box-shadow: 0 4px 14px rgba(16, 49, 79, .28), 0 0 0 0 rgba(15, 108, 214, .55); }
  50%      { box-shadow: 0 4px 18px rgba(16, 49, 79, .34), 0 0 0 10px rgba(15, 108, 214, 0); }
}
/* Somebody who has asked for less motion gets a static button that still
   stands out: a ring, just not a moving one. */
@media (prefers-reduced-motion: reduce) {
  .fb-throb { animation: none; }
  .fb-throb::before { display: none; }
  .fb-throb::after { animation: none; opacity: .6; transform: scale(1.25); }
}

/* display:flex on the rule below would silently defeat the hidden
   attribute (an author display beats the UA's [hidden]{display:none}), and
   the invisible overlay then eats every click on the page - the Playwright
   suite caught exactly that. Said explicitly so it cannot regress. */
.fb-panel[hidden] { display: none; }
.fb-panel {
  position: fixed;
  inset: 0;
  z-index: 950;
  background: rgba(16, 49, 79, .45);
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  padding: 20px;
}
.fb-card {
  background: var(--card);
  border-radius: 12px;
  width: min(560px, 100%);
  max-height: 88vh;
  overflow-y: auto;
  padding: 16px 18px 18px;
  box-shadow: 0 18px 50px rgba(16, 49, 79, .35);
  transition: width .25s ease;
}
/* The dialog GROWS when the person touches the screenshot and shrinks back
   when they click into the note (Peter, Aug 28 2026: the shot was too small
   to see). The width is the only thing that moves - the canvas rides it at
   100% - and the note box stays visible below so the trade is size, never
   losing your place in the form. */
.fb-panel.fb-big { align-items: center; justify-content: center; }
.fb-panel.fb-big .fb-card { width: min(1500px, 96vw); max-height: 94vh; }
@media (prefers-reduced-motion: reduce) {
  .fb-card { transition: none; }
}
.fb-card-head { display: flex; align-items: center; gap: 10px; }
.fb-card-head h2 { margin: 0; font-size: 17px; }
.fb-x {
  margin-left: auto;
  background: none;
  color: var(--muted);
  font-size: 22px;
  line-height: 1;
  padding: 0 4px;
}
.fb-x:hover { background: none; color: var(--ink); }

.fb-kinds { border: 0; padding: 0; margin: 14px 0 6px; display: flex; gap: 8px; }
.fb-kinds legend { font-size: 13px; color: var(--muted); padding: 0 0 6px; }
.fb-kind { flex: 1; }
.fb-kind input { position: absolute; opacity: 0; pointer-events: none; }
.fb-kind span {
  display: block;
  text-align: center;
  padding: 10px 6px;
  border: 1px solid var(--border);
  border-radius: 9px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.fb-kind input:checked + span {
  border-color: var(--accent);
  background: var(--tintblue);
  color: var(--accent);
}
.fb-kind input:focus-visible + span { outline: 2px solid var(--accent); }

.fb-label { display: block; font-size: 13px; font-weight: 600; margin: 10px 0 4px; }
.fb-form textarea {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 9px 10px;
  font: inherit;
  font-size: 14px;
  resize: vertical;
}

.fb-shotwrap { margin: 14px 0 4px; }
.fb-shot-head { display: flex; gap: 8px; align-items: baseline; margin-bottom: 6px; }
.fb-canvaswrap {
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  background: var(--tint2);
  line-height: 0;
}
#fb-canvas { width: 100%; height: auto; cursor: crosshair; touch-action: none; }
.fb-tools { display: flex; gap: 6px; align-items: center; margin-top: 8px; flex-wrap: wrap; }
.fb-tools button {
  background: var(--tint);
  color: var(--ink);
  font-size: 12px;
  font-weight: 600;
  padding: 6px 10px;
}
.fb-tools button:hover { background: var(--border); }
.fb-tools button.on { background: var(--accent); color: #fff; }
.fb-tools .check { font-size: 12px; color: var(--muted); }

.fb-who { margin: 12px 0 0; }
.fb-error {
  margin: 8px 0 0;
  color: var(--bad);
  font-size: 13px;
  font-weight: 600;
}
.fb-send { display: flex; gap: 8px; margin-top: 14px; }
.fb-send button:not(.primary) { background: var(--tint); color: var(--ink); }
.fb-send button:not(.primary):hover { background: var(--border); }
.fb-done { padding: 18px 2px; }

.fb-mine { margin-top: 16px; border-top: 1px solid var(--border); padding-top: 12px; }
.fb-mine h3 { font-size: 13px; color: var(--muted); margin: 0 0 8px; }
.fb-mine ul { list-style: none; margin: 0; padding: 0; }
.fb-mine li {
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-size: 13px;
  padding: 5px 0;
  border-bottom: 1px solid var(--border);
}
.fb-mine li:last-child { border-bottom: 0; }
/* The conversation under a person's own item (082): questions from the
   office and the reply box that answers straight onto the item. */
.fb-mine li { flex-wrap: wrap; }
ul.fb-thread {
  flex-basis: 100%; list-style: none; margin: 2px 0 0; padding: 0 0 0 12px;
  border-left: 2px solid var(--border); display: flex;
  flex-direction: column; gap: 3px; font-size: 12.5px;
}
ul.fb-thread li { border-bottom: 0; padding: 0; display: block; }
.fb-replyrow { flex-basis: 100%; display: flex; gap: 6px; margin-top: 4px; }
.fb-replyrow input { flex: 1; font-size: 13px; padding: 6px 8px; }
/* The admin-side thread on Settings -> Feedback. */
ul.fb-notes {
  list-style: none; margin: 8px 0; padding: 8px 12px;
  background: var(--bg); border-radius: 8px; display: flex;
  flex-direction: column; gap: 6px; font-size: 13px;
}
ul.fb-notes li { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.fb-buildform { display: inline-flex; gap: 8px; align-items: center; }
/* One-tap contact icons beside every member email (Peter, Aug 29 2026). */
a.contacticon { color: var(--muted); margin-left: 4px; vertical-align: middle; }
/* The collapsed contact column (Peter, Sep 7 2026): the handset button
   wears the icon dress, and the little card pops beside it. */
button.contacticon { background: none; border: 0; padding: 0; cursor: pointer;
                     color: var(--muted); margin-left: 4px;
                     vertical-align: middle; }
button.contacticon:hover, a.contacticon:hover { color: var(--ink); }
.contactcell { position: relative; white-space: nowrap; }
.contactpop { position: absolute; z-index: 40; top: 100%; left: 0;
              min-width: 240px; background: var(--card);
              border: 1px solid var(--border); border-radius: 10px;
              padding: 10px 12px; box-shadow: 0 10px 28px rgba(15, 23, 42, .18);
              white-space: nowrap; }
.contactpop .tt-row { display: flex; justify-content: space-between;
                      gap: 16px; font-size: 13px; line-height: 1.7; }
.contactpop .tt-row span { color: var(--muted); }
a.contacticon:hover { color: var(--accent); }

/* --- the admin review list ---------------------------------------------- */

.fb-filters { display: flex; gap: 6px; align-items: center; margin: 14px 0; flex-wrap: wrap; }
.fb-filters a.pill { text-decoration: none; color: var(--muted); }
.fb-filters a.pill.on { background: var(--accent); color: #fff; }
.pill.flagged { background: #fbe2e0; color: var(--bad); }
.pill.kind-broken { background: #fbe2e0; color: var(--bad); }
.pill.kind-idea { background: #ede9fe; color: #6d28d9; }
.pill.kind-question { background: #dbeafe; color: var(--link); }
.pill.status-new { background: #fdeeda; color: var(--warn); }
.pill.status-looking { background: #dbeafe; color: var(--link); }
.pill.status-done { background: #d9f2e5; color: var(--ok); }
.pill.status-declined { background: var(--tint); color: var(--muted); }

.fb-item {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 12px;
}
/* --- The Grid (Jobber-classic scheduler) ------------------------------- */
.glayout { display: flex; gap: 14px; align-items: flex-start; }
.gmain { flex: 1; min-width: 0; }
.gchrome { display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
           margin-bottom: 8px; }
.glabel { font-size: 1.1em; }
.gfilters { display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
            margin-bottom: 10px; }
.gdept { display: inline-flex; gap: 5px; align-items: center;
         font-size: .85em; cursor: pointer; }
.gswatch { width: 11px; height: 11px; border-radius: 3px;
           background: var(--dept, #475569); display: inline-block; }
/* The table gotcha, paid before: a clipped popup is the Stephany cutoff.
   The grid table must never hide its own popups. */
.gridtable { width: 100%; border-collapse: collapse; overflow: visible; }
.gridtable th, .gridtable td { border: 1px solid var(--line, #d8dee7);
                               vertical-align: top; padding: 4px;
                               overflow: visible; }
.gday .gwho { text-align: left; min-width: 170px; font-weight: 500; }
.gday .gwho .gname { display: inline-block; }
.gwho.goff .gname { text-decoration: line-through; opacity: .6; }
.gcell { min-width: 64px; min-height: 34px; }
/* The day view is a DESKTOP surface (Peter, Aug 30 2026): show the full
   12 hours beside the queue with no horizontal scroll - fixed layout,
   the hour columns share the width evenly. Below desktop width the
   scrolling table above stands; nobody schedules a day from a phone. */
@media (min-width: 1100px) {
  .gday { table-layout: fixed; }
  .gday .gwho { width: 150px; min-width: 0; overflow: hidden; }
  .gday .gcell { min-width: 0; }
  .gday .gchip { font-size: .74em; padding: 2px 4px; }
  .gday .gchip .gplace { display: block; margin-left: 0; }
}
.gcell.gover { outline: 2px dashed var(--accent, #2563eb);
               outline-offset: -2px; }
.gunassignedrow { background: rgba(220, 38, 38, .05); }
.gmonth td { width: 14%; height: 92px; }
.gmonth .gout { opacity: .55; }
.gtoday { box-shadow: inset 0 0 0 2px var(--accent, #2563eb); }
.gdaynum { display: flex; gap: 6px; align-items: baseline; }
.gallday { background: rgba(37, 99, 235, .04); }

.gchip { position: relative; border-left: 4px solid var(--dept, #475569);
         background: color-mix(in srgb, var(--dept, #475569) 12%, white);
         border-radius: 4px; padding: 2px 5px; margin: 2px 0;
         font-size: .82em; }
.gchip[draggable="true"] { cursor: grab; }
.gchip.gdragging { opacity: .4; }
.gchip.gdone summary { text-decoration: line-through; opacity: .65; }
.gchip.gunassigned { outline: 1.5px solid var(--bad, #dc2626); }
.gchip.goverbudget { outline: 2px solid #d97706;
                     background: color-mix(in srgb, #d97706 18%, white); }
.gchip .gtime { font-weight: 600; margin-right: 3px; }
.gchip .gplace { color: var(--muted, #64748b); margin-left: 3px; }
.gchip .gflag { background: var(--bad, #dc2626); color: #fff;
                border-radius: 3px; padding: 0 4px; margin-left: 4px;
                font-size: .85em; }
.gpop > summary { cursor: pointer; list-style: none; }
.gpop > summary::-webkit-details-marker { display: none; }
.gpop[open] .gpopbody { position: absolute; z-index: 40; left: 0; top: 100%;
                        min-width: 260px; background: var(--card, #fff);
                        border: 1px solid var(--line, #d8dee7);
                        border-radius: 6px; padding: 8px;
                        box-shadow: 0 6px 18px rgba(0, 0, 0, .18); }
.gqueue { width: 300px; flex-shrink: 0; max-height: 78vh; overflow: auto;
          border: 1px solid var(--line, #d8dee7); border-radius: 8px;
          padding: 8px; }
.gqchip a { font-weight: 600; margin-right: 4px; }

.fb-item.is-flagged { border-color: var(--bad); }
.fb-head { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
/* The items are collapsible now (Peter, Aug 29 2026): the summary line IS
   the list. display:flex on a summary drops the browser's disclosure
   marker, so the fold state gets its own chevron. */
summary.fb-head { cursor: pointer; }
summary.fb-head::before { content: "▸"; color: var(--muted); }
details[open] > summary.fb-head::before { content: "▾"; }

/* The person's own words, and they are meant to be the loudest thing in the
   card. Everything a model wrote sits below in a quieter box. */
.fb-body {
  margin: 10px 0 6px;
  padding: 8px 12px;
  border-left: 3px solid var(--accent);
  background: var(--tint2);
  font-size: 15px;
  white-space: pre-wrap;
}
.fb-original { margin: 0 0 6px; }
.fb-where { margin: 4px 0; }
.fb-shot img { max-width: 100%; border: 1px solid var(--border); border-radius: 8px; margin-top: 8px; }

.fb-ai {
  margin: 10px 0 4px;
  padding: 10px 12px;
  background: var(--tint2);
  border: 1px dashed #ddd6fe;
  border-radius: 8px;
  font-size: 14px;
}
.fb-ai p { margin: 4px 0; }
.fb-prompt {
  width: 100%;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px;
  margin-top: 6px;
}

.fb-flag {
  margin: 10px 0;
  padding: 10px 12px;
  background: #fbe2e0;
  border-radius: 8px;
  font-size: 13px;
}
.fb-flag p { margin: 4px 0; }

.fb-actions { display: flex; gap: 8px; align-items: center; margin-top: 10px; flex-wrap: wrap; }
.fb-actions form { display: inline; }

/* The owner's new-feedback bubble in the header (supers only). Explicit
   colors - the default button/link styling is exactly the white-text trap. */
.fb-bubble {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-right: 10px;
  padding: 3px 12px;
  border-radius: 999px;
  background: #fdeeda;
  color: var(--warn);
  font-size: 12.5px;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}
.fb-bubble::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--warn);
}
.fb-bubble:hover { background: #fbe3c0; }

/* --- the property panel + hover card (Aug 28 2026 scope) ---------------- */
.unitpanel { max-width: 1100px; }
.up-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.up-head h1 { margin: 0; }
.up-head small { font-weight: 400; color: var(--muted); font-size: 14px; }
.up-stop {
  background: #fbe2e0;
  border: 2px solid var(--bad);
  border-radius: 10px;
  padding: 12px 16px;
  margin: 12px 0;
  font-size: 15px;
}
.up-strip {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 14px;
  margin: 12px 0;
  font-size: 14px;
}
.up-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
  gap: 12px;
}
.up-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
}
.up-card h2 { font-size: 14px; margin: 0 0 8px; color: var(--navyink); }
.up-card dl { margin: 0; font-size: 13.5px; }
.up-card dt { font-weight: 700; margin-top: 8px; }
.up-card dd { margin: 2px 0 0; white-space: pre-wrap; }
.up-code { font-family: ui-monospace, Menlo, monospace; font-weight: 700; }
.up-warn { background: #fdeeda; border-radius: 6px; padding: 4px 8px; }
.pill.from-building { background: #dbeafe; color: var(--link); font-weight: 600; }
.up-links a { margin-right: 12px; }

/* find results */
.find-list { display: flex; flex-direction: column; gap: 6px; margin: 10px 0 18px; }
.find-row {
  display: flex;
  gap: 12px;
  align-items: baseline;
  flex-wrap: wrap;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 9px 12px;
  text-decoration: none;
  color: var(--ink);
}
.find-row:hover { border-color: var(--accent); }
.find-row span { color: var(--muted); font-size: 13px; }
.find-snippet { flex-basis: 100%; }
.find-snippet b { color: var(--accent); }

/* the pill in the subnav */
.subnav .unitfind { margin-left: auto; }
.subnav .unitfind input {
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 5px 14px;
  font-size: 13px;
  width: 210px;
}

/* the hover card */
.unitlink { color: inherit; text-decoration: none; border-bottom: 1px dotted var(--accent); }
.unitlink:hover { color: var(--accent); }
.uf-hover {
  position: absolute;
  z-index: 800;
  width: 360px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(16, 49, 79, .25);
  padding: 10px 12px;
  font-size: 13px;
}
.uc-head { margin-bottom: 6px; }
.uc-head span { color: var(--muted); }
.uc-line { margin: 3px 0; }
.uc-warn { background: #fdeeda; border-radius: 5px; padding: 2px 6px; }
.uc-stop { background: #fbe2e0; font-weight: 700; border-radius: 5px; padding: 2px 6px; }
.uc-more { margin-top: 6px; color: var(--muted); font-size: 12px; }

/* Tier 2 answers on the find page. */
.ai-answer {
  background: var(--tint2);
  border: 1px dashed #ddd6fe;
  border-radius: 10px;
  padding: 12px 16px;
  margin: 12px 0 18px;
}
.ai-answer.ai-no { background: var(--tint2); border-color: var(--border); }
.ai-label { margin: 0 0 4px; font-size: 12px; font-weight: 700; color: #6d28d9; }
.ai-text { margin: 0; font-size: 15px; }
.ai-cites { margin: 8px 0 0; }
.ai-offer { margin: 8px 0 14px; }

/* Bodega linen highlight (Peter, Aug 29 2026): any sheet or pillowcase row,
   IN PLACE - no regrouping, no badges, no reordering. YELLOW since Sep 5
   2026 (Juan, feedback #29; Peter: "do not move them, just change the
   highlight color"). */
.packitem.linen {
  background: #fde68a;
  border-radius: 5px;
  padding: 1px 6px;
}

/* Section 2: sort pills, shared across the Limpia views. */
.sortbarline { margin: 6px 0; }
.sortbar { display: inline-flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.sortpill {
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 12px;
  text-decoration: none;
  color: var(--muted);
}
.sortpill.on { border-color: var(--accent); color: var(--accent); font-weight: 700; }
.sortpill.clear { border-style: dashed; }

/* Section 3a: building headers in the dispatch pool. */
.poolbuilding {
  display: flex;
  gap: 8px;
  align-items: baseline;
  border-bottom: 2px solid var(--border);
  margin: 10px 0 4px;
  padding-bottom: 2px;
}
.poolbuilding.working { background: #fdf6e3; border-radius: 6px 6px 0 0; padding-left: 6px; }

/* Section 4b: the live-board banner. Advisory presence, never a lock. */
.liveboard-banner {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  background: var(--tintblue);
  border: 1px solid #bfdbfe;
  border-radius: 999px;
  padding: 4px 14px;
  font-size: 13px;
  margin: 6px 0;
}
.livedot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #16a34a;
  animation: livedot 2s ease-in-out infinite;
}
@keyframes livedot { 50% { opacity: .4; } }
@media (prefers-reduced-motion: reduce) { .livedot { animation: none; } }

.dispatchtotals {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 12px;
  margin-bottom: 8px;
  font-size: 13px;
}

/* The per-person edit drawer on Settings -> Team (Peter, Aug 29 2026). */
.editbox summary { cursor: pointer; color: var(--accent); font-size: 13px; }
/* Edit is a BUTTON, and Save is a real button (Peter, Aug 29 2026). The
   default button paints its text white with no background - the recorded
   gotcha - so button.btn/summary.btn get the full a.btn treatment. */
button.btn, summary.btn {
  padding: 9px 14px;
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  display: inline-block;
}
button.btn:hover, summary.btn:hover { background: #0c5cba; }
button.btn.small, summary.btn.small, a.btn.small,
.editbox summary.btn.small {
  padding: 5px 12px;
  font-size: 13px;
  color: #fff;
}
.editpanel {
  position: absolute;
  right: 24px;
  z-index: 60;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(16, 49, 79, .2);
  padding: 14px 16px 40px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 440px;
  max-width: 560px;
  white-space: normal;
}
.editform { display: flex; flex-direction: column; gap: 10px; }
/* The disable control lives in the drawer's LOWER-LEFT corner (Peter,
   Aug 29 2026: "so it does not accidentally get clicked") - the opposite
   corner from Save and resend. */
.editpanel .cornerform { position: absolute; bottom: 8px; left: 12px; margin: 0; }
.editpanel .endrow { justify-content: flex-end; }
/* A popup near the bottom of the window opens UPWARD instead of clipping
   (Stephany's row, Aug 29 2026). td.actions is the positioning context. */
.editpanel.up { bottom: 30px; }
.jobmenu.up { top: auto; bottom: calc(100% + 4px); }
/* The global `table { overflow: hidden }` (for the rounded corners) was
   CUTTING OFF these absolutely-positioned popups near the table's bottom
   edge - the member list keeps its radius but lets popups escape. */
table.memberlist { overflow: visible; }
/* Sortable member-list columns (Peter, Aug 29 2026). */
.memberlist th a.sorthead { color: inherit; text-decoration: none; }
.memberlist th a.sorthead:hover { color: var(--accent); }
.memberlist th a.sorthead.on { color: var(--accent); }
/* The batch-departments Save rides along a long list. */
.savebar {
  position: sticky; bottom: 8px; display: flex; justify-content: flex-end;
  padding: 8px 0; z-index: 40;
}
/* Disabled members, shown by the All filter: visibly parked, not gone. */
.memberlist tr.inactiverow td { opacity: .6; }

/* P4e(c): while dragging a skill-tagged job (or person), the targets that
   would be refused dim out - the write refuses regardless. */
.droptarget.skillno, .droprow.skillno { opacity: .4; cursor: not-allowed; }
.memberlist td.actions { position: relative; }
details.addbox.quiet summary { color: var(--muted); font-weight: 400; font-size: 13px; }
.skillrow { display: flex; gap: 12px; flex-wrap: wrap; }

/* The WO page's materials rows (§3): short numeric inputs. */
.numshort { width: 90px; }

/* Shift week grid (Peter, Sep 1 2026, revised same day): the Person +
   dates header row pins to the VIEWPORT while the PAGE scrolls - "when
   I scroll down the schedule I can still see that row". On desktop the
   wrapper must NOT be a scroll container (the generic .tblscroll
   overflow clip is undone; any non-visible overflow ancestor kills
   viewport sticky). Phones keep the scrolling box so the wide grid can
   still pan sideways - the header sticks inside it instead. */
.schedwrap { overflow: visible; max-height: none; }
/* The generic rule also puts overflow:hidden on TABLE itself, which
   makes the table the sticky containing block - undo it here too. */
.schedwrap .schedgrid { overflow: visible; }
.schedwrap thead th { position: sticky; top: 0; z-index: 6;
                      background: var(--bg); }
.schedwrap thead th.todaycol { background: var(--tintblue); }
@media (max-width: 999px) {
  .schedwrap { overflow: auto; max-height: calc(100vh - 120px); }
}
#schedsearch { min-width: 170px; }
/* Week-of heading with its arrows either side, the whole trio packed on
   the LEFT (Peter, Sep 3 2026) - the generic .qhead space-between had
   thrown the right arrow to the far edge of the row. */
.weekhead { display: flex; align-items: center; gap: 10px;
            justify-content: flex-start; }
.weekhead h2 { margin: 0; }
/* Per-person week totals under the name: draft vs published hours. */
.hourssum { margin-top: 3px; display: flex; gap: 4px; flex-wrap: wrap; }

/* Dropping a scheduled chip back on the backlog unschedules it
   (Peter, Sep 1 2026) - the panel lights up as a drop target. */
.gqueue.gover { outline: 2px dashed var(--accent, #2563eb);
                outline-offset: -2px; background: var(--tintblue); }

/* The spotlight tour (Peter, Sep 1 2026): the overlay IS the spotlight -
   a hole punched by an enormous box-shadow; the card floats beside it. */
.tourlight { position: absolute; z-index: 900; border-radius: 8px;
             box-shadow: 0 0 0 9999px rgba(15, 27, 40, .62);
             pointer-events: none; transition: all .18s ease; }
.tourcard { position: absolute; z-index: 901; width: 340px; max-width: 92vw;
            background: var(--card); border-radius: 10px; padding: 14px 16px;
            box-shadow: 0 8px 30px rgba(0, 0, 0, .35); }
.tourcard h3 { margin: 0 0 6px; font-size: 15px; color: #10314f; }
.tourcard p { margin: 0 0 12px; font-size: 13.5px; line-height: 1.5;
              color: var(--ink2); }
.tourrow { display: flex; gap: 8px; align-items: center; }
.tourcount { color: #94a3b8; font-size: 12px; margin-right: auto; }
.tourrow button { border: 1px solid #cbd5e1; background: var(--card);
                  border-radius: 7px; padding: 6px 14px; font-size: 13px;
                  cursor: pointer; }
.tourrow button.tourmain { background: #0f6fde; border-color: var(--accent);
                           color: #fff; font-weight: 700; }
.tourrow button.tourskip { border: 0; color: var(--muted);
                           text-decoration: underline; }

/* Desk search (feedback #13): the reservation row opens Track; this is the
   quieter second link to that day's board. */
.find-sub { display: block; margin: -4px 0 10px 14px; font-size: 12px; color: var(--muted); }

/* Radar building -> Track node tree (Peter, Sep 5 2026). */
.card-head h3 .tracklink { font-size: 12px; margin-left: 4px; text-decoration: none; color: var(--muted); }
.card-head h3 .tracklink:hover { color: var(--ink); }

/* --- The workload picture (P3b(p), Sep 6 2026) --------------------------
   Two surfaces: the ribbon strip on every module (a stamp that draws), and
   the full chart page. Colors rhyme with the department palette without
   claiming it: arrivals blue, departures slate, B2Bs amber - the series
   Track never had - and in-house a quiet line. */
/* Chart-only and dressed as a BUTTON (Peter, Sep 7 2026): the sparkline
   is the whole message, in a pill that visibly wants the click. */
.workstrip { display: inline-flex; align-items: flex-end;
             padding: 3px 9px; border-radius: 9px;
             border: 1px solid rgba(255, 255, 255, .22);
             background: rgba(255, 255, 255, .08);
             transition: background .15s ease, border-color .15s ease; }
a.workstrip:hover { background: rgba(255, 255, 255, .18);
                    border-color: rgba(255, 255, 255, .45);
                    text-decoration: none; }
.workstrip svg { display: block; }
.workstrip .wl-arr { fill: #5aa2f8; }
.workstrip .wl-dep { fill: #b9c6d6; }
.workstrip .wl-b2b { fill: #f59e0b; }
@media (max-width: 900px) { .workstrip { display: none; } }

.wl-insights { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
.wl-card { border: 1px solid var(--border); border-radius: 8px; padding: 6px 10px;
           font-size: 13px; background: var(--card); }
.wl-card b { margin-right: 6px; }
.wl-card.wl-warn { border-color: #f59e0b; background: #fffbeb; }
.wl-card.wl-b2b { border-color: #d97706; background: #fff7ed; }
.wl-legend { display: flex; gap: 6px; margin: 4px 0 8px; }
.wl-legend .swatch { display: inline-block; width: 10px; height: 10px;
                     border-radius: 2px; margin-right: 5px; }
/* Swatches are shared by the legend chips AND the hover tooltip. */
.sw-arr { background: #0f6fde; }
.sw-dep { background: #94a3b8; }
.sw-b2b { background: #d97706; }
.sw-ih { background: #16a34a; }
.wl-legend .wl-off { opacity: .45; text-decoration: line-through; }

.wlchart { background: linear-gradient(180deg, var(--chart-top), var(--tint2));
           border: 1px solid var(--border); border-radius: 12px;
           box-shadow: 0 1px 3px rgba(15, 23, 42, .06);
           width: 100%; height: auto; display: block; margin: 0 auto; }
.wlchart .wl-arr { fill: url(#g-arr); }
.wlchart .wl-dep { fill: url(#g-dep); }
.wlchart .wl-b2b { fill: url(#g-b2b); }
.wlchart .wl-ih { stroke: #16a34a; stroke-width: 2.5;
                  stroke-linejoin: round; stroke-linecap: round; }
.wlchart .wl-area { fill: url(#g-ih); }
.wlchart .wl-dot { fill: var(--card); stroke: #16a34a; stroke-width: 2; }
.wlchart .wl-occ { font-size: 10px; font-weight: 700; fill: #15803d;
                   paint-order: stroke; stroke: var(--card); stroke-width: 3px; }
.wlchart .wl-weekend { fill: rgba(100, 116, 139, .07); }
.wlchart .wl-grid { stroke: var(--border); stroke-dasharray: 2 4; }
.wlchart .wl-base { stroke: var(--border); }
.wlchart .wl-y { font-size: 10px; fill: #94a3b8; }
.wlchart .wl-ihy { font-size: 10px; fill: #16a34a; font-weight: 600; }
.wlchart .wl-x { font-size: 10px; fill: #64748b; }
.wlchart .wl-w { font-size: 9px; fill: #94a3b8; font-weight: 600;
                 text-transform: uppercase; letter-spacing: .04em; }
.wlchart .wl-hit { fill: transparent; cursor: pointer; }
.wlchart .wl-day:hover .wl-hit { fill: rgba(15, 111, 222, .06); }
.wlchart .wl-tline { stroke: #0f6fde; stroke-dasharray: 4 4; opacity: .5; }
.wlchart .wl-tlabel { font-size: 10px; font-weight: 700; fill: #0f6fde;
                      text-transform: uppercase; letter-spacing: .05em; }
.wlchart .wl-today .wl-hit { stroke: rgba(15, 111, 222, .35);
                             stroke-dasharray: 3 3; }
.wlchart .wl-pin .wl-hit { fill: rgba(15, 111, 222, .08);
                           stroke: #0f6fde; stroke-dasharray: none; }
.wlchart.hide-arr .wl-arr { display: none; }
.wlchart.hide-dep .wl-dep { display: none; }
.wlchart.hide-b2b .wl-b2b { display: none; }
.wlchart.hide-ih .wl-ihg { display: none; }

/* The chart grows out of the baseline once per visit; the in-house line
   fades in after it. Off entirely for reduced-motion users. */
@media (prefers-reduced-motion: no-preference) {
  .wlchart .wl-day rect:not(.wl-hit) {
    transform-box: fill-box; transform-origin: bottom;
    animation: wlgrow .5s cubic-bezier(.2, .7, .3, 1) backwards;
    animation-delay: var(--wld, 0ms);
  }
  .wlchart .wl-ihg { animation: wlfade .7s .5s ease-out backwards; }
}
@keyframes wlgrow { from { transform: scaleY(0); } }
@keyframes wlfade { from { opacity: 0; transform: translateY(6px); } }

.wl-tip { position: fixed; z-index: 200; pointer-events: none;
          background: rgba(15, 23, 42, .94); color: var(--tint2);
          border-radius: 10px; padding: 8px 12px; font-size: 12.5px;
          line-height: 1.5; min-width: 180px;
          box-shadow: 0 6px 20px rgba(2, 6, 23, .35); }
.wl-tip[hidden] { display: none; }
.wl-tip .tt-day { display: block; margin-bottom: 4px; font-size: 11px;
                  color: #cbd5e1; text-transform: uppercase;
                  letter-spacing: .04em; }
.wl-tip .tt-row { display: flex; justify-content: space-between; gap: 16px; }
.wl-tip .tt-row .swatch { display: inline-block; width: 8px; height: 8px;
                          border-radius: 2px; margin-right: 6px; }
.wl-tip .tt-v { font-weight: 700; }

.wl-panel { border: 1px solid var(--border); border-radius: 12px;
            padding: 10px 14px; margin: 12px 0; background: var(--card);
            box-shadow: 0 1px 3px rgba(15, 23, 42, .05); }
.wl-panel h3 { margin: 2px 0 6px; }

/* The vacation calendar (Peter, Sep 16 2026): pickable months, the
   regular days off grey, one tap per day. */
.vacmonths { display: flex; gap: 18px; flex-wrap: wrap; }
.vacmonth h3 { margin: 6px 0; font-size: 15px; }
.vacgrid { display: grid; grid-template-columns: repeat(7, 40px); gap: 3px; }
.vacwd { font-size: 11px; text-align: center; color: var(--muted, #64748b); }
.vacday { position: relative; height: 44px; border: 1px solid var(--border);
  border-radius: 8px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; cursor: pointer;
  background: var(--card); font-size: 13px; }
.vacday small { font-size: 9px; color: var(--muted); line-height: 1; }
.vacday.regoff { background: var(--tint); color: var(--muted); }
.vacday.dead { cursor: default; background: var(--tint); color: #94a3b8; }
.vacday input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.vacday:has(input:checked) { background: #1d6fb8; border-color: #1d6fb8;
  color: #fff; }
.vacday:has(input:checked) small { color: #dbeafe; }
.vacreq { border: 1px solid var(--border); border-radius: 10px;
  padding: 10px 14px; margin: 10px 0; }
.inlineform { display: inline; }
.deptsup label, .deptjobs label { display: block; }
.deptsup .execflag { margin-top: 6px; border-top: 1px dashed var(--border);
  padding-top: 4px; }

/* BizDev multi-select chips + the projection comp picker (Justine,
   Sep 16 2026). */
.chipbox { display: inline-flex; gap: 4px; flex-wrap: wrap; margin-left: 6px;
  vertical-align: middle; }
.chipbox .chip { font: inherit; font-size: 12px; padding: 2px 8px;
  border-radius: 999px; border: 1px solid #1d6fb8; background: #e8f1fa;
  color: #10314f; cursor: pointer; }
.comp-picks { display: flex; gap: 4px 12px; flex-wrap: wrap; margin-top: 6px; }
.comp-pick-l { font-size: 12px; white-space: nowrap; cursor: pointer; }

/* Static mini calendars on the vacation approvals (Peter, Sep 16 2026). */
.minicals { display: flex; gap: 14px; flex-wrap: wrap; margin: 6px 0; }
.minical { border-collapse: collapse; font-size: 11px; }
.minical caption { font-weight: 700; font-size: 12px; padding: 2px; }
.minical th { color: var(--muted); font-weight: 400; padding: 1px 4px; }
.minical td { text-align: center; padding: 1px 4px; color: #94a3b8; }
.minical td.on { background: #1d6fb8; color: #fff; border-radius: 4px;
  font-weight: 700; }

/* Directory working-today section rows (staff feedback, Sep 17 2026).
   Ink rides the theme vars so the headers hold up in dark mode too. */
.dirtable .dirsect td { background: var(--tintblue); color: var(--ink);
  font-weight: 700; border-top: 2px solid var(--border);
  padding: 6px 10px; }

/* Retired departments hide until the toggle asks (Peter, Sep 16 2026). */
.hideretired .retiredrow { display: none; }

/* The floating Save on Settings -> Departments (Peter, Sep 16 2026).
   Sits LEFT of the feedback bubble (.fb-fab, 52px at right:22), which was
   covering it (Peter, Sep 16 2026). */
.floatsave { position: fixed; right: 86px; bottom: 22px; z-index: 40;
  display: flex; gap: 10px; align-items: center; background: var(--card);
  border: 1px solid var(--border); border-radius: 12px;
  padding: 8px 12px; box-shadow: 0 4px 16px rgba(16,49,79,.18); }
#deptsave-note { color: #92400e; }

/* --- Yeti Sherpa (Peter, Sep 17-18 2026) ----------------------------------- */
.sherpa { display: flex; gap: 18px; align-items: flex-start; }
.sherparail { flex: 0 0 240px; max-width: 240px; position: sticky; top: 12px; }
.sherparail h4 { margin: 14px 0 6px; font-size: 12px; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted); }
.sherparail .shsearch { margin-top: 8px; }
.sherparail .shsearch input { width: 100%; box-sizing: border-box; }
.sherparail .wide { width: 100%; }
.shlist { list-style: none; margin: 0; padding: 0; }
.shlist li a { display: block; padding: 6px 8px; border-radius: 8px; color: var(--ink);
  text-decoration: none; position: relative; }
/* Chats working in the background (Peter, Sep 18 2026): a pulsing dot
   while the turn runs, a steady green one once it finished unseen. */
.shlist .shwork { display: none; position: absolute; right: 8px; top: 10px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--accent); }
.shlist li.working .shwork { display: block; animation: shdots 1.2s ease-in-out infinite; }
.shlist li.fresh .shwork { display: block; background: var(--good, #15803d); }
.shlist li.working .shtitle, .shlist li.fresh .shtitle { padding-right: 16px; }
.shlist li a:hover { background: var(--tint2, #eef2f7); }
.shlist li.active a { background: var(--card); border: 1px solid var(--border); }
.shlist .shtitle { display: block; font-size: 14px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.sherpamain { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.shhead { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.shhead h2 { margin: 0; font-size: 16px; }
.shtitleform input { font-size: 16px; font-weight: 600; border: 1px solid transparent;
  background: transparent; color: var(--navyink, var(--ink)); width: 100%; min-width: 220px; }
.shtitleform input:hover, .shtitleform input:focus { border-color: var(--border); background: var(--card); }
.shshare { position: relative; }
.shsharepanel { position: absolute; right: 0; z-index: 30; background: var(--card);
  border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; min-width: 300px;
  box-shadow: 0 4px 16px rgba(16,49,79,.18); }
.shmsgs { display: flex; flex-direction: column; gap: 12px; min-height: 240px; }
.shmsg.user { display: flex; justify-content: flex-end; }
.shmsg.user .shbubble { background: var(--navy, #14324f); color: #fff; border-radius: 14px 14px 4px 14px;
  padding: 9px 13px; max-width: 78%; white-space: pre-wrap; }
.shmsg.assistant { background: var(--card); border: 1px solid var(--border); border-radius: 12px;
  padding: 10px 14px; max-width: 92%; }
.shmsg.assistant.streaming { border-style: dashed; }
.shanswer p { margin: 6px 0; }
.shanswer table { border-collapse: collapse; margin: 6px 0; font-size: 13px; }
.shanswer th, .shanswer td { border: 1px solid var(--border); padding: 3px 8px; text-align: left; }
.shanswer ul, .shanswer ol { margin: 4px 0 4px 18px; }
.shstreamtext { white-space: pre-wrap; }
.shdots::after { content: '…'; animation: shdots 1.2s steps(3, end) infinite; }
@keyframes shdots { 0% { opacity: .2; } 50% { opacity: 1; } 100% { opacity: .2; } }
.shpending, .shlive { color: var(--muted); font-size: 13px; }
.shtool { border-left: 3px solid var(--border); padding: 2px 8px; margin: 4px 0; font-size: 13px; }
.shtool.err { border-left-color: var(--bad); }
.shtool summary { cursor: pointer; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; list-style: none; }
.shtool summary::-webkit-details-marker { display: none; }
.shtool-ic { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); display: inline-block; }
.shtool-guest .shtool-ic, .shtool-ic.shtool-guest { background: #6d28d9; }
.shtool-ic.shtool-wo { background: #b45309; }
.shtool-ic.shtool-ticket { background: #0f766e; }
.shtool-ic.shtool-chart { background: #be185d; }
.shtool-ic.shtool-sheet { background: #15803d; }
.shtool-ic.shtool-write { background: var(--bad); }
.shrows { overflow-x: auto; margin: 6px 0; }
.shrows table { min-width: 100%; }
.shrefused { background: #fbe2e0; color: var(--bad); border-radius: 8px; padding: 8px 12px; margin: 6px 0; }
.shcard { margin: 8px 0; padding: 10px 12px; border-radius: 10px; }
.shcard-head { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.shdiff { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 8px 0; }
.shval { background: var(--card); border: 1px solid var(--border); border-radius: 6px; padding: 6px 8px;
  white-space: pre-wrap; font-size: 13px; }
.shform { display: flex; gap: 8px; align-items: flex-end; position: sticky; bottom: 10px;
  background: var(--bg); padding-top: 6px; }
.shform textarea { flex: 1 1 auto; resize: vertical; min-height: 44px; font: inherit; padding: 8px 10px;
  border-radius: 10px; border: 1px solid var(--border); background: var(--card); color: var(--ink); }
.shmic { width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--border); background: var(--card);
  color: var(--ink); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; position: relative; }
.shmic.on { background: var(--bad); color: #fff; border-color: var(--bad); animation: shpulse 1.2s ease-in-out infinite; }
.shmic.on::after { content: attr(data-live); position: absolute; bottom: 44px; right: 0; white-space: nowrap;
  font-size: 12px; color: var(--muted); }
@keyframes shpulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, .4); } 50% { box-shadow: 0 0 0 8px rgba(220, 38, 38, 0); } }
.shfoot { margin: 0; }
.shempty { text-align: center; padding: 30px 10px; }
.shempty h2 { margin: 0 0 6px; }
.shchips { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 14px; }
.shchip { border: 1px solid var(--border); background: var(--card); color: var(--ink); border-radius: 999px;
  padding: 7px 12px; font-size: 13px; cursor: pointer; }
.shchip:hover { border-color: var(--accent); color: var(--accent); }
.shcards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; margin: 10px 0; }
.shcardt { background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; }
.shcardt h3 { margin: 0 0 6px; font-size: 15px; }
.shcardt p { margin: 4px 0; font-size: 14px; }
.shtutorial .wxsheet { padding: 18px 22px; }
.shqlist li { margin: 4px 0; }
.shweek { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; margin: 12px 0; }
.shweek .card h3 { margin: 0 0 6px; font-size: 14px; }
.shweek ul { margin: 0; padding-left: 18px; }
@media (max-width: 800px) {
  .sherpa { flex-direction: column; }
  .sherparail { position: static; flex: none; max-width: none; width: 100%; }
  .shmsg.assistant { max-width: 100%; }
  .shdiff { grid-template-columns: 1fr; }
}
html[data-theme="dark"] .shrefused { background: #3b1a1a; color: #fca5a5; }
@media (prefers-color-scheme: dark) {
  html[data-theme="auto"] .shrefused { background: #3b1a1a; color: #fca5a5; }
}

/* Way to Go on the Den + the send popup (Peter, Sep 18 2026) */
.homerecog { max-width: 980px; margin: 22px auto 10px; }
.homerecog .card-head h2 { margin: 0; }
.homerecog .recoglayout { margin-top: 10px; }
.recogsheet { max-width: 560px; }
.recogsheet h3 { margin: 0 0 8px; }
.recogsendform label { display: block; margin: 8px 0 4px; font-size: 14px; }
.recogsendform select, .recogsendform textarea { width: 100%; box-sizing: border-box; }
.recogsendform .recogleaders { margin-top: 12px; }

.shhowto { display: flex; justify-content: flex-end; }
.shhowto button { font-size: 13px; }
.shhelp .wxsheet { padding: 18px 22px; }

/* Sherpa answers read like a document (Peter, Sep 18 2026: rich text) */
.shanswer { font-size: 15px; line-height: 1.5; }
.shanswer h1, .shanswer h2, .shanswer h3 { margin: 12px 0 6px; color: var(--navyink, var(--ink)); }
.shanswer h1 { font-size: 20px; } .shanswer h2 { font-size: 17px; } .shanswer h3 { font-size: 15px; }
.shanswer pre { background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; overflow-x: auto; font-size: 13px; }
.shanswer code { background: var(--bg); border-radius: 4px; padding: 1px 4px; font-size: 13px; }
.shanswer pre code { background: none; padding: 0; }
.shanswer hr { border: 0; border-top: 1px solid var(--border); margin: 10px 0; }
.shanswer table { width: auto; max-width: 100%; display: block; overflow-x: auto; }
.shanswer th { background: var(--bg); }
.shanswer a { color: var(--link); }

.shtitleform { display: flex; align-items: center; gap: 6px; flex: 1 1 auto; }
.shrules-builtin li { margin: 4px 0; }

/* Grid: the Owner Relations badge inside the Front Desk colour (W2) and the
   per-user default control (spec 5b). */
.gflag.gor { background: #fff; color: var(--navy, #14324f); border: 1px solid currentColor; font-weight: 700; }
.gdefault { margin: 2px 0 6px; }

/* Radar: the soonest-first list above the building groups (Sep 19 2026). */
.radarlist { margin: 10px 0 14px; }
.radarlist h3 { margin: 0 0 6px; }
.radarlist .tablewrap { overflow-x: auto; }
.radartable td, .radartable th { vertical-align: top; }
.radartable tr.today td:first-child { font-weight: 600; }
.radartable .cardwhen .whentimes { margin-left: 6px; color: var(--muted); }
