/* ═══════════════════════════════════════════════════════════════
   TABLE OF CONTENTS — grep `═══ N\.` to jump to a section.
   ───────────────────────────────────────────────────────────────
   Mobile / tablet rules live as nested @media inside their base
   rule (e.g. inside .stepper, .cal-pane). Multi-component / multi-
   selector mobile rules that don't fit cleanly inside any one
   component live in section 20.
   ───────────────────────────────────────────────────────────────
     1. Variables & base
     2. Site header
     3. Help menu
     4. Site footer
     5. Booking page chrome
     6. Hero
     7. Stepper
     8. Step card (FLIP wrapper)
     9. Step panels base
     10. Step 2 prelude/summary
     11. Property-type pills
     12. Commercial notice
     13. Trip-charge agreement
     14. Trip-charge admin input
     15. Serif heading utility
     16. Step 3 ledger textarea
     17. Step 1 service cards
     18. Service-card issues list
     19. Forms / fields
     20. Cross-component mobile rules
     24. Buttons
     25. Progressive exposure
     26. Button arrows
     27. Address field
     28. ZIP field
     29. Calendar (centric)
     30. Calendar centric drawer
     31. Calendar skeleton
     32. Alerts
     33. Step 5 success
   ═══════════════════════════════════════════════════════════════ */

/* ═══ 1. Variables & base ═══ */
:root {
  /* All dark text / lines / chrome use a single unified ink color
     (#272936) — was a mix of #1E293B / #0F172A / #1D1D1F (text). */
  --navy: #272936;
  --navy-dark: #272936;
  --orange: #E07A2A;
  --orange-dark: #B86012;
  --orange-soft: #FFF1E5;
  --orange-dim: #C68A5C;
  --cream: #F2EEE6;
  /* Canonical Sunwave warm canvas, per INTERFACE_DESIGN_PHILOSOPHY_NEW
     ("Color Palette and Accent Strategy"). The doc names this the
     base canvas and pairs it specifically with #FCFAF6 cards on top
     ("close cousins, not the same color... subtle enough to feel
     premium, but visible enough that cards still read as physical
     objects resting on the canvas"). Earlier passes drifted to
     #FAF9F6 (too close to card, page read cold) and then to #F3EDDF
     (drifted into beige, which the doc explicitly warns against).
     Keep this at the canonical value unless the doc changes. */
  --bg: #F8F5EF;
  --card: #FFFFFF;
  --card-tint: #F4F5F7;
  /* Muted "selected" tone for non-CTA selections (service cards,
     property pills, slot buttons). Orange is reserved for the primary
     action button + the currently selected calendar date — every
     other "selected" state uses this charcoal so the orange stays a
     guide, not noise. */
  --selected-ink: #272936;
  --selected-soft: rgba(39, 41, 54, 0.10);
  --text: #272936;
  /* Deep editorial ink — used on serif headers / important wordmarks
     so they read as authored content rather than UI text. Slightly
     darker than --text, never pure black. */
  --ink: #1A1C1E;
  --text-muted: #86868B;
  --border: #E4E4E7;
  --border-soft: #ECECEE;
  --success: #15803D;
  --success-bg: #DCFCE7;
  --warning-bg: #FEF3C7;
  --warning-text: #92400E;
  --error: #B91C1C;
  --error-bg: #FEE2E2;
  --radius: 14px;
  --radius-sm: 10px;
  --shadow: 0 1px 2px rgba(39, 41, 54, 0.04);
  --shadow-lg: 0 12px 36px rgba(39, 41, 54, 0.10);
}

html {
  font-feature-settings: "tnum" 1, "ss01" 1;
  /* Reserve space for the vertical scrollbar always, so the layout
     doesn't jolt left when a step transition (e.g. step 1 → step 2)
     pushes the page tall enough to need scrolling. Without this,
     the scrollbar appears mid-FLIP and ~15px of content width
     vanishes, shifting the whole card. */
  scrollbar-gutter: stable;
}

* { box-sizing: border-box; }
/* Kill the iOS/Android default tap highlight — that translucent grey
   rectangle that ignores border-radius and flashes on every tap. We
   rely on the per-element :active/:hover/:focus styles for tap
   feedback (they respect rounded corners since they style the
   element's own background/shadow). */
* { -webkit-tap-highlight-color: transparent; }
html, body { margin: 0; padding: 0; }
body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
body.embed-mode { background: transparent; }

/* Admin-booking-page mesh canvas — layered pastel blobs on top of
   the warm canvas. Body gets a peach blob anchored top-right and a
   pale-blue blob anchored bottom-left, both at very low opacity so
   they read as atmospheric depth rather than decorative color. The
   blobs are fixed-position so they stay anchored as the page scrolls
   (the canvas feels like an actual lighting environment, not a
   pattern). Scoped to the admin booking page so the public flow
   keeps the cleaner flat canvas. Philosophy: "extremely subtle,
   diffused mesh gradients where soft blobs of pastel colors bleed
   seamlessly into one another." */
body:has(.booking-page--admin) {
  background:
    radial-gradient(ellipse 60% 50% at 100% 0%, rgba(243, 138, 63, 0.08), transparent 60%) fixed,
    radial-gradient(ellipse 55% 60% at 0% 100%, rgba(191, 224, 243, 0.18), transparent 60%) fixed,
    radial-gradient(ellipse 40% 35% at 80% 90%, rgba(75, 170, 120, 0.05), transparent 65%) fixed,
    var(--bg);
}
/* Fallback for browsers without :has() — slap the same gradients on
   the booking-page--admin element directly. Less smooth (the blobs
   scroll with the page) but the visual effect lands. Drops in on
   Firefox <121 and pre-2024 Safari/Chrome. */
@supports not (selector(:has(*))) {
  .booking-page--admin {
    background:
      radial-gradient(ellipse 60% 50% at 100% 0%, rgba(243, 138, 63, 0.08), transparent 60%),
      radial-gradient(ellipse 55% 60% at 0% 100%, rgba(191, 224, 243, 0.18), transparent 60%),
      radial-gradient(ellipse 40% 35% at 80% 90%, rgba(75, 170, 120, 0.05), transparent 65%),
      var(--bg);
  }
}

