/* style.css — app styling on top of base.css — v2.6.4 */

/* v2.6.4: PlaceAutocompleteElement web component — match input styling */
gmp-place-autocomplete {
  display: block;
  width: 100%;
}
gmp-place-autocomplete::part(input) {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 12px;
  width: 100%;
  font: inherit;
}

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

.header {
  position: sticky; top: 0; z-index: 10;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}
.header-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px; gap: 16px; flex-wrap: wrap;
}
.brand { font-weight: 700; font-size: 18px; letter-spacing: -0.01em; color: var(--ink); }
.brand small { display: block; font-weight: 500; font-size: 12px; color: var(--ink-muted); letter-spacing: 0; }
.header-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

.region-tabs {
  display: flex; gap: 4px; padding: 0 20px 12px; overflow-x: auto;
}
.region-tab {
  padding: 6px 14px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-muted);
  font-size: 13px; font-weight: 500; white-space: nowrap;
  transition: all .15s;
}
.region-tab:hover { border-color: var(--line-strong); color: var(--ink); }
.region-tab.active {
  background: var(--primary); color: var(--primary-ink); border-color: var(--primary);
}

/* v2.9.9f: widen the main content area on large monitors so the calendar
   isn't squeezed into a narrow band. Capping at 1920px still keeps text
   readable on ultrawide screens while letting the grid breathe. */
.main { flex: 1; padding: 20px 24px; max-width: 1920px; margin: 0 auto; width: 100%; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px; border-radius: 8px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line);
  font-weight: 500; font-size: 14px;
  transition: all .15s;
}
.btn:hover { border-color: var(--line-strong); background: var(--surface-muted); }
.btn-primary { background: var(--primary); color: var(--primary-ink); border-color: var(--primary); }
.btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
.btn-ghost { border-color: transparent; }
.btn-ghost:hover { background: var(--surface-muted); }
.btn-danger { color: var(--danger); border-color: var(--danger-soft); }
.btn-danger:hover { background: var(--danger-soft); }
.btn-icon { padding: 8px; width: 36px; height: 36px; justify-content: center; }
.btn-sm { padding: 4px 10px; font-size: 13px; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* ---------- v2.6.4: View mode segmented control ---------- */
.view-mode-group {
  display: inline-flex; border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
}
.view-mode-btn {
  border-radius: 0; border: none; border-right: 1px solid var(--line);
  background: var(--surface); color: var(--ink-muted);
  font-size: 13px; padding: 6px 12px;
}
.view-mode-btn:last-child { border-right: none; }
.view-mode-btn:hover { background: var(--surface-muted); color: var(--ink); }
.view-mode-btn.active {
  background: var(--primary); color: var(--primary-ink);
}
.view-mode-btn:focus { outline: 2px solid var(--primary); outline-offset: -2px; }

/* ---------- v2.6.4: Toolbar label + select ---------- */
.toolbar-group {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 8px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface);
}
.toolbar-label { font-size: 12px; font-weight: 500; color: var(--ink-muted); white-space: nowrap; }
.toolbar-select {
  border: none; background: transparent; font-size: 13px; color: var(--ink);
  padding: 0; cursor: pointer; outline: none;
}
.toolbar-select:focus { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 4px; }

/* ---------- Sign in card ---------- */
.signin-screen {
  min-height: 100vh; display: grid; place-items: center;
  background: linear-gradient(135deg, #e0f2f4 0%, #f6f7f9 100%);
  padding: 20px;
}
.signin-card {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 40px;
  box-shadow: var(--shadow-lg);
  max-width: 420px; width: 100%;
  text-align: center;
}
.signin-card h1 { margin: 0 0 8px; font-size: 24px; letter-spacing: -0.01em; }
.signin-card p { color: var(--ink-muted); margin: 0 0 24px; }
.signin-card .btn-primary { width: 100%; justify-content: center; padding: 12px; font-size: 15px; }

/* ---------- Week grid (Feature B: resizable via CSS custom property) ---------- */
.week-bar {
  display: flex; align-items: center; gap: 12px; padding: 0 20px 14px;
}
.week-label { font-weight: 600; min-width: 200px; text-align: center; }

.grid-wrap {
  overflow-x: auto;
  /* v2.9.9: explicit overflow-y:visible so position:sticky inside .grid
     resolves against the viewport (not against this scroll container).
     Without this, browsers compute overflow-y as auto when overflow-x is
     auto, which traps sticky cells inside the wrapper and causes them to
     land below the page header (overlapping the first IHSC row). */
  overflow-y: visible;
  border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--surface);
}

/* Default non-resizable grid (fallback) */
.grid {
  display: grid;
  /* Mon-Sat: 6 day columns. IHSC name column capped at 110px. */
  grid-template-columns: 130px repeat(6, minmax(140px, 1fr)); /* z74: 110 to 130 name col */
  min-width: 900px;
}

/* Resizable grid: uses --grid-cols custom property set by JS */
.grid-resizable .grid-col-var {
  grid-template-columns: var(--grid-cols, 130px repeat(6, 140px)); /* z74 */
  min-width: 0;
}

