/* Soonest-availability slot highlight. Applied to OPEN cells in the
   earliest time slot of the day where any visible tech is free.
   Uses the Sunwave light-blue (#BFE0F3) calm support accent per
   the philosophy doc so it complements the orange (selection) and
   gold (previous tech) without competing. */
.admin-cal-cell--soonest.admin-cal-cell--open {
  background: rgba(31, 90, 134, 0.10);
  border-color: rgba(31, 90, 134, 0.32);
  color: #1F5A86;
}
.admin-cal-cell--soonest.admin-cal-cell--open:hover {
  background: rgba(31, 90, 134, 0.18);
  border-color: rgba(31, 90, 134, 0.45);
}
/* If a cell is BOTH soonest AND in the previous-tech row, the
   soonest blue wins — that's the strongest recommendation and
   should read clearly. */
.admin-cal-cell--soonest.admin-cal-cell--prev.admin-cal-cell--open {
  background: rgba(31, 90, 134, 0.10);
  border-color: rgba(31, 90, 134, 0.32);
  color: #1F5A86;
}
/* Legend pill row above the grid — describes the in-grid color
   highlights. Pills are non-interactive (just a key), small, and
   only render when their highlight is actually present on this
   day (calendar.js filters the list). */
/* Controls row — job-length box (left) + legend pills (right) on one
   line so the slot grid rises. They used to be two stacked full-width
   rows. Wraps on narrow widths. */
.admin-cal-controls-row {
  display: flex;
  align-items: center;
  gap: 10px 14px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.admin-cal-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  /* Pushed to the right of the job-length box on the shared controls
     row; margin-left:auto only bites when both are on the same line. */
  margin-left: auto;
}
.admin-cal-legend[hidden] { display: none; }
.admin-cal-legend-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 999px;
  font: inherit;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: #373B4D;
  white-space: nowrap;
}
/* Clickable variant — renders as a <button>. Cursor pointer +
   subtle hover wash + active press feedback so the pill reads as
   "I can click this." */
button.admin-cal-legend-pill {
  cursor: pointer;
  transition: background 0.14s ease, border-color 0.14s ease,
              transform 0.08s ease, box-shadow 0.14s ease;
}
button.admin-cal-legend-pill:hover {
  background: #FFFAF1;
  border-color: rgba(243, 138, 63, 0.40);
  color: #B86012;
  box-shadow: 0 2px 8px rgba(60, 42, 16, 0.06);
}
button.admin-cal-legend-pill:hover .admin-cal-legend-dot {
  box-shadow: 0 0 0 3px rgba(243, 138, 63, 0.12);
}
button.admin-cal-legend-pill:active { transform: scale(0.97); }
button.admin-cal-legend-pill:focus-visible {
  outline: 2px solid #F38A3F;
  outline-offset: 2px;
}
/* Empty-state variant — rendered when there's nothing to jump to
   (no soonest slot in the visible window / no previous tech for
   the picked customer). Muted so the pill reads as a "this is
   what would be here" placeholder, not an actionable control. */
.admin-cal-legend-pill.is-empty {
  background: #FFFDF9;
  color: #8A8475;
  border-color: rgba(229, 222, 211, 0.7);
  cursor: not-allowed;
  opacity: 0.7;
}
.admin-cal-legend-pill.is-empty .admin-cal-legend-dot {
  opacity: 0.55;
}
.admin-cal-legend-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: 0 0 9px;
}
.admin-cal-legend-pill--soonest .admin-cal-legend-dot {
  background: #1F5A86;
}
.admin-cal-legend-pill--prev .admin-cal-legend-dot {
  background: #D39A2E;
}
.admin-cal-tech-head strong {
  display: block;
  font-size: 0.98rem;
  font-weight: 800;
  color: #373B4D;
  line-height: 1.2;
  letter-spacing: -0.005em;
}
.admin-cal-tech-head small {
  display: block;
  font-size: 0.74rem;
  color: #7B8190;
  margin-top: 3px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.admin-cal-time-head {
  /* Now a top-row COLUMN header (was a left-column row label before
     the axis flip). Centered text, slot label in tabular nums, sits
     above each slot column. Bolder than the old side-label
     treatment so it reads as a real header for the column under it. */
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.82rem;
  font-weight: 800;
  color: #373B4D;
  padding: 10px 10px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: center;
  letter-spacing: 0.02em;
}
.admin-cal-cell {
  border: 1px solid transparent;
  border-radius: 10px;
  padding: 11px 6px;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  font-family: inherit;
  text-align: center;
  font-variant-numeric: tabular-nums;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease, transform 0.06s ease;
}
.admin-cal-cell:focus { outline: none; box-shadow: 0 0 0 3px rgba(243, 138, 63, 0.22); }
.admin-cal-cell--open {
  /* Positive-green wash on warm canvas — same green family as the
     paid-invoice pill, so "open slot" and "paid" both read as good
     things at a glance. */
  background: rgba(75, 170, 120, 0.10);
  color: #2E7D4F;
  border-color: rgba(75, 170, 120, 0.22);
}
.admin-cal-cell--open:hover {
  background: rgba(75, 170, 120, 0.18);
  border-color: rgba(75, 170, 120, 0.38);
}
.admin-cal-cell--busy {
  background: #FFFDF9;
  color: rgba(55, 59, 77, 0.32);
  border-color: transparent;
  cursor: not-allowed;
}
.admin-cal-cell--busy.admin-cal-cell--overrideable {
  cursor: pointer;
}
.admin-cal-cell--busy.admin-cal-cell--overrideable:hover {
  background: rgba(243, 138, 63, 0.10);
  color: #C4631F;
  border-color: rgba(243, 138, 63, 0.24);
}
.admin-cal-cell.is-selected {
  background: #F38A3F;
  color: #fff;
  border-color: #F38A3F;
  box-shadow: 0 4px 14px rgba(243, 138, 63, 0.32);
}
.admin-cal-cell.is-selected.is-override {
  background: #C4631F;
  border-color: #C4631F;
}
.admin-cal-cell.is-selected:hover {
  background: #E07A2A;
}

/* ─── Multi-slot booking states ─────────────────────────────────
   Cells that are individually open but don't fit a multi-slot run
   ("Short"): legible-but-demoted, cursor not-allowed so admins can't
   accidentally click a slot lacking consecutive coverage. */
.admin-cal-cell--short {
  background: rgba(75, 170, 120, 0.04);
  color: rgba(46, 125, 79, 0.50);
  border-color: rgba(75, 170, 120, 0.18);
  cursor: not-allowed;
}
.admin-cal-cell--short:hover {
  background: rgba(75, 170, 120, 0.07);
  border-color: rgba(75, 170, 120, 0.28);
}
/* Reject shake — bounces the cell back when the admin clicks a slot
   that lacks consecutive coverage. Short, single-axis horizontal
   shake (≤4px). Self-removes after the keyframe so the cell goes
   back to its short-state appearance. */
@keyframes adminCalRejectShake {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-3px); }
  40%      { transform: translateX(3px); }
  60%      { transform: translateX(-2px); }
  80%      { transform: translateX(2px); }
}
.admin-cal-cell--reject-shake {
  animation: adminCalRejectShake 0.42s ease;
}
@media (prefers-reduced-motion: reduce) {
  .admin-cal-cell--reject-shake { animation: none; }
}
/* Hover preview band for multi-slot runs. Lights the N cells that
   would be reserved as the admin hovers a valid start cell. Softer
   than .is-selected so the difference between "previewing" and
   "actually picked" reads clearly. Combined with the bracket-like
   border treatment via a tinted backdrop instead of an outline so
   stacked cells in the run merge visually. */