/* When the admin booker is embedded inside the dashboard shell, drop its own
   canvas (both the :has mesh above and the no-:has fallback) so the dashboard
   background flows straight through the transparent iframe with no seam. This
   rule sits after the mesh so it wins on source order. */
body.embed-mode,
body.embed-mode .booking-page--admin {
  background: transparent;
}

a { color: var(--orange-dark); text-decoration: none; }
a:hover { text-decoration: underline; }

.container { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
.muted { color: var(--text-muted); font-size: 0.9rem; }
.mt { margin-top: 16px; }

/* ═══ 2. Site header ═══ */
/* Header */
.site-header {
  background: var(--navy);
  color: #fff;
  padding: 18px 0;
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  color: #fff;
  text-decoration: none;
}
.brand:hover { text-decoration: none; }
/* The brandmark SVG has a portrait viewBox (730×1080). The old
   width:48; height:48; object-fit:contain combo letterboxed it into
   a square — content rendered at ~32×48px so the mark looked tiny
   and "fuzzy" inside a half-empty box. Sizing by height with auto
   width lets the SVG render at its natural aspect ratio (no
   letterboxing, no anamorphic scaling). */
.brand-mark {
  display: block;
  height: 56px;
  width: auto;
}
.brand-text { display: flex; flex-direction: column; line-height: 1; }
.brand-text strong {
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: #fff;
  @media (max-width: 540px) { font-size: 1.3rem; }
}
.brand-text small { font-size: 0.78rem; opacity: 0.75; margin-top: 4px; }

/* Phone CTA — modern translucent pill with icon */
.phone-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px 10px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.22);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.01em;
  text-decoration: none;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
  @media (max-width: 540px) {
    padding: 9px 14px 9px 12px;
    font-size: 0.9rem;
  }
}
.phone-cta-icon {
  flex-shrink: 0;
  opacity: 0.9;
  transition: transform 0.25s ease, opacity 0.18s ease;
}
.phone-cta-text { white-space: nowrap; }
.phone-cta:hover {
  background: #fff;
  color: var(--navy, #0e2a47);
  border-color: #fff;
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
}
.phone-cta:hover .phone-cta-icon { opacity: 1; transform: rotate(-12deg); }
.phone-cta:active { transform: translateY(0); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18); }
.phone-cta:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}
/* ═══ 3. Help menu ═══ */
/* "Need help?" menu — replaces the prominent single phone CTA. The trigger
   is intentionally quieter (ghost-style on the navy header) so it doesn't
   compete with the address-entry task. The popover lists every location's
   phone, since we don't know which one the customer should call until they
   give us an address. */
.help-menu {
  position: relative;
}
.help-menu-trigger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px 8px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.85);
  border: 1px solid rgba(255, 255, 255, 0.16);
  font-weight: 500;
  font-size: 0.88rem;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
  @media (max-width: 540px) { padding: 7px 12px 7px 10px; font-size: 0.82rem; }
}
.help-menu-trigger::-webkit-details-marker { display: none; }
.help-menu-trigger:hover {
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.28);
}
.help-menu-icon { flex-shrink: 0; opacity: 0.85; }
.help-menu-chevron {
  font-size: 0.65rem;
  opacity: 0.7;
  transition: transform 0.2s ease;
}
.help-menu[open] .help-menu-chevron { transform: rotate(180deg); }
.help-menu[open] .help-menu-trigger {
  background: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.32);
  color: #fff;
}

.help-menu-panel {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  min-width: 280px;
  max-width: 360px;
  background: #FFFFFF;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 18px 40px rgba(39, 41, 54, 0.18);
  padding: 8px;
  z-index: 200;
  animation: helpPanelIn 0.22s cubic-bezier(0.22, 1, 0.36, 1);
  @media (max-width: 540px) { min-width: 240px; right: -4px; }
}
@keyframes helpPanelIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.help-menu-eyebrow {
  margin: 4px 8px 6px;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.help-menu-row {
  display: grid;
  grid-template-columns: 24px 1fr;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 10px;
  text-decoration: none;
  color: var(--text);
  transition: background 0.15s ease, transform 0.15s ease;
}
.help-menu-row:hover {
  background: var(--orange-soft);
  text-decoration: none;
  transform: translateX(2px);
}
.help-menu-row[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
}
.help-menu-row-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  color: var(--orange-dark);
}
.help-menu-row-body { display: flex; flex-direction: column; min-width: 0; }
.help-menu-row-body strong {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text);
}
.help-menu-row-body small {
  font-size: 0.82rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  margin-top: 1px;
}
/* ═══ 4. Site footer ═══ */
/* Footer */
.site-footer {
  margin-top: 80px;
  padding: 30px 0;
  background: var(--navy-dark);
  color: rgba(255,255,255,0.7);
  font-size: 0.9rem;
  text-align: center;
}

/* Sticky footer for the booking page. Without this the footer follows
   whatever height the active step happens to render at — step 1
   (services grid, ~560px) pushes it way down, step 5 (success card,
   ~280px) pulls it up, and the page rolls up and down each transition.
   Body becomes a flex column with min-height 100vh, main grows to fill
   the gap, footer always anchors at the bottom of the viewport (or
   below content when the page does need to scroll). Scoped with :has()
   so admin/auth/embed pages are untouched. */
body:has(.booking-page) {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* Lock horizontal scroll on the booking page. If any child element
     (drawer slot text, suggestion list during open, etc.) briefly
     exceeds viewport width during render, mobile browsers compensate
     by zooming the whole page out. Clipping x-overflow keeps every
     transient overhang invisible and preserves the native 1.0 zoom
     level. Vertical scroll still works via min-height: 100vh above. */
  @media (max-width: 600px) { overflow-x: hidden; }
}
body:has(.booking-page) > main { flex: 1 0 auto; }
body:has(.booking-page) > .site-footer { flex-shrink: 0; }

/* ───── Booking-page header + footer blend ─────
   The default header/footer use navy backgrounds (good for admin
   chrome). On the booking page that high-contrast cap fights the
   peaceful "warm paper" stage — the card should feel like it's
   floating, not bookended by dark bars. These overrides drop the
   dark fills and recolor the text to the warm-neutral palette, only
   when the body has a .booking-page (so admin/auth pages stay as
   they were). */