.grid-cell {
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 6px;
  min-height: 92px;
  position: relative;
}
.grid-cell:last-child { border-right: 0; }
.day-head, .ihsc-head { font-weight: 600; background: var(--surface-muted); padding: 12px; }
.day-head { text-align: center; }
.day-head .dow { font-size: 12px; color: var(--ink-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.day-head .dom { font-size: 16px; }
.day-head.today .dom { color: var(--primary); }
/* v2.9.9z55c: Sunday orphan-rescue column. Only appears when a booking
   accidentally landed on Sunday (pre-z55c bug). Muted red styling so
   staff know this shouldn't be here and can click through to delete. */
.day-head.day-closed { background: repeating-linear-gradient(45deg, #fef2f2, #fef2f2 6px, #fee2e2 6px, #fee2e2 12px); color: #b91c1c; }
.day-head.day-closed .dow { color: #b91c1c; }
.day-head.day-closed .dom { color: #b91c1c; }

.ihsc-head {
  display: flex; align-items: center; gap: 8px;
  border-right: 1px solid var(--line);
  /* v2.9.9z74 (8/23 item 9): wrap at WORD boundaries only — word-break:
     break-word + overflow-wrap:anywhere was shattering names like
     "Andrew Campos" into one-letter-per-line columns. break-word stays as
     the last-resort fallback for a single unbroken token, and the 110px
     max-width cap is gone (the grid column controls width, min 130px). */
  white-space: normal;
  overflow-wrap: break-word;
  word-break: normal;
  font-size: 13px;
}
.color-dot { width: 12px; height: 12px; border-radius: 999px; flex-shrink: 0; }

/* ---------- Feature B: Column resizer handle ---------- */
.col-resizer {
  position: absolute; top: 0; bottom: 0; right: 0;
  /* z60b: 4px was a needle-thin target — 8px + touch-action:none so drags
     work with fingers/stylus on tablets and don't fight page scroll. */
  width: 8px; cursor: col-resize;
  touch-action: none;
  background: transparent;
  transition: background .15s;
  z-index: 2;
  border-radius: 0 4px 4px 0;
}
.col-resizer:hover,
.col-resizer.active {
  background: var(--primary);
  opacity: 0.5;
}

/* ---------- Booking tiles (v2.3 + v2.6.4) ---------- */
.slot-list { display: flex; flex-direction: column; gap: 4px; }

.tile {
  position: relative;
  display: grid;
  /* stripe | content */
  grid-template-columns: 6px 1fr;
  align-items: stretch;
  gap: 0;
  padding: 0;
  border-radius: 6px;
  background: var(--surface-muted);
  cursor: pointer;
  min-height: 36px;
  transition: background .12s, transform .08s, box-shadow .12s;
  overflow: hidden;
}
.tile:hover { background: var(--primary-soft); }
.tile-stripe {
  width: 4px; align-self: stretch;
  border-radius: 4px 0 0 4px;
  background: var(--ihsc-color, var(--line));
  margin-left: 2px;
  flex-shrink: 0;
}

/* tile-body: wraps all content rows after the stripe */
.tile-body {
  min-width: 0; overflow: hidden;
  display: flex; flex-direction: column;
}

/* tile-row: time on left (fixed width), city flex-grows and truncates */
.tile-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 6px 2px;
  min-width: 0;
  overflow: hidden;
}
.tile-time {
  font-size: 11px; font-weight: 700; color: var(--ink-muted);
  white-space: nowrap;
  flex-shrink: 0;
  min-width: 28px;
}
.tile-city {
  font-weight: 600; font-size: 12px;
  color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 1; min-width: 0;
}

/* v2.9.9f: '(confirmed)' chip on confirmed appointments.
   v2.9.9z9-5: moved out of the inline city row into the top-right corner,
   just LEFT of the sold-status "outcome bubble" so the two live side by
   side. Was previously inline next to the city and would get pushed off
   the visible tile on detailed mode when the city name/(no ZIP) chip took
   up the row. Absolute positioning guarantees it always shows. */
.tile-confirmed-chip {
  position: absolute;
  top: 3px;
  right: 22px; /* sits just left of the 16px sold-badge (right:2px + 16 + 4 gap) */
  z-index: 3;
  font-size: 10px;
  font-style: italic;
  font-weight: 500;
  color: #15803d; /* green-700 */
  background: rgba(255, 255, 255, 0.85);
  padding: 0 4px;
  border-radius: 4px;
  opacity: 0.95;
  letter-spacing: 0.01em;
  white-space: nowrap;
  pointer-events: none;
  line-height: 1.3;
}
/* Light-on-colored-tile readability: tinted background tiles keep the
   green text but use a soft green backdrop for contrast. */
.tile.has-type .tile-confirmed-chip {
  color: rgba(20, 83, 45, 0.95);
  background: rgba(220, 252, 231, 0.9);
}
/* If the outcome (CANCELLED / NO SHOW) rectangle badge is also present,
   it sits at right:4px and is wider than the sold bubble, so nudge the
   confirmed chip further left so all three fit without overlap. */
.tile.outcome-cancelled .tile-confirmed-chip,
.tile.outcome-noshow .tile-confirmed-chip {
  right: 96px;
}

/* Feature A: customer name row */
.tile-name {
  display: block;
  font-size: 11px; font-weight: 400; opacity: 0.85;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding: 0 6px 4px;
  /* inherits text color from tile — works on both light (dark text) and colored tiles */
}

/* Feature C: phone row in detailed mode */
.tile-phone {
  display: block;
  font-size: 11px; font-weight: 400; opacity: 0.75;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding: 0 6px 2px;
}

/* Feature C: appointment type label in detailed mode */
.tile-type-label {
  display: block;
  font-size: 10px; font-weight: 400; opacity: 0.75;
  text-transform: uppercase; letter-spacing: 0.3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding: 0 6px 4px;
}

/* v2.6.4: detailed mode extra rows */
/* v2.9.7: address line on tile is now a clickable Google Maps link. */
.tile-address-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: rgba(0,0,0,0.25);
  text-underline-offset: 2px;
}
.tile-address-link:hover { text-decoration-color: currentColor; }
/* v2.9.8: map-pin glyph nudged so it reads as part of the link. */
.tile-maps-icon {
  display: inline-block;
  margin-right: 1px;
  font-size: 10px;
  opacity: 0.85;
  text-decoration: none;
}
.tile-address-link:hover .tile-maps-icon { opacity: 1; }
.tile-prop-row { gap: 4px; align-items: center; flex-wrap: wrap; }
.tile-prop {
  font-size: 11px; color: var(--muted); white-space: nowrap;
}
.tile-address {
  display: block;
  font-size: 11px; font-weight: 400; opacity: 0.75;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding: 0 6px 2px;
}
.tile-meta {
  display: block;
  font-size: 10px; font-weight: 500; opacity: 0.8;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding: 0 6px 2px;
}
.tile-notes {
  display: block;
  font-size: 10px; font-weight: 400; opacity: 0.7;
  font-style: italic;
  white-space: normal; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  padding: 0 6px 4px;
  line-height: 1.3;
}

.tile.booked { background: #fff; box-shadow: inset 0 0 0 1px var(--line); }
.tile.booked:hover { box-shadow: inset 0 0 0 1px var(--line-strong); transform: translateY(-1px); }
.tile.booked.customer .tile-stripe {
  /* Customer source — color still comes from IHSC */
  background: var(--ihsc-color, var(--accent));
  box-shadow: 0 0 0 2px var(--accent-soft);
}
.tile.empty {
  background: transparent; border: 1px dashed var(--line);
  grid-template-columns: 1fr; /* no stripe on empty */
  padding: 0;
}
.tile.empty:hover { border-color: var(--primary); background: var(--primary-soft); }
.tile.empty .tile-row { padding: 5px 8px; }
.tile.empty .tile-empty-label { font-size: 12px; color: var(--ink-muted); }
.tile.empty .tile-time { color: var(--ink-muted); font-weight: 600; flex-shrink: 0; }

/* ---------- Time-off ---------- */
.timeoff-strip {
  position: absolute; inset: 0;
  background: repeating-linear-gradient(
    45deg, rgba(245, 158, 11, 0.10), rgba(245, 158, 11, 0.10) 8px,
    rgba(245, 158, 11, 0.22) 8px, rgba(245, 158, 11, 0.22) 16px);
  border-radius: 4px; margin: 4px;
  display: flex; align-items: center; justify-content: center;
  gap: 6px; flex-direction: column;
  font-size: 11px; color: #92400e; font-weight: 600;
  pointer-events: none;
}
.timeoff-badge {
  background: #92400e; color: #fff; padding: 2px 8px; border-radius: 999px;
  font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase;
}
.timeoff-reason { color: #78350f; font-weight: 500; font-size: 11px; }

/* v2.9.9z9-4 — partial-slot PTO. Renders in place of a single empty tile
   (not the whole day-cell), so other slots stay bookable. Uses the same
   diagonal-hatch amber pattern as .timeoff-strip so it reads as OFF at a
   glance, but keeps a tile-shaped rectangle so it sits neatly in the slot
   list. Non-interactive (no onclick), and pointer-events pass through the
   inner text so tooltips still surface the reason. */
.tile.timeoff-slot {
  background: repeating-linear-gradient(
    45deg, rgba(245, 158, 11, 0.10), rgba(245, 158, 11, 0.10) 8px,
    rgba(245, 158, 11, 0.22) 8px, rgba(245, 158, 11, 0.22) 16px);
  /* v2.9.9z9-5: mirror .tile.empty — this variant has no stripe child, so the
     default grid-template-columns:6px 1fr from .tile would push the OFF pill
     and reason text into the 6px stripe column (clipped to invisible).
     Collapse to a single column so the tile-row is actually visible. */
  grid-template-columns: 1fr;
  border: 1px solid rgba(146, 64, 14, 0.35);
  color: #92400e;
  cursor: not-allowed;
  padding: 0;
}
.tile.timeoff-slot .tile-row {
  align-items: center;
  gap: 6px;
  padding: 5px 8px;
  min-width: 0;
  overflow: hidden;
}
.tile.timeoff-slot .tile-time { color: #78350f; font-weight: 700; flex-shrink: 0; }
.tile.timeoff-slot .timeoff-reason {
  /* Truncate long reasons so they don't blow out the tile. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}
.timeoff-badge-slot {
  /* Smaller pill for the tile-inline variant. Same amber palette. */
  font-size: 9px; padding: 1px 6px;
  flex-shrink: 0;
}

/* ---------- Modal ---------- */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(15, 35, 45, 0.5);
  display: grid; place-items: center; z-index: 100; padding: 20px;
}
.modal {
  background: var(--surface); border-radius: var(--radius-lg);
  max-width: 600px; width: 100%; max-height: 90vh; overflow: auto;
  box-shadow: var(--shadow-lg);
}
.modal-wide { max-width: 760px; }
.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 22px; border-bottom: 1px solid var(--line);
}
.modal-header h2 { margin: 0; font-size: 18px; }
.modal-body { padding: 22px; }
.modal-footer {
  padding: 16px 22px; border-top: 1px solid var(--line);
  display: flex; justify-content: flex-end; gap: 8px;
  /* v2.9.9z71b: wrap instead of overflowing — super admins get an extra
     "Preview customer view" button in the booking modal, which pushed the
     leftmost button (Delete) out of view on desktop. Mobile footers
     already wrapped. */
  flex-wrap: wrap;
}

.tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--line); }
.tab {
  padding: 8px 14px; font-weight: 500; color: var(--ink-muted);
  border-bottom: 2px solid transparent; transition: all .15s;
}
.tab.active { color: var(--primary); border-bottom-color: var(--primary); }

.field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
.field label { font-size: 13px; font-weight: 500; color: var(--ink-muted); }
/* v2.9.9z51: exclude checkbox+radio from the width:100% rule. Otherwise
 * checkboxes inside flex-row consent labels stretch to fill the row and
 * push their sibling label text to a narrow strip on the right side
 * (visible on the SMS-consent row of the New Booking modal at 375px). */
.field input:not([type="checkbox"]):not([type="radio"]),
.field select, .field textarea { width: 100%; }

/* v2.9.9z51: staff-attested SMS/email consent row. Explicitly pin the
 * checkbox at a fixed size and let the label text take the rest so the
 * layout is stable across viewports. */
.field.consent-attest > label { display: flex; gap: 10px; align-items: flex-start; cursor: pointer; }
.field.consent-attest input[type="checkbox"] {
  flex: 0 0 auto;
  width: 20px; height: 20px;
  margin: 2px 0 0 0;
}
.field.consent-attest > label > span { flex: 1 1 auto; min-width: 0; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.field-row3 { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 12px; }

.row-item {
  display: flex; align-items: center; gap: 8px;
  padding: 10px; border: 1px solid var(--line); border-radius: 8px;
  margin-bottom: 8px;
}
.row-item input[type="text"] { flex: 1; }
.row-item input[type="color"] {
  width: 40px; height: 40px; padding: 2px; border-radius: 8px; cursor: pointer;
}

/* ---------- Time-off recurring controls ---------- */
.weekday-row { display: flex; flex-wrap: wrap; gap: 6px; }
.weekday-pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 6px 10px; border: 1px solid var(--line);
  border-radius: 999px; font-size: 13px; cursor: pointer;
  background: var(--surface);
}
.weekday-pill input[type="checkbox"] { width: auto; margin: 0; }
.weekday-pill:has(input:checked) {
  background: var(--primary-soft); border-color: var(--primary); color: var(--primary);
}
.skip-list { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.skip-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 8px 4px 10px;
  background: var(--accent-soft); color: #78350f;
  border-radius: 999px; font-size: 12px; font-weight: 500;
}

/* ---------- Audit log ---------- */
.audit-list { display: flex; flex-direction: column; gap: 8px; max-height: 60vh; overflow-y: auto; }
.audit-row {
  padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface);
}
.audit-row-meta {
  display: flex; justify-content: space-between; gap: 8px; font-size: 12px;
  margin-bottom: 4px;
}
.audit-action {
  padding: 2px 8px; border-radius: 999px; font-weight: 600; text-transform: uppercase;
  font-size: 10px; letter-spacing: 0.04em;
}
.audit-create { background: #ecfdf5; color: #047857; }
.audit-update { background: #eff6ff; color: #1d4ed8; }
.audit-delete { background: var(--danger-soft); color: var(--danger); }
.audit-when { color: var(--ink-muted); font-feature-settings: 'tnum'; }
.audit-row-summary { font-size: 13px; line-height: 1.45; word-break: break-word; }
.audit-row-who { font-size: 12px; margin-top: 2px; }

.history-heading {
  font-size: 13px; font-weight: 600; text-transform: uppercase;
  color: var(--ink-muted); margin: 18px 0 8px;
  letter-spacing: 0.04em; border-top: 1px solid var(--line); padding-top: 14px;
}
.history-host { max-height: 220px; overflow-y: auto; }

/* ---------- Toasts ---------- */
.toasts { position: fixed; bottom: 20px; right: 20px; z-index: 1000; display: flex; flex-direction: column; gap: 8px; }
.toast {
  background: var(--ink); color: white; padding: 12px 16px;
  border-radius: 10px; box-shadow: var(--shadow-md);
  font-size: 14px; max-width: 360px;
  animation: slide-in .2s ease-out;
}
.toast.error { background: var(--danger); }
.toast.success { background: var(--primary); }
@keyframes slide-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }

.muted { color: var(--ink-muted); }
.spacer { flex: 1; }
.hidden { display: none !important; }
.center { text-align: center; }
.error-text { color: var(--danger); font-size: 13px; }
.success-text { color: var(--primary); font-size: 13px; font-weight: 500; }

/* ---------- Booking page (book.html) ---------- */
.book-shell { min-height: 100vh; padding: 40px 20px; background: var(--bg); }
.book-card {
  max-width: 620px; margin: 0 auto;
  background: var(--surface); border-radius: var(--radius-lg);
  padding: 32px; box-shadow: var(--shadow-md);
}
.book-card h1 { margin: 0 0 4px; font-size: 26px; letter-spacing: -0.01em; }
.book-card .subtitle { color: var(--ink-muted); margin-bottom: 24px; }
.step { margin-bottom: 24px; }
.step h3 { margin: 0 0 8px; font-size: 15px; font-weight: 600; }

.zip-row { display: flex; gap: 8px; align-items: stretch; }
.zip-row input { flex: 1; padding: 12px 14px; font-size: 16px; letter-spacing: 0.05em; }
.zip-row .btn { white-space: nowrap; }

.day-list { display: flex; flex-direction: column; gap: 10px; }
.day-row {
  border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px;
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
  background: var(--surface);
}
.day-row-label { font-weight: 600; font-size: 14px; min-width: 160px; }
.day-row-times { display: flex; flex-wrap: wrap; gap: 6px; }
.time-btn { padding: 6px 12px; font-size: 13px; }

.option-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 8px; }
.option-btn {
  padding: 10px 14px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface); text-align: left; font-weight: 500;
  transition: all .15s;
}
.option-btn:hover { border-color: var(--primary); }
.option-btn.selected { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }
.success-banner {
  background: var(--primary-soft); border: 1px solid var(--primary);
  color: var(--primary); padding: 16px; border-radius: 10px;
  text-align: center; font-weight: 600; margin-bottom: 16px;
}

/* ---------- v2.6.4: Day view ---------- */
.day-view-wrap { }
.day-grid { grid-template-columns: var(--grid-cols, 110px 1fr) !important; }
.day-view-cell { min-height: 120px; }

/* ---------- v2.6.4: Month view ---------- */
.month-wrap {
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  background: var(--surface);
}
.month-header-row {
  display: grid; grid-template-columns: repeat(7, 1fr);
  background: var(--surface-muted);
  border-bottom: 1px solid var(--line);
}
.month-dow-head {
  padding: 8px; text-align: center;
  font-size: 12px; font-weight: 600; color: var(--ink-muted);
  text-transform: uppercase; letter-spacing: 0.04em;
  border-right: 1px solid var(--line);
}
.month-dow-head:last-child { border-right: none; }
.month-week-row {
  display: grid; grid-template-columns: repeat(7, 1fr);
  border-bottom: 1px solid var(--line);
  min-height: 100px;
}
.month-week-row:last-child { border-bottom: none; }
.month-day-cell {
  border-right: 1px solid var(--line); padding: 6px;
  position: relative; min-height: 100px; overflow: hidden;
}
.month-day-cell:last-child { border-right: none; }
.month-day-out { background: var(--surface-muted); opacity: 0.65; }
.month-day-sun { background: #f9fafb; }
.month-day-today { background: #eff6ff; }
.month-day-num {
  font-size: 13px; font-weight: 600; color: var(--ink-muted);
  margin-bottom: 4px; line-height: 1;
}
.month-day-num.today {
  background: var(--primary); color: var(--primary-ink);
  width: 22px; height: 22px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px;
}
.month-mini-tile {
  display: flex; align-items: center; gap: 4px;
  padding: 2px 4px; margin-bottom: 2px;
  border-radius: 4px; background: var(--surface-muted);
  cursor: pointer; overflow: hidden;
  transition: background .12s;
  font-size: 11px;
  min-width: 0;
}
.month-mini-tile:hover { background: var(--primary-soft); }
.month-mini-bar {
  display: inline-block; width: 3px; height: 14px; border-radius: 2px;
  background: var(--mini-bar, #94a3b8); flex-shrink: 0;
}
.month-mini-time {
  font-weight: 700; font-size: 10px; color: var(--ink-muted);
  white-space: nowrap; flex-shrink: 0;
}
.month-mini-city {
  font-size: 11px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 1; min-width: 0;
}
.month-more-btn {
  display: block; width: 100%;
  font-size: 11px; color: var(--primary); font-weight: 500;
  padding: 2px 4px; text-align: left; background: none; border: none;
  cursor: pointer; border-radius: 4px;
}
.month-more-btn:hover { background: var(--primary-soft); }

/* ---------- Mobile ---------- */
/* v2.9.9i: scope the hide-non-active-day rule to .week-grid only. The
 * previous selector matched every grid cell, including the single-column
 * day view, which left the day grid completely blank. Day view now gets
 * its own 90px-IHSC + 1fr layout and stays fully visible. The .grid-wrap
 * gets touch-friendly scrolling restored so IHSCs can swipe through their
 * column on a phone. */
@media (max-width: 720px) {
  .header-row { padding: 12px 14px; }
  .brand { font-size: 16px; }
  .main { padding: 12px; }
  .ihsc-head { max-width: 90px; }

  /* WEEK view (mobile) — v2.9.9z77a: full Normal/Detailed tiles, exactly
   * like desktop, scrolled HORIZONTALLY to reach the other days (Justin:
   * "they can scroll horizontally to get to other days"). The z76a chip
   * compression is gone; the ⊖ button (below) is how phones reclaim
   * vertical space. The old one-day pager stays retired. */
  .week-grid { min-width: 900px; }
  body.view-week .mobile-day-pager { display: none !important; }

  /* DAY view: a real two-column layout (IHSC label + single day column).
   * No "active-day" filtering — every IHSC row must be visible. Use
   * !important to beat the inline --grid-cols set by JS. */
  .day-grid { grid-template-columns: 90px minmax(220px, 1fr) !important; min-width: 0; }

  /* Allow the calendar to be scrolled vertically on a phone (IHSCs may have
   * many rows and tiles stack vertically inside the day cell). The grid-wrap
   * was previously letting the page scroll, but on iOS the inner grid was
   * absorbing touch — force vertical scrolling here. */
  .grid-wrap { -webkit-overflow-scrolling: touch; overscroll-behavior: contain; max-height: none; }

  .mobile-day-pager { display: flex; gap: 8px; padding: 0 12px 12px; }
  .field-row, .field-row3 { grid-template-columns: 1fr; }
  .modal { max-height: 100vh; border-radius: 0; }
  .day-row-label { min-width: 0; flex-basis: 100%; }
  .month-mini-time { display: none; }
  .month-day-cell { min-height: 64px; }
}
@media (min-width: 721px) { .mobile-day-pager { display: none; } }

/* ---------- v2.3: Appointment Type Legend ---------- */
#typeLegend:empty { display: none; }
.type-legend {
  display: flex; flex-wrap: wrap; gap: 10px 14px;
  padding: 8px 12px; margin-bottom: 12px;
  background: var(--surface-muted);
  border: 1px solid var(--line);
  border-radius: 8px;
  font-size: 12px;
}
.type-legend-item {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--ink); white-space: nowrap;
}
.type-legend-swatch {
  display: inline-block; width: 14px; height: 14px;
  border-radius: 4px; border: 1px solid rgba(15, 23, 42, 0.18);
  flex-shrink: 0;
}
.type-legend-name { font-weight: 500; }

/* v2.9.4: divider between Appointment Type legend and Outcome legend */
.type-legend-divider {
  display: inline-block;
  width: 1px;
  align-self: stretch;
  background: var(--line);
  margin: 0 4px;
  flex-shrink: 0;
}
.type-legend-section-label {
  font-weight: 600;
  color: var(--muted, #64748b);
  text-transform: uppercase;
  font-size: 10px;
  letter-spacing: 0.04em;
  align-self: center;
  margin-right: 2px;
}
/* Outcome badge used inline in the legend (override the tile-corner positioning) */
.tile-sold-badge.legend-badge {
  position: static;
  width: 14px;
  height: 14px;
  font-size: 10px;
  box-shadow: none;
  flex-shrink: 0;
}

/* ---------- v2.3: Alert banner (customer-initiated changes) ---------- */
#alertBanner:empty { display: none; }
.alert-banner {
  display: flex; align-items: center; gap: 10px;
  background: #fef3c7; color: #92400e;
  border: 1px solid #fde68a; border-radius: 8px;
  padding: 10px 14px; margin-bottom: 12px;
  font-size: 14px; font-weight: 500;
}
.alert-banner .alert-icon { font-size: 18px; line-height: 1; }
.alert-banner .alert-text { flex: 1; }
.alert-banner .btn-primary { background: #92400e; color: #fff; border-color: #92400e; }
.alert-banner .btn-primary:hover { background: #78350f; border-color: #78350f; }

.change-list { display: flex; flex-direction: column; gap: 8px; }
.change-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface);
}
.change-row-text { flex: 1; min-width: 0; }
.change-row-summary { font-weight: 500; color: var(--ink); font-size: 14px; }
.change-row-meta { font-size: 12px; margin-top: 2px; }

/* ---------- v2.3: Tile coloring when an appointment type is assigned ---------- */
.tile.has-type {
  background: var(--type-color, #fff);
  color: var(--type-text, #0f172a);
}
.tile.has-type .tile-city,
.tile.has-type .tile-time,
.tile.has-type .tile-name,
.tile.has-type .tile-phone,
.tile.has-type .tile-address,
.tile.has-type .tile-meta,
.tile.has-type .tile-notes,
.tile.has-type .tile-type-label {
  color: var(--type-text, #0f172a);
}
.tile.has-type:hover {
  filter: brightness(0.96);
  background: var(--type-color, #fff);
}
.tile.has-type .tile-stripe {
  background: var(--ihsc-color, var(--line));
  opacity: 0.6;
}

/* ---------- v2.7: Modal compact layout + Out-of-area badge + Managers + Optimizer ---------- */
.modal-body.modal-compact .field { margin-bottom: 8px; }
.modal-body.modal-compact .field label {
  font-size: 12px; font-weight: 600; color: var(--muted);
  margin-bottom: 3px; display: block; letter-spacing: 0.01em;
}
.modal-body.modal-compact .field input[type="text"],
.modal-body.modal-compact .field input[type="email"],
.modal-body.modal-compact .field input[type="tel"],
.modal-body.modal-compact .field select,
.modal-body.modal-compact .field textarea {
  font-size: 13px;
  padding: 6px 9px;
  min-height: 32px;
}
.modal-body.modal-compact textarea.textarea-tall {
  font-size: 12.5px;
  line-height: 1.45;
  /* v2.9.9z39: staff put a lot into Notes; give it real breathing room so
     they don't have to scroll a tiny window to see recent entries. */
  min-height: 240px;
  resize: vertical;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.modal-body.modal-compact .field-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  margin-bottom: 8px;
}
.modal-body.modal-compact .field-row .field { margin-bottom: 0; }
.modal-body.modal-compact .field-row3 {
  display: grid; grid-template-columns: 2fr 0.7fr 1fr; gap: 10px;
  margin-bottom: 8px;
}
.modal-body.modal-compact .field-row3 .field { margin-bottom: 0; }
.modal-body.modal-compact .history-heading { font-size: 14px; margin: 16px 0 6px; }
.modal-body.modal-compact .modal-meta { margin-bottom: 10px; }

.badge-ooa {
  display: inline-block; margin-left: 10px;
  padding: 2px 8px; border-radius: 999px;
  background: #fee2e2; color: #991b1b;
  font-size: 11px; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid #fecaca;
  vertical-align: middle;
}

/* Mobile fallback */
@media (max-width: 560px) {
  .modal-body.modal-compact .field-row,
  .modal-body.modal-compact .field-row3 { grid-template-columns: 1fr; }
}

/* ---------- Region Managers tab ---------- */
.mgr-region-block {
  border: 1px solid var(--line); border-radius: 10px;
  margin-bottom: 14px; overflow: hidden;
  background: var(--surface);
}
.mgr-region-header {
  padding: 10px 14px;
  background: var(--surface-2, #f8fafc);
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between;
  font-weight: 600;
}
.mgr-list { padding: 8px 12px; }
.mgr-row {
  display: grid; grid-template-columns: 0.9fr 1.3fr 150px 95px 130px; gap: 8px;
  align-items: center;
  padding: 6px 0;
  border-bottom: 1px dashed var(--line);
}
.mgr-row:last-child { border-bottom: none; }
.mgr-row input, .mgr-row select { font-size: 13px; padding: 5px 8px; min-height: 30px; }
.mgr-row .mgr-status {
  font-size: 11px; padding: 2px 8px; border-radius: 999px;
  text-align: center; font-weight: 600;
}
.mgr-status.active { background: #dcfce7; color: #166534; }
.mgr-status.inactive { background: #f1f5f9; color: #64748b; }
.mgr-empty { padding: 8px 0; font-size: 13px; color: var(--muted); }
.mgr-add-row {
  display: grid; grid-template-columns: 0.9fr 1.3fr 150px 95px; gap: 8px;
  padding: 8px 0 4px;
  border-top: 1px solid var(--line);
  margin-top: 6px;
}
.mgr-add-row input, .mgr-add-row select { font-size: 13px; padding: 5px 8px; min-height: 30px; }

/* ---------- Routing Optimizer ---------- */
.opt-controls { display: flex; gap: 10px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; }
.opt-controls .field { margin-bottom: 0; }
.opt-controls label { font-size: 12px; font-weight: 600; color: var(--muted); display: block; margin-bottom: 3px; }
.opt-controls input { font-size: 13px; padding: 5px 8px; min-height: 30px; }
.opt-empty { padding: 16px; text-align: center; color: var(--muted); font-size: 14px; border: 1px dashed var(--line); border-radius: 8px; }
.opt-suggestion {
  border: 1px solid var(--line); border-radius: 10px;
  padding: 12px 14px; margin-bottom: 10px;
  background: var(--surface);
}
.opt-suggestion-header {
  font-weight: 600; font-size: 14px; color: var(--ink);
  margin-bottom: 8px;
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
}
.opt-savings { color: #166534; font-size: 13px; font-weight: 600; white-space: nowrap; }
.opt-swap-row {
  font-size: 13px; color: var(--ink-2, #334155); line-height: 1.5;
}
.opt-swap-row .opt-arrow {
  color: var(--muted); font-weight: 600; text-align: center; margin: 6px 0;
}
/* v2.9.7: address line inside a swap suggestion. */
.opt-swap-row .opt-addr {
  font-size: 12px; color: var(--muted); margin-left: 0;
  padding: 2px 0 6px 14px; border-left: 2px solid var(--line); margin-bottom: 2px;
}
.opt-miles-detail {
  margin-top: 8px; font-size: 12px; color: var(--ink-2, #334155);
  background: var(--surface-2, #f8fafc); border-radius: 6px; padding: 6px 10px;
}
.opt-miles-detail summary { cursor: pointer; font-weight: 600; color: var(--muted); }
.opt-miles-list { margin: 6px 0 4px 18px; padding: 0; }
.opt-miles-list li { margin: 2px 0; line-height: 1.45; }
.opt-actions { margin-top: 10px; display: flex; gap: 8px; justify-content: flex-end; }

/* ---------- v2.9: Settings panes (App Settings + Property Data) ---------- */
.settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 14px;
  margin-top: 12px;
}
.settings-card {
  background: #fff;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 10px;
  padding: 14px 14px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.settings-card > label,
.settings-card > .field-label {
  font-weight: 600;
  font-size: 13px;
  color: var(--ink, #0f172a);
}
.settings-card .hint {
  font-size: 12px;
  color: var(--muted, #64748b);
  line-height: 1.45;
  margin-top: 2px;
}
.settings-card input,
.settings-card select,
.settings-card textarea {
  margin-top: 6px;
}
.settings-card .row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 6px;
}

/* ---------- v2.9: Users & Roles ---------- */
.users-table {
  margin-top: 12px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 10px;
  overflow: hidden;
  background: #fff;
}
.users-row {
  display: grid;
  /* v2.9.9z52: reverted to the pre-z51 6-column layout after removing the
     Alerts + Last-login columns. Order: Email | Name | Role | Regions |
     Status | Actions */
  grid-template-columns: 1.6fr 1.3fr 1fr 1.7fr 0.5fr 0.7fr;
  gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border, #e2e8f0);
  align-items: center;
}
.users-row:last-child { border-bottom: none; }
/* v2.9.6: extra leading column for the bulk-select checkbox */
.users-row--with-pick {
  grid-template-columns: 36px 1.6fr 1.3fr 1fr 1.7fr 0.5fr 0.9fr;
}
.users-row--with-pick input[type="checkbox"].user-pick {
  width: auto;
  margin: 0;
}
.users-toolbar {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin: 0 0 12px;
  padding: 10px 12px;
  background: #f8fafc;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 10px;
}
.users-head {
  background: #f8fafc;
  font-weight: 600;
  font-size: 12px;
  color: var(--muted, #64748b);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.users-row input[type="text"],
.users-row input[type="email"],
.users-row select {
  width: 100%;
  font-size: 13px;
  padding: 6px 8px;
}
.users-row .user-email { font-weight: 600; color: var(--ink, #0f172a); font-size: 13px; word-break: break-all; }
.users-row .user-actions { display: flex; gap: 6px; justify-content: flex-end; }
.users-row.self {
  background: #fffbeb;
}

.users-region-checks {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
}
.users-region-check {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--ink-2, #334155);
  background: #f1f5f9;
  padding: 2px 8px;
  border-radius: 999px;
  cursor: pointer;
}
.users-region-check input { margin: 0; }

.users-addcard {
  margin-top: 14px;
  background: #f8fafc;
  border: 1px dashed var(--border, #cbd5e1);
  border-radius: 10px;
  padding: 14px;
}
.users-addcard h4 {
  margin: 0 0 8px;
  font-size: 13px;
  color: var(--ink, #0f172a);
}
.users-addgrid {
  display: grid;
  grid-template-columns: 1.6fr 1.3fr 1fr;
  gap: 10px;
  margin-bottom: 10px;
}

/* ---------- v2.9: Square-footage + dual-slot badges ---------- */
.tile-sqft {
  font-size: 11px;
  color: var(--ink-2, #334155);
  background: rgba(15,23,42,0.06);
  padding: 1px 6px;
  border-radius: 6px;
  display: inline-block;
  margin-top: 2px;
}
.tile-ext {
  font-size: 10px;
  font-weight: 700;
  color: #1e3a8a;
  background: #dbeafe;
  padding: 1px 6px;
  border-radius: 6px;
  display: inline-block;
  margin-left: 4px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.detail-sqft-banner {
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 13px;
  color: #1e3a8a;
  margin: 8px 0;
}
.detail-sqft-banner strong { font-weight: 700; }

/* ---------- v2.9: Mobile responsive for new panes ---------- */
@media (max-width: 720px) {
  .users-row {
    grid-template-columns: 1fr 1fr;
    grid-auto-rows: auto;
  }
  .users-row .user-email { grid-column: 1 / -1; }
  .users-row .user-regions { grid-column: 1 / -1; }
  .users-row .user-actions { grid-column: 1 / -1; justify-content: flex-start; }
  .users-addgrid { grid-template-columns: 1fr; }
}

/* ============================================================
   v2.9.2 — bigger settings modal + denser body type
   ============================================================ */
/* Bigger Settings modal — readability fix. */
.modal-wide {
  max-width: min(1100px, 95vw);
  width: 95vw;
  max-height: 92vh;
}
.modal-wide .modal-body {
  font-size: 13px;
  line-height: 1.45;
}
.modal-wide .modal-body label {
  font-size: 12px;
}
.modal-wide .modal-body .tab {
  font-size: 13px;
  padding: 7px 12px;
}
.modal-wide .modal-body h3 {
  font-size: 14px;
  margin: 14px 0 6px;
}
.modal-wide .modal-body table {
  font-size: 12.5px;
}
.modal-wide .modal-body input[type="text"],
.modal-wide .modal-body input[type="email"],
.modal-wide .modal-body input[type="number"],
.modal-wide .modal-body input[type="tel"],
.modal-wide .modal-body select,
.modal-wide .modal-body textarea {
  font-size: 13px;
  padding: 6px 9px;
}

/* ============================================================
   v2.9.2 — merged Regions + IHSCs editor (left/right split)
   ============================================================ */
.r-ihsc-shell {
  display: grid;
  grid-template-columns: minmax(260px, 360px) 1fr;
  gap: 18px;
  align-items: start;
}
.r-ihsc-left,
.r-ihsc-right {
  background: var(--surface-muted, #f6f8fa);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px 12px 14px;
  min-height: 220px;
}
.r-ihsc-section-title {
  font-weight: 600;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  margin-bottom: 8px;
}
.r-ihsc-region-list,
.r-ihsc-ihsc-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 10px;
}
.r-ihsc-region {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 7px 10px;
  border-radius: 6px;
  background: var(--surface);
  border: 1px solid transparent;
  cursor: pointer;
  font-size: 13px;
}
.r-ihsc-region:hover { background: var(--primary-soft, #e8f3f6); }
.r-ihsc-region.active {
  background: var(--primary-soft, #e8f3f6);
  border-color: var(--primary, #0ea5a4);
  font-weight: 600;
}
.r-ihsc-region-name { flex: 1; }
.r-ihsc-region-actions {
  display: inline-flex;
  gap: 4px;
}
.r-ihsc-region-actions .btn {
  padding: 3px 7px;
  font-size: 11px;
}
.r-ihsc-add-region,
.r-ihsc-add-ihsc {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 8px;
  border-top: 1px dashed var(--line);
  padding-top: 10px;
}
.r-ihsc-add-region input,
.r-ihsc-add-ihsc input {
  flex: 1;
  font-size: 13px;
  padding: 5px 8px;
}
.r-ihsc-ihsc {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: var(--surface);
  border-radius: 6px;
  font-size: 13px;
}
.r-ihsc-swatch {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  border: 1px solid rgba(0,0,0,0.1);
  flex-shrink: 0;
}
.r-ihsc-readonly {
  font-size: 12px;
  font-style: italic;
  margin-top: 8px;
}
@media (max-width: 720px) {
  .r-ihsc-shell { grid-template-columns: 1fr; }
}

/* ============================================================
   v2.9.3 — post-appointment outcome badge on tiles
   ============================================================ */
.tile-sold-badge {
  position: absolute;
  top: 2px;
  right: 2px;
  z-index: 3;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  pointer-events: none;
  box-shadow: 0 0 0 1.5px var(--surface, #fff);
  font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
}
.tile-sold-badge.sb-onsite { background: #16a34a; color: #fff; }   /* green $ */
.tile-sold-badge.sb-later  { background: #16a34a; color: #fff; }   /* green ✓ */
.tile-sold-badge.sb-not    { background: #dc2626; color: #fff; }   /* red ✕ */
.tile-sold-badge.sb-unknown {
  /* v2.9.4: empty grey circle (no glyph) for bookings without an outcome */
  background: #d1d5db;
  color: transparent;
  border: 1px solid #9ca3af;
  box-shadow: 0 0 0 1.5px var(--surface, #fff);
}

/* v2.9.4: Refresh button spin animation */
@keyframes sg-refresh-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
#refreshBtn.is-refreshing {
  animation: sg-refresh-spin 0.8s linear infinite;
}
#refreshBtn {
  font-size: 16px;
  line-height: 1;
}

/* ------- v2.9.8: per-user email alerts editor ------- */
.btn-xs {
  font-size: 11px; padding: 3px 8px; border-radius: 4px;
}
.users-row-block {
  border-bottom: 1px solid var(--line, #e5e7eb);
}
.users-row-block:last-child { border-bottom: none; }
.users-row-block .users-row { border-bottom: none; }
.user-alerts-host {
  background: #fafbfc;
  padding: 12px 16px 14px;
  border-top: 1px dashed var(--line, #e5e7eb);
}
.user-alerts-editor {
  max-width: 760px;
}
.user-alerts-header {
  font-size: 13px;
  margin-bottom: 4px;
}
.user-alerts-header code {
  font-size: 12px;
  background: #eef2f7;
  padding: 1px 6px;
  border-radius: 4px;
}
.user-alerts-regions {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin-top: 6px;
}
@media (min-width: 720px) {
  .user-alerts-regions { grid-template-columns: 1fr 1fr; }
}
.user-alerts-region-block {
  background: #fff;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 6px;
  padding: 10px 12px;
}
.user-alerts-region-name {
  font-weight: 600;
  font-size: 13px;
  margin-bottom: 6px;
}
.user-alerts-region-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.user-alerts-region-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 6px;
  align-items: center;
}
.user-alerts-region-row select {
  min-width: 0;
}
.user-alerts-region-add {
  margin-top: 4px;
  border-top: 1px dashed var(--line, #e5e7eb);
  padding-top: 8px;
  grid-template-columns: 1fr auto;
}

/* ============================================================
   v2.9.9 additions
   - Sticky date-header row when scrolling many IHSCs
   - Directions chip (replaces 📍 emoji that didn't render)
   - Colored bullet in typed selects
   - Version badge in header
   - Property diagnostic banner
   ============================================================ */

/* v2.9.9 sticky calendar date strip.
   The date row is now rendered into a SEPARATE element (.date-strip-wrap)
   that sits above .grid-wrap and is NOT inside any scroll container. That
   way position:sticky resolves against the viewport so the strip parks
   directly below the page header (which is also sticky at top:0 and
   publishes its actual height into --header-h via JS).

   The strip itself has overflow hidden so it doesn't show a horizontal
   scrollbar. Its inner .date-strip is translated horizontally in JS to
   mirror .grid-wrap's scrollLeft. */
.date-strip-wrap {
  position: sticky;
  top: var(--header-h, 60px);
  z-index: 5;
  overflow: hidden;
  background: var(--surface-muted);
  border: 1px solid var(--line);
  border-bottom: none;
  border-radius: var(--radius) var(--radius) 0 0;
  /* Subtle shadow to make the parked strip visually distinct from page header */
  box-shadow: 0 1px 0 var(--line);
}
.date-strip {
  /* grid-template-columns is set by applyGridCols(); we just need the same
     base styling as .grid so cells look identical */
  will-change: transform;
}
/* When the strip is present, the grid-wrap below it should have no top border
   to avoid a double line. */
.date-strip-wrap + .grid-wrap {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

/* v2.9.9f: sticky horizontal scrollbar that follows the viewport bottom.
   The real .grid-wrap scrollbar only appears at the bottom of the calendar
   — useless on tall calendars where users need to scroll right mid-page.
   This is a position:fixed proxy whose inner spacer matches the grid width;
   scrolling it programmatically drives .grid-wrap's scrollLeft. */
.sticky-hscroll {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 14px;
  overflow-x: auto;
  overflow-y: hidden;
  background: rgba(248, 250, 252, 0.92);
  border-top: 1px solid var(--line);
  z-index: 20;
  /* Hidden by default; JS toggles 'visible' class when grid actually overflows */
  display: none;
  /* Match the viewport-fit-cover safe area on iOS so the bar doesn't fall
     into the home-indicator gutter. */
  padding-bottom: env(safe-area-inset-bottom, 0);
}
.sticky-hscroll.visible { display: block; }
.sticky-hscroll-inner { height: 1px; }
/* When the grid is short enough that its bottom is on-screen, also hide
   the proxy bar to avoid two scrollbars at the same time. */
.sticky-hscroll.at-bottom { display: none; }

/* Address row with visible Directions chip (no emoji dependency) */
.tile-address-with-dir {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  padding: 0 6px 2px;
}
.tile-address-with-dir .tile-address-link {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tile-dir-btn {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  flex-shrink: 0;
  padding: 1px 8px;
  font-size: 10px;
  font-weight: 600;
  line-height: 1.5;
  border-radius: 999px;
  border: 1px solid currentColor;
  background: rgba(255,255,255,0.55);
  color: inherit;
  text-decoration: none;
  opacity: 0.85;
  transition: opacity .15s, background .15s;
}
.tile-dir-btn:hover {
  opacity: 1;
  background: rgba(255,255,255,0.85);
  text-decoration: none;
}

/* Colored bullet in appointment-type dropdowns */
.typed-select option {
  font-family: inherit;
  font-size: inherit;
}

/* Version badge next to brand */
.app-version-badge {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--surface-muted, #f4f4f5);
  color: var(--ink-muted, #6b7280);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.02em;
  vertical-align: middle;
}

/* Property diagnostic banner */
.diag-box { font-size: 13px; }
.diag-banner {
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid;
  margin-bottom: 10px;
  font-weight: 500;
  line-height: 1.4;
}
.diag-banner.diag-warn {
  background: #fef3c7;
  border-color: #f59e0b;
  color: #92400e;
}
.diag-banner.diag-ok {
  background: #d1fae5;
  border-color: #10b981;
  color: #065f46;
}
.diag-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 4px 14px;
  background: var(--surface-muted, #f9fafb);
  padding: 10px 12px;
  border-radius: 6px;
  border: 1px solid var(--line, #e5e7eb);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
}
.diag-k { color: var(--ink-muted, #6b7280); }
.diag-v { color: var(--ink, #111827); font-weight: 600; }

/* ============================================================
   v2.9.9 mobile pass
   - Prevent iOS zoom on input focus (16px min font)
   - Larger tap targets
   - Modal goes full-screen on phones
   - Header denser; region tabs horizontally scrollable
   - Sticky date row is disabled on phones (1 day visible at a time)
   - Settings grids and diag grid stack
   - No-horizontal-scroll on the body
   ============================================================ */

/* Prevent the whole page from scrolling sideways. Calendar grid has its
   own horizontal scroll via .grid-wrap.
   v2.9.9: use overflow-x:clip (not :hidden) so html/body do NOT become a
   scroll container — otherwise position:sticky on the date strip resolves
   against body's scroll context and the strip never actually sticks (it
   just scrolls off-screen with the page). overflow-x:clip clips overflow
   without creating a scroll container, which is exactly what we want. */
html, body { max-width: 100%; overflow-x: clip; }
body { -webkit-text-size-adjust: 100%; }

/* iOS auto-zooms on inputs <16px. Force 16px on all form controls. */
@media (max-width: 720px) {
  input:not([type="checkbox"]):not([type="radio"]),
  select, textarea,
  .field input:not([type="checkbox"]):not([type="radio"]),
  .field select, .field textarea {
    font-size: 16px;
  }
  /* Bigger, easier-to-tap buttons on phones */
  .btn { padding: 10px 14px; min-height: 40px; }
  .btn-sm { padding: 6px 12px; min-height: 32px; font-size: 13px; }
  .btn-icon { width: 40px; height: 40px; padding: 8px; }

  /* Header layout: stack the rows so the toolbar doesn't overflow */
  .header-row {
    padding: 10px 12px; gap: 8px;
    align-items: flex-start;
  }
  .brand { font-size: 15px; line-height: 1.2; }
  .brand small { display: none; }            /* hide subtitle / userBadge to save space */
  /* Keep version badge inline & visible so we can confirm deploys on phone */
  .brand small.app-version-badge { display: inline-block; font-size: 9px; padding: 1px 6px; vertical-align: middle; margin-left: 4px; }
  .header-actions {
    gap: 6px;
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    flex-wrap: nowrap;          /* let row scroll horizontally instead */
    padding-bottom: 2px;
  }
  .header-actions::-webkit-scrollbar { height: 4px; }
  .header-actions > * { flex-shrink: 0; }

  /* Region tabs already overflow-x:auto — make scrollbar invisible-but-functional */
  .region-tabs {
    padding: 0 12px 10px;
    -webkit-overflow-scrolling: touch;
  }
  .region-tabs::-webkit-scrollbar { height: 4px; }

  /* Main padding tighter */
  .main { padding: 12px 10px; }

  /* Sticky date row would only have ONE visible column on mobile (the active
     day). Sticky is unnecessary noise — disable to avoid overlap with header. */
  .date-strip-wrap {
    position: static;
  }

  /* Modal: truly full-screen on phones */
  .modal-backdrop { padding: 0; }
  .modal {
    max-width: 100%; width: 100%;
    height: 100vh; height: 100dvh;
    max-height: 100vh; max-height: 100dvh;
    border-radius: 0;
  }
  .modal-header { padding: 14px 16px; position: sticky; top: 0; background: var(--surface); z-index: 1; }
  .modal-body   { padding: 16px; }
  .modal-footer {
    padding: 12px 16px;
    position: sticky; bottom: 0; background: var(--surface); z-index: 1;
    flex-wrap: wrap;
  }
  .modal-footer .btn { flex: 1 1 auto; justify-content: center; }
  .modal-footer .btn-danger { flex-basis: 100%; order: 99; }
  .modal-footer .spacer { display: none; }

  /* Settings grid stacks */
  .settings-grid { display: block !important; }
  .settings-card { margin-bottom: 12px; }

  /* Diag grid stays as 2-col label/value but tighter */
  .diag-grid { padding: 8px 10px; font-size: 11px; }

  /* Detail sqft banner can get long — let it wrap */
  .detail-sqft-banner { white-space: normal; line-height: 1.45; }

  /* Field rows already stack via 720 breakpoint; keep the override explicit */
  .field-row, .field-row3 { display: block; }
  .field-row > .field, .field-row3 > .field { margin-bottom: 12px; }

  /* Toast position adjusted so it doesn't overlap mobile keyboard */
  .toasts { left: 10px; right: 10px; bottom: 12px; }
  .toast { max-width: none; }
}

/* Extra-narrow phones (<=380px) */
@media (max-width: 380px) {
  .header-row { padding: 8px 10px; }
  .brand { font-size: 14px; }
  .btn { padding: 8px 10px; font-size: 13px; }
  .region-tab { padding: 5px 10px; font-size: 12px; }
}

/* ============================================================
   v2.9.9 (b) — sales rep, clickable phone, mobile tile pass
   ============================================================ */

/* Customer name + sales rep on one row in the detailed tile */
.tile-name-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  padding: 0 6px 4px;
  font-size: 11px;
  line-height: 1.3;
  min-width: 0;
}
.tile-name-row .tile-name {
  padding: 0;
  font-weight: 500;
  opacity: 1;
  flex: 1 1 auto;
  min-width: 0;
}
.tile-rep {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  opacity: 0.8;
  padding: 1px 6px;
  border-radius: 999px;
  background: rgba(0,0,0,0.06);
  white-space: nowrap;
  flex: 0 0 auto;
}

/* v2.9.9t: product-type initials — small inline letters that sit to the
   right of the customer name in the detailed tile. Each letter is its own
   pill so the hover tooltip per-letter still works. */
.tile-product-initials {
  display: inline-flex;
  gap: 3px;
  align-items: center;
  flex: 0 0 auto;
  line-height: 1;
}
.tile-product-initial {
  display: inline-block;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 5px;
  border-radius: 4px;
  background: rgba(0, 122, 138, 0.12);
  color: #00606e;
  text-transform: uppercase;
  line-height: 1.1;
  white-space: nowrap;
}
.tile.has-type .tile-product-initial {
  /* Use the appt-type contrast colors so initials remain readable when
     the tile background is dark (e.g. red "Service" type). */
  background: rgba(255,255,255,0.22);
  color: var(--type-text, inherit);
}

/* Clickable phone — sms: link (text customer) + tiny call icon */
.tile-phone {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  padding: 0 6px 2px;
}
.tile-phone-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-color: currentColor;
  text-underline-offset: 2px;
  cursor: pointer;
  font-weight: 500;
  /* Bigger tappable area without changing visual size */
  padding: 4px 2px;
  margin: -4px -2px;
  display: inline-block;
  min-width: 0;
  flex: 1 1 auto;
}
.tile-phone-link:hover { text-decoration-color: var(--primary, #0ea5e9); }
.tile-call-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 22px; height: 22px;
  border-radius: 999px;
  background: rgba(255,255,255,0.55);
  color: inherit;
  text-decoration: none;
  font-size: 12px;
  opacity: 0.85;
  border: 1px solid currentColor;
}
.tile-call-btn:hover { opacity: 1; background: rgba(255,255,255,0.85); }

/* ============================================================
   Mobile-only tile rework — bigger tap targets, clearer rows
   ============================================================ */
@media (max-width: 720px) {
  /* The whole tile is clickable to open the modal. Anchors inside the tile
     (address, phone, call, directions) must stop propagation so tapping them
     does the link action, NOT open the modal. The :hover stop is handled by
     the inline onclick handler. We still need to make sure they get a wider
     tap target so they're hittable with a finger. */

  /* Tile spacing tighter so more content fits */
  .tile { padding: 8px 0; min-height: 0; }
  .tile-body { gap: 4px; }
  .tile-time { font-size: 13px; }
  .tile-city { font-size: 12px; }

  /* Name + rep stack vertically on phone for legibility */
  .tile-name-row { flex-direction: column; gap: 2px; align-items: flex-start; padding: 0 8px 4px; }
  .tile-rep { font-size: 11px; padding: 2px 8px; }
  .tile-name { font-size: 13px; }

  /* Phone row: bigger tap targets */
  .tile-phone { padding: 4px 6px; gap: 10px; font-size: 13px; }
  .tile-phone-link {
    padding: 8px 4px;
    margin: -8px -4px;
    min-height: 32px;
    display: inline-flex;
    align-items: center;
  }
  .tile-call-btn { width: 32px; height: 32px; font-size: 16px; }

  /* Address row: stack address text above Directions button for hit area.
     Force the button to be tall enough to hit. */
  .tile-address-with-dir {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    padding: 2px 6px 4px;
  }
  .tile-address-with-dir .tile-address-link {
    white-space: normal;
    text-overflow: clip;
    padding: 6px 4px;
    margin: -6px -4px;
    font-size: 13px;
    line-height: 1.35;
    min-height: 32px;
    display: flex;
    align-items: center;
  }
  .tile-dir-btn {
    align-self: flex-start;
    padding: 6px 12px;
    font-size: 12px;
    min-height: 32px;
    background: rgba(255,255,255,0.85);
  }
}

/* Day view (single-day) on mobile: more vertical, tile spans full width */
@media (max-width: 720px) {
  .day-view-cell { padding: 4px; }
  .day-grid {
    /* Make IHSC column narrower and day column wider on mobile */
    grid-template-columns: 90px 1fr !important;
  }
  .day-grid .ihsc-head { padding: 8px 6px; font-size: 12px; }
  /* In day view we want detailed tiles to use the available width fully */
  .day-view-cell .slot-list { gap: 6px; }
  .day-view-cell .tile { width: 100%; }
}

/* ============================================================
 * v2.9.9h — Missing-ZIP warnings (tile chip + optimizer banner)
 * ============================================================
 * The route optimizer silently drops any booking without a ZIP.
 * Surface that with a small inline warning chip on each tile and
 * a yellow banner at the top of the optimizer pane.
 */
.tile-no-zip-chip {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-left: 6px;
  padding: 1px 6px;
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1.4;
  color: #7a4500;
  background: #fff4d6;
  border: 1px solid #f0c46b;
  border-radius: 999px;
  white-space: nowrap;
  cursor: help;
}
.tile-no-zip-chip:hover {
  background: #ffe8a8;
  border-color: #d99a2e;
}

.opt-warn-banner {
  margin: 0 0 14px 0;
  padding: 10px 14px;
  border: 1px solid #f0c46b;
  background: #fff8e6;
  border-radius: 8px;
  color: #5a3300;
}
.opt-warn-title {
  font-weight: 600;
  font-size: 14px;
  margin-bottom: 6px;
  color: #7a4500;
}
.opt-warn-list {
  margin: 4px 0 6px 0;
  padding-left: 22px;
  font-size: 13px;
  line-height: 1.45;
}
.opt-warn-list li {
  margin: 1px 0;
}
.opt-warn-hint {
  margin-top: 4px;
  font-size: 12px;
  font-style: italic;
}

/* ============================================================
 * v2.9.9i — Brand logo in header + sign-in card
 * ============================================================
 * Wide horizontal logo (1001x401) — sized by height so it scales
 * predictably on every breakpoint. Sits left of "S&G Estimation
 * Scheduler" on desktop, stacks above on small phones.
 */
.brand-wrap {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.brand-logo {
  height: 38px;
  width: auto;
  flex-shrink: 0;
  display: block;
}
.signin-logo {
  display: block;
  max-width: 240px;
  width: 100%;
  height: auto;
  margin: 0 auto 14px;
}

@media (max-width: 720px) {
  .brand-logo { height: 30px; }
  .brand-wrap { gap: 8px; }
}
@media (max-width: 480px) {
  /* On very small screens, drop the wordmark text so the recognizable
   * S&G Carpet and More logo gets the space. The view buttons need room. */
  .brand-logo { height: 28px; }
  .brand-wrap .brand { font-size: 13px; line-height: 1.15; }
}

/* v2.9.9j — Optimizer min-miles threshold note */
.opt-threshold-note {
  margin: 0 0 12px 0;
  padding: 6px 10px;
  font-size: 12px;
  background: #f1f5f9;
  border: 1px solid #cbd5e1;
  border-radius: 6px;
  color: #475569;
}

/* ===== v2.9.9z7: appt_outcome overlay + IHSC editor + settings ===== */

/* Calendar tile overlay when sales rep marks an appointment cancelled or
   no-show. The tile keeps occupying its slot (per the user's explicit
   requirement: estimator already lost the time), but strike-through + dim
   make the outcome legible at a glance. */
.tile.outcome-cancelled,
.tile.outcome-noshow {
  position: relative;
  opacity: 0.72;
  filter: grayscale(0.65);
  /* z54: diagonal hatch overlay so preserved no-show / cancel-clone
     originals read as "history, not active" at a glance. */
  background-image: repeating-linear-gradient(
    135deg,
    rgba(15, 23, 42, 0.10) 0,
    rgba(15, 23, 42, 0.10) 6px,
    transparent 6px,
    transparent 12px
  );
}

/* z54: month-view mini tiles for preserved no-show / cancel-clone rows. */
.month-mini-tile.month-mini-outcome-cancelled,
.month-mini-tile.month-mini-outcome-noshow {
  opacity: 0.72;
  filter: grayscale(0.65);
  text-decoration: line-through;
  background-image: repeating-linear-gradient(
    135deg,
    rgba(15, 23, 42, 0.10) 0,
    rgba(15, 23, 42, 0.10) 4px,
    transparent 4px,
    transparent 8px
  );
}
.month-mini-tile.month-mini-outcome-cancelled::after,
.month-mini-tile.month-mini-outcome-noshow::after {
  margin-left: auto;
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-decoration: none;
  color: #334155;
}
.month-mini-tile.month-mini-outcome-cancelled::after { content: 'CXL'; }
.month-mini-tile.month-mini-outcome-noshow::after    { content: 'NS';  }
.tile.outcome-cancelled .tile-time,
.tile.outcome-cancelled .tile-name,
.tile.outcome-cancelled .tile-city,
.tile.outcome-cancelled .tile-address-link,
.tile.outcome-noshow .tile-time,
.tile.outcome-noshow .tile-name,
.tile.outcome-noshow .tile-city,
.tile.outcome-noshow .tile-address-link {
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}

/* Corner badge. Sits in the top-right; the SOLD badge sits to its left
   when both are present. */
.tile-outcome-badge {
  position: absolute;
  top: 4px;
  right: 4px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 2px 5px;
  border-radius: 3px;
  z-index: 2;
  white-space: nowrap;
  pointer-events: none;
  text-decoration: none;   /* override the line-through above on the badge */
}
.outcome-cancelled-badge {
  background: #dc2626;
  color: #fff;
  box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}
.outcome-noshow-badge {
  background: #f59e0b;
  color: #1f2937;
  box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}
/* If both outcome and sold are present, nudge the sold badge left so they
   don't overlap. */
.tile.outcome-cancelled .sold-badge,
.tile.outcome-noshow .sold-badge {
  right: 78px;
}

/* v2.9.9z8 — multi-slot appointment styling ---------------------------------
   A single appointment can span multiple consecutive slots. Backend creates
   N linked rows sharing multi_slot_group_id; frontend renders each as its
   own tile with role classes (primary/child/tail). Visually we remove the
   interior borders between spanned tiles so they read as ONE tall block
   with a shared outline. Legacy 2-slot pairs (linked_booking_id /
   is_extension_slot) use the same classes for consistency.

   The tiles are rendered vertically stacked inside each IHSC's day column,
   so we use border-radius on primary (top) + last-of-type visual cues, and
   collapse the horizontal borders between adjacent multi-slot tiles.
---------------------------------------------------------------------------*/
.tile.multi-slot {
  /* Slightly thicker outline to make the group stand out from single-slot
     neighbors. Uses the IHSC color so it visually stays with its column. */
  border-color: var(--ihsc-color, #4f46e5);
  border-width: 2px;
  position: relative;
}
.tile.multi-slot-primary {
  /* Top of the group — keep top corners rounded, flatten bottom so it
     visually connects to the next spanned tile. */
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  border-bottom-width: 1px;
  border-bottom-style: dashed;
  border-bottom-color: color-mix(in srgb, var(--ihsc-color, #4f46e5) 40%, transparent);
}
.tile.multi-slot-child {
  /* Middle/end spanned tiles — flatten top corners, and dim the top border
     so the group reads as continuous. Bottom stays solid so if this ends up
     being the last visible tile, the group still has a clean closing edge. */
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  border-top-width: 1px;
  border-top-style: dashed;
  border-top-color: color-mix(in srgb, var(--ihsc-color, #4f46e5) 40%, transparent);
}
.tile.multi-slot-child + .tile.multi-slot-child,
.tile.multi-slot-primary + .tile.multi-slot-child {
  /* Pull adjacent multi-slot tiles up by 1px so their borders visually merge
     into a single continuous outline. Safe because vertical stacking is via
     block layout in the day column. */
  margin-top: -1px;
}

/* v2.9.9z9-4 — child tile continuation row. Renders only "↳ continued" next
   to the slot label so the user can see the appointment spans multiple slots
   without duplicating name/phone/address on every row. Muted color; the
   primary tile carries the actual customer details. */
.tile.multi-slot-child {
  min-height: 28px;
  padding: 4px 10px;
}
.tile.multi-slot-child .tile-body { padding: 0; }
.tile-continued-row {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px;
}
.tile-continued-label {
  color: var(--ink-muted, #6b7280);
  font-style: italic;
  font-size: 11px;
}

/* Slot-count chip on the primary tile — sits top-right, to the LEFT of the
   sold + outcome badges. Uses the IHSC color so it reads as part of the
   group outline. Fixed width-ish label keeps it tidy for x2/x3/All-day. */
.tile-slotcount-chip {
  position: absolute;
  top: 4px;
  right: 4px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 6px;
  border-radius: 10px;
  z-index: 2;
  white-space: nowrap;
  pointer-events: none;
  background: var(--ihsc-color, #4f46e5);
  color: #fff;
  box-shadow: 0 1px 2px rgba(0,0,0,0.15);
  text-decoration: none;
}
/* v2.9.9z9-5c: When a multi-slot PRIMARY tile also has a sold-badge, the
   slot-count chip (×N or All day) needs to move LEFT so it doesn't sit on
   top of the sold badge. Layout (right-to-left) on the primary tile:
   [ sold-badge @ right:2px ] [ slot-count-chip @ right:24px ]
     [ confirmed-chip @ right:60px ]
   Selectors below were previously written as .sold-badge (missing tile-
   prefix) so they were dead — fixed here. */
.tile.multi-slot-primary .tile-slotcount-chip { right: 24px; }
.tile.multi-slot-primary .tile-confirmed-chip { right: 60px; }
/* With CANCELLED / NO SHOW outcome badges present, the rectangle badge sits
   at right:4px and is ~68px wide, so push everything further left. */
.tile.multi-slot-primary.outcome-cancelled .tile-sold-badge,
.tile.multi-slot-primary.outcome-noshow .tile-sold-badge { right: 78px; }
.tile.multi-slot-primary.outcome-cancelled .tile-slotcount-chip,
.tile.multi-slot-primary.outcome-noshow .tile-slotcount-chip { right: 100px; }
.tile.multi-slot-primary.outcome-cancelled .tile-confirmed-chip,
.tile.multi-slot-primary.outcome-noshow .tile-confirmed-chip { right: 136px; }

/* Compact/day-view density: primary tiles still show the chip but a tiny
   bit smaller so it doesn't crowd the 9am/11am/2pm/4pm labels. */
.day-view-cell .tile-slotcount-chip { font-size: 8px; padding: 1px 5px; }

/* v2.9.9z8 — slot-count control in the edit-booking modal ------------------
   Primary rows show a <select> + "Change span" button side-by-side.
   Children / legacy pairs show a compact read-only note. The button is
   disabled until the picker value differs from the current slot_count so
   staff can't accidentally submit a no-op resize. */
.slot-count-editor {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.slot-count-editor select.booking-slotcount-sel {
  flex: 0 1 220px;
  min-width: 180px;
}
.slot-count-editor .btn.btn-sm {
  padding: 6px 12px;
  font-size: 13px;
}
.slot-count-editor .btn.btn-sm[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
.slot-count-readonly .slot-count-note {
  font-size: 13px;
  line-height: 1.4;
  color: #475569;
  background: #f1f5f9;
  padding: 8px 10px;
  border-radius: 6px;
  border: 1px solid #e2e8f0;
}
.slot-count-readonly .slot-count-note strong { color: #1e293b; }
.slot-count-readonly .btn.btn-ghost.btn-sm {
  font-size: 12px;
  padding: 4px 10px;
}

/* IHSC Regions editor — new 2-line block layout. */
.r-ihsc-block {
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  padding: 8px 10px;
  margin-bottom: 6px;
  background: #fff;
}
.r-ihsc-block .r-ihsc-ihsc {
  margin: 0 0 6px 0;
  padding: 0;
  border: 0;
  background: transparent;
}
.r-ihsc-addr-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  padding-top: 4px;
  border-top: 1px dashed #e5e7eb;
}
.r-ihsc-addr-row input { font-size: 12px; padding: 4px 6px; }
.r-ihsc-addr        { flex: 1 1 240px; min-width: 180px; }
.r-ihsc-addr-city   { flex: 0 1 130px; }
.r-ihsc-addr-state  { flex: 0 0 44px; text-align: center; text-transform: uppercase; }
.r-ihsc-addr-zip    { flex: 0 0 80px; }
.r-ihsc-geo-badge {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 10px;
  white-space: nowrap;
  margin-left: auto;
  cursor: help;
}
.r-ihsc-geo-badge.geo-ok {
  background: #dcfce7;
  color: #166534;
  border: 1px solid #86efac;
}
.r-ihsc-geo-badge.geo-missing {
  background: #fef3c7;
  color: #92400e;
  border: 1px solid #fcd34d;
}

/* v2.9.9z8: IHSC home-branch row (below address row). Inline label + select. */
.r-ihsc-branch-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-top: 4px;
  font-size: 12px;
}
.r-ihsc-branch-label {
  color: #6b7280;
  font-weight: 500;
  white-space: nowrap;
}
.r-ihsc-branch-sel {
  flex: 0 1 240px;
  font-size: 12px;
  padding: 3px 6px;
  border: 1px solid #d1d5db;
  border-radius: 4px;
  background: #fff;
}

/* v2.9.9z8: Branches sub-section inside Regions & IHSCs card. */
.r-ihsc-branches {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 2px solid #e5e7eb;
}
.r-ihsc-branches .r-ihsc-section-title {
  margin-bottom: 10px;
}
.r-ihsc-branch-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.r-ihsc-branch-block {
  padding: 8px 10px;
  background: #f9fafb;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
}
.r-ihsc-branch-block.inactive {
  opacity: 0.55;
  background: #f3f4f6;
}
.r-branch-top {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.r-branch-top .r-branch-name {
  flex: 1 1 180px;
  min-width: 140px;
  font-size: 13px;
  font-weight: 600;
  padding: 4px 6px;
}
.r-branch-top .r-branch-sort {
  flex: 0 0 60px;
  font-size: 12px;
  padding: 4px 6px;
  text-align: center;
}
.r-branch-active-label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: #374151;
  white-space: nowrap;
  cursor: pointer;
}
.r-branch-addr-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  padding-top: 6px;
  margin-top: 6px;
  border-top: 1px dashed #e5e7eb;
}
.r-branch-addr-row input { font-size: 12px; padding: 4px 6px; }
.r-branch-addr  { flex: 1 1 220px; min-width: 160px; }
.r-branch-city  { flex: 0 1 130px; }
.r-branch-state { flex: 0 0 44px; text-align: center; text-transform: uppercase; }
.r-branch-zip   { flex: 0 0 80px; }
.r-ihsc-add-branch {
  margin-top: 12px;
  padding: 8px 10px;
  background: #fff;
  border: 1px dashed #cbd5e1;
  border-radius: 6px;
}

/* Customer-confirmed pill under the Confirmation dropdown in the
   booking-edit modal. Surfaces when the customer texted YES in response
   to an automated reminder. Purely informational for the sales rep. */
.customer-confirmed-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 6px;
  padding: 4px 8px;
  font-size: 12px;
  font-weight: 600;
  background: #dcfce7;
  color: #166534;
  border: 1px solid #86efac;
  border-radius: 12px;
  cursor: help;
  line-height: 1.2;
}

/* ============================================================
   v2.9.9z10 — Dashboard & Monthly Measures Report
   ============================================================ */

.dashboard-modal { max-width: 1200px; }
.dashboard-modal .modal-body { padding: 12px 20px 20px; max-height: 85vh; overflow-y: auto; }

.dashboard-tabs { margin: 0 0 12px; }

.dashboard-filters {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px 12px; background: #f8fafc; border: 1px solid #e2e8f0;
  border-radius: 8px; margin-bottom: 16px;
}
.dashboard-filters .df-row {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
}
.dashboard-filters .df-lbl {
  font-size: 12px; color: #475569; font-weight: 600;
  margin-right: -2px;
}
.dashboard-filters .df-inline {
  font-size: 13px; color: #334155; display: inline-flex; align-items: center; gap: 6px;
}
.dashboard-filters .dash-date {
  padding: 4px 8px; border: 1px solid #cbd5e1; border-radius: 6px;
  font-size: 13px; height: 32px;
}
.dashboard-filters .toolbar-select { height: 32px; }

.dashboard-content { min-height: 240px; }

.dash-loading, .dash-empty, .dash-empty-sm {
  padding: 40px 20px; text-align: center; color: #64748b;
}
.dash-empty-sm { padding: 20px; font-size: 13px; }

/* ---- KPI hero ---- */
.kpi-hero {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
  margin-bottom: 16px;
}
.kpi-card {
  background: #fff; border: 1px solid #e2e8f0; border-radius: 10px;
  padding: 16px 18px; box-shadow: 0 1px 2px rgba(0,0,0,.03);
}
.kpi-card--hero {
  background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
  color: #f8fafc; border-color: #0f172a;
}
.kpi-card--hero .kpi-label { color: #cbd5e1; }
.kpi-card--hero .kpi-sub   { color: #94a3b8; }
.kpi-label {
  font-size: 12px; text-transform: uppercase; letter-spacing: .04em;
  color: #64748b; font-weight: 600; margin-bottom: 6px;
}
.kpi-value { font-size: 40px; font-weight: 700; line-height: 1.05; letter-spacing: -.02em; }
.kpi-value--sm { font-size: 22px; }
.kpi-sub { font-size: 12px; color: #64748b; margin-top: 4px; }

.kpi-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
  margin-bottom: 22px;
}
.kpi-card--sm { padding: 10px 12px; }

@media (max-width: 720px) {
  .kpi-hero { grid-template-columns: 1fr; }
  .kpi-grid { grid-template-columns: repeat(2, 1fr); }
  .kpi-value { font-size: 32px; }
}

.dash-section { margin-top: 22px; }
.dash-section h3 {
  font-size: 15px; font-weight: 700; color: #0f172a;
  margin: 0 0 10px; letter-spacing: -.01em;
}

/* ---- Branch ranked bars ---- */
.branch-bars { display: flex; flex-direction: column; gap: 8px; }
.branch-bar-row {
  display: grid;
  grid-template-columns: 180px 1fr 60px 220px;
  gap: 12px; align-items: center;
  padding: 8px 10px; background: #fff;
  border: 1px solid #e2e8f0; border-radius: 8px;
}
.branch-bar-name { font-size: 14px; font-weight: 600; color: #0f172a; }
.branch-bar-track {
  position: relative; height: 10px; background: #e2e8f0;
  border-radius: 999px; overflow: hidden;
}
.branch-bar-fill {
  height: 100%; background: linear-gradient(90deg, #10b981 0%, #059669 100%);
  border-radius: 999px; transition: width .3s ease;
}
.branch-bar-stat { font-size: 15px; font-weight: 700; color: #059669; text-align: right; }
.branch-bar-meta { font-size: 12px; color: #64748b; }

@media (max-width: 720px) {
  .branch-bar-row { grid-template-columns: 1fr 50px; grid-auto-rows: auto; }
  .branch-bar-track, .branch-bar-meta { grid-column: 1 / -1; }
  .branch-bar-name { grid-column: 1; }
  .branch-bar-stat { grid-column: 2; }
}

/* ---- IHSC leaderboard table ---- */
.ihsc-table { border: 1px solid #e2e8f0; border-radius: 8px; overflow: hidden; }
/* v2.9.9z37: 5-column grid — Branch column removed since IHSC leaderboard
   now dedupes to one row per estimator (grouped in dashboard-stats.php). */
.ihsc-row {
  display: grid;
  grid-template-columns: 44px minmax(180px, 2fr) 90px 90px 100px;
  gap: 10px; padding: 8px 12px; background: #fff; align-items: center;
  border-top: 1px solid #f1f5f9; font-size: 13px;
}
.ihsc-row:first-child { border-top: none; }
/* v2.9.9z13: scope to .ihsc-table so we override the calendar's global
   .ihsc-head rule (which sets max-width:110px, display:flex, padding:12px,
   word-break: break-word) that was making the dashboard header cells appear
   misaligned above the right-aligned data columns. */
.ihsc-table .ihsc-head {
  /* v2.9.9z13.1: the calendar's global .ihsc-head rule sets max-width:110px,
     which was shrinking the entire header ROW to 110px (a 6-column grid
     jammed into a 110px box), leaving all headers piled at the far left
     while the body row filled the container. Force width auto here. */
  max-width: none;
  width: auto;
  background: #f8fafc; font-weight: 700; text-transform: uppercase;
  font-size: 11px; color: #64748b; letter-spacing: .04em;
  white-space: nowrap;
}
.ihsc-table .ihsc-head > div {
  display: block;
  max-width: none;
  padding: 0;
  border-right: 0;
  word-break: normal;
  white-space: nowrap;
}
.ihsc-row > div {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ihsc-row .r { text-align: right; font-variant-numeric: tabular-nums; }
.ihsc-table .ihsc-head .r { text-align: right; }
.ihsc-row .strong { font-weight: 700; color: #059669; }
.ihsc-row .muted { color: #64748b; font-size: 12px; }
/* v2.9.9z41: clickable sort headers for the IHSC leaderboard. Match the
   Monthly Measures Report table treatment so the two feel consistent. */
.ihsc-table .ihsc-head .ihsc-th-sortable {
  cursor: pointer;
  user-select: none;
  transition: color .12s ease;
}
.ihsc-table .ihsc-head .ihsc-th-sortable:hover { color: #0f172a; }
.ihsc-table .ihsc-head .ihsc-th-sortable.sort-active { color: #0f172a; }
.ihsc-table .ihsc-head .sort-ind { color: #94a3b8; font-size: 10px; margin-left: 2px; }
.ihsc-table .ihsc-head .sort-active .sort-ind { color: #0f172a; }

@media (max-width: 720px) {
  /* v2.9.9z37: 5 cols on desktop; on mobile hide Total close (5th col) to
     keep #, IHSC, Measured, Same-day visible in a 4-col grid. */
  .ihsc-row { grid-template-columns: 32px minmax(0,1fr) 70px 80px; gap: 6px; }
  .ihsc-row > div:nth-child(5) { display: none; }
  /* v2.9.9z13: neutralize the calendar's mobile max-width: 90px on our
     dashboard header cells. */
  .ihsc-table .ihsc-head { max-width: none; }
  .ihsc-table .ihsc-head > div { max-width: none; }
}

/* ---- Sortable report table headers (v2.9.9z13) ---- */
.report-table thead th.sortable {
  cursor: pointer;
  user-select: none;
  position: relative;
  padding-right: 22px;
}
.report-table thead th.sortable:hover { background: #f1f5f9; color: #0f172a; }
.report-table thead th.sortable .sort-ind {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  font-size: 10px; color: #94a3b8; opacity: .5;
}
.report-table thead th.sortable.sort-active .sort-ind { opacity: 1; color: #0f172a; }

/* ---- Appointment-type category breakdown (Traditional / Phone-in / Shop / Yelp) ---- */
.cat-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
}
.cat-card {
  background: #fff; border: 1px solid #e2e8f0; border-radius: 10px;
  padding: 12px 14px; position: relative; overflow: hidden;
}
.cat-card::before {
  content: ''; position: absolute; inset: 0 auto 0 0; width: 4px;
  background: var(--cat-color, #64748b);
}
.cat-card--traditional { --cat-color: #22c55e; }
.cat-card--phone_in    { --cat-color: #eab308; }
.cat-card--shop_at_home{ --cat-color: #ec4899; }
.cat-card--yelp        { --cat-color: #0ea5e9; }

.cat-name {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: #64748b; margin-bottom: 4px;
  padding-left: 6px;
}
.cat-rate {
  font-size: 24px; font-weight: 700; letter-spacing: -.02em;
  color: #0f172a; line-height: 1.05; padding-left: 6px;
}
.cat-meta {
  font-size: 12px; color: #64748b; margin-top: 4px; padding-left: 6px;
}
.cat-bonus-note {
  display: block; font-size: 11px; color: #94a3b8;
  margin-top: 6px; padding-left: 6px; font-style: italic;
}
@media (max-width: 720px) {
  .cat-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ---- Users row: dashboard tri-state ---- */
.user-dash-select {
  padding: 3px 6px; border: 1px solid #cbd5e1; border-radius: 6px;
  font-size: 12px; background: #fff;
}

/* ---- Monthly Measures Report ---- */
.report-actions {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 12px;
}
.report-print-header {
  margin-bottom: 8px; padding-bottom: 8px; border-bottom: 2px solid #0f172a;
}
.report-title { font-size: 20px; font-weight: 700; color: #0f172a; }
.report-subtitle { font-size: 13px; color: #64748b; margin-top: 2px; }

.report-summary {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 10px 12px; background: #f8fafc;
  border: 1px solid #e2e8f0; border-radius: 8px;
  margin-bottom: 14px; font-size: 13px; color: #334155;
}
.report-summary strong { color: #0f172a; font-weight: 700; margin-right: 3px; }
/* v2.9.9z40: two-group summary strip — measure stats left, exception counts right. */
.report-summary-left  { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
.report-summary-right { display: flex; flex-wrap: wrap; gap: 8px;  align-items: center; }
.report-chip {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 3px 10px; border-radius: 999px;
  font-size: 12.5px; font-weight: 500;
  border: 1px solid transparent;
}
.report-chip strong { margin-right: 2px; }
.report-chip-cancelled { background: #fef2f2; color: #991b1b; border-color: #fecaca; }
.report-chip-noshow    { background: #fff7ed; color: #9a3412; border-color: #fed7aa; }

/* v2.9.9z23: bonus verification scoreboard (IHSC verify sheet parity). */
.report-bonus {
  display: grid; grid-template-columns: 1fr 1fr; gap: 14px;
  margin-bottom: 14px;
}
/* v2.9.9z39: solo (no right-hand card) — scoreboard spans the full width. */
.report-bonus.report-bonus-solo { grid-template-columns: 1fr; }
.report-bonus-left, .report-bonus-right {
  border: 1px solid #e2e8f0; border-radius: 8px; overflow: hidden;
  background: #fff;
}
.report-bonus-hdr {
  background: #0f172a; color: #f8fafc; padding: 8px 12px;
  font-size: 12px; font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase;
}
.report-bonus-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.report-bonus-table th, .report-bonus-table td {
  padding: 8px 12px; border-top: 1px solid #f1f5f9; text-align: left;
}
.report-bonus-table thead th {
  background: #f8fafc; color: #64748b; font-weight: 600;
  font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
}
.report-bonus-table th.r, .report-bonus-table td.r { text-align: right; }
.report-bonus-table td.big { font-size: 18px; font-weight: 700; color: #0f172a; }
.report-bonus-table tr.row-phone th { background: #fef9c3; color: #0f172a; font-weight: 700; }
.report-bonus-table tr.row-phone td { background: #fef9c3; }
.report-bonus-table tr.row-trad  th { background: #e2e8f0; color: #0f172a; font-weight: 700; }
.report-bonus-table tr.row-trad  td { background: #e2e8f0; }
.report-bonus-table tr.row-total th,
.report-bonus-table tr.row-total td { background: #0f172a; color: #f8fafc; font-weight: 700; }
.report-bonus-foot {
  padding: 6px 12px; font-size: 11px; color: #64748b; font-style: italic;
  background: #f8fafc; border-top: 1px solid #e2e8f0;
}
.report-bonus-right { display: flex; flex-direction: column; }
.report-bonus-rate {
  flex: 1; display: flex; align-items: center; justify-content: center;
  font-size: 56px; font-weight: 800; color: #0f172a;
  background: #f0fdf4; letter-spacing: -0.02em;
  padding: 12px 8px;
}
.report-bonus-rate-sub {
  text-align: center; font-size: 11px; color: #64748b;
  background: #f0fdf4; padding: 4px 8px 2px;
}
.report-bonus-rate-frac {
  text-align: center; font-size: 13px; color: #0f172a; font-weight: 600;
  background: #f0fdf4; padding: 0 8px 10px;
}

@media (max-width: 720px) {
  .report-bonus { grid-template-columns: 1fr; }
}

.report-table {
  width: 100%; border-collapse: collapse; background: #fff;
  border: 1px solid #e2e8f0; border-radius: 8px; overflow: hidden;
  font-size: 12.5px;
}
.report-table thead th {
  background: #0f172a; color: #f8fafc; text-align: left;
  padding: 8px 10px; font-size: 11px; text-transform: uppercase;
  letter-spacing: .04em; font-weight: 700;
}
.report-table tbody td {
  padding: 6px 10px; border-top: 1px solid #f1f5f9; vertical-align: top;
}
.report-table tbody tr:nth-child(even) td { background: #fafbfc; }
.report-table .oc-cancelled, .report-table .sl-not_sold { color: #b91c1c; font-weight: 600; }
.report-table .oc-no_show { color: #b45309; font-weight: 600; }
.report-table .sl-sold_on_site { color: #059669; font-weight: 700; }
.report-table .sl-sold_later { color: #0369a1; font-weight: 600; }

/* v2.9.9z38: dim + strike-through cancelled / no-show rows so IHSCs can see
   they were scheduled without counting them toward bonus totals. */
.report-table tbody tr.report-row-excluded td {
  color: #94a3b8;
  text-decoration: line-through;
  text-decoration-color: #cbd5e1;
  background: #f8fafc !important;
}
/* Keep the Outcome cell readable (so the reason is obvious) */
.report-table tbody tr.report-row-excluded td.oc-cancelled,
.report-table tbody tr.report-row-excluded td.oc-no_show {
  text-decoration: none;
  color: #b91c1c;
  font-weight: 700;
}
.report-table tbody tr.report-row-excluded td.oc-no_show { color: #b45309; }

/* v2.9.9z38: Confirmation column badges */
.report-table .conf-yes { color: #047857; font-weight: 600; }
.report-table .conf-no  { color: #64748b; }

/* ============================================================
   Print CSS — v2.9.9z22

   Prints two different things:

     (a) The Monthly Measures Report inside .dashboard-modal.
     (b) The main calendar (#gridHost) — Day/Week/Month view.

   z20 and earlier only had (a): body * was hidden, only
   .dashboard-modal was un-hidden. That's why Ctrl+P on the
   calendar produced a blank page.

   z21 rewrote this: default to hiding the shell chrome and
   un-hide the report modal + calendar grid host.

   z22 fixed the blank first page on the report: .app-shell
   has min-height:100vh; display:flex which forced a full
   empty page BEFORE the modal (a body sibling) could paint.
   We now collapse .app-shell entirely when printing the
   report, and collapse #modalHost when printing the calendar.
   ============================================================ */
/* v2.9.9z42: on-screen the print-only calendar header is hidden. It's a
   standalone block that only appears when @media print applies so that the
   current view + date range + print timestamp are visible on every printed
   page even if the user hit Ctrl+P from a scrolled-down position (previous
   behavior lost the date because #weekLabel lives inside .header-actions,
   which is display:none in print). */
.calendar-print-header { display: none; }

/* v2.9.9z42: idle-timeout warning modal. Rendered directly to <body> so it
   sits above any other overlay/modal. Uses a lower z-index than the toast
   layer so error toasts still peek over the top if something is wrong. */
.idle-warn-scrim {
  position: fixed; inset: 0;
  background: rgba(15,23,42,0.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 9500;
}
.idle-warn-card {
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 24px 48px rgba(15,23,42,0.24);
  padding: 24px;
  max-width: 420px; width: calc(100% - 32px);
  color: #0f172a;
}
.idle-warn-title {
  font-size: 18px; font-weight: 700; margin-bottom: 8px;
}
.idle-warn-body {
  font-size: 14px; line-height: 1.5; color: #334155;
}
.idle-warn-body .idle-warn-count {
  font-weight: 700; color: #b91c1c; font-variant-numeric: tabular-nums;
}
.idle-warn-actions {
  display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px;
}

/* v2.9.9z42: notice banner on the sign-in card explaining why the previous
   session ended (idle timeout, disabled account, etc). */
.signin-notice {
  background: #fef3c7;
  border: 1px solid #fcd34d;
  color: #78350f;
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 13px;
  margin: 12px 0;
  text-align: left;
}

@media print {
  @page { size: landscape; margin: 0.4in; }

  /* Universal reset for print */
  html, body {
    background: #fff !important;
    color: #000 !important;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .no-print, .no-print * { display: none !important; }

  /* Hide app chrome we don't want in print */
  .header-actions,
  .region-tabs,
  .mobile-day-pager,
  #alertBanner,
  #toasts,
  #tileTooltip { display: none !important; }

  /* v2.9.9z42: reveal the always-populated print header at the top of the
     printed calendar. Uses position:running() semantics via a plain block
     placed at the very top of <main> so it appears on page 1; the
     .grid-wrap page-break-avoid rules below let it repeat visually as
     needed. Keep it compact so it doesn't push tiles onto page 2. */
  .calendar-print-header {
    display: flex !important;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 0 0 6px 0;
    margin: 0 0 8px 0;
    border-bottom: 1px solid #cbd5e1;
    font-family: inherit;
    color: #000 !important;
  }
  .calendar-print-header .print-brand {
    display: flex; align-items: center; gap: 8px;
  }
  .calendar-print-header .print-brand img {
    max-height: 28px; width: auto;
  }
  .calendar-print-header .print-brand-text {
    font-size: 14px; font-weight: 700;
  }
  .calendar-print-header .print-meta {
    text-align: right; font-size: 11px;
  }
  .calendar-print-header .print-view {
    font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: #475569;
  }
  .calendar-print-header .print-range {
    font-size: 16px; font-weight: 700; color: #0f172a;
  }
  .calendar-print-header .print-stamp {
    font-size: 10px; color: #64748b; margin-top: 2px;
  }
  /* When printing the report modal, hide the calendar print header so it
     doesn't compete with the report's own print header. */
  body.printing-report .calendar-print-header { display: none !important; }

  /* v2.9.9z43: the app-shell .header is position:sticky on screen. In print
     it was rendering (with brand + user email + version) mid-page-2 because
     the sticky positioning reserved vertical space at whatever scroll
     offset the user was at when they hit Print. The new .calendar-print-
     header already carries the brand + view + date + timestamp, so hide
     the original .header entirely on calendar prints — there is no need
     for both. Report prints still hide it via body.printing-report rules
     further down. */
  body.printing-calendar .app-shell > .header { display: none !important; }
  /* Belt-and-suspenders: even outside .printing-calendar (e.g. plain Ctrl+P)
     the sticky .header should not print. Its content is duplicated in
     .calendar-print-header. */
  .app-shell > .header {
    position: static !important;
    display: none !important;
  }

  /* Main + gridHost fill the page for calendar prints */
  .app-shell .main { padding: 0 !important; margin: 0 !important; }
  #gridHost {
    width: 100% !important;
    max-width: none !important;
    overflow: visible !important;
  }

  /* v2.9.9z43: the sticky day-of-week strip (.date-strip-wrap) was
     rendering mid-page-2 because position:sticky reserves space at the
     user's scroll offset. Force static positioning + reset the shifted
     transform so the day-of-week row prints at the top of the grid where
     it belongs, and the day-head cells will be repeated only on page 1.
     For a repeat-on-every-page day strip we'd need to convert the grid
     to a CSS table with display:table-header-group — out of scope for
     this hotfix. */
  .date-strip-wrap {
    position: static !important;
    top: auto !important;
    z-index: auto !important;
    box-shadow: none !important;
    border-radius: 0 !important;
  }
  .date-strip {
    transform: none !important;
  }
  /* Also flatten the sticky horizontal scrollbar mimic — it's a screen
     affordance that should never print. */
  .sticky-hscroll { display: none !important; }

  /* --- Calendar view: keep appt-tile colors, prevent row splits --- */
  #gridHost .grid-wrap {
    display: grid !important;
    overflow: visible !important;
    height: auto !important;
    max-height: none !important;
  }
  /* v2.9.9z51: don't page-break-inside a small tile, but ALLOW a tall
   * calendar day-cell to split across pages. Previously we blanket-avoided
   * splitting on .grid-cell which meant tall IHSC rows (each row is 6 grid
   * cells with many appointment tiles) got forced onto the next page —
   * leaving page 1 blank for detailed week views. Only protect the small
   * pieces from splitting; the row itself is allowed to split. */
  #gridHost .appt-tile,
  #gridHost .tile,
  #gridHost .booking-tile,
  #gridHost .month-day,
  #gridHost .day-head {
    page-break-inside: avoid !important;
    break-inside: avoid !important;
  }

  /* v2.9.9z51: keep the print header attached to the grid — no blank page 1.
   * page-break-after:avoid + orphans/widows encourage the browser to keep
   * the header + first row of tiles together. The IHSC-head + first tile
   * gets page-break-after:auto so paginate freely from there. */
  .calendar-print-header {
    page-break-after: avoid !important;
    break-after: avoid !important;
  }
  .date-strip-wrap {
    page-break-after: avoid !important;
    break-after: avoid !important;
    page-break-inside: avoid !important;
    break-inside: avoid !important;
  }

  /* v2.9.9z51: compact tile rendering for print. Screen tile density is
   * driven by ‘Normal/Detailed’ selector, but on paper we always want the
   * densest legible version so more content fits per page. */
  #gridHost .appt-tile,
  #gridHost .tile,
  #gridHost .booking-tile {
    font-size: 9.5px !important;
    line-height: 1.25 !important;
    padding: 3px 4px !important;
    margin: 2px 0 !important;
  }
  #gridHost .appt-tile .tile-time,
  #gridHost .appt-tile .tile-cust,
  #gridHost .tile .tile-time,
  #gridHost .tile .tile-cust {
    font-size: 10px !important;
    font-weight: 700 !important;
  }
  #gridHost .appt-tile .tile-addr,
  #gridHost .appt-tile .tile-notes,
  #gridHost .tile .tile-addr,
  #gridHost .tile .tile-notes {
    font-size: 8.5px !important;
  }
  /* Tighter cell padding + smaller min-height so the calendar packs. */
  #gridHost .grid-cell {
    padding: 3px !important;
    min-height: 60px !important;
  }
  #gridHost .day-head { padding: 6px 4px !important; }
  #gridHost .ihsc-head { padding: 6px 4px !important; font-size: 10px !important; }
  #gridHost .day-head .dow { font-size: 9px !important; }
  #gridHost .day-head .dom { font-size: 12px !important; }

  /* v2.9.9z51: allow a really tall IHSC row (lots of stacked tiles) to
   * split. min-height:0 defeats the implicit min-content sizing that was
   * forcing tall rows to reserve a full page. */
  #gridHost .grid { grid-auto-rows: min-content !important; }
  #gridHost .grid-cell { min-height: 0 !important; }
  /* Preserve tile background colors and text contrast on paper */
  #gridHost .appt-tile,
  #gridHost .tile,
  #gridHost .booking-tile,
  #gridHost .day-head,
  #gridHost .month-day-today {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }
  /* Legend is fine to show — helps interpret tile colors */
  #typeLegend { display: block !important; margin: 4px 0 8px 0 !important; }

  /* --- Any lingering modal-backdrop: hide by default in print.
     The report's Print button sets .printing-report on <body>
     which re-shows and un-modals it below. --- */
  .modal-backdrop { display: none !important; }

  /* --- Report modal: only shown when .printing-report is set --- */
  body.printing-report .modal-backdrop {
    display: block !important;
    position: static !important; background: none !important;
    padding: 0 !important;
  }
  body.printing-report .dashboard-modal {
    display: block !important;
    position: static !important; box-shadow: none !important;
    border: none !important; max-width: none !important; width: 100% !important;
    max-height: none !important;
  }
  body.printing-report .dashboard-modal .modal-header { display: none !important; }
  body.printing-report .dashboard-modal .modal-body {
    overflow: visible !important; max-height: none !important; padding: 0 !important;
  }
  .report-print-header, .report-summary, .report-bonus, .report-table { page-break-inside: avoid; }
  .report-bonus { page-break-inside: avoid; }
  .report-table { page-break-inside: auto; }
  .report-table thead { display: table-header-group; }
  .report-table tbody tr { page-break-inside: avoid; }
  .report-table thead th { background: #0f172a !important; color: #fff !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .report-summary { background: #f8fafc !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  /* v2.9.9z23: keep bucket colors on paper */
  .report-bonus-hdr,
  .report-bonus-table thead th,
  .report-bonus-table tr.row-phone th, .report-bonus-table tr.row-phone td,
  .report-bonus-table tr.row-trad  th, .report-bonus-table tr.row-trad  td,
  .report-bonus-table tr.row-total th, .report-bonus-table tr.row-total td,
  .report-bonus-foot,
  .report-bonus-rate, .report-bonus-rate-sub, .report-bonus-rate-frac {
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .report-table tbody td { padding: 4px 6px; font-size: 11px; }

  /* When body is flagged .printing-report, hide the entire app-shell
     so the modal (a body-level sibling of .app-shell) doesn't get
     pushed onto page 2 by app-shell's min-height:100vh flex layout.
     This was the z21 blank-first-page bug — hiding just .header +
     #gridHost left .app-shell in place with 100vh reserved. */
  body.printing-report .app-shell {
    display: none !important;
    min-height: 0 !important;
    height: 0 !important;
  }
  body.printing-report #typeLegend,
  body.printing-report #alertBanner,
  body.printing-report #toasts { display: none !important; }

  /* Symmetric protection for calendar print mode: hide the modal
     host + toasts / tooltips so nothing sneaks onto page 1. */
  body.printing-calendar #modalHost,
  body.printing-calendar #toasts,
  body.printing-calendar #tileTooltip { display: none !important; }

  /* Guarantee .modal-backdrop (when kept for report print) sits
     at the top of the flow with no reserved viewport space. */
  body.printing-report #modalHost {
    position: static !important;
    min-height: 0 !important;
    height: auto !important;
  }
  body.printing-report .report-print-header {
    page-break-before: avoid !important;
    break-before: avoid !important;
    margin-top: 0 !important;
  }
}

/* ============================================================
   v2.9.9z38 — Help & Support drawer
   ============================================================
   Right-side sliding panel opened from the header "?" button.
   ------------------------------------------------------------ */
.help-drawer {
  position: fixed; inset: 0;
  z-index: 5000;
  display: flex; justify-content: flex-end;
}
.help-drawer-scrim {
  position: absolute; inset: 0;
  background: rgba(15, 23, 42, 0.45);
  animation: helpFade .15s ease-out;
}
.help-drawer-panel {
  position: relative;
  width: min(560px, 92vw);
  height: 100%;
  background: #ffffff;
  box-shadow: -8px 0 30px rgba(15, 23, 42, 0.25);
  display: flex; flex-direction: column;
  animation: helpSlideIn .18s ease-out;
}
@keyframes helpFade    { from { opacity: 0; } to { opacity: 1; } }
@keyframes helpSlideIn { from { transform: translateX(24px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }

.help-drawer-hdr {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px 10px 18px;
  border-bottom: 1px solid #e2e8f0;
  background: #0f172a;
  color: #f8fafc;
}
.help-drawer-title { font-size: 16px; font-weight: 700; }
.help-drawer-close {
  background: transparent; border: 0;
  color: #f8fafc;
  font-size: 22px; line-height: 1;
  cursor: pointer;
  padding: 4px 10px; border-radius: 6px;
}
.help-drawer-close:hover { background: rgba(255,255,255,0.08); }

.help-drawer-meta {
  padding: 8px 18px;
  background: #f8fafc;
  color: #475569;
  font-size: 11.5px;
  border-bottom: 1px solid #e2e8f0;
}
.help-tabbar {
  display: flex; gap: 4px;
  padding: 6px 10px 0 10px;
  background: #f8fafc;
  border-bottom: 1px solid #e2e8f0;
  flex-wrap: wrap;
}
.help-tab {
  background: transparent; border: 0;
  padding: 8px 12px;
  border-radius: 6px 6px 0 0;
  font-size: 13px; font-weight: 600;
  color: #64748b;
  cursor: pointer;
}
.help-tab:hover { background: #e2e8f0; color: #0f172a; }
.help-tab.active {
  background: #ffffff;
  color: #0f172a;
  box-shadow: 0 -1px 0 #ffffff inset, 0 1px 0 #ffffff;
  border: 1px solid #e2e8f0; border-bottom-color: #ffffff;
}
.help-drawer-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 16px 18px 24px 18px;
  background: #ffffff;
}
.help-section h3 {
  margin: 0 0 8px 0;
  font-size: 14px; font-weight: 700;
  color: #0f172a;
  letter-spacing: .01em;
}
.help-section .help-block { margin: 14px 0 18px 0; }
.help-section .help-block:first-child { margin-top: 0; }
/* v2.9.9z40: separator heading that sits between the Welcome intro list
   and the folded-in Feature Guide sections. Slightly muted vs the top h3
   so it reads as "section 2" rather than a peer of the drawer title. */
.help-section .help-guide-sep {
  margin-top: 22px;
  padding-top: 14px;
  border-top: 1px solid #e2e8f0;
  font-size: 15px;
  color: #0f172a;
}
.help-section .help-block h4 {
  margin: 0 0 6px 0;
  font-size: 14px;
  font-weight: 600;
  color: #0f172a;
}
.help-section .help-muted {
  color: #64748b;
  font-size: 12.5px;
  margin: 0 0 12px 0;
}
.help-list {
  margin: 0; padding-left: 18px;
  color: #1e293b;
  font-size: 13px;
  line-height: 1.55;
}
.help-list li { margin: 4px 0; }

.help-kv-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}
.help-kv-table th, .help-kv-table td {
  padding: 6px 8px;
  border-bottom: 1px solid #f1f5f9;
  text-align: left;
  vertical-align: top;
}
.help-kv-table th {
  color: #475569;
  font-weight: 600;
  width: 40%;
  background: #f8fafc;
}
.help-kv-table td {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: #0f172a;
  word-break: break-word;
}

.help-field { display: block; margin: 10px 0 12px 0; }
.help-field-label {
  font-size: 12.5px; font-weight: 600;
  color: #334155;
  margin-bottom: 4px;
}
.help-field .input {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid #cbd5e1;
  border-radius: 6px;
  font-size: 13px;
  font-family: inherit;
  color: #0f172a;
  background: #ffffff;
  box-sizing: border-box;
}
.help-field textarea.input { resize: vertical; min-height: 140px; }
.help-field-actions { margin-top: 10px; }
.help-ticket-status {
  margin-top: 10px;
  font-size: 12.5px;
  padding: 8px 10px;
  border-radius: 6px;
  min-height: 1em;
}
.help-ticket-status.ok  { background: #ecfdf5; color: #065f46; border: 1px solid #a7f3d0; }
.help-ticket-status.err { background: #fef2f2; color: #991b1b; border: 1px solid #fecaca; }

/* Mobile: full-width drawer */
@media (max-width: 640px) {
  .help-drawer-panel { width: 100vw; }
}

/* v2.9.9z39 — Release entries in the What's New tab */
.help-release {
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  padding: 12px 14px;
  margin: 12px 0 14px 0;
  background: #ffffff;
}
.help-release-hdr {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}
.help-release-ver {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px; font-weight: 700;
  color: #0f172a;
  background: #f1f5f9;
  padding: 2px 8px;
  border-radius: 999px;
}
.help-release-date {
  font-size: 11.5px;
  color: #64748b;
}
.help-release-headline {
  font-size: 13.5px;
  font-weight: 600;
  color: #0f172a;
  margin: 4px 0 6px 0;
}
.help-release .help-list { font-size: 12.5px; }

/* ============================================================
 * v2.9.9z50 — Mobile a11y pass (375px)
 * ============================================================
 * IHSCs use the scheduler on their phones in the field. At 375px
 * (iPhone SE / 13 mini) the existing 720px breakpoint helps but
 * still leaves modal footers cramped, field-row3 too tight, and
 * tap targets below the 44px iOS guideline.
 */
@media (max-width: 480px) {
  /* Modal backdrop: reclaim the 20px padding — phone screens are precious. */
  .modal-backdrop { padding: 0; align-items: stretch; }

  /* Modal fills the screen edge-to-edge, no rounded corners. */
  .modal, .modal-wide {
    max-width: 100%; width: 100%;
    max-height: 100vh; min-height: 100vh;
    border-radius: 0;
    display: flex; flex-direction: column;
  }

  /* Header stays visible at the top while the body scrolls. */
  .modal-header {
    position: sticky; top: 0; z-index: 2;
    background: var(--surface);
    padding: 14px 16px;
    /* z50: bigger close-× tap target for thumbs. */
    min-height: 52px;
  }
  .modal-header h2 { font-size: 17px; line-height: 1.25; }
  .modal-header .btn-icon,
  .modal-header button {
    min-width: 44px; min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 22px; line-height: 1;
  }

  /* Body scrolls independently of the sticky header + footer. */
  .modal-body {
    padding: 16px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    flex: 1 1 auto;
  }

  /* Footer sticks to the bottom for reliable "Save"/"Cancel" reach. */
  .modal-footer {
    position: sticky; bottom: 0; z-index: 2;
    background: var(--surface);
    padding: 12px 16px;
    border-top: 1px solid var(--line);
    box-shadow: 0 -2px 6px rgba(15, 35, 45, 0.06);
    flex-wrap: wrap;
    justify-content: stretch;
    gap: 8px;
  }
  .modal-footer .btn {
    flex: 1 1 auto;
    min-height: 44px;
    padding: 10px 14px;
    font-size: 15px;
  }
  /* Primary action stays on top when we stack. */
  .modal-footer .btn-primary { order: -1; flex-basis: 100%; }

  /* Collapse field grids to single column. field-row already collapses at
   * 720px; field-row3 (New Booking type/outcome/slots) also gets forced
   * to a single column here as extra insurance. */
  .field-row, .field-row3 { grid-template-columns: 1fr !important; gap: 10px; }

  /* Bigger form controls on touch. iOS won't zoom text inputs whose
   * font-size is >= 16px, which matters for our sign-in flow embedded
   * in a Places autocomplete. */
  .field input[type="text"],
  .field input[type="email"],
  .field input[type="tel"],
  .field input[type="number"],
  .field input[type="date"],
  .field input[type="time"],
  .field input[type="search"],
  .field select,
  .field textarea {
    font-size: 16px;
    min-height: 44px;
    padding: 10px 12px;
  }
  .field textarea { min-height: 88px; }

  /* Tabs inside modals (used by Booking Detail: Details / History / Comm) */
  .tabs { overflow-x: auto; flex-wrap: nowrap; }
  .tab {
    flex-shrink: 0;
    min-height: 44px; padding: 10px 14px;
    font-size: 14px;
  }

  /* Help drawer: full-screen on phones. */
  .help-drawer-panel {
    width: 100vw !important;
    max-width: 100vw !important;
  }
  .help-drawer-close {
    min-width: 44px; min-height: 44px;
    font-size: 22px;
  }
  .help-tabbar { overflow-x: auto; flex-wrap: nowrap; }
  .help-tab {
    flex-shrink: 0;
    min-height: 44px; padding: 10px 12px;
    font-size: 13px;
  }

  /* Idle-warn card: full-width buttons stacked. */
  .idle-warn-card {
    margin: 0 12px;
    max-width: calc(100vw - 24px);
  }
  .idle-warn-actions {
    flex-direction: column-reverse;
    gap: 8px;
  }
  .idle-warn-actions .btn {
    width: 100%; min-height: 44px;
  }
}

/* iOS Safari 100vh includes the address bar; use svh where supported for
 * exact viewport fit. Falls back to 100vh above. */
@supports (height: 100svh) {
  @media (max-width: 480px) {
    .modal, .modal-wide {
      max-height: 100svh; min-height: 100svh;
    }
  }
}

/* ============================================================
   v2.9.9z51 — Staff-side look-and-feel polish
   Low-risk visual and accessibility improvements applied in one
   isolated block so they're easy to review or roll back. Nothing
   here changes layout structure or component APIs.
   ============================================================ */

/* Keyboard-only focus ring on interactive elements. Browsers still
   suppress the ring on mouse click (:focus-visible) but keyboard
   users get a clear indicator. */
.btn:focus-visible,
button:focus-visible,
select:focus-visible,
input:focus-visible,
textarea:focus-visible,
a:focus-visible,
[role="button"]:focus-visible,
[tabindex]:not([tabindex="-1"]):focus-visible {
  outline: 2px solid var(--primary, #2563eb);
  outline-offset: 2px;
  border-radius: 6px;
}
/* Suppress the default browser focus ring for mouse users. */
.btn:focus:not(:focus-visible),
button:focus:not(:focus-visible),
select:focus:not(:focus-visible),
input:focus:not(:focus-visible),
textarea:focus:not(:focus-visible) {
  outline: none;
}

/* Sortable column headers — indicate they're clickable. */
.users-head [role="button"],
.users-head button,
.users-head .sortable {
  cursor: pointer;
  user-select: none;
  transition: color .12s;
}
.users-head [role="button"]:hover,
.users-head button:hover,
.users-head .sortable:hover {
  color: var(--ink, #0f172a);
}

/* Slightly tighter, more legible small-text muted labels used all
   over the admin panes. Improves scanability without changing the
   type scale. */
.muted.small,
.small.muted {
  line-height: 1.4;
}

/* Data-table row hover — subtle highlight so admins see where they
   are while scanning long lists. Skipped on the header row. */
.users-table .users-row:not(.users-head):hover {
  background: rgba(37, 99, 235, 0.03);
}
.data-table tbody tr:hover {
  background: rgba(37, 99, 235, 0.03);
}

/* z51 alerts summary cell — tighten the badge-plus-list stack. */
.user-alerts-summary { align-items: flex-start; }
.user-alerts-summary ul li { padding: 1px 0; }

/* Empty-state polish — the "No results" muted-p we sprinkle
   everywhere. Center it and add breathing room. */
.empty-state,
.list-empty {
  padding: 24px 12px;
  text-align: center;
  color: var(--ink-muted, #64748b);
  font-size: 13px;
}

/* z51 last-login cell — muted "Never" gets a subtle dashed
   underline so it reads as "not set" not "missing data". */
.users-row .muted[title*="Has not signed in"] {
  border-bottom: 1px dashed var(--line, #e2e8f0);
  display: inline-block;
  padding-bottom: 1px;
}

/* Toast polish — soft shadow + smoother slide-in. Applies only if
   the toast root already exists (no impact when disabled). */
.toast {
  box-shadow: 0 4px 14px rgba(15, 23, 42, 0.12), 0 1px 4px rgba(15, 23, 42, 0.06);
}

/* Reduced-motion honor — respect the OS setting for users who need
   it. Kills page-level transitions/animations. Focus rings stay. */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ===== v2.9.9z60 ===== */

/* Bolder separators between IHSC rows (manager request — "make the lines
   between people bolder"). Applied to every cell in an IHSC row so the line
   runs the full grid width.
   z60a: var(--line-strong) still blended in on busy calendars (Justin, 8/9)
   — now a hard dark slate line. */
.grid-cell.ihsc-row-sep { border-top: 4px solid #475569; }

/* IHSC head: name + phone stacked. */
.ihsc-head-text { display: inline-flex; flex-direction: column; min-width: 0; }
.ihsc-head-name { overflow-wrap: break-word; } /* v2.9.9z74: was 'anywhere' (letter-stacking) */
.ihsc-phone {
  font-size: 11.5px; font-weight: 500; color: var(--ink-muted);
  text-decoration: none; margin-top: 1px;
}
.ihsc-phone:hover { color: var(--primary); text-decoration: underline; }
.r-ihsc-phone-input { max-width: 150px; }

/* Sales rep line on Normal-density tiles. */
.tile-rep-row {
  font-size: 11px; color: var(--ink-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* PICK UP SAMPLES tag — bold and loud on purpose, only rendered when set. */
.tile-samples {
  display: inline-block; font-size: 10px; font-weight: 800;
  letter-spacing: 0.04em; color: #92400e; background: #fef3c7;
  border: 1px solid #f59e0b; border-radius: 4px; padding: 1px 5px;
}

/* v2.9.9z60a: empty (+ Add) slots were near-invisible — white on white with
   a hairline dashed border. Darker dashed border + faint slate tint so open
   slots read as "bookable here" even on a packed calendar. */
.tile.empty {
  border: 1.5px dashed #64748b;
  background: rgba(100, 116, 139, 0.07);
}
.tile.empty .tile-empty-label { color: #475569; font-weight: 600; }
.tile.empty .tile-time { color: #475569; }

/* v2.9.9z60a: inline (confirmed) chip — normal view only. Sits on the
   bottom chips row instead of floating over the city name. */
.tile-confirmed-inline {
  display: inline-block; font-size: 10px; font-weight: 700;
  color: #15803d; background: rgba(220, 252, 231, 0.92);
  border: 1px solid rgba(21, 128, 61, 0.35); border-radius: 4px;
  padding: 0 5px; line-height: 1.5; white-space: nowrap;
}
.tile-chips-row { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }

/* Static (buttons-only) modals: pulse the border when a click bounces off
   the backdrop so staff learn where the exits are. */
@keyframes modalAttention {
  0%   { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.55); }
  100% { box-shadow: 0 0 0 14px rgba(220, 38, 38, 0); }
}
.modal.modal-attention { animation: modalAttention 0.45s ease-out 1; }

/* ===== v2.9.9z60c: print pagination fix ===== */
@media print {
  /* Chromium's CSS-grid fragmentation is unreliable: when an IHSC row is
     allowed to split at a page break (the z51 behavior), the overflowing
     tiles of a tall cell get painted OVER the first row of the next page
     (reported 8/9: Andrew's 4th appointment printed on top of Robert's
     row). Keep every cell — and therefore every IHSC row — unfragmented,
     and let the page break fall BETWEEN rows. With the z51 compact print
     tiles a full row is far shorter than a landscape page, so this no
     longer causes the blank-page-1 problem that motivated z51's
     allow-split rule. If a row ever exceeds a full page the browser will
     still split it as a last resort. */
  #gridHost .grid-cell {
    page-break-inside: avoid !important;
    break-inside: avoid !important;
  }
}

/* ===== v2.9.9z61: region top bar (follow-ups + manager notes) ===== */
.region-topbar {
  display: flex; flex-direction: column; gap: 6px;
  margin: 0 0 10px 0;
}
.topbar-strip {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  padding: 7px 10px; border-radius: 8px;
}
.topbar-followups {
  background: #fef2f2; border: 1px solid #fecaca;
}
.topbar-notes {
  background: #eff6ff; border: 1px solid #bfdbfe;
}
.topbar-label {
  font-size: 12px; font-weight: 800; letter-spacing: 0.03em;
  text-transform: uppercase; margin-right: 2px;
}
.topbar-followups .topbar-label { color: #b91c1c; }
.topbar-notes .topbar-label { color: #1d4ed8; }
.topbar-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; line-height: 1.4;
  padding: 3px 9px; border-radius: 999px;
  border: 1px solid transparent; background: #fff;
  color: var(--ink); text-align: left;
}
button.topbar-chip { cursor: pointer; }
button.topbar-chip:hover { filter: brightness(0.97); box-shadow: 0 1px 3px rgba(15,23,42,0.15); }
.topbar-chip strong { font-size: 10.5px; letter-spacing: 0.03em; }
.topbar-chip.chip-cancelled { border-color: #fca5a5; }
.topbar-chip.chip-cancelled strong { color: #b91c1c; }
.topbar-chip.chip-noshow { border-color: #fdba74; }
.topbar-chip.chip-noshow strong { color: #c2410c; }
.topbar-chip.chip-note { border-color: #bfdbfe; white-space: pre-wrap; }
.topbar-chip-x {
  border: none; background: transparent; cursor: pointer;
  color: var(--ink-muted); font-size: 14px; line-height: 1;
  padding: 0 2px; border-radius: 3px;
}
.topbar-chip-x:hover { color: #b91c1c; background: #fee2e2; }
.topbar-add-note { font-size: 12px; }

/* Print: follow-ups + notes are useful on paper (managers asked for the
   audit line) — keep them, compact, and never split across pages. */
@media print {
  .region-topbar { margin-bottom: 6px; }
  .topbar-strip {
    page-break-inside: avoid !important; break-inside: avoid !important;
    padding: 4px 6px;
  }
  .topbar-chip { font-size: 9.5px; padding: 1px 6px; }
  .topbar-add-note, .topbar-chip-x { display: none !important; }
}

/* ===== v2.9.9z62: search filters + print creator ===== */
.search-filter-row {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin-top: 8px;
}
.search-filter {
  font-size: 13px; padding: 6px 8px;
  border: 1px solid var(--line); border-radius: 6px; background: #fff;
  max-width: 220px;
}

/* Creator line on detailed tiles — paper only. */
.tile-createdby { display: none; }
@media print {
  .tile-createdby {
    display: block !important;
    font-size: 8px !important; color: #475569 !important;
    font-style: italic;
  }
}

/* ===== v2.9.9z63: live calendar filter ===== */
.cal-filter-wrap { display: inline-flex; align-items: center; gap: 2px; }
.cal-filter-input {
  font-size: 13px; padding: 6px 10px; width: 170px;
  border: 1px solid var(--line); border-radius: 8px;
  box-sizing: border-box;
}
/* z63a: fixed width — the focus-grow (150→200px) reflowed the whole
   toolbar every time the box gained/lost focus (Justin, 8/9). Focus is
   indicated by border color only; nothing moves. */
.cal-filter-input:focus { border-color: var(--primary); outline: none; }
/* Amber tint while a filter is active so nobody forgets it's on. */
.cal-filter-input.filter-active { background: #fef3c7; border-color: #f59e0b; }

/* While filtering: only matching appointment tiles remain. Hide the +Add
   pills, OFF strips/pills, and empty slots so the calendar reads clean,
   exactly like the old Kashmoo filter. */
#gridHost.cal-filtering .tile.empty,
#gridHost.cal-filtering .tile.timeoff-slot,
#gridHost.cal-filtering .timeoff-strip { display: none !important; }

/* ===== v2.9.9z64: note region checks + range suffix ===== */
.note-region-checks { display: flex; flex-wrap: wrap; gap: 4px 14px; padding: 4px 0; }
.note-region-check { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer; }
.note-range { color: #1d4ed8; font-weight: 600; font-size: 11px; }
/* v2.9.9z64a: note chips are clickable (edit) for managers */
.chip-note-editable { cursor: pointer; }
.chip-note-editable:hover { filter: brightness(0.96); }

/* ===== v2.9.9z65: custom per-IHSC schedules ===== */
.ihsc-sched-btn {
  margin-left: auto; flex: 0 0 auto;
  width: 22px; height: 22px; line-height: 20px;
  border: 1px solid var(--line); border-radius: 6px;
  background: #fff; color: #64748b; font-size: 13px;
  cursor: pointer; padding: 0;
}
.ihsc-sched-btn:hover { border-color: var(--primary); color: var(--primary); }
/* amber dot style when a custom schedule exists so managers can spot overrides */
.ihsc-sched-btn.has-custom { background: #fef3c7; border-color: #f59e0b; color: #92400e; }
.sched-list { display: flex; flex-direction: column; gap: 6px; }
.sched-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px;
  background: #f8fafc; font-size: 13px;
}
.sched-row.editing { border-color: var(--primary); background: #eff6ff; }
.sched-row-main { flex: 1 1 auto; min-width: 0; }

/* ===== v2.9.9z67: time-off types + clickable pills ===== */
/* The original .timeoff-strip had pointer-events:none — that's why hovering
   never showed a tooltip and clicks did nothing. Pills are interactive now. */
.timeoff-strip { pointer-events: auto; cursor: pointer; }
.tile.timeoff-slot { cursor: pointer; }
/* S&G RELATED = light teal WITH the same diagonal hatch as PERSONAL
   (v2.9.9z67a — Justin: stripes must clearly say "off / not bookable" for
   both types; the color alone tells you personal vs company work). */
.timeoff-strip.off-sg {
  background: repeating-linear-gradient(
    45deg, rgba(20, 184, 166, 0.14), rgba(20, 184, 166, 0.14) 8px,
    rgba(20, 184, 166, 0.32) 8px, rgba(20, 184, 166, 0.32) 16px);
  border: 1px solid rgba(20, 184, 166, 0.55);
  color: #0f766e;
}
.timeoff-strip.off-sg .timeoff-reason { color: #115e59; }
.timeoff-badge.off-sg { background: #0f766e; }
.tile.timeoff-slot.off-sg {
  background: repeating-linear-gradient(
    45deg, rgba(20, 184, 166, 0.14), rgba(20, 184, 166, 0.14) 8px,
    rgba(20, 184, 166, 0.32) 8px, rgba(20, 184, 166, 0.32) 16px);
  border: 1px solid rgba(20, 184, 166, 0.55);
  color: #0f766e;
}
.tile.timeoff-slot.off-sg .tile-time { color: #0f766e; }
.tile.timeoff-slot.off-sg .timeoff-reason { color: #115e59; }
/* type chips in the Time Off modal list + details modal header */
.to-type-chip {
  display: inline-block; font-size: 10px; padding: 1px 7px; border-radius: 999px;
  font-weight: 700; letter-spacing: 0.04em; vertical-align: middle;
}
.to-type-chip.to-personal { background: #fef3c7; color: #92400e; border: 1px solid #f59e0b; }
.to-type-chip.to-sg { background: #ccfbf1; color: #0f766e; border: 1px solid #14b8a6; }

/* ===== v2.9.9z69: sticky belt above the calendar + DO NOT COUNT chip ===== */
/* Everything above the date row now stays put while scrolling: alert banner,
   color legend, and the follow-ups/notes bar stack under the sticky page
   header. Their cumulative heights are published as CSS vars by
   _publishStickyHeights() so each layer parks exactly below the one above. */
#alertBanner {
  position: sticky;
  top: var(--header-h, 60px);
  z-index: 8;
  background: var(--bg);
}
#typeLegend {
  position: sticky;
  top: calc(var(--header-h, 60px) + var(--alert-h, 0px));
  z-index: 8;
  background: var(--bg);
}
.region-topbar {
  position: sticky;
  top: calc(var(--header-h, 60px) + var(--alert-h, 0px) + var(--legend-h, 0px));
  z-index: 7;
  background: var(--bg);
}
/* Date strip parks below the whole belt (was: directly below the header). */
.date-strip-wrap {
  top: calc(var(--header-h, 60px) + var(--alert-h, 0px) + var(--legend-h, 0px) + var(--topbar-h, 0px));
}

/* DO NOT COUNT tile chip — muted gray so it reads as "excluded", distinct
   from the green confirmed chip and amber PICK UP SAMPLES. */
.tile-dnc-inline {
  display: inline-block;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 1px 6px;
  border-radius: 3px;
  background: #e2e8f0;
  color: #475569;
  border: 1px dashed #94a3b8;
  white-space: nowrap;
}

/* ===== v2.9.9z71: IHSC display-order arrows (Settings → Regions & IHSCs) */
.r-ihsc-move {
  padding: 2px 7px;
  font-size: 11px;
  line-height: 1.2;
  flex: 0 0 auto;
}
.r-ihsc-move:disabled { opacity: 0.35; cursor: default; }

/* ===== v2.9.9z74 (8/23 item 4): month-view $ sold badge ===== */
.month-mini-sold {
  margin-left: auto;
  flex: 0 0 auto;
  font-weight: 800;
  font-size: 11px;
  color: #fff;
  background: #16a34a;
  border-radius: 999px;
  width: 15px; height: 15px;
  line-height: 15px;
  text-align: center;
}

/* ===== v2.9.9z74 (8/23 item 1): LEFT MESSAGE chip — amber, distinct from
   the green confirmed chip and the gray DO NOT COUNT chip. ===== */
.tile-leftmsg-inline {
  display: inline-block;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 1px 6px;
  border-radius: 3px;
  background: #fef3c7;
  color: #92400e;
  border: 1px solid #f59e0b;
  white-space: nowrap;
}

/* ===== v2.9.9z74 (8/23 item 2): print-mode menu + ink-saver print ===== */
.print-mode-menu {
  position: fixed;
  z-index: 9600;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(15,23,42,0.18);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 250px;
}
.print-mode-opt {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  padding: 9px 12px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  font: inherit;
}
.print-mode-opt:hover { background: var(--surface-muted, #f1f5f9); }
.print-mode-opt-label { font-size: 13.5px; font-weight: 600; color: var(--ink, #0f172a); }
.print-mode-opt-sub { font-size: 11.5px; color: var(--ink-muted, #64748b); }

@media print {
  /* Ink saver: every filled box prints WHITE with black text and a black
     border. !important also beats the inline background colors set per
     appointment type. Chips/badges keep their shape as outlined pills. */
  body.print-bw .tile,
  body.print-bw .tile * ,
  body.print-bw .month-mini-tile,
  body.print-bw .month-mini-tile *,
  body.print-bw .timeoff-strip,
  body.print-bw .timeoff-strip *,
  body.print-bw .timeoff-slot,
  body.print-bw .timeoff-slot *,
  body.print-bw .tile-note-recurring,
  body.print-bw .tile-note-recurring * {
    background: #fff !important;
    background-image: none !important;
    color: #000 !important;
    border-color: #000 !important;
    text-shadow: none !important;
    box-shadow: none !important;
  }
  body.print-bw .tile,
  body.print-bw .month-mini-tile,
  body.print-bw .timeoff-strip,
  body.print-bw .timeoff-slot { border: 1px solid #000 !important; }
  /* The colored type stripe / bar becomes a thin outlined cell so column
     alignment is preserved without ink. */
  body.print-bw .tile-stripe,
  body.print-bw .month-mini-bar { background: #fff !important; border-right: 1px solid #000 !important; }
  /* Legend + region tabs print as outlines. */
  body.print-bw .type-legend, body.print-bw .type-legend *,
  body.print-bw .type-legend-swatch {
    background: #fff !important; color: #000 !important; border-color: #000 !important;
  }
  body.print-bw .type-legend-swatch { border: 1px solid #000 !important; }
  /* Time-off diagonal stripe backgrounds are set inline via style attr on
     some paths — background-image:none above kills the stripes; the
     timeoff-badge keeps its label so OFF blocks stay identifiable. */
  /* Follow-up chips outline too (when printed from top of page). */
  body.print-bw .topbar-chip, body.print-bw .topbar-chip * {
    background: #fff !important; color: #000 !important; border-color: #000 !important;
  }
}

/* ===== v2.9.9z74 (8/23 item 5): follow-ups collapse on scroll + compact top ===== */
/* Hide ONLY the follow-up strip while scrolled; manager notes, alerts, and
   date headers stay. Never applies in print. */
@media screen {
  body.calendar-scrolled .topbar-followups { display: none !important; }
}

/* Compact the top chrome on desktop/tablet so the calendar gets more rows.
   Mobile (<=720px) keeps its own touch-target rules further down the sheet. */
@media (min-width: 721px) {
  .header-row { padding: 8px 20px; gap: 10px; }         /* was 14px 20px / 16px */
  .region-tabs { padding: 0 20px 8px; }                 /* was 0 20px 12px */
  .week-bar { padding: 0 20px 8px; }                    /* was 0 20px 14px */
  .week-label { min-width: 150px; }                     /* was 200px */
  .topbar-strip { padding-top: 5px; padding-bottom: 5px; }
}

/* ===== v2.9.9z74 (8/23 item 6): × on follow-up chips ===== */
.topbar-chip { position: relative; padding-right: 26px; }
.topbar-chip-clear {
  position: absolute;
  right: 4px; top: 50%;
  transform: translateY(-50%);
  width: 18px; height: 18px;
  line-height: 16px;
  border: 1px solid currentColor;
  border-radius: 999px;
  background: transparent;
  color: inherit;
  font-size: 12px;
  cursor: pointer;
  opacity: .55;
  padding: 0;
}
.topbar-chip-clear:hover { opacity: 1; background: rgba(0,0,0,0.06); }

/* ===== v2.9.9z74 (8/23 item 7): recurring tile notes ===== */
.tile-note-recurring {
  display: flex;
  align-items: flex-start;
  gap: 5px;
  padding: 4px 7px;
  border-radius: 6px;
  background: #ccfbf1;                 /* teal — matches the S&G event tone */
  border: 1px solid #5eead4;
  color: #115e59;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.25;
}
.tile-note-recurring.tile-note-editable { cursor: pointer; }
.tile-note-recurring.tile-note-editable:hover { background: #99f6e4; }
.tile-note-recurring-badge { flex: 0 0 auto; font-size: 10px; }
.tile-note-recurring-text { min-width: 0; overflow-wrap: break-word; }

.ihsc-note-btn {
  border: 1px solid var(--line);
  background: var(--surface, #fff);
  border-radius: 6px;
  font-size: 11px;
  padding: 2px 5px;
  cursor: pointer;
  flex: 0 0 auto;
  opacity: .75;
}
.ihsc-note-btn:hover { opacity: 1; }
.ihsc-note-btn.has-notes { background: #ccfbf1; border-color: #5eead4; opacity: 1; }

/* ===== v2.9.9z74 (8/23 item 3): one-page landscape day sheet ===== */
#daySheetHost { display: none; }

@media print {
  /* When printing the day sheet, it is the ONLY thing on paper.
     v2.9.9z75: hide every direct body child EXCEPT the sheet — the previous
     rule hid .header/main but left the empty .app-shell wrapper, whose
     min-height:100vh consumed all of page 1 (same mechanism as the old z21
     report blank-page bug), so the sheet printed on page 2. */
  body.printing-daysheet > :not(#daySheetHost) { display: none !important; }

  body.printing-daysheet #daySheetHost {
    display: block;
    color: #000;
    font-size: 8.5pt;
    line-height: 1.25;
  }
  .daysheet-title {
    display: flex; justify-content: space-between; align-items: baseline;
    border-bottom: 1.5pt solid #000;
    padding-bottom: 3pt; margin-bottom: 4pt;
    font-size: 11pt;
  }
  .daysheet-stamp { font-size: 7pt; color: #444; }
  .daysheet-table { width: 100%; }
  .daysheet-row {
    display: flex;
    align-items: stretch;
    border-bottom: 0.75pt solid #000;
    page-break-inside: avoid;
  }
  .daysheet-name {
    flex: 0 0 95pt;
    font-weight: 700;
    font-size: 9pt;
    padding: 3pt 4pt 3pt 0;
    border-right: 1.25pt solid #000;
    display: flex; flex-direction: column; justify-content: center;
  }
  .daysheet-name-phone { font-weight: 400; font-size: 7pt; color: #333; }
  .daysheet-boxes {
    flex: 1 1 auto;
    display: flex;
    flex-wrap: wrap;
    gap: 2pt;
    padding: 2pt 0 2pt 3pt;
    min-width: 0;
  }
  .daysheet-box {
    flex: 1 1 0;
    min-width: 110pt;
    border: 0.75pt solid #000;
    border-radius: 2pt;
    padding: 2pt 3pt;
    display: flex; flex-direction: column;
    background: #fff;
    overflow: hidden;
  }
  .daysheet-box-time { font-weight: 700; }
  .daysheet-box-note { font-weight: 700; }
  .daysheet-cancelled { text-decoration: line-through; }
  .daysheet-cancelled .daysheet-box-time { text-decoration: line-through; }
  .daysheet-off, .daysheet-open {
    justify-content: center; text-align: center;
    font-weight: 700; letter-spacing: .04em;
  }
  .daysheet-open { color: #555; border-style: dashed; font-weight: 400; }
  .daysheet-note { flex: 0 1 auto; min-width: 60pt; font-weight: 700; }
}

/* ===== v2.9.9z75: IHSC header tools row (under name), compact date header,
   header/toolbar consolidation ===== */
.ihsc-head-text { flex: 1 1 auto; min-width: 0; }
.ihsc-head-tools { display: flex; gap: 4px; margin-top: 4px; align-items: center; }
.ihsc-head-tools .ihsc-sched-btn { margin-left: 0; }

/* v2.9.9z75: brand block = title + (email · Sign out) on ONE line each. */
.brand-account { display: flex; align-items: center; gap: 8px; }
.btn-signout-inline {
  padding: 1px 8px;
  font-size: 11.5px;
  line-height: 1.4;
  border: 1px solid var(--line);
  border-radius: 5px;
  flex: 0 0 auto;
}

@media (min-width: 721px) {
  /* Date header row: the generic .grid-cell min-height:92px was the real
     height driver, not padding. 'Mon 17' needs ~48px. */
  .grid-cell.day-head { min-height: 44px; padding: 5px 8px; }
  .day-head .dom { font-size: 15px; }
  .grid-cell.ihsc-head { padding: 8px; }
  /* Tighter chrome: one-row toolbar at laptop widths. */
  .header-actions { gap: 6px; }
  .toolbar-label { display: none; }        /* "Tile info" — select keeps its title */
  .cal-filter-input { width: 140px; }
  .main { padding: 8px 24px 20px; }        /* was 20px top */
}

/* ===== v2.9.9z76: date strip on ONE line ("MON 17"), ~half the height ===== */
@media (min-width: 721px) {
  .grid-cell.day-head {
    min-height: 30px;
    padding: 4px 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
  }
  .day-head .dow { font-size: 11px; }
  .day-head .dom { font-size: 14px; font-weight: 700; }
  .grid-cell.corner-cell { min-height: 30px; padding: 4px 8px; display: flex; align-items: center; }
}

/* ===== v2.9.9z77: phone landscape week + chrome minimize button ===== */
/* The ⊖/⊕ button exists on phone-class devices only. */
#phoneChromeToggle { display: none; }

@media (max-width: 720px),
       ((pointer: coarse) and (orientation: landscape) and (max-width: 950px) and (max-height: 500px)) {
  #phoneChromeToggle {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 6px);
    right: calc(env(safe-area-inset-right, 0px) + 6px);
    z-index: 9400;
    width: 40px; height: 40px;
    border-radius: 999px;
    border: 1px solid var(--line);
    background: rgba(255,255,255,0.92);
    box-shadow: 0 2px 8px rgba(15,23,42,0.18);
    font-size: 20px;
    line-height: 1;
    color: #0f172a;
    padding: 0;
  }
  /* Collapsed: EVERYTHING above the dates goes away; date strip parks at 0. */
  body.phone-chrome-collapsed .header,
  body.phone-chrome-collapsed #alertBanner,
  body.phone-chrome-collapsed #typeLegend,
  body.phone-chrome-collapsed .region-topbar,
  body.phone-chrome-collapsed .mobile-day-pager { display: none !important; }
  body.phone-chrome-collapsed .main { padding: 4px; }
  body.phone-chrome-collapsed .date-strip-wrap { top: 0; }
}

@media print { #phoneChromeToggle { display: none !important; } }

/* v2.9.9z79: dashboard multi-select (regions / IHSCs) checkbox dropdown. */
.dash-multi { position: relative; display: inline-block; }
.dash-multi-btn { cursor: pointer; text-align: left; min-width: 130px; }
.dash-multi-pop {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 60;
  background: #fff; border: 1px solid var(--line, #e2e8f0); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15,23,42,.14);
  min-width: 210px; max-height: 280px; overflow-y: auto; padding: 6px;
}
.dash-multi-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px; border-radius: 6px; font-size: 13px; cursor: pointer;
  user-select: none; white-space: nowrap;
}
.dash-multi-row:hover { background: #f1f5f9; }
.dash-multi-row input { margin: 0; }

/* v2.9.9z79: Costco road show banners + manager modal. */
.tile-roadshow {
  display: flex; align-items: center; gap: 5px;
  padding: 2px 7px; margin: 0 0 3px; border-radius: 5px;
  font-size: 11px; font-weight: 700; line-height: 1.25;
  letter-spacing: .02em; cursor: default;
  border: 1px solid transparent; overflow: hidden;
}
.tile-roadshow.rs-open  { background: #ffedd5; color: #9a3412; border-color: #fdba74; }
.tile-roadshow.rs-close { background: #ede9fe; color: #5b21b6; border-color: #c4b5fd; }
.tile-roadshow[onclick], .tile-roadshow.rs-open:hover, .tile-roadshow.rs-close:hover { }
.tile-roadshow-badge { flex: 0 0 auto; }
.tile-roadshow-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
body.print-bw .tile-roadshow { background: #fff !important; color: #000 !important; border: 1px solid #000 !important; }

.roadshow-event { border: 1px solid #e2e8f0; border-radius: 8px; padding: 10px 12px; margin: 0 0 12px; }
.roadshow-event-head { display: flex; align-items: center; margin-bottom: 8px; }
.roadshow-grid {
  display: grid; grid-template-columns: 110px 1fr 1fr; gap: 4px 8px;
  align-items: center; font-size: 13px;
}
.roadshow-grid-head { font-weight: 600; font-size: 12px; color: #64748b; }
.roadshow-grid-day { font-weight: 600; }
.roadshow-grid-cell { display: flex; align-items: center; gap: 6px; min-height: 30px; }
.roadshow-grid-cell.rs-assigned { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 6px; padding: 3px 8px; font-weight: 600; color: #166534; }
.roadshow-pick { width: 100%; max-width: 220px; }
.roadshow-x {
  margin-left: auto; border: none; background: transparent; color: #b91c1c;
  font-size: 15px; font-weight: 700; cursor: pointer; padding: 0 4px; line-height: 1;
}
.roadshow-report { border-collapse: collapse; }
.roadshow-report th, .roadshow-report td { border: 1px solid #e2e8f0; padding: 4px 12px; text-align: left; font-size: 13px; }
.roadshow-report th { background: #f8fafc; }
.tile-roadshow.rs-clickable { cursor: pointer; }
.tile-roadshow.rs-clickable:hover { filter: brightness(0.96); }

/* v2.9.9z79a: archived IHSC rows — visible history, clearly not bookable. */
.ihsc-archived { opacity: .62; }
.ihsc-archived .ihsc-head-name { text-decoration: line-through; text-decoration-thickness: 1px; }
.ihsc-archived-cell { background: repeating-linear-gradient(45deg, #f8fafc 0 10px, #f1f5f9 10px 20px); }
.ihsc-archived-cell .tile { opacity: .82; }
.ihsc-archived-chip {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  background: #e2e8f0; color: #475569; font-size: 9.5px; font-weight: 800;
  letter-spacing: .06em; margin-top: 2px;
}

/* v2.9.9z80: iPhone — the ZIP row overflowed and cut off the Check
 * availability button. On narrow screens the button drops to its own
 * full-width line under the ZIP input. */
@media (max-width: 480px) {
  .zip-row { flex-wrap: wrap; }
  .zip-row input { flex: 1 1 100%; min-width: 0; }
  .zip-row .btn { flex: 1 1 100%; justify-content: center; padding: 12px; }
}