.admin-cal-cell--run-preview {
  background: rgba(243, 138, 63, 0.14) !important;
  border-color: rgba(243, 138, 63, 0.38) !important;
  color: #C4631F !important;
}
.admin-cal-cell--run-preview:hover {
  background: rgba(243, 138, 63, 0.22) !important;
}
/* Trail cells in a selected multi-slot run. The CLICKED cell uses
   the standard .is-selected orange + pulse; trail cells share the
   selected fill but get a slight ribbon-style left border so the
   group reads as one continuous reservation rather than separate
   selections. The bookend-style left border on each trail visually
   stitches them into a band. */
.admin-cal-cell--run-trail {
  position: relative;
}
.admin-cal-cell--run-trail::before {
  content: '';
  position: absolute;
  left: -4px;
  top: 50%;
  width: 7px;
  height: 2px;
  background: #F38A3F;
  transform: translateY(-50%);
  border-radius: 2px;
  pointer-events: none;
}

/* Job-length picker row above the calendar grid. Inline label +
   small select + optional hint chip. Sits between the warn banner
   and the legend pill row so it's clearly tied to "what kind of
   job we're booking." */
.admin-cal-length-row {
  display: flex;
  align-items: center;
  gap: 10px;
  /* Margin removed — the box now lives inside .admin-cal-controls-row,
     which owns the spacing below it. */
  margin-bottom: 0;
  padding: 6px 8px;
  background: #FCFAF6;
  border: 1px solid #ECE5D6;
  border-radius: 10px;
  flex-wrap: wrap;
}
.admin-cal-length-label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #8A8475;
  margin: 0;
}
.admin-cal-length-select {
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  color: #373B4D;
  padding: 5px 28px 5px 10px;
  background: #FFFFFF;
  border: 1px solid #DDD3BA;
  border-radius: 8px;
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6' fill='none' stroke='%237A7466' stroke-width='1.6'><path d='M1 1l4 4 4-4'/></svg>");
  background-repeat: no-repeat;
  background-position: right 9px center;
  background-size: 9px 5px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.admin-cal-length-select:hover { border-color: #C8BDA0; }
.admin-cal-length-select:focus-visible {
  outline: none;
  border-color: transparent;
  box-shadow: var(--sw-focus-shadow, 0 0 0 1px #F38A3F, 0 6px 13px rgba(243, 138, 63, 0.30));
}
.admin-cal-length-hint {
  font-size: 0.72rem;
  font-weight: 600;
  color: #7A7466;
  background: #F2EAD3;
  padding: 3px 9px;
  border-radius: 999px;
}
.admin-cal-length-hint[hidden] { display: none; }

/* ─── Drive-time annotation on admin cells ───────────────────────
   Small text that appears at the bottom of each OPEN cell once the
   /drive-times overlay resolves. Sits inside the cell in normal flow,
   stacked under the existing "Open" label. The cell becomes flex
   column so the label centers and the drive line tucks under it with
   a hairline of gap. Only present after the lazy fetch lands — until
   then the cell is exactly as before. */
.admin-cal-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
}
.admin-cal-cell-drive {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: none;
  color: #7A7466;
  background: rgba(255, 255, 255, 0.55);
  padding: 1px 7px;
  border-radius: 999px;
  line-height: 1.3;
  white-space: nowrap;
  /* Subtle fade-in so the overlay arrival doesn't feel jumpy. The
     0.18s matches the grid cell stagger ramp at the top of renderDay
     so the drive-time line feels like part of the same paint. */
  animation: adminCalDriveFade 0.25s ease both;
}
@keyframes adminCalDriveFade {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .admin-cal-cell-drive { animation: none; }
}
/* Quieter variant for techs whose first job of the day IS this slot.
   No driving cost, but admins still benefit from knowing the tech
   hasn't started yet (vs. "missing" annotation which could mean
   anything). Italic + lower contrast so it reads as a side-note. */
.admin-cal-cell-drive--first {
  color: #9A9485;
  font-style: italic;
  background: transparent;
}
/* First job of the day measured from the tech's home base. Calm blue
   support pill (the secondary accent) so it reads as a real drive but
   from home, distinct from the gray prev-job drive. Defined before
   --shortest so the green shortest-winner treatment still wins when a
   home-origin cell is also the closest at its slot. */
.admin-cal-cell-drive--home {
  background: #E4F1FA;
  color: #1F5A86;
}
/* Shortest-drive winner at a given slot time. Sage-green pill so the
   admin can scan a slot row and pick the tech with minimum routing
   impact. Only applied when ≥2 techs are competing for that slot. */
.admin-cal-cell-drive--shortest {
  background: #DDEFE3;
  color: #1F6A41;
}
/* Selected cell flips drive-time to a translucent white-on-orange
   pill so it stays legible against the bright orange selected
   background. Otherwise the muted gray vanishes. */
.admin-cal-cell.is-selected .admin-cal-cell-drive {
  background: rgba(255, 255, 255, 0.22);
  color: rgba(255, 255, 255, 0.9);
}
.admin-cal-cell.is-selected .admin-cal-cell-drive--shortest {
  background: rgba(255, 255, 255, 0.32);
  color: #fff;
}
.admin-cal-cell.is-selected .admin-cal-cell-drive--home {
  background: rgba(255, 255, 255, 0.28);
  color: #fff;
}
/* Loading placeholder — three tiny dots that pulse in sequence while
   the /drive-times fetch is in flight. Minimum visual weight: only
   ~10px wide so it doesn't shift the grid much; replaced inline once
   the response arrives. */
.admin-cal-cell-drive--loading {
  padding: 3px 7px;
  background: transparent;
  gap: 3px;
}
.admin-cal-cell-drive--loading > span {
  width: 3px;
  height: 3px;
  background: #BBB3A0;
  border-radius: 50%;
  animation: adminCalDriveDots 1.2s ease-in-out infinite;
}
.admin-cal-cell-drive--loading > span:nth-child(2) { animation-delay: 0.15s; }
.admin-cal-cell-drive--loading > span:nth-child(3) { animation-delay: 0.3s; }
@keyframes adminCalDriveDots {
  0%, 80%, 100% { opacity: 0.25; transform: scale(0.8); }
  40%           { opacity: 1;    transform: scale(1.1); }
}
@media (prefers-reduced-motion: reduce) {
  .admin-cal-cell-drive--loading > span { animation: none; opacity: 0.5; }
}

/* ─── Admin booking page · 2-col left-rail layout ──────────────
   Activated by the booking-page--admin class on <main>. Banner spans
   both columns at the top; customer-history rail occupies column 1;
   the form occupies column 2. Collapses to single-column under 960px
   so phone-booked-by-CSR-on-a-tablet still works. */
.booking-page--admin {
  width: 100%;
  max-width: 1680px;
  display: grid;
  grid-template-columns: minmax(300px, 360px) minmax(760px, 1fr);
  /* Tighter horizontal gap between the customer rail and the form
     column, plus a tighter vertical gap between the full-width banner
     row and the rail+form row. Was 28px; the mockup landed closer to
     20px and the page reads denser without feeling crowded. */
  gap: 20px;
  align-items: start;
}
.booking-page--admin > .alert,
.booking-page--admin > .admin-booking-banner { grid-column: 1 / -1; }
/* Left rail wrapper — stacks the customer rail + keyboard shortcuts
   card with a small gap, so the card sits directly under the
   customer rail without inheriting the grid's row 3 placement
   (which would push it down to align with the bottom of the form). */
.booking-page--admin > .admin-rail-column {
  grid-column: 1;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
  /* Stretch the rail column to the same height as the form column so
     the recent-bookings card at the bottom can grow to fill remaining
     vertical space (its own list scrolls internally). Without this,
     the rail would only be as tall as its natural content and the
     recent-bookings card would sit short, leaving a big void next to
     the scheduler. */
  align-self: stretch;
  min-height: 0;
}
.booking-page--admin > form#booking-form { grid-column: 2; }
@media (max-width: 1180px) {
  .booking-page--admin {
    grid-template-columns: minmax(280px, 320px) minmax(0, 1fr);
    gap: 22px;
  }
}
@media (max-width: 960px) {
  .booking-page--admin {
    grid-template-columns: 1fr;
    max-width: 100%;
  }
  .booking-page--admin > .admin-rail-column { grid-column: 1; }
  .booking-page--admin > form#booking-form { grid-column: 1; }
}

/* ─── Wizard step scoping: the left rail is Customer-step only ─────
   (2026-06-14) In the stepped admin wizard the left column (customer
   context + shortcuts + recent bookings) belongs to the Customer
   step. On Schedule (2), Work (3), and the success screen (5) it is
   hidden and the form takes the full width, so the scheduler isn't
   boxed into a narrow column. Driven by data-active-step — which
   showStep keeps in sync on #step-card — and scoped to wizard mode
   via the form flag so the classic single-page layout is untouched.
   Pure CSS via :has(); no JS hook needed. */
.booking-page--admin:has(form[data-admin-wizard="1"] #step-card[data-active-step="2"]),
.booking-page--admin:has(form[data-admin-wizard="1"] #step-card[data-active-step="3"]),
.booking-page--admin:has(form[data-admin-wizard="1"] #step-card[data-active-step="5"]) {
  grid-template-columns: 1fr;
}
.booking-page--admin:has(form[data-admin-wizard="1"] #step-card[data-active-step="2"]) > .admin-rail-column,
.booking-page--admin:has(form[data-admin-wizard="1"] #step-card[data-active-step="3"]) > .admin-rail-column,
.booking-page--admin:has(form[data-admin-wizard="1"] #step-card[data-active-step="5"]) > .admin-rail-column {
  display: none;
}
.booking-page--admin:has(form[data-admin-wizard="1"] #step-card[data-active-step="2"]) > form#booking-form,
.booking-page--admin:has(form[data-admin-wizard="1"] #step-card[data-active-step="3"]) > form#booking-form,
.booking-page--admin:has(form[data-admin-wizard="1"] #step-card[data-active-step="5"]) > form#booking-form {
  grid-column: 1 / -1;
}

/* ─── Wizard: one column, customer rail tucked UNDERNEATH the form ──
   (2026-06-14) The admin scheduler now reads straight down a single
   column — stepper → customer search → form — with the customer
   context rail (profile + keyboard shortcuts + recent bookings) sitting
   BELOW the card on the Customer step instead of in a side column. So
   nothing is boxed into a narrow rail and the admin isn't asked to fill
   the whole left column before moving on. The DOM order stays banner →
   rail → form; `order` re-flows the render to banner → form → rail
   without touching the markup (every listener stays bound by id). The
   step-scoping block above still hides the rail on Schedule/Work/
   success, and .step-card's own per-step max-width keeps the form a
   comfortable width even though the page is now full-bleed. */
.booking-page--admin:has(form[data-admin-wizard="1"]) {
  grid-template-columns: 1fr;
}
.booking-page--admin:has(form[data-admin-wizard="1"]) > form#booking-form {
  grid-column: 1;
  order: 1;
}
.booking-page--admin:has(form[data-admin-wizard="1"]) > .admin-rail-column {
  grid-column: 1;
  order: 2;
  /* Center the stacked rail under the Customer-step card (both 1120px wide)
     so it lines up beneath the now-centered card (2026-06-16). No full-
     height stretch — underneath, it's natural height. */
  width: 100%;
  max-width: 1120px;
  justify-self: center;
  align-self: start;
}
/* Center the wizard on screen (2026-06-16, REVERSES the earlier left-
   align). The stepper and the step-card keep their default margin:0 auto,
   so the 1·2·3 and the cards beneath sit centered in the content area
   instead of hugging the left edge. The Customer step no longer has a
   separate grid override — its customer strip flows inline inside the
   card (see the strip restyle below). */

/* ─── Wizard Customer step: compact inline strip (2026-06-16) ─────────
   RETIRES the side-by-side "Option A" cockpit. admin-wizard.js now moves
   the customer-context rail (#admin-customer-context) INTO the Customer
   panel, so the first page flows search → customer strip → fields in one
   column instead of splitting into a rail + form. With the rail inside
   the form there's nothing to lay out in a second grid column — the base
   single-column wizard block above already centers the page. What's left
   here is the STRIP restyle of the rail: slimmer padding, the stat band
   as a wrap of pills, and a quiet "View history" disclosure pill that
   holds the timeline, address, tags, and duplicates. The rail is only
   ever shown on the Customer step (it lives in that panel), so scoping to
   wizard mode targets just this surface. */
form[data-admin-wizard="1"] .wizard-customer-search { margin-bottom: 12px; }
form[data-admin-wizard="1"] .admin-customer-context--rail {
  padding: 16px 18px;
  margin-bottom: 4px;
}
/* Mode banner → one slim line. Drop the "changes save back" detail row;
   the eyebrow + Start fresh still say what submit will do. */
form[data-admin-wizard="1"] .acc-mode {
  margin-bottom: 12px;
  padding: 7px 10px 7px 13px;
}
form[data-admin-wizard="1"] .acc-mode-detail { display: none; }
/* Tighter head — smaller name so identity reads as a strip, not a hero. */
form[data-admin-wizard="1"] .acc-head { margin-bottom: 12px; }
form[data-admin-wizard="1"] .acc-name { font-size: 1.06rem; margin-bottom: 2px; }
/* Stat band → a wrap of small bordered pills (number + label inline)
   instead of a boxed grid of big hero numbers. The loading skeleton
   keeps its own boxed look (excluded below). */
form[data-admin-wizard="1"] .acc-stats {
  gap: 8px;
  padding: 0;
  background: none;
  border: none;
  margin-bottom: 12px;
}
form[data-admin-wizard="1"] .acc-stat:not(.acc-stat--skeleton) {
  flex-direction: row;
  align-items: baseline;
  gap: 6px;
  padding: 5px 11px;
  background: var(--sw-card-lift, #FFFDF9);
  border: 1px solid var(--sw-border, #E5DED3);
  border-radius: 999px;
}
form[data-admin-wizard="1"] .acc-stat:not(.acc-stat--skeleton) .acc-stat-num {
  font-size: 0.95rem;
  font-weight: 700;
}
form[data-admin-wizard="1"] .acc-stat:not(.acc-stat--skeleton) .acc-stat-label {
  font-size: 0.72rem;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 600;
  color: var(--sw-muted, #7B8190);
}
/* "View history" disclosure → a quiet inline pill that hugs its label,
   not a full-width bar. */
form[data-admin-wizard="1"] .acc-more-toggle {
  width: auto;
  margin: 0;
  padding: 7px 13px;
  border-radius: 999px;
}
form[data-admin-wizard="1"] .acc-more-toggle-hint { flex: 0 0 auto; }
form[data-admin-wizard="1"] .acc-more--open { margin-top: 12px; }

/* Grouped form headings (2026-06-16) — small section labels over the
   contact cluster and the address block so the Customer form reads as two
   tidy groups, matching the compact mockup. Wizard-only; the classic
   single-page admin form is untouched. */
.wizard-group-label { display: none; }
form[data-admin-wizard="1"] .wizard-group-label {
  display: block;
  grid-column: 1 / -1;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--sw-muted, #7B8190);
  letter-spacing: 0.01em;
  margin: 2px 0 -2px;
}
/* The address autocomplete carries its own aria-label, so its visible
   "Service address" caption is redundant once the group heading shows —
   hide it visually but keep it for assistive tech. */
form[data-admin-wizard="1"] .address-field > span {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* ─── Wizard: customer search relocated into the Customer step ─────
   (2026-06-14) admin-wizard.js moves #admin-customer-search (+ the
   "Search all locations" scope toggle) out of the top banner row and
   into the top of the Customer step panel, so it reads as part of
   step 1 and is simply absent on steps 2/3 (their content sits
   higher). In this block context the search is full-width with the
   scope toggle stacked beneath it, not a flex item in the banner. */
.wizard-customer-search {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 18px;
}
.wizard-customer-search .admin-customer-search {
  flex: none;
  width: 100%;
  min-width: 0;
}

/* ─── Customer-context panel ────────────────────────────────────
   Lives as the left rail in admin mode (booking-page--admin). Sticky
   so it stays visible as the admin scrolls through the form below.
   Populated by booking.js from
   /admin/api/booking/:slug/customer/:id. Shows empty state until a
   customer is picked, then swaps to profile + stat row +
   recent-jobs + recent-invoices. Invoices section degrades gracefully
   when the location's HCP plan doesn't expose /invoices. */
.admin-customer-context {
  /* Hero bento card on the rail: warm card surface, large 22px
     squircle radius, soft-warm border instead of cool gray, ambient
     soft shadow with warm undertone. Padding bumped from 18/20 to 24
     per the philosophy's "oceans of whitespace" rule for major
     cards. */
  background: #FCFAF6;
  border: 1px solid #E5DED3;
  border-radius: 22px;
  /* Was 24px on every side. The rail reads denser in the mockup with
     ~18px padding — the inner blocks (head, stats, notes, history)
     have their own internal margins so the rail wrapper doesn't need
     this much of its own. */
  padding: 18px;
  box-shadow: 0 14px 36px rgba(55, 59, 77, 0.05),
              0 1px 0 rgba(255, 255, 255, 0.85) inset;
}
.admin-customer-context--rail {
  /* No inner scroll. The rail flows naturally with the page now —
     previously this had `position: sticky; max-height: calc(100vh
     - 32px); overflow-y: auto;` which made the rail a separate
     scrolling container, which read as funky next to the page's
     own scroll. The form column is almost always taller than the
     rail, so dropping the sticky behavior costs nothing in the
     common case, and tall histories now just extend the rail
     downward into the available page space. */
}

/* Empty state shown until a customer is picked. Calm, low-density
   so the rail doesn't feel like a wall of placeholder text. */
.acc-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 28px 12px 20px;
  color: var(--text-muted);
}
.acc-empty-icon {
  color: rgba(243, 138, 63, 0.55);
  margin-bottom: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  background: rgba(243, 138, 63, 0.08);
  border-radius: 50%;
}
.acc-empty-title {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--text);
  margin: 0 0 6px;
}
.acc-empty-body {
  font-size: 0.83rem;
  line-height: 1.45;
  margin: 0;
  max-width: 240px;
}
/* New-customer tag editor — surfaces in the empty rail once the
   admin starts typing a name (signaling "I'm creating a new
   customer"). Soft inset divider above so it reads as a separate
   sub-section, not part of the introductory empty state. */
.acc-empty-tags {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px dashed rgba(55, 59, 77, 0.18);
  width: 100%;
  max-width: 280px;
  text-align: left;
}
.acc-empty-tags-eyebrow {
  display: block;
  font-size: 0.66rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #7B8190;
  margin-bottom: 8px;
}
/* Customer mode banner — sits at the very top of the customer rail
   card when a customer is matched. Tells the admin what's happening
   ("you're editing this customer's HCP record") and carries the
   Start Fresh escape hatch for wrong-customer matches. Subtle warm
   inset wash so it reads as meta-context, not as primary content;
   the actual customer info below is still the hero. */
.acc-mode {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  padding: 9px 12px;
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 12px;
}
.acc-mode-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
}
.acc-mode-eyebrow {
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #7B8190;
}
.acc-mode-detail {
  font-size: 0.78rem;
  color: var(--text-muted);
  line-height: 1.35;
}
.acc-mode-start-fresh {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 11px;
  flex: 0 0 auto;
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 999px;
  color: #373B4D;
  font-size: 0.74rem;
  font-weight: 700;
  cursor: pointer;
  font-family: inherit;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.85) inset;
  transition: background 0.12s ease, border-color 0.12s ease,
              color 0.12s ease, transform 0.06s ease;
  white-space: nowrap;
}
.acc-mode-start-fresh svg { color: #7B8190; transition: color 0.12s ease, transform 0.2s ease; }
.acc-mode-start-fresh:hover {
  background: #FFFAF1;
  border-color: rgba(243, 138, 63, 0.4);
  color: #373B4D;
}
.acc-mode-start-fresh:hover svg { color: #F38A3F; transform: rotate(-90deg); }
.acc-mode-start-fresh:active { transform: scale(0.97); }
/* Future-proofing: variant for the "Creating a new customer" mode.
   Same structural rules, slightly orange-tinted wash so the admin
   can tell at a glance "no customer matched, this is fresh." Not
   yet emitted by booking.js — wired up in a later phase that adds
   an explicit "new customer" mode signal. */
.acc-mode--new {
  background: rgba(243, 138, 63, 0.08);
  border-color: rgba(243, 138, 63, 0.24);
}
.acc-mode--new .acc-mode-eyebrow { color: #B86012; }

.acc-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 14px;
}
.acc-head-text { flex: 1 1 auto; min-width: 0; }
.acc-name {
  display: block;
  font-size: 1.2rem;
  font-weight: 800;
  color: #373B4D;
  line-height: 1.25;
  letter-spacing: -0.015em;
  margin-bottom: 4px;
}
.acc-email, .acc-phone {
  display: inline-block;
  font-size: 0.85rem;
  color: #7B8190;
  margin-right: 12px;
  font-variant-numeric: tabular-nums;
}
.acc-meta {
  display: block;
  font-size: 0.74rem;
  color: #7B8190;
  margin-top: 6px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* ── Customer rail summary chrome (2026-06-14 redesign) ───────────
   Avatar with a tier-keyed status ring, tap-to-act contact links, the
   at-a-glance "signal" badge, and the "Show details" disclosure that
   keeps the rail compact on open. New classes only — the acc-* rules
   above are untouched. Tokens with hex fallbacks per the design
   system (this sheet predates the token migration). */
.acc-avatar {
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  border-radius: var(--sw-radius-pill, 999px);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--sw-blue, #BFE0F3);
  color: var(--sw-ink, #373B4D);
  font-weight: 800;
  font-size: 0.92rem;
  /* Status ring — soft halo keyed to the customer tier. */
  box-shadow: 0 0 0 2px var(--sw-card, #FCFAF6), 0 0 0 4px rgba(123, 129, 144, 0.28);
}
.acc-avatar-initials { line-height: 1; }
.acc-avatar--repeat {
  background: var(--sw-orange-soft, #FFEEDC);
  color: var(--sw-orange-dark, #C66518);
  box-shadow: 0 0 0 2px var(--sw-card, #FCFAF6), 0 0 0 4px rgba(243, 138, 63, 0.45);
}
.acc-avatar--vip {
  background: rgba(211, 154, 46, 0.16);
  color: var(--sw-orange-dark, #C66518);
  box-shadow: 0 0 0 2px var(--sw-card, #FCFAF6), 0 0 0 4px rgba(211, 154, 46, 0.5);
}

/* Tap-to-act contact lines — email opens the mail client, phone dials
   / texts. Quiet links: color + underline only on hover. */
a.acc-email, a.acc-phone {
  text-decoration: none;
  cursor: pointer;
  transition: color 0.12s ease;
}
a.acc-email:hover, a.acc-phone:hover {
  color: var(--sw-orange-dark, #C66518);
  text-decoration: underline;
}

/* Signal badge — gold "attention" wash (e.g. jobs on file but $0
   billed), never a screaming red panel. */
.acc-signal {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 16px;
  padding: 10px 13px;
  border-radius: 12px;
  font-size: 0.8rem;
  font-weight: 650;
  line-height: 1.35;
}
.acc-signal svg { flex: 0 0 auto; }
.acc-signal--attention {
  background: rgba(211, 154, 46, 0.14);
  color: var(--sw-orange-dark, #C66518);
}

/* Details disclosure — quiet full-width control; caret flips when
   open, the heavy sections fade in below it. */
.acc-more-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 0 0 14px;
  padding: 10px 14px;
  background: var(--sw-card-lift, #FFFDF9);
  border: 1px solid var(--sw-border, #E5DED3);
  border-radius: var(--sw-radius-input, 14px);
  color: var(--sw-ink, #373B4D);
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.acc-more-toggle:hover {
  background: #FFFAF1;
  border-color: rgba(243, 138, 63, 0.4);
}
.acc-more-toggle-label { font-size: 0.82rem; font-weight: 700; flex: 0 0 auto; }
.acc-more-toggle-hint {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.7rem;
  color: var(--sw-muted, #7B8190);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.acc-more-toggle-caret {
  flex: 0 0 auto;
  color: var(--sw-muted, #7B8190);
  transition: transform 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}
.acc-more-toggle[aria-expanded="true"] .acc-more-toggle-caret { transform: rotate(180deg); }

.acc-more { display: none; }
.acc-more--open {
  display: block;
  animation: accMoreIn 0.26s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes accMoreIn {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .acc-more--open { animation: none; }
  .acc-more-toggle-caret { transition: none; }
}

.acc-details {
  margin: 0 0 16px;
  padding: 12px 14px;
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 14px;
  display: grid;
  gap: 10px;
}
.acc-detail-row {
  display: grid;
  gap: 3px;
}
.acc-detail-label {
  margin: 0;
  color: #7B8190;
  font-size: 0.58rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.acc-detail-value {
  margin: 0;
  color: #373B4D;
  font-size: 0.82rem;
  line-height: 1.35;
  font-weight: 650;
  overflow-wrap: anywhere;
}

/* Tags row — soft inset pills, fully-rounded ends, all sit on one
   horizontal flow that wraps. Used for whatever HCP labels the
   customer with (VIP, do-not-service, frequent, etc.). */
.acc-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 16px;
}
.acc-tag {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(191, 224, 243, 0.42);
  color: #1F5A86;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}
/* Derived (synthesized server-side) tags read differently from HCP
   tags so admins know which labels came from Housecall Pro and which
   we computed. Warm inset wash + dashed hairline border + lighter
   weight — quieter than the blue HCP pill, but still clearly a tag. */
.acc-tag--derived {
  background: rgba(243, 138, 63, 0.10);
  color: #B86012;
  border: 1px dashed rgba(243, 138, 63, 0.42);
  font-weight: 600;
  padding: 3px 9px;
}

/* ─── Tag editor (admin-only) ──────────────────────────────────────
   Variant pills used by renderTagEditor when the customer rail is in
   edit mode. The four states map to the four tag kinds: hcp (real,
   removable), pending-add (queued, undo with ×), pending-remove
   (queued for delete, struck through, revert with ↶), and derived
   (read-only, lighter style — same as .acc-tag--derived above).
   The + Add chip sits at the end of the row. */
.acc-tags--editable {
  align-items: center;
}
/* Slight spacing tweak so the × button has visual room. */
.acc-tags--editable .acc-tag {
  padding-right: 4px;
}
.acc-tag-label {
  /* Reserves the same baseline as the bare pills so adding a button
     doesn't shift the pill height. */
  padding: 0 4px 0 2px;
}
.acc-tag-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-left: 2px;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  border-radius: 50%;
  cursor: pointer;
  font-size: 0.85rem;
  line-height: 1;
  opacity: 0.55;
  transition: opacity 0.12s ease, background 0.12s ease;
}
.acc-tag-btn:hover,
.acc-tag-btn:focus-visible {
  opacity: 1;
  outline: none;
  background: rgba(55, 59, 77, 0.10);
}
/* Pending-add: green pill, signals "this is queued, not yet on HCP". */
.acc-tag--pending-add {
  background: rgba(46, 138, 86, 0.16);
  color: #1F6B40;
  box-shadow: inset 0 0 0 1px rgba(46, 138, 86, 0.32);
}
.acc-tag--pending-add::before {
  content: '+';
  margin-right: 4px;
  font-weight: 800;
  font-size: 0.7rem;
  line-height: 1;
}
/* Pending-remove: strikethrough + muted color. Pill stays in place so
   the admin can revert with the ↶ button. */
.acc-tag--pending-remove {
  background: rgba(196, 53, 53, 0.10);
  color: #8B1F1F;
  text-decoration: line-through;
  text-decoration-color: rgba(139, 31, 31, 0.55);
}
/* + Add tag chip. Reads as a "do something" affordance — dashed
   hairline, neutral fill, snaps to a solid orange border on hover. */
.acc-tag-add {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px 4px 8px;
  border: 1px dashed rgba(55, 59, 77, 0.32);
  border-radius: 999px;
  background: transparent;
  color: #373B4D;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: border-color 0.14s ease, background 0.14s ease, color 0.14s ease;
}
.acc-tag-add:hover,
.acc-tag-add:focus-visible {
  outline: none;
  border-style: solid;
  border-color: #F38A3F;
  background: rgba(243, 138, 63, 0.10);
  color: #B86012;
}
.acc-tag-add svg { stroke: currentColor; }

/* Combobox dropdown — opens below the tag row when + Add fires.
   Warm-card chrome, soft border, generous padding so the suggestion
   list is comfortable to scan. */
.acc-tag-combobox {
  margin: 8px 0 16px;
  padding: 10px;
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 14px;
  box-shadow: 0 6px 18px rgba(55, 59, 77, 0.06),
              0 1px 0 rgba(255, 255, 255, 0.9) inset;
}
.acc-tag-combo-input-wrap {
  display: flex;
  align-items: center;
  gap: 6px;
}
.acc-tag-combo-input {
  flex: 1 1 auto;
  padding: 8px 12px;
  border: 1px solid #E5DED3;
  border-radius: 10px;
  background: #FCFAF6;
  font-size: 0.88rem;
  color: #373B4D;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.acc-tag-combo-input:focus {
  outline: none;
  background: #FFFDF9;
  border-color: transparent;
  box-shadow: var(--sw-focus-shadow, 0 0 0 1px #F38A3F, 0 6px 13px rgba(243, 138, 63, 0.30));
}
.acc-tag-combo-close {
  width: 26px;
  height: 26px;
  border: 0;
  background: transparent;
  color: #7B8190;
  font-size: 1rem;
  line-height: 1;
  border-radius: 50%;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.acc-tag-combo-close:hover,
.acc-tag-combo-close:focus-visible {
  outline: none;
  background: rgba(55, 59, 77, 0.08);
  color: #373B4D;
}
.acc-tag-combo-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  max-height: 240px;
  overflow-y: auto;
}
.acc-tag-combo-item {
  padding: 7px 10px;
  border-radius: 8px;
  cursor: pointer;
  font-size: 0.86rem;
  color: #373B4D;
  transition: background 0.12s ease;
}
.acc-tag-combo-item:hover,
.acc-tag-combo-item:focus {
  outline: none;
  background: rgba(191, 224, 243, 0.28);
}
.acc-tag-combo-empty {
  margin: 8px 4px 0;
  font-size: 0.78rem;
  color: #7B8190;
  font-style: italic;
}
/* Soft dupe guard. "Did you mean X?" appears above the create row
   when the typed text is close to an existing tag. */
.acc-tag-combo-guard {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
  padding: 7px 10px;
  background: rgba(243, 138, 63, 0.10);
  border: 1px solid rgba(243, 138, 63, 0.34);
  border-radius: 10px;
}
.acc-tag-combo-guard-text {
  font-size: 0.8rem;
  color: #6E4218;
  flex: 1 1 auto;
}
.acc-tag-combo-guard-text strong {
  color: #B86012;
}
.acc-tag-combo-guard-btn {
  flex: 0 0 auto;
  padding: 5px 10px;
  border: 1px solid #B86012;
  background: transparent;
  color: #B86012;
  border-radius: 999px;
  font-size: 0.74rem;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.acc-tag-combo-guard-btn:hover,
.acc-tag-combo-guard-btn:focus-visible {
  outline: none;
  background: #B86012;
  color: #FFFDF9;
}
/* Create-new row. Dashed border + plus glyph + sage green styling so
   it reads as the "new thing" action, distinct from picking an
   existing tag. */
.acc-tag-combo-create {
  margin-top: 8px;
}
.acc-tag-combo-create-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border: 1px dashed rgba(46, 138, 86, 0.46);
  background: rgba(46, 138, 86, 0.06);
  color: #1F6B40;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.acc-tag-combo-create-btn:hover,
.acc-tag-combo-create-btn:focus-visible {
  outline: none;
  border-style: solid;
  background: rgba(46, 138, 86, 0.14);
}
.acc-tag-combo-create-btn strong {
  font-weight: 700;
}

.acc-duplicates {
  margin: 0 0 16px;
  padding: 14px 16px;
  background: rgba(243, 138, 63, 0.08);
  border: 1px solid rgba(243, 138, 63, 0.24);
  border-radius: 14px;
}
.acc-duplicates-eyebrow {
  display: block;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #B86012;
  margin-bottom: 6px;
}
.acc-duplicates-body {
  margin: 0 0 10px;
  font-size: 0.8rem;
  line-height: 1.45;
  color: #60452D;
}
.acc-duplicate-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
}
.acc-duplicate-row {
  display: grid;
  gap: 3px;
  padding: 9px 10px;
  border-radius: 11px;
  background: #FFFDF9;
  border: 1px solid rgba(243, 138, 63, 0.18);
}
.acc-duplicate-name {
  font-size: 0.86rem;
  font-weight: 800;
  color: #373B4D;
}
.acc-duplicate-meta {
  font-size: 0.72rem;
  line-height: 1.35;
  color: #7B8190;
}

/* Notes block — quiet inset card with eyebrow + body paragraph.
   Reads as context, not alert; HCP "Customer notes" are free-text. */
.acc-notes {
  margin: 0 0 18px;
  padding: 14px 16px;
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 14px;
}
.acc-notes-eyebrow {
  display: block;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #7B8190;
  margin-bottom: 6px;
}
.acc-notes-body {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.5;
  color: #373B4D;
  white-space: pre-wrap;
}

/* Past technicians list — chip-per-tech with avatar bullet, name,
   and a meta line ("3 visits · last Sep 18"). Sorted most-recent
   first server-side; first row is the tech who saw this customer
   most recently and is the natural rebook candidate. */
.acc-techs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.acc-techs > li {
  margin: 0;
  padding: 0;
}
.acc-tech {
  display: grid;
  gap: 8px;
  padding: 10px 12px;
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 12px;
}
.acc-tech-main {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  min-width: 0;
  list-style: none;
  cursor: pointer;
}
.acc-tech-main::-webkit-details-marker { display: none; }
.acc-tech-bullet {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(243, 138, 63, 0.16);
  color: #B86012;
  font-size: 0.78rem;
  font-weight: 800;
  flex: 0 0 28px;
  order: 1;
}
.acc-tech-name {
  font-size: 0.9rem;
  font-weight: 700;
  color: #373B4D;
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  order: 2;
}
.acc-tech-meta {
  font-size: 0.72rem;
  color: #7B8190;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  flex: 1 1 100%;
  text-align: left;
  max-width: none;
  line-height: 1.35;
  min-width: 90px;
  margin-left: 38px;
  order: 4;
}
.acc-tech-caret {
  color: #7B8190;
  font-size: 0.92rem;
  font-weight: 800;
  line-height: 1;
  transform-origin: center;
  transition: transform 0.15s ease;
  margin-left: auto;
  order: 3;
}
.acc-tech[open] .acc-tech-caret {
  transform: rotate(180deg);
}
.acc-tech-appointments {
  list-style: none;
  margin: 2px 0 0 38px;
  padding: 0;
  display: grid;
  gap: 5px;
}
.acc-tech-appointment {
  display: grid;
  grid-template-columns: minmax(74px, auto) auto 1fr;
  gap: 6px;
  align-items: baseline;
  font-size: 0.72rem;
  color: #7B8190;
  line-height: 1.35;
}
.acc-tech-appt-date {
  font-weight: 800;
  color: #373B4D;
  font-variant-numeric: tabular-nums;
}
.acc-tech-appt-status {
  font-size: 0.58rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 2px 7px;
  border-radius: 999px;
  background: #FFFDF9;
  color: #7B8190;
  font-weight: 800;
}
.acc-tech-appt-desc {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.acc-tech-appointment--empty {
  display: block;
  color: #7B8190;
  font-size: 0.74rem;
  font-style: italic;
}
/* Inactive tech (no longer bookable). Subtler look + lower contrast
   so admins know not to count on this tech for new bookings. */
.acc-tech--inactive {
  opacity: 0.7;
}
.acc-tech--inactive .acc-tech-bullet {
  background: #FFFDF9;
  color: #7B8190;
}
/* Z-pattern action cluster — sits in the top-right corner of the
   rail head. Pairs the "Open in HCP" jump-link (primary action,
   per philosophy doc's "primary action / filter top-right" rule)
   with the close button as a secondary affordance. Vertically
   centered against the name on the left. */
.acc-head-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.acc-hcp-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 6px 12px;
  background: rgba(243, 138, 63, 0.10);
  color: #B86012;
  border-radius: 999px;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
  white-space: nowrap;
}
.acc-hcp-link:hover {
  background: rgba(243, 138, 63, 0.18);
  color: #8C4710;
}
.acc-hcp-link svg { transition: transform 0.18s ease; }
.acc-hcp-link:hover svg { transform: translate(2px, -2px); }
/* Quieter sibling to the "Open in HCP" pill. Opens the raw HCP API
   diagnostics viewer for this customer in a new tab. Same shape as
   the HCP link but tinted neutral so it reads as a developer/admin
   tool rather than a primary action. */
.acc-diag-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 6px 12px;
  background: rgba(55, 59, 77, 0.06);
  color: #4a4f60;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
  white-space: nowrap;
}
.acc-diag-link:hover {
  background: rgba(55, 59, 77, 0.12);
  color: #2A2A2A;
}
.acc-close {
  border: 0;
  background: transparent;
  font-size: 1.4rem;
  line-height: 1;
  color: #7B8190;
  cursor: pointer;
  padding: 4px 10px;
  border-radius: 999px;
  transition: background 0.12s ease, color 0.12s ease;
}
.acc-close:hover { background: rgba(55, 59, 77, 0.06); color: #373B4D; }

.acc-stats {
  display: flex;
  flex-wrap: wrap;
  /* KPI band: warm card-highlight surface (one tone lighter than the
     rail's own card so the stats lift), generous gap so each cluster
     has air, larger 16px squircle radius. */
  gap: 20px 28px;
  padding: 18px 20px;
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 16px;
  margin-bottom: 18px;
}
.acc-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  /* Tight cluster per philosophy "Rule of Proximity" — number and
     label are one visual unit. */
}
.acc-stat-num {
  /* Hero number per philosophy: large, heavy weight, deep navy ink so
     it acts as an anchor for the eye. Tabular-nums prevents layout
     shift when the value updates. */
  font-size: 1.55rem;
  font-weight: 800;
  color: #373B4D;
  letter-spacing: -0.015em;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.acc-stat-label {
  font-size: 0.7rem;
  color: #7B8190;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  font-weight: 700;
}
.acc-stat--warn .acc-stat-num { color: #D65F4F; }
.acc-stat--info .acc-stat-num { color: #1F5A86; }

/* ─── Loading skeleton — basic phase ─────────────────────────────
   While the slow customer-history fetch is in flight, the timeline +
   stats sections render as pulsing placeholders. Same dimensions as
   the real content so nothing reflows when history loads. Pulse
   alternates between two cream tones from the Bento-Box palette to
   stay quiet against the surrounding rail. */
@keyframes accSkelPulse {
  0%, 100% { background-color: rgba(195, 184, 159, 0.22); }
  50%      { background-color: rgba(195, 184, 159, 0.42); }
}
.acc-skel-bar {
  display: inline-block;
  height: 0.78em;
  background: rgba(195, 184, 159, 0.30);
  border-radius: 6px;
  animation: accSkelPulse 1.4s ease-in-out infinite;
  vertical-align: middle;
}
.acc-skel-bar--sm { width: 48px; height: 0.65em; }
.acc-skel-bar--md { width: 96px; }
.acc-skel-bar--lg { width: 140px; height: 1.05em; }
.acc-stat--skeleton {
  background: rgba(245, 240, 228, 0.55);
  border-color: rgba(195, 184, 159, 0.25);
}
.acc-stat--skeleton .acc-stat-num,
.acc-stat--skeleton .acc-stat-label {
  background: transparent;
  display: block;
}
.acc-stat--skeleton .acc-stat-num {
  margin-bottom: 8px;
}
.acc-section-pill--loading {
  background: rgba(195, 184, 159, 0.18);
  color: #8a7d63;
  animation: accSkelPulse 1.4s ease-in-out infinite;
}
.acc-tl-visit--skeleton .acc-tl-dot {
  background: rgba(195, 184, 159, 0.40);
  border-color: rgba(195, 184, 159, 0.55);
  animation: accSkelPulse 1.4s ease-in-out infinite;
}
.acc-tl-visit--skeleton .acc-tl-connector {
  background: rgba(195, 184, 159, 0.25);
}
.acc-tl-visit--skeleton .acc-skel-bar { background: rgba(195, 184, 159, 0.28); }
.acc-section-note--loading {
  color: #8a7d63;
  font-style: italic;
  font-size: 0.78rem;
}
.acc-section--loading .acc-timeline--skeleton {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Respect reduced-motion: drop the pulse entirely. */
@media (prefers-reduced-motion: reduce) {
  .acc-skel-bar,
  .acc-section-pill--loading,
  .acc-tl-visit--skeleton .acc-tl-dot {
    animation: none;
  }
}

.acc-section { margin-top: 14px; }
.acc-section + .acc-section { margin-top: 18px; }
.acc-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 10px;
  padding: 0 2px;
}
.acc-section-title {
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: #7B8190;
  font-weight: 800;
  margin: 0;
  padding: 0;
}
.acc-section-pill {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: 4px 10px;
  background: #FFFDF9;
  color: #373B4D;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.acc-list {
  list-style: none;
  margin: 0;
  padding: 0;
  /* Bento sub-card: warm card-highlight fill (lifted off the rail's
     own card), soft-warm 1px border, 14px squircle radius. */
  border: 1px solid #E5DED3;
  border-radius: 14px;
  background: #FFFDF9;
  overflow: hidden;
}
.acc-list > li {
  /* Taller row rhythm + airier columns per the philosophy doc's
     "tall row heights" guidance for list architecture. */
  padding: 12px 14px;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 14px;
  font-size: 0.88rem;
  color: #373B4D;
}
.acc-list > li + li { border-top: 1px solid #E5DED3; }

/* Visit history timeline. Each <li> is one visit, laid out as a
   two-column grid: left column holds a vertical "rail" with a dot
   + connector line; right column holds the date/tech header and
   one-or-more clickable document chips (invoices, estimates).
   The connector line visually links each visit's dot to the
   next, giving the section a real timeline feel rather than a
   bare list. */
.acc-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
}
.acc-tl-visit {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  gap: 14px;
  padding: 0 6px;
}
.acc-tl-node {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Nudge the dot down to vertically align with the date label
     in the content column. */
  padding-top: 7px;
}
.acc-tl-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #FCFAF6;
  border: 2px solid #D39A2E;
  flex: 0 0 12px;
  box-shadow: 0 0 0 3px rgba(211, 154, 46, 0.10);
  z-index: 1;
}
.acc-tl-connector {
  position: absolute;
  top: 19px;
  bottom: -14px;
  width: 2px;
  background: #E5DED3;
}
/* Last visit in the timeline has no downward connector — caps
   the rail at the bottom. */
.acc-tl-node--last .acc-tl-connector { display: none; }

/* Visit history defaults to the 3 most recent. Rows past the third are
   --extra and hidden while the list is .is-collapsed; the "Show all" toggle
   removes that class. The third (now last visible) row's connector is capped
   so it doesn't dangle into the hidden rows. */
.acc-timeline.is-collapsed > .acc-tl-visit--extra { display: none; }
.acc-timeline.is-collapsed > .acc-tl-visit:nth-child(3) .acc-tl-connector { display: none; }
.acc-tl-showall {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  width: 100%; margin: 10px 0 0; padding: 9px 12px; cursor: pointer;
  background: transparent; border: 1px solid var(--sw-border, #E5DED3);
  border-radius: var(--sw-radius-input, 14px);
  font-family: inherit; font-size: 0.8rem; font-weight: 700; color: var(--sw-muted, #7B8190);
  transition: background 140ms ease, color 140ms ease, border-color 140ms ease;
}
.acc-tl-showall:hover { background: #FFFAF1; color: var(--sw-ink, #373B4D); }
.acc-tl-showall-caret { transition: transform 180ms cubic-bezier(0.22, 1, 0.36, 1); }
.acc-tl-showall[aria-expanded="true"] .acc-tl-showall-caret { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .acc-tl-showall-caret { transition: none; } }

.acc-tl-content {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-bottom: 18px;
  min-width: 0;
}
.acc-tl-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}
.acc-tl-date {
  font-size: 0.92rem;
  font-weight: 700;
  color: #373B4D;
  letter-spacing: -0.005em;
}
.acc-tl-tech {
  font-size: 0.82rem;
  color: var(--text-muted);
  font-weight: 500;
}
/* Appointment scope-of-work text — sits between the date/tech header
   and the document chips. Quieter than the date but more substantial
   than the meta line so admins notice it as the visit's purpose
   without it competing for attention. */
.acc-tl-job-desc {
  margin: 4px 0 6px;
  font-size: 0.85rem;
  color: #444a5a;
  line-height: 1.45;
  white-space: pre-line;
}

/* Document chips — each invoice / estimate / "no paperwork"
   placeholder is its own clickable pill that expands inline to
   show its details. Multiple chips stack vertically with a
   small gap so a visit with both an invoice and an estimate
   reads as two related but distinct documents. */
.acc-tl-docs {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.acc-tl-doc {
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.85) inset;
}
.acc-tl-doc--invoice { border-left: 3px solid rgba(75, 170, 120, 0.55); }
.acc-tl-doc--estimate { border-left: 3px solid rgba(31, 90, 134, 0.55); }
.acc-tl-doc--empty {
  border-left: 3px solid rgba(123, 129, 144, 0.30);
  padding: 9px 13px;
  background: #FFFDF9;
}
.acc-tl-doc-label--muted {
  color: var(--text-muted);
  font-size: 0.82rem;
  font-style: italic;
}

.acc-tl-doc-summary {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) auto auto 14px;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 12px;
  background: transparent;
  border: 0;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: background 0.12s ease;
}
.acc-tl-doc-summary:hover { background: #FFFAF1; }
.acc-tl-doc-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 6px;
  background: #FFFDF9;
}
.acc-tl-doc--invoice .acc-tl-doc-icon { color: #2E7D4F; background: rgba(75, 170, 120, 0.14); }
.acc-tl-doc--estimate .acc-tl-doc-icon { color: #1F5A86; background: rgba(31, 90, 134, 0.14); }
.acc-tl-doc-label {
  font-size: 0.86rem;
  font-weight: 700;
  color: #373B4D;
  letter-spacing: -0.005em;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.acc-tl-doc-amount {
  font-size: 0.88rem;
  font-weight: 700;
  color: #373B4D;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.acc-tl-doc-status {
  font-size: 0.66rem;
  font-weight: 800;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 3px 8px;
  background: #FFFDF9;
  border-radius: 999px;
  white-space: nowrap;
}
.acc-tl-doc--invoice .acc-tl-doc-status { color: #2E7D4F; background: rgba(75, 170, 120, 0.16); }
.acc-tl-doc--estimate .acc-tl-doc-status { color: #1F5A86; background: rgba(31, 90, 134, 0.16); }
.acc-tl-doc-caret {
  color: var(--text-muted);
  font-size: 0.92rem;
  transition: transform 0.2s ease;
  user-select: none;
}
.acc-tl-doc-summary[aria-expanded="true"] .acc-tl-doc-caret {
  transform: rotate(180deg);
}
.acc-tl-doc-detail {
  padding: 0 14px 12px;
  border-top: 1px solid #E5DED3;
}
.acc-tl-doc-detail[hidden] { display: none; }
.acc-tl-doc-desc {
  font-size: 0.82rem;
  color: var(--text);
  line-height: 1.5;
  margin: 10px 0 8px;
  /* HCP description fields come through with embedded \n newlines
     for multi-paragraph content (Scope of Work, Detailed Scope of
     Work, etc.). Without pre-line, those collapse into one run of
     text and a multi-paragraph description reads as a single
     hard-to-parse blob. */
  white-space: pre-line;
}
.acc-tl-doc-lines { margin: 0; }
.acc-tl-doc-lines[hidden] { display: none; }
.acc-tl-doc-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.78rem;
  font-weight: 600;
  color: #1F5A86;
  margin-top: 10px;
}
.acc-tl-doc-link[hidden] { display: none; }
.acc-tl-doc-link:hover { color: #373B4D; }