body:has(.booking-page) > .site-header {
  background: transparent;
  color: var(--navy);
  padding: 22px 0 0; /* tighter, since there's no dark band to fill */
}
body:has(.booking-page) > .site-header .brand,
body:has(.booking-page) > .site-header .brand-text strong {
  color: var(--navy);
}
body:has(.booking-page) > .site-header .brand-text small {
  color: var(--text-muted);
  opacity: 1;
}
body:has(.booking-page) > .site-footer {
  background: transparent;
  color: var(--text-muted);
  margin-top: 0; /* the booking-page padding-bottom handles the gap */
}
/* Footer Help-menu trigger — was white-on-navy for the dark footer.
   Re-skinned for the now-transparent booking footer: dark text on
   a soft warm-paper pill. */
body:has(.booking-page) .help-menu--footer .help-menu-trigger {
  background: rgba(39, 41, 54, 0.04);
  border-color: rgba(39, 41, 54, 0.10);
  color: var(--text);
}
body:has(.booking-page) .help-menu--footer .help-menu-trigger:hover,
body:has(.booking-page) .help-menu--footer[open] .help-menu-trigger {
  background: rgba(39, 41, 54, 0.08);
  border-color: rgba(39, 41, 54, 0.18);
  color: var(--navy);
}
.site-footer-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}
.site-footer-copy { margin: 0; }

/* Help-menu in the footer: opens UPWARD instead of down (since the
   trigger is near the bottom of the page) and centers itself on the
   trigger instead of right-aligning. The trigger pill itself adopts a
   subtle white-on-navy treatment to match the footer surface. */
.help-menu--footer { position: relative; }
.help-menu--footer .help-menu-trigger {
  background: rgba(255, 255, 255, 0.10);
  border-color: rgba(255, 255, 255, 0.18);
  color: rgba(255, 255, 255, 0.92);
}
.help-menu--footer .help-menu-trigger:hover {
  background: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.32);
  color: #fff;
}
.help-menu--footer[open] .help-menu-trigger {
  background: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.32);
  color: #fff;
}
.help-menu--footer .help-menu-panel {
  top: auto;
  right: auto;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
  animation: helpPanelInUp 0.22s cubic-bezier(0.22, 1, 0.36, 1);
  /* Mobile: anchor to the screen rather than translateX-centered when
     very narrow, so it never overflows the viewport. */
  @media (max-width: 600px) { min-width: 92vw; }
}
@keyframes helpPanelInUp {
  from { opacity: 0; transform: translate(-50%, 6px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* ═══ 5. Booking page chrome ═══ */
/* Booking page */
/* "Stage" effect — the white card sits with breathing room on every
   side so it reads as a centered object, not a tab pinned to the top
   of the page. Was 88/120 — tightened to 36/80 so the top stack
   doesn't dominate and the card is closer to vertical center on
   typical laptop viewports. */
.booking-page {
  padding: 36px 24px 80px;
  @media (min-width: 601px) and (max-width: 760px) { padding: 56px 18px 80px; }
  /* Mobile: tighter top + bottom padding so the page doesn't look
     letter-boxed on a 360x640 phone. Side padding stays generous
     enough that the card has air on the left/right edges. */
  @media (max-width: 600px) { padding: 18px 14px 36px; }
  @media (max-width: 380px) { padding: 22px 10px 48px; }
}
body.embed-mode .booking-page { padding: 24px; }
/* Admin scheduler embed: the dashboard shell above the iframe already
   clears the top chrome, so the inner page needs only a sliver of top
   padding. Trimmed further (2026-06-14) to pull the wizard up. Scoped
   to the admin page so the public booking preview iframe (Online
   Booking tab) keeps its full 24px frame. */
body.embed-mode .booking-page--admin { padding-top: 2px; }
/* Recent-bookings moved out of the embedded scheduler into the
   dashboard's left-nav dock (2026-06-14, .scheduler-recent-dock); hide
   the in-frame copy so it isn't shown twice. The standalone (non-embed)
   admin booking page keeps its own card. */
body.embed-mode #admin-recent-bookings { display: none !important; }
/* ═══ 6. Hero ═══ */
.hero { text-align: center; margin-bottom: 32px; }
.hero h1 {
  font-size: 2.4rem;
  font-weight: 800;
  color: var(--navy);
  margin: 0;
  letter-spacing: -0.025em;
  line-height: 1.1;
}
@media (max-width: 540px) {
  .hero h1 { font-size: 1.8rem; }
}
/* Legacy sub-heading (some flows still render it). New booking page hero
   is a single heading. */
.hero-sub {
  color: var(--text-muted);
  font-size: 1rem;
  margin: 8px 0 0;
  font-weight: 400;
}

/* ═══ 7. Stepper ═══ */
/* ───── Stepper (architectural / fluid) ─────
   Goal: a delicate, lifestyle-tech progress indicator. Thin 1px
   connecting lines, a "looming" larger active circle with a soft
   orange halo, completed steps replaced by a flat checkmark
   (instead of holding the number forever), and an animated "ink
   flow" through each connector when the previous step completes.
   Generous bottom margin so the stepper feels like it's floating
   above the card rather than sitting on top of it. */
.stepper {
  list-style: none;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0;
  padding: 0;
  /* Tightened from 64 → 24 so the stepper sits close to the card
     instead of floating in a slab of empty space above it. */
  margin: 0 auto 24px;
  position: relative;
  max-width: 620px;
  /* Mobile: sticky-pinned at the top of the viewport so it stays locked
     in place while the .step-card morphs height during transitions.
     Without this the entire stack (stepper + card) shifts together
     during the FLIP, reading as "everything jiggles". Negative side
     margins extend the cream background to viewport edges so there's
     no fade-line where the page padding ends. */
  @media (max-width: 600px) {
    position: sticky;
    top: 0;
    z-index: 10;
    max-width: 100%;
    margin: 0 -14px 18px;
    padding: 14px 14px 12px;
    background: var(--bg);
    flex-wrap: nowrap;
  }
  @media (max-width: 380px) {
    /* Tiny-phone (≤380) page padding is 22px/10px — re-tune side
       margins so the cream background still bleeds to viewport edges
       without overlapping the card on first load. */
    margin: 0 -10px 18px;
    padding: 16px 10px 12px;
  }
}
/* Old continuous .stepper::before line removed — connectors now live
   on each .step + .step pair (rule below) so we can independently
   animate each segment as the user advances. */

.stepper .step {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0;
  background: transparent;
  border: 0;
  font-size: 0.86rem;
  /* Letter-spacing — the "luxury brand" airy tracking. */
  letter-spacing: 0.04em;
  font-weight: 400;
  color: var(--text-muted);
  position: relative;
  z-index: 1;
  /* Soft fades for color/opacity. Weight changes between active/done
     are discrete (font-weight can't smoothly tween) but the opacity
     and color crossfade carry most of the perceived smoothness. */
  transition: color 0.32s ease;
  /* Mobile: tighten gap and size so all four pills fit on a 360px
     screen without wrapping. */
  @media (max-width: 600px) { padding: 0; font-size: 0.76rem; gap: 8px; }
  @media (max-width: 380px) { gap: 0; padding: 0; }
}

/* Spacing between steps to host the line connector. Doesn't apply to
   the first step (no connector to its left). */
.stepper .step + .step {
  margin-left: 56px;
  @media (max-width: 600px) { margin-left: 28px; }
  @media (max-width: 380px) { margin-left: 22px; }
}

/* Base connector — thin 1px gray line between this step and the
   previous one. Sits behind the marker circles. */
.stepper .step + .step::before {
  content: '';
  position: absolute;
  top: 50%;
  right: calc(100% + 6px); /* small breath off the marker */
  width: 44px;
  height: 1px;
  background: var(--border);
  transform: translateY(-50%);
  pointer-events: none;
  z-index: 0;
  border-radius: 999px;
  @media (max-width: 600px) { width: 18px; right: calc(100% + 5px); }
  @media (max-width: 380px) { width: 14px; right: calc(100% + 4px); }
}

/* Foreground "ink flow" — orange line that animates from 0 to full
   width when the previous step becomes .done (or this step itself
   becomes .done while navigating back). The width transition reads
   as ink flowing through the line into the next circle. */
.stepper .step + .step::after {
  content: '';
  position: absolute;
  top: 50%;
  right: calc(100% + 6px);
  width: 0;
  height: 1px;
  background: var(--orange);
  transform: translateY(-50%);
  pointer-events: none;
  z-index: 1;
  border-radius: 999px;
  transition: width 0.65s cubic-bezier(0.22, 1, 0.36, 1);
  @media (max-width: 600px) { right: calc(100% + 5px); }
  @media (max-width: 380px) { right: calc(100% + 4px); }
}

/* Fill the connector if the previous step is done OR if this step
   itself is done (handles the user navigating back, where step N
   stays .done even though step N-1 is now .active). */
.stepper .step.done + .step::after,
.stepper .step + .step.done::after {
  width: 44px;
  @media (max-width: 600px) { width: 18px; }
  @media (max-width: 380px) { width: 14px; }
}

/* The marker circle — number when inactive/active, checkmark when
   .done. Position relative so the absolutely-positioned num/check
   stack on top of each other and crossfade. */
.stepper .step .step-marker {
  position: relative;
  /* Locked size across all states. Size used to bump 24 → 30 on active
     and that 6px delta re-flowed the centered stepper on every step
     change ("pills moving all over the place"). The active emphasis
     is now carried by background + halo only — no layout impact. */
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--border);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  flex-shrink: 0;
  transition:
    background 0.28s ease,
    border-color 0.28s ease,
    color 0.28s ease,
    box-shadow 0.32s ease;
  /* Mobile: locked size across all states — same reasoning as desktop
     above. Active emphasis stays via the orange fill + halo. */
  @media (max-width: 600px) { width: 26px; height: 26px; font-size: 0.74rem; }
}

/* Number + checkmark stacked. .step-num is shown for inactive/active,
   .step-check is shown when .done. Both fade. */
.stepper .step .step-num,
.stepper .step .step-check {
  position: absolute;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.28s ease;
}
.stepper .step .step-check {
  opacity: 0;
  width: 14px;
  height: 14px;
  @media (max-width: 600px) { width: 12px; height: 12px; }
}

/* Ghost inactive — faint outline, paper-tone fill. The user sees
   the steps coming but they read as quiet roadmap markers. */
.stepper .step .step-marker {
  background: var(--bg);
  border-color: var(--border);
}

/* Active — orange fill + soft halo. The size used to bump from 24 →
   30, but that re-flowed the row; emphasis is carried by color +
   shadow instead now. */
.stepper .step.active .step-marker {
  background: var(--orange);
  border-color: var(--orange);
  color: #fff;
  box-shadow:
    0 0 0 6px rgba(224, 122, 42, 0.10),
    0 4px 14px rgba(224, 122, 42, 0.22),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
}

/* Done — flat orange circle, checkmark in white. Crossfade swaps
   number → checkmark. */
.stepper .step.done .step-marker {
  background: var(--orange);
  border-color: var(--orange);
  color: #fff;
  cursor: pointer;
}
.stepper .step.done .step-num   { opacity: 0; }
.stepper .step.done .step-check { opacity: 1; }

/* Labels — single locked weight so font-weight changes don't cause
   glyph-width drift on each step transition (the other half of the
   "stepper moves all over the place" symptom). State emphasis is
   carried by color + opacity only. */
.stepper .step .step-label {
  transition: color 0.32s ease, opacity 0.32s ease;
  font-weight: 500;
  opacity: 0.55;
  letter-spacing: 0.04em;
  white-space: nowrap;
  /* Tiny phones: drop the text labels and leave only the marker
     circles — the active/done coloring still tells the user
     which step they're on. */
  @media (max-width: 380px) { display: none; }
}
.stepper .step.done .step-label {
  opacity: 0.85;
  color: var(--text);
}
.stepper .step.active .step-label {
  opacity: 1;
  color: var(--text);
}
.stepper .step.done:hover .step-label { color: var(--text); }

/* Step panels — luminous card with light-catch inner highlight */
/* ═══ 8. Step card (FLIP wrapper) ═══ */
/* Persistent outer card (.step-card) — owns the visual chrome (bg,
   border, radius, shadow, max-width). The step panels inside are
   just content containers. JS animates `height` on this wrapper
   between steps via the FLIP technique (capture old height, swap
   visible panel, capture new height, transition between them). The
   user sees ONE card smoothly resizing instead of separate cards
   flashing in different sizes. */
.step-card {
  /* Bento hero card: warm card surface (#FCFAF6) replaces the pure
     white that used to anchor the right column, soft warm border
     instead of cool charcoal, and a quiet ambient shadow with a
     warm undertone so the card hovers above the canvas like the
     philosophy doc describes. The 22px squircle radius stays. */
  background: #FCFAF6;
  border-radius: 22px;
  border: 1px solid #E5DED3;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 14px 36px rgba(55, 59, 77, 0.05),
    0 2px 6px rgba(55, 59, 77, 0.03);
  max-width: 1080px;
  margin: 0 auto;
  overflow: hidden; /* clip rounded corners; suggestions list is portaled */
  /* Slow + symmetric sine ease-in-out so big size changes read as one
     smooth morph. Both height AND max-width transition — the card
     visibly narrows as the user progresses through the flow (calendar
     = wide, form = narrower, success = narrowest). 0.85s is long
     enough to feel like a deliberate morph rather than a snap; sine
     curve eases in and out symmetrically so the card never lurches. */
  transition:
    height 0.85s cubic-bezier(0.65, 0, 0.35, 1),
    max-width 0.85s cubic-bezier(0.65, 0, 0.35, 1);
}

/* Per-step card width — set by JS via data-active-step on the card.
   The transitions above interpolate between these values so the card
   visibly resizes side-to-side as well as top-to-bottom on each
   showStep. Steps with grid/calendar content stay wide; content-light
   steps (description / success) tuck in narrower for focus. */
.step-card[data-active-step="1"] { max-width: 1200px; } /* services grid */
.step-card[data-active-step="2"] { max-width: 1200px; } /* calendar */
.step-card[data-active-step="3"] { max-width: 1040px; } /* description */
.step-card[data-active-step="4"] { max-width: 920px; }  /* form */
.step-card[data-active-step="5"] { max-width: 720px; }  /* success */

/* Step 2 + Commercial picked — calendar is hidden, so the wide
   card has nothing to fill and reads as oversized. Pull it in to
   match the form/success widths so the notice + address sit
   centered in a card sized to the content. The same height
   transition runs on the .step-card so the narrowing animates
   smoothly when the user toggles between Home and Commercial. */
.step-card[data-active-step="2"]:has(input[name="property_type"][value="commercial"]:checked) {
  max-width: 720px;
}

/* ═══ 9. Step panels base ═══ */
/* Step panels — chrome moved to .step-card above. Every panel is a
   flex column with a moderate baseline min-height. Steps with more
   content (services grid, calendar, form) will grow past it; steps
   with less content (single textarea, success card) will sit at the
   baseline rather than collapsing to ~280px. The result: the card
   has visible-but-modest variance between steps, which gives the
   FLIP height-transition something to actually animate (it's a
   no-op when first/last heights match). The actions row gets
   margin-top: auto so Continue/Back anchor to the bottom of the
   panel regardless of how much content is above them. */
.step-panel {
  padding: 48px 52px;
  min-height: 540px;
  display: flex;
  flex-direction: column;
  transform-origin: top center;
  will-change: opacity;
  /* Mid-tablet / large phone (601-760px) — lighter padding than desktop
     so the panel doesn't waste edge real estate at narrower widths. */
  @media (min-width: 601px) and (max-width: 760px) {
    padding: 36px 32px;
    min-height: 480px;
  }
  /* Drop the desktop min-height on phones — the card already fills the
     viewport and a fixed minimum just creates dead space below short
     steps when the user can already see the whole thing at once.
     Heights go natural on mobile. */
  @media (max-width: 600px) {
    padding: 24px;
    min-height: auto;
  }
}
.step-panel .actions { margin-top: auto; }
/* Step 1 (Service pick): a wider panel with normal padding so the
   service-grid has room to breathe and fit 3-4 cards comfortably.
   The panel is a flex column with a generous min-height so it
   pre-reserves the vertical space a card's expanded "Common issues"
   list will need. The Continue button (.actions) is pushed to the
   bottom with margin-top: auto. When a card expands, the grid grows
   into the slack between itself and Continue — Continue itself stays
   put. Net: clicking cards doesn't make the bottom of the page
   bounce around, and the elastic press scale is preserved (transforms
   don't affect layout flow). */
.step-panel[data-step="1"] {
  /* No per-step layout overrides on desktop — the base .step-panel rule
     already gives every step flex column + min-height + margin-top:
     auto on actions. Mobile drops the desktop min-height and tightens
     padding so phones don't read as letter-boxed. */
  @media (max-width: 600px) {
    padding: 18px 16px;
    min-height: auto;
  }
  @media (max-width: 380px) { padding: 22px 14px; }
}
/* `display: flex` above outweighs the UA stylesheet's `[hidden] { display: none }`
   on specificity, so without this explicit override the panel stays visible
   even after JS sets `step1.hidden = true`. Result: step 1 and step 2 both
   render on the page. Same trick used for .save-bar and .field elsewhere. */
.step-panel[hidden] { display: none !important; }
/* Step 2 (Address + Calendar) keeps the edge-to-edge treatment so the
   #availability calendar pills can extend the full panel width. The
   panel has 0 horizontal padding; every direct child gets margin by
   DEFAULT, and only #availability opts out via :not().
   This is intentional — earlier we used an allow-list of named
   children and every new element added to step 2 (e.g. the Back
   button's .actions wrapper) ended up flush against the card edge.
   Inverting to a default-on/explicit-opt-out pattern makes the layout
   self-correcting for future additions. */
.step-panel[data-step="2"] {
  /* Outer card chrome (max-width, bg, shadow) from .step-panel.
     Horizontal padding overridden to 0 so #availability (the calendar
     + slots two-column grid) can extend edge-to-edge inside the card.
     Every other child gets symmetric horizontal margin via the
     deny-list selector below — see comment above .step-panel about why
     that's a deny-list rather than an allow-list. */
  padding: 44px 0 48px;
  @media (max-width: 760px) { padding: 28px 0 28px; }
}
.step-panel[data-step="2"] > *:not(#availability) {
  margin-left: 52px;
  margin-right: 52px;
  @media (max-width: 760px) { margin-left: 20px; margin-right: 20px; }
}
/* Generous vertical rhythm between every section in step 2. Each
   margin was tighter before (4–24px) and the page felt squished;
   bumped across the board so property-type → address → calendar
   → actions each have real room to breathe. */
.step-panel[data-step="2"] > .zip-field { margin-bottom: 32px; }
/* Property type / address now live inside `.step2-prelude` so their
   margins use descendant selectors instead of `>`. The prelude itself
   gets the bottom margin that previously lived on `.address-field`. */
.step-panel[data-step="2"] .address-field { margin-top: 0; margin-bottom: 0; }
.step-panel[data-step="2"] .address-help { margin-top: 18px; margin-bottom: 12px; }
.step-panel[data-step="2"] .property-type-field {
  margin-top: 0;
  margin-bottom: 18px;
  @media (max-width: 600px) { margin-bottom: 16px; }
}
.step-panel[data-step="2"] .commercial-notice { margin-top: 18px; margin-bottom: 18px; }
.step-panel[data-step="2"] > .step2-prelude {
  margin-bottom: 18px;
  /* Pull the prelude in by 8px and add 8px internal padding so the
     address input's focus ring has clearance to render without being
     clipped by the prelude's overflow: hidden (needed for collapse).
     Net visual indent matches sibling elements (44 + 8 = 52). */
  margin-left: 44px;
  margin-right: 44px;
  padding-left: 8px;
  padding-right: 8px;
  /* Mobile: panel uses 20px margin on direct children (deny-list above).
     Pull prelude in to 14 + 6 padding = 20 so input has focus-ring
     clearance. */
  @media (max-width: 600px) {
    margin-bottom: 14px;
    margin-left: 14px;
    margin-right: 14px;
    padding-left: 6px;
    padding-right: 6px;
  }
}
/* Tightened 18 → 8. With #availability margin-top trimmed below, the
   total gap between summary chip and "May 2026" is ~14px, not ~34. */
.step-panel[data-step="2"] > .step2-summary {
  margin-bottom: 8px;
  @media (max-width: 600px) { margin-bottom: 14px; padding: 10px 12px; }
}
.step-panel[data-step="2"] > #availability {
  margin-top: 6px;
  @media (max-width: 600px) { margin-top: 8px; }
}
.step-panel[data-step="2"] > .actions {
  margin-top: 32px;
  padding-top: 4px;
  @media (max-width: 600px) { margin-top: 28px; }
}

/* ═══ 10. Step 2 prelude/summary ═══ */
/* ───── Step 2 collapse: prelude → summary ─────
   Prelude (property type pills + address input) collapses to a thin
   summary row once the address verifies. Saves ~350px so the calendar
   lands near the top of the viewport rather than below the fold. */
.step2-prelude {
  overflow: hidden;
  /* Cap above any realistic content height; collapses to 0 when
     `.is-collapsed` is added. The transition runs on max-height +
     opacity together so the section visibly fades while shrinking. */
  max-height: 720px;
  opacity: 1;
  transition:
    max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1),
    opacity 0.32s ease,
    margin-bottom 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.step2-prelude.is-collapsed {
  max-height: 0;
  opacity: 0;
  margin-bottom: 0 !important;
  pointer-events: none;
}
/* Used during step-card re-entry to suppress the prelude's own
   transition so the showStep FLIP can animate the card height in a
   single smooth motion instead of competing with the inner collapse. */
.step2-prelude.no-transition { transition: none !important; }
/* The collapsed summary chip — Home icon + property label + address
   + edit pencil, all on a single ~52px row. Reads as a "you've told us
   this; click to edit" affordance rather than competing with the
   calendar for attention. */
.step2-summary {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: #FAF7F1;
  border: 1px solid rgba(39, 41, 54, 0.10);
  border-radius: 14px;
  /* Settle in: tiny drop + fade so the row appears as the prelude
     collapses, not after it. The animation duration matches the
     prelude collapse so they finish in lockstep. */
  animation: step2SummaryIn 0.46s cubic-bezier(0.22, 1, 0.36, 1);
}
.step2-summary[hidden] { display: none !important; }

/* Rotating loader caption under the address summary. Phrases swap on
   fixed beats (see startLoadingCaption in calendar.js) while the
   /api/availability request is in flight. Visual hierarchy:
   - Sits aligned with the address summary, NOT inside the calendar
     skeleton, so it reads as "the page is still working on it"
     rather than "the calendar is broken."
   - Warm muted ink so it's clearly secondary copy.
   - The 5s "sleepy servers" line picks up .is-slow which warms the
     color a touch toward the brand orange — same as the page's
     "we know this is taking longer" voice. */
.calendar-loading-caption {
  margin: 10px 4px 14px;
  font-size: 0.95rem;
  line-height: 1.4;
  color: var(--text-muted);
  font-style: italic;
  letter-spacing: 0.005em;
  transition: color 0.3s ease;
  /* Fade-in on swap — the textContent change retriggers the animation
     via a key swap below; here we just ensure the very first render
     fades up rather than snapping in. */
  animation: captionFadeIn 0.28s ease both;
}
.calendar-loading-caption[hidden] { display: none !important; }
.calendar-loading-caption.is-slow { color: var(--orange-dark, #B86012); }
@keyframes captionFadeIn {
  from { opacity: 0; transform: translateY(-2px); }
  to   { opacity: 1; transform: translateY(0); }
}
.step2-summary-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  color: var(--text-muted);
}
.step2-summary-icon svg { width: 18px; height: 18px; }
.step2-summary-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 0.95rem;
  color: var(--text);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.step2-summary-prop {
  font-weight: 600;
  flex: 0 0 auto;
}
.step2-summary-sep {
  color: var(--text-muted);
  flex: 0 0 auto;
}
.step2-summary-addr {
  color: var(--text);
  font-weight: 400;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  min-width: 0;
}
.step2-summary-edit {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 0;
  background: transparent;
  color: var(--text-muted);
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}
.step2-summary-edit:hover {
  background: rgba(39, 41, 54, 0.06);
  color: var(--orange);
}
@keyframes step2SummaryIn {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ═══ 11. Property-type pills ═══ */
/* ───── Property type — segmented control ─────
   Sits directly under the address; defaults to Home so the common
   path is zero-click. Picking Commercial flips the calendar off and
   shows a redirect notice. */
.property-type-field {
  border: 0;
  padding: 0;
  margin: 0;
}

/* ═══════════════════════════════════════════════════════════════
   Admin booking banner + customer search
   Rendered on /admin/book/:slug only. The banner sits ABOVE the
   stepper to make it unmistakable that this is an admin-mode page,
   and to hold the customer name-lookup typeahead that's only useful
   when the admin is filling out a booking on someone else's behalf.
   Visual language: same cream/charcoal-soft skin as the booking
   card, with a subtle orange accent stripe so it reads as elevated
   without being loud.
   ═══════════════════════════════════════════════════════════════ */
.admin-booking-banner {
  width: 100%;
  max-width: none;
  /* No bottom margin: the admin grid's 20px row-gap already spaces
     the banner from the rail/form row below; a margin here would
     stack on top of that gap and double the spacing. */
  margin: 0 auto;
  /* Bento card, toolbar-slim: the banner is a single control row
     (pill + location + customer search + scope toggle), so padding
     is control-strip tight rather than content-card generous. Warm
     surface, soft-warm border, ambient shadow per the philosophy
     doc. */
  padding: 10px 16px;
  background: #FCFAF6;
  border: 1px solid #E5DED3;
  border-left: 3px solid #F38A3F;
  border-radius: 18px;
  box-shadow: 0 12px 32px rgba(55, 59, 77, 0.05),
              0 1px 0 rgba(255, 255, 255, 0.85) inset;
}
@media (max-width: 600px) {
  .admin-booking-banner {
    padding: 10px 14px;
    border-radius: 16px;
  }
}
.admin-booking-banner-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.admin-booking-banner-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  background: rgba(243, 138, 63, 0.14);
  color: #B86012;
  border-radius: 999px;
  font-size: 0.66rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
/* Single-location case (no picker dropdown). Sized to match the
   .admin-loc-picker-summary pill above so single-location and
   multi-location banners read at the same height. */
.admin-booking-banner-loc {
  display: inline-flex;
  align-items: center;
  padding: 7px 14px;
  min-height: 32px;
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 999px;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.8) inset;
  min-width: 0;
}
.admin-booking-banner-loc strong {
  font-size: 0.92rem;
  font-weight: 700;
  color: #373B4D;
  letter-spacing: -0.005em;
  line-height: 1.2;
}
/* Secondary action pill — philosophy doc: "Secondary Actions...
   wrapped in a faint, light-gray pill or a thin 1px outline."
   Warm-card fill + warm border + pill radius matches the rest of
   the page's secondary affordances (admin-cal-nav, etc.). */
.admin-booking-banner-back {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  font-weight: 600;
  color: #373B4D;
  text-decoration: none;
  padding: 7px 14px;
  background: #FFFDF9;
  border: 1px solid #E5DED3;
  border-radius: 999px;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.85) inset;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.06s ease;
}
.admin-booking-banner-back svg { transition: transform 0.18s ease; }
.admin-booking-banner-back:hover {
  background: #FFFAF1;
  border-color: rgba(243, 138, 63, 0.35);
  color: #373B4D;
}
.admin-booking-banner-back:hover svg { transform: translateX(-2px); }
.admin-booking-banner-back:active { transform: scale(0.98); }

/* The admin "Booking stats strip" (Today / Week / Best-day chips) was
   removed 2026-06-14 along with its markup and JS — styles deleted. */

/* ─── Recent bookings rail card (admin) ─────────────────────────────
   Stacked directly under the customer rail. Shows the last ~15 admin-
   filed bookings as stacked mini cards. The list scrolls internally
   so the card matches the height of the scheduling form to its right
   without pushing the page taller. Each row is collapsed by default;
   clicking expands to reveal the customer's stated problem, full
   address, and an "Open in HCP" link that opens the parent job
   page. Quiet visual treatment — warm-canvas cards, no shadows on
   the items themselves; the only emphasis is the colored avatar
   chip on the left and the time pill on the right. */
.admin-recent {
  display: flex;
  flex-direction: column;
  /* Take the remaining vertical space in the rail column (which is
     stretched to match the form column's height — see
     .admin-rail-column.align-self: stretch above). min-height: 0 is
     critical for the internal list to scroll instead of pushing the
     card taller. */
  flex: 1 1 auto;
  min-height: 220px;
  background: #FFFCF6;
  border: 1px solid #ECE5D6;
  border-radius: 14px;
  padding: 12px 6px 10px 12px;
  box-shadow: 0 1px 0 rgba(55, 59, 77, 0.02);
}
.admin-recent-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 0 6px 8px 0;
  border-bottom: 1px solid #F1ECDC;
  margin-bottom: 4px;
}
.admin-recent-title {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #8A8475;
}
.admin-recent-refresh {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  color: #8A8475;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease, transform 200ms ease;
}
.admin-recent-refresh:hover {
  background: #F5EFE0;
  border-color: #E5DDC8;
  color: #373B4D;
}
.admin-recent-refresh:focus-visible {
  outline: 2px solid #B6D4F2;
  outline-offset: 2px;
}
.admin-recent-refresh.is-spinning svg {
  animation: adminRecentSpin 700ms linear;
}
@keyframes adminRecentSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .admin-recent-refresh.is-spinning svg { animation: none; }
}
/* Internal scroll container. min-height: 0 is critical — without it
   the flex child refuses to shrink below its content height and the
   overflow:auto never engages. Custom scrollbar styling keeps the
   rail looking quiet on macOS (where scrollbars overlay) and on
   Windows (where they take up gutter). */
.admin-recent-list {
  list-style: none;
  margin: 0;
  padding: 6px 6px 6px 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
  scrollbar-width: thin;
  scrollbar-color: #DCD2BA #FFFCF6;
}
.admin-recent-list::-webkit-scrollbar { width: 8px; }
.admin-recent-list::-webkit-scrollbar-track { background: transparent; }
.admin-recent-list::-webkit-scrollbar-thumb {
  background: #E5DDC8;
  border-radius: 999px;
  border: 2px solid #FFFCF6;
}
.admin-recent-list::-webkit-scrollbar-thumb:hover { background: #DCD2BA; }

.admin-recent-empty {
  padding: 28px 12px;
  text-align: center;
  color: #9A9485;
  font-size: 0.82rem;
  line-height: 1.5;
}
.admin-recent-empty strong { display: block; color: #6B6555; margin-bottom: 4px; font-weight: 700; }

/* Mini card row. <li> is the click target (set role=button via JS so
   keyboard still works); the expanded body is a sibling that toggles
   via [data-open] / [hidden]. Native <details> would be simpler but
   we want the avatar+name+slot row to be the summary surface and
   <summary> with custom content is harder to style consistently. */
.admin-recent-item {
  display: flex;
  flex-direction: column;
  background: #FCFAF6;
  border: 1px solid #ECE5D6;
  border-radius: 10px;
  overflow: hidden;
  transition: border-color 140ms ease, transform 140ms ease, box-shadow 140ms ease;
}
.admin-recent-item:hover {
  border-color: #DDD3BA;
}
.admin-recent-item[data-open="1"] {
  border-color: #C8BDA0;
  box-shadow: 0 2px 6px rgba(55, 59, 77, 0.05);
}
.admin-recent-item.is-new {
  animation: adminRecentSlide 420ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes adminRecentSlide {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .admin-recent-item.is-new { animation: none; }
}

.admin-recent-summary {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) auto;
  align-items: center;
  gap: 9px;
  padding: 8px 10px;
  background: transparent;
  border: 0;
  width: 100%;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
}
.admin-recent-summary:focus-visible {
  outline: 2px solid #B6D4F2;
  outline-offset: -2px;
  border-radius: 10px;
}
.admin-recent-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  background: #C68C5B; /* default warm; overridden per item via inline style */
  border: 1.5px solid rgba(255, 255, 255, 0.9);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15);
  flex-shrink: 0;
}
.admin-recent-stack {
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: 1px;
}
.admin-recent-name {
  font-size: 0.84rem;
  font-weight: 600;
  color: #373B4D;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.2;
}
.admin-recent-sub {
  font-size: 0.7rem;
  color: #7A7466;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.25;
}
.admin-recent-sub b {
  color: #4A4434;
  font-weight: 600;
}
.admin-recent-pill {
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #7A7466;
  background: #F2EAD3;
  padding: 3px 7px;
  border-radius: 999px;
  white-space: nowrap;
  flex-shrink: 0;
}

.admin-recent-body {
  padding: 4px 12px 12px 12px;
  border-top: 1px dashed #ECE5D6;
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: #FFFEFA;
}
.admin-recent-body[hidden] { display: none; }
.admin-recent-row {
  font-size: 0.78rem;
  color: #4A4434;
  line-height: 1.4;
}
.admin-recent-row dt {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #9A9485;
  margin-bottom: 2px;
}
.admin-recent-row dd { margin: 0; }
.admin-recent-row--summary dd {
  background: #FCFAF6;
  border-left: 2px solid #D8C99F;
  padding: 6px 9px;
  border-radius: 0 6px 6px 0;
  color: #3A3424;
  white-space: pre-wrap;
}
.admin-recent-actions {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
  padding-top: 2px;
}
.admin-recent-hcp {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 6px 10px;
  background: #373B4D;
  color: #FFFFFF;
  border-radius: 8px;
  font-size: 0.74rem;
  font-weight: 600;
  text-decoration: none;
  letter-spacing: 0.01em;
  transition: background 140ms ease, transform 100ms ease;
}
.admin-recent-hcp:hover { background: #143666; }
.admin-recent-hcp:active { transform: translateY(1px); }
.admin-recent-hcp svg { flex-shrink: 0; }
.admin-recent-hcp.is-disabled {
  background: #E5DDC8;
  color: #9A9485;
  pointer-events: none;
}

.admin-customer-search {
  position: relative;
  /* Flex item in the single-row banner: fills the room between the
     location picker and the scope toggle, and wraps to its own
     full-width line when the row gets squeezed (the banner row is
     flex-wrap: wrap). */
  flex: 1 1 280px;
  min-width: 240px;
}
/* Scope toggle. Lives inline in the banner row beside the location
   picker so it doesn't eat vertical space above the customer search.
   Slowness warning is tucked behind a help icon (tooltip on
   hover/focus). Minimal chrome — reads as a subtle control, not a
   panel. */
.admin-customer-search-scope {
  display: flex;
  align-items: center;
  gap: 6px;
}
.admin-customer-search-scope-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px 4px 4px;
  background: transparent;
  border: 0;
  border-radius: 999px;
  font: inherit;
  cursor: pointer;
  color: #373B4D;
  transition: background 0.12s ease;
}
.admin-customer-search-scope-toggle:hover,
.admin-customer-search-scope-toggle:focus-visible {
  outline: none;
  background: rgba(191, 224, 243, 0.22);
}
.admin-customer-search-scope-toggle[data-scope-state="on"] {
  background: rgba(31, 90, 134, 0.10);
}
.admin-customer-search-scope-switch {
  position: relative;
  width: 30px;
  height: 17px;
  background: #E5DED3;
  border-radius: 999px;
  flex: 0 0 auto;
  transition: background 0.18s ease;
}
.admin-customer-search-scope-switch-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: #FFFDF9;
  box-shadow: 0 1px 3px rgba(55, 59, 77, 0.18);
  transition: transform 0.18s ease;
}
.admin-customer-search-scope-toggle[data-scope-state="on"] .admin-customer-search-scope-switch {
  background: #1F5A86;
}
.admin-customer-search-scope-toggle[data-scope-state="on"] .admin-customer-search-scope-switch-knob {
  transform: translateX(13px);
}
.admin-customer-search-scope-label {
  font-size: 0.82rem;
  font-weight: 600;
  color: #373B4D;
  letter-spacing: 0.01em;
}
.admin-customer-search-scope-toggle[data-scope-state="on"] .admin-customer-search-scope-label {
  color: #1F5A86;
}
