﻿/* ============================================================
   Kylo App — Custom Styles
   Bootstrap 5 + Figtree (+ Playfair Display on public/platform pages only)
   ============================================================ */

/* === Google Fonts loaded in HTML === */

/* === Root Variables === */
:root {
  --sage-50:  #F0F5F0;
  --sage-100: #D6E8D6;
  --sage-200: #AECFAE;
  --sage-500: #5B7A5A;
  --sage-600: #4A6449;
  --sage-700: #3A5039;
  --sage-800: #283928;

  /* RGB triplets for gradient overlays — overridden by applyTheme() */
  --sage-overlay-dark:  40 57 40;
  --sage-overlay-mid:   58 80 57;
  --sage-overlay-light: 74 100 73;

  --gold-400: #D4A853;
  --gold-500: #C49A3C;

  --warm-50:  #FDFAF5;
  --warm-100: #F5EFE0;
  --warm-200: #E8DCCA;

  --text-primary:   #1C2B1C;
  --text-secondary: #4A5C4A;
  --text-muted:     #7A8C7A;

  /* Public-surface tokens (v323). Light presets inherit these defaults; only a
     dark preset (carbon) overrides them via applyTheme(). ⚠ PUBLIC pages only —
     admin components read --bs-* from the portal skin, never these. */
  --surface:    #fff;      /* card / panel background */
  --on-accent:  #fff;      /* text sitting ON a --sage-500 fill */
  --rating-off: #cfc6b6;   /* unlit rating star + carousel dot */

  /* Slot colours — duration based */
  --slot-30:      #0D9488;
  --slot-30-bg:   #99F6E4;
  --slot-30-text: #134E4A;

  --slot-45:      #2563EB;
  --slot-45-bg:   #93C5FD;
  --slot-45-text: #1E3A8A;

  --slot-60:      #7C3AED;
  --slot-60-bg:   #C4B5FD;
  --slot-60-text: #3B0764;

  --slot-75:      #9333EA;
  --slot-75-bg:   #E879F9;
  --slot-75-text: #4A044E;

  --slot-pending:      #3B82F6;
  --slot-pending-bg:   #DBEAFE;
  --slot-pending-text: #1E3A8A;

  --slot-requested:      #D97706;
  --slot-requested-bg:   #FDE68A;
  --slot-requested-text: #78350F;

  --slot-confirmed:      #16A34A;
  --slot-confirmed-bg:   #DCFCE7;
  --slot-confirmed-text: #14532D;

  --slot-booked:      #DC2626;
  --slot-booked-bg:   #FECACA;
  --slot-booked-text: #7F1D1D;

  --slot-blocked:      #6B7280;
  --slot-blocked-bg:   #D1D5DB;
  --slot-blocked-text: #374151;

  --radius:    0.75rem;
  --radius-lg: 1.25rem;
  --shadow:    0 2px 8px rgba(0,0,0,.07);
  --shadow-lg: 0 8px 24px rgba(0,0,0,.10);
}

/* === Placeholder styling — clearly distinct from entered text === */
::placeholder {
  font-style: italic;
  color: #9CA3AF;
  opacity: 1; /* Firefox reduces opacity by default */
}

/* === Field help text — de-emphasized so the input stays front === */
.form-text {
  font-size: .72rem;
  line-height: 1.35;
}

/* === Base === */
body {
  font-family: 'Figtree', system-ui, -apple-system, sans-serif;
  color: var(--text-primary);
  background-color: var(--warm-50);
  line-height: 1.65;
}

h1, h2, h3, h4, .font-serif {
  font-family: 'Playfair Display', Georgia, serif;
}

/* === Links — APP-WIDE STANDARD ==============================================
   Every textual hyperlink, public site and admin portal alike:
     • colour = the classic web link blue (decided 2026-07-31: theme-derived
       link colours are OUT — the user chose the blue everyone already reads
       as "this is a link" over matching the tenant palette). The pair below
       is Bootstrap's own default link/hover blue, so .btn-link and every
       other link-derived component matches natively. #0d6efd sits at ~3.7:1
       on white — under WCAG AA, accepted deliberately.
     • underlined
     • NOT bold
   Route any future tweak through --link-color / --link-color-hover — never
   hand-style an anchor inline (that is what this block replaced).

   Anchors that are CONTROLS — buttons, nav items, dropdown items, chips,
   pagination, list-group rows, and the links sitting on the dark sage chrome
   (topbar, footer, logout splash) — are not links and must NOT pick this up.
   They all carry their own class rule with both `color` and
   `text-decoration: none` at >= (0,1,0) specificity, so the bare `a` selector
   below loses to them by cascade.

   THE HOVER RULE MUST STAY INSIDE :where(). Component base rules
   (.dropdown-item, .nav-link, .btn) declare text-decoration: none at (0,1,0)
   but do NOT re-declare it in their :hover rules — a plain `a:hover` at
   (0,1,1) out-specifies the base rule the moment the cursor arrives and
   underlines every anchor-built control in the app (that is exactly how the
   ribbon Status menu shipped with underlined entries). :where() zeroes the
   pseudo-class, keeping hover at (0,0,1), so a control's base rule keeps
   winning in every state. `.link-plain` is the escape hatch for any new
   chrome anchor that has no rule of its own.
   ========================================================================== */
:root {
  --link-color:       #0d6efd;
  --link-color-hover: #0a58ca;

  /* Bootstrap components that derive from the link colour (.btn-link, etc.) */
  --bs-link-color:       var(--link-color);
  --bs-link-hover-color: var(--link-color-hover);
}

a {
  color: var(--link-color);
  text-decoration: underline;
  font-weight: 400;
}
a:where(:hover, :focus) {
  color: var(--link-color-hover);
  text-decoration: underline;
}

/* Escape hatch: an anchor used as chrome, not as a link */
a.link-plain,
a.link-plain:hover,
a.link-plain:focus {
  color: inherit;
  font-weight: inherit;
  text-decoration: none;
}

/* === Navbar === */
#mainNav {
  background-color: var(--warm-50);
  border-bottom: 1px solid var(--warm-200);
  padding: .875rem 0;
}
#mainNav .navbar-brand {
  font-family: 'Playfair Display', serif;
  font-weight: 700;
  font-size: 1.2rem;
  color: var(--sage-700);
  letter-spacing: -.01em;
}
#mainNav .navbar-brand:hover { color: var(--sage-500); }
#mainNav .nav-link {
  color: var(--text-secondary);
  font-weight: 500;
  font-size: .9375rem;
  padding: .4375rem .875rem;
  transition: color .15s;
}
#mainNav .nav-link:hover { color: var(--sage-500); }
#mainNav .nav-link.active {
  color: var(--sage-700);
  font-weight: 600;
  background: var(--sage-100);
  border-radius: .375rem;
}

/* === Buttons === */
.btn-sage {
  background-color: var(--sage-500);
  border-color: var(--sage-500);
  color: var(--on-accent);
  font-weight: 500;
  border-radius: .5rem;
  transition: background-color .2s, transform .1s;
}
.btn-sage:hover, .btn-sage:focus {
  background-color: var(--sage-600);
  border-color: var(--sage-600);
  color: var(--on-accent);
  transform: translateY(-1px);
}
.btn-sage:active { transform: none; }

.btn-outline-sage {
  border-color: var(--sage-500);
  color: var(--sage-500);
  font-weight: 500;
  border-radius: .5rem;
  transition: all .2s;
}
.btn-outline-sage:hover,
.btn-outline-sage:focus,
.btn-outline-sage.active,
.btn-outline-sage:active {
  background-color: var(--sage-500);
  border-color: var(--sage-500);
  color: var(--on-accent);
}

/* === Hero === */
.hero-section {
  position: relative;
  min-height: 43.2vh;
  display: flex;
  align-items: center;
  overflow: hidden;
  background-color: var(--sage-800);
}
.hero-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: .55;
}
.hero-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg,
    rgb(var(--sage-overlay-dark) / .85) 0%,
    rgb(var(--sage-overlay-mid)  / .60) 100%);
}
.hero-content {
  position: relative;
  z-index: 2;
  color: #fff;
}
.hero-content h1 {
  font-size: clamp(2.5rem, 5vw, 4rem);
  font-weight: 700;
  line-height: 1.1;
  margin-bottom: 1.25rem;
}
.hero-content .lead {
  font-size: 1.15rem;
  opacity: .9;
  max-width: 560px;
}

/* Industry-specific static fallback copy (hero headline, trust bar, business
   description…) is hidden until components.js has applied the tenant's own
   text, then revealed via html.business-ready — otherwise the massage-flavored
   markup defaults flash before the config fetch returns (same anti-flicker
   contract as the data-fallback-src images). visibility (not display) keeps
   the layout stable, so there is no reflow on reveal. */
.tenant-copy { visibility: hidden; }
html.business-ready .tenant-copy { visibility: visible; }

/* Flag-gated copy: [data-tenant-flag="<TENANT_FEATURES key>"] elements stay
   hidden until components.js confirms the tenant feature applies (adds
   .flag-on) — e.g. the insurance-receipts note on the Services page. */
[data-tenant-flag]:not(.flag-on) { display: none; }

/* Sub-page hero (shorter) */
.page-hero {
  position: relative;
  padding: 2.88rem 0;
  background-color: var(--sage-800);
  overflow: hidden;
}
.page-hero .hero-bg { opacity: .35; }
.page-hero .hero-overlay {
  background: linear-gradient(135deg,
    rgb(var(--sage-overlay-dark)  / .92) 0%,
    rgb(var(--sage-overlay-light) / .75) 100%);
}
.page-hero h1 {
  position: relative;
  z-index: 2;
  color: #fff;
  font-size: clamp(1.75rem, 4vw, 2.75rem);
}
.page-hero p {
  position: relative;
  z-index: 2;
  color: rgba(255,255,255,.8);
}

/* === Section helpers === */
.section-label {
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gold-500);
  margin-bottom: .5rem;
}
.section-title {
  font-size: clamp(1.625rem, 3vw, 2.25rem);
  font-weight: 700;
  color: var(--sage-700);
  margin-bottom: .5rem;
}
.section-sub {
  color: var(--text-muted);
  font-size: 1.0625rem;
  max-width: 560px;
}
hr.divider {
  width: 3rem;
  height: 3px;
  background: var(--gold-500);
  border: none;
  border-radius: 2px;
  margin: .75rem 0 1.75rem;
  opacity: 1;
}

/* === Cards === */
.card {
  border: 1px solid var(--warm-200);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  transition: box-shadow .2s, transform .2s;
  background: var(--surface);
}
.card:hover {
  box-shadow: var(--shadow-lg);
  transform: translateY(-3px);
}

/* === Modals on PUBLIC pages ================================================
   Bootstrap paints .modal-content from ITS tokens (white), while the text
   inside inherits the tenant palette's --text-primary — under a dark preset
   that is near-white text on a white dialog. Pin public modals to the tenant
   surface tokens instead; light presets resolve to exactly Bootstrap's own
   white-on-dark-text, so nothing changes for them. Admin modals are excluded:
   they belong to the portal skin (v301 boundary). */
body:not(.admin-page) .modal-content {
  background: var(--surface);
  color: var(--text-primary);
}

/* === Client feedback (v307) === */
/* Stars. Gold is the review convention everywhere on the web, and this is the
   one place on a tenant site where matching the convention beats matching the
   brand — a sage star does not read as a rating. */
.fb-stars { color: var(--gold-500); letter-spacing: .1em; white-space: nowrap; line-height: 1; }
.fb-stars .bi-star { opacity: .32; }
.fb-stars-sm { font-size: .8rem; }
.fb-quote { font-size: clamp(1.05rem, 2vw, 1.35rem); font-weight: 500; letter-spacing: -.01em; }
/* Bootstrap positions .carousel-indicators absolutely; pull it back into the
   flow so it can sit between the two arrows instead of over the quote. */
.fb-dots { position: static; display: flex; align-items: center; justify-content: center; gap: .4rem; margin: 0; padding: 0; }
.fb-dots [data-bs-target] {
  width: 7px; height: 7px; margin: 0; padding: 0; border: 0; opacity: 1; text-indent: 0;
  border-radius: 50%; background: var(--rating-off);
  transition: width .22s ease, background .22s ease, border-radius .22s ease;
}
.fb-dots .active { width: 22px; border-radius: 4px; background: var(--gold-500); }
/* The rating input in the portal's feedback modal. A radio group under the
   hood — the stars are the LABELS, so keyboard and screen readers get a real
   control instead of five clickable icons. */
.fb-rate { display: inline-flex; flex-direction: row; gap: .15rem; }
.fb-rate input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.fb-rate label { cursor: pointer; font-size: 1.6rem; line-height: 1; color: var(--rating-off); transition: color .12s ease; }
.fb-rate label:hover { color: var(--gold-500); }
.fb-rate.is-set label.fb-on { color: var(--gold-500); }
.fb-rate input:focus-visible + label { outline: 2px solid var(--sage-600); outline-offset: 2px; border-radius: 3px; }

/* === Pricing Cards === */
.pricing-card { border-top-width: 4px; }
.pricing-card.dur-30 { border-top-color: var(--slot-30); }
.pricing-card.dur-45 { border-top-color: var(--slot-45); }
.pricing-card.dur-60 { border-top-color: var(--slot-60); }
.pricing-card.dur-75 { border-top-color: var(--slot-75); }

.duration-badge {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .3rem .85rem;
  border-radius: 999px;
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
}
.dur-30 .duration-badge { background: var(--slot-30-bg); color: var(--slot-30-text); }
.dur-45 .duration-badge { background: var(--slot-45-bg); color: var(--slot-45-text); }
.dur-60 .duration-badge { background: var(--slot-60-bg); color: var(--slot-60-text); }
.dur-75 .duration-badge { background: var(--slot-75-bg); color: var(--slot-75-text); }

.price-big {
  font-family: 'Playfair Display', serif;
  font-size: 2.75rem;
  font-weight: 700;
  line-height: 1;
  color: var(--sage-700);
}

/* === Calendar / Slot Buttons === */
.slot-btn {
  display: block;
  width: 100%;
  text-align: left;
  border: none;
  border-radius: .5rem;
  padding: .625rem .875rem;
  font-size: .8125rem;
  font-weight: 500;
  cursor: pointer;
  transition: opacity .15s, transform .1s;
  margin-bottom: .4375rem;
  border-left: 4px solid transparent;
  line-height: 1.4;
}
.slot-btn:last-child { margin-bottom: 0; }
.slot-btn:hover:not([disabled]) { opacity: .85; transform: translateX(2px); }
.slot-btn[disabled] { cursor: not-allowed; }

.slot-btn.dur-30       { background: var(--slot-30-bg);        color: var(--slot-30-text);        border-left-color: var(--slot-30); }
.slot-btn.dur-45       { background: var(--slot-45-bg);        color: var(--slot-45-text);        border-left-color: var(--slot-45); }
.slot-btn.dur-60       { background: var(--slot-60-bg);        color: var(--slot-60-text);        border-left-color: var(--slot-60); }
.slot-btn.dur-75       { background: var(--slot-75-bg);        color: var(--slot-75-text);        border-left-color: var(--slot-75); }
.slot-btn.requested    { background: var(--slot-requested-bg); color: var(--slot-requested-text); border-left-color: var(--slot-requested); }
.slot-btn.confirmed    { background: var(--slot-booked-bg);    color: var(--slot-booked-text);    border-left-color: var(--slot-booked); }
.slot-btn.blocked      { background: repeating-linear-gradient(135deg, #E5E7EB 0px, #E5E7EB 6px, #D1D5DB 6px, #D1D5DB 12px); color: var(--slot-blocked-text); border-left-color: var(--slot-blocked); }

/* Calendar day card */
.day-card {
  border: 1px solid var(--warm-200);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.day-card .day-header {
  background: var(--sage-50);
  border-bottom: 1px solid var(--sage-100);
  padding: .75rem 1rem;
  display: flex;
  align-items: center;
  gap: .75rem;
}
.day-card .day-num {
  font-family: 'Playfair Display', serif;
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--sage-700);
  line-height: 1;
}
.day-card .day-name {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.day-card .day-month {
  font-size: .8125rem;
  color: var(--text-secondary);
}
.day-card .day-body { padding: .875rem; }
.day-card .no-slots {
  color: var(--text-muted);
  font-size: .8125rem;
  font-style: italic;
  text-align: center;
  padding: .75rem 0;
}

/* Holiday day card */
.day-card--holiday { opacity: .75; }
.day-card--holiday .day-header {
  background: var(--slot-blocked-bg);
  border-bottom-color: var(--slot-blocked);
}
.day-card--holiday .day-header .day-num,
.day-card--holiday .day-header .day-name,
.day-card--holiday .day-header .day-month { color: var(--slot-blocked-text); }

.holiday-closed {
  background: var(--slot-blocked-bg);
  color: var(--slot-blocked-text);
  border-left: 4px solid var(--slot-blocked);
  border-radius: .5rem;
  padding: .625rem .875rem;
  font-size: .8125rem;
  font-weight: 500;
}

/* === Legend === */
.legend-swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  flex-shrink: 0;
}

/* === Steps === */
.step-circle {
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--sage-500);
  color: var(--on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1.125rem;
  flex-shrink: 0;
  box-shadow: 0 4px 12px rgba(91,122,90,.35);
}

/* === Service chip (provider qualifications list) === */
.svc-chip {
  display: inline-block;
  font-size: .72rem;
  font-weight: 500;
  padding: .18rem .52rem;
  border-radius: .3rem;
  border: 1px solid var(--sage-200);
  color: var(--sage-600);
  background: transparent;
  text-decoration: none;
  transition: background .15s, border-color .15s, color .15s, box-shadow .15s;
  white-space: nowrap;
}
.svc-chip:hover {
  background: var(--sage-50);
  border-color: var(--sage-500);
  color: var(--sage-700);
  box-shadow: 0 1px 4px rgba(0,0,0,.08);
  text-decoration: none;
}

/* === Feature Icons === */
.feature-icon {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: var(--radius);
  background: var(--sage-50);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  color: var(--sage-500);
  margin-bottom: 1rem;
  flex-shrink: 0;
}

/* === Footer === */
#site-footer {
  background: var(--sage-800);
  color: rgba(255,255,255,.8);
}
#site-footer h5, #site-footer h6 {
  color: #fff;
  font-family: 'Playfair Display', serif;
}
#site-footer a { color: rgba(255,255,255,.65); text-decoration: none; transition: color .15s; }
#site-footer a:hover { color: #fff; }
#site-footer hr { border-color: rgba(255,255,255,.15); opacity: 1; }

/* === Admin === */
/* 2026-08-03 theme adoption: the admin portal wears STOCK BOOTSTRAP colors —
   sage retired back-office-wide (public tenant pages keep their brand
   palettes). Chrome went from dark sage to Bootstrap's neutral dark. */
/* ⚠ Both background AND color pin to the PORTAL skin's tokens. The tenant's
   public palette is injected into :root on admin pages too (applyAdminTheme),
   and since carbon (v323) that palette can be DARK — without these pins a dark
   tenant preset would repaint admin text/cards while the skin stays light. */
.admin-page { min-height: 100vh; background: var(--bs-body-bg, #fff); color: var(--bs-body-color, #212529); }
/* Admin cards wear the skin, not the tenant brand: the bare .card rule above
   is a PUBLIC component (tenant --surface / --warm borders). This also gives
   Darkly/Slate dark cards instead of the white publics ones. */
body.admin-page .card {
  background: var(--bs-card-bg, var(--bs-body-bg, #fff));
  border-color: var(--bs-border-color, #dee2e6);
}
/* .bg-warm on an admin page = "subtle hint band", not the tenant's warm cream —
   the tenant token goes near-black under carbon. */
body.admin-page .bg-warm { background-color: var(--bs-tertiary-bg, #f8f9fa) !important; }

.admin-accent {
  position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 1200;
  background: linear-gradient(90deg,#9a7a2e 0%,#C9A84C 35%,#e8d08a 50%,#C9A84C 65%,#9a7a2e 100%);
}
.admin-topbar {
  background: #212529 !important;
  border-bottom: 1px solid rgba(255,255,255,.08) !important;
}
#adminFooter {
  background: #212529 !important;
}
.admin-topbar .btn-outline-secondary {
  color: rgba(255,255,255,.65); border-color: rgba(255,255,255,.18); background: transparent;
}
.admin-topbar .btn-outline-secondary:hover {
  background: rgba(255,255,255,.1); color: #fff; border-color: rgba(255,255,255,.3);
}
.admin-topbar .btn-outline-secondary.active {
  background: #fff; color: #212529; border-color: #fff; font-weight: 600;
}
.admin-topbar .month-label         { color: #fff; }
/* "Muted" on the dark topbar was .4 — legible on a big bright monitor, dim
   everywhere else, and the signed-in email is the one label an operator checks
   at a glance (is this the right account?). Lifted to .78, with the whole
   profile link going white on hover so it reads as the link it has always been. */
.admin-topbar .text-muted          { color: rgba(255,255,255,.78) !important; }
.admin-topbar .bi-person-circle    { color: rgba(255,255,255,.7) !important; }
.admin-topbar a:hover .text-muted,
.admin-topbar a:hover .bi-person-circle { color: #fff !important; }
.admin-topbar .admin-user-sep      { border-left: 1px solid rgba(255,255,255,.15) !important; }
.admin-supertitle {
  font-size: .62rem; letter-spacing: .12em; text-transform: uppercase;
  color: rgba(255,255,255,.3); font-weight: 500; line-height: 1; margin-bottom: 4px;
}
.admin-badge {
  font-size: .58rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  background: #DC2626; color: #fff; padding: .15rem .45rem; border-radius: 3px;
  vertical-align: middle; position: relative; top: -1px;
}

.admin-login-wrap {
  min-height: 100vh;
  background: linear-gradient(135deg, #212529 0%, #495057 100%);
  display: flex;
  align-items: center;
}

/* Width lives in a CSS var so the drag divider (#sidebarResizer) can set it
   inline; the collapsed rail below is id+class, so it still wins over the var.
   280px (was 240) because the header row didn't fit: the MafcoTrades™ wordmark
   is ≈135px (Figtree 700 at 1.4rem, measured), plus the logo mark, the rail
   toggle, ~36px of padding and the nav's own scrollbar — ≈260px in total, which
   ellipsised itself to "MafcoTrad…" at 240. */
#adminSidebar {
  width: var(--admin-sidebar-w, 280px);
  height: 100vh;
  overflow-y: auto;
  overflow-x: hidden;
  background: #212529;
  flex-shrink: 0;
  position: sticky;
  top: 0;
  transition: width .22s ease;
}
#adminSidebar.sidebar--collapsed { width: 58px; }
#adminSidebar.sidebar--resizing { transition: none; }  /* no easing while dragging */

/* ── Dark admin skins (v301) ──────────────────────────────────────────────────
   The chrome above is deliberately a CONSTANT neutral dark (#212529) rather
   than a skin token: it is the product's frame, and under the ten light skins
   it must keep reading exactly as it does today. That constant is what breaks
   on Darkly/Slate — their canvas is ~#222, near-identical to the chrome, so the
   sidebar, topbar and footer dissolve into the page and the portal loses its
   structure. A hairline is enough to restore the edge; nothing is recoloured.
   applyAdminSkin() (config.js) sets the attribute from the registry's dark
   flag, and the <head> pre-paint re-applies it from cache before first paint. */
:root[data-admin-skin-dark] #adminSidebar { border-right:  1px solid var(--bs-border-color); }
:root[data-admin-skin-dark] .admin-topbar { border-bottom: 1px solid var(--bs-border-color) !important; }
/* ⚠ !important on both: the topbar's border-bottom is set by an !important rule
   above, and #adminFooter carries its border-top as an INLINE style on every
   admin page — a plain rule here would silently never apply. */
:root[data-admin-skin-dark] #adminFooter  { border-top:    1px solid var(--bs-border-color) !important; }
#adminSidebar.sidebar--collapsed .nav-text { display: none; }
#adminSidebar.sidebar--collapsed .nav-link { justify-content: center; padding: .75rem 0; }
#adminSidebar.sidebar--collapsed .sidebar-divider { margin: .375rem .5rem; }
#adminSidebar.sidebar--collapsed #sidebarChevron { transform: rotate(180deg); }

.sidebar-header {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: .85rem 1rem .7rem 1.25rem;
  border-bottom: 1px solid rgba(255,255,255,.1);
  min-width: 0;
}
.sidebar-brand {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  min-width: 0;
}
.sidebar-header .nav-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* Collapsed rail (58px): stack the mark above the toggle, centered; text hides via .nav-text */
#adminSidebar.sidebar--collapsed .sidebar-header { align-items: center; padding: .7rem 0; }
#adminSidebar.sidebar--collapsed .sidebar-brand { flex-direction: column; gap: .45rem; }
/* Rail toggle: the chevron beside the wordmark. It was rgba(255,255,255,.5) with
   no background — invisible against the dark chrome. Now a solid pill that reads
   as a control, gold on hover. Fixed 26px square so the header width is predictable. */
#sidebarToggleBtn {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  background: rgba(255,255,255,.14);
  border: 1px solid rgba(255,255,255,.28);
  color: #fff;
  cursor: pointer;
  border-radius: 6px;
  line-height: 1;
  transition: color .15s, background .15s, border-color .15s;
}
#sidebarToggleBtn:hover,
#sidebarToggleBtn:focus-visible {
  background: var(--gold-400);
  border-color: var(--gold-400);
  color: #212529;
}
#sidebarChevron { transition: transform .22s ease; display: block; font-size: .85rem; }
/* (Legacy #adminSidebar .sidebar-brand block removed — its 1.5rem padding + display:block
   fought the new logo row and clipped the wordmark; the .sidebar-brand flex rule above governs.) */
#adminSidebar .sidebar-divider {
  border: 0;
  border-top: 1px solid rgba(255,255,255,.15);
  margin: .5rem 1rem;
  opacity: 1;
}

/* ── Drag divider between the menu and the content ─────────────────────────
   #sidebarResizer is injected right after #adminSidebar by initSidebar(); it
   writes --admin-sidebar-w on the sidebar, so the 58px rail rule (id + class)
   still outranks it while collapsed. Hidden in rail mode and on mobile. */
.sidebar-resizer {
  flex: 0 0 6px;
  align-self: stretch;
  position: relative;
  background: #212529;
  cursor: col-resize;
  touch-action: none;
}
.sidebar-resizer::before {
  content: '';
  position: absolute;
  inset: 0 2px;
  background: rgba(255,255,255,.12);
  transition: background .15s;
}
.sidebar-resizer:hover::before,
.sidebar-resizer:focus-visible::before,
.sidebar-resizer.is-dragging::before { background: var(--gold-400); }
.sidebar-resizer:focus { outline: none; }
#adminSidebar.sidebar--collapsed + .sidebar-resizer { display: none; }

/* ── Collapsible nav groups (v238) ─────────────────────────────────────────── */
#adminSidebar .nav-group { display: flex; flex-direction: column; }
#adminSidebar .nav-group-header {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  background: none;
  border: 0;
  cursor: pointer;
  color: rgba(255,255,255,.45);
  font-size: .9375rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: .8rem 1.5rem .35rem;
  transition: color .15s;
}
#adminSidebar .nav-group-header:hover { color: rgba(255,255,255,.8); }
#adminSidebar .nav-group-caret { font-size: .7rem; transition: transform .2s ease; flex-shrink: 0; }
#adminSidebar .nav-group.collapsed .nav-group-caret { transform: rotate(-90deg); }
#adminSidebar .nav-group.collapsed .nav-group-items { display: none; }
/* Icon rail (58px): hide the headers and always show the icons — a flat rail, so
   per-group collapse is ignored while collapsed (matches the pre-v238 behaviour). */
#adminSidebar.sidebar--collapsed .nav-group-header { display: none; }
#adminSidebar.sidebar--collapsed .nav-group.collapsed .nav-group-items { display: block; }
/* Blank until role + feature gating has run, so nobody clicks a header that is
   about to move (see .nav--gating in admin-common.js injectSharedHTML). */
#adminSidebar .nav--gating { visibility: hidden; }

.settings-section-heading {
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--bs-secondary-color, #6c757d);
  margin-bottom: 1rem;
  padding-bottom: .4rem;
  border-bottom: 2px solid var(--bs-border-color, #dee2e6);
}

/* ── ADMIN PORTAL TYPOGRAPHY ───────────────────────────────────────────────────
   The back-office is an operational tool, not an editorial page, so admin
   headings drop the Playfair serif and run Figtree — the same call the public
   pages made in the Trades skin block below, which keeps one typeface across the
   whole product. Weight and tracking carry the hierarchy instead of a change of
   voice. (Lowercase "skin" on purpose: trades-skin.test.js splits styles.css on
   the literal banner text, so that marker has to stay unique to the real block.)

   Selector list mirrors the base `h1,h2,h3,h4,.font-serif` rule so nothing
   shifts unpredictably (h5/h6 already inherit Figtree from body). Weight is set
   only on .font-serif — the admin's "this names a record" marker — because a
   blanket weight here would out-specify Bootstrap's .fw-* utilities on plain
   headings.

   Scoped body.admin-page: the marketing pages keep the serif and must render
   byte-identical, so every selector below is prefixed (grep-auditable).
   ───────────────────────────────────────────────────────────────────────────── */
body.admin-page h1, body.admin-page h2, body.admin-page h3,
body.admin-page h4, body.admin-page .font-serif {
  font-family: 'Figtree', system-ui, -apple-system, sans-serif;
  letter-spacing: -.015em;
}
body.admin-page .font-serif { font-weight: 600; }

/* Figures: identifiers and money are data, not prose. Fixed-width digits so
   Q-000459 reads as a record number and amount columns align down the grid
   instead of drifting row to row. Figtree ships `tnum` and has only the one
   (lining) figure style — no lnum/onum — so `tabular-nums` alone is the whole
   declaration; adding lining-nums would be a no-op. */
body.admin-page h1, body.admin-page h2, body.admin-page h3,
body.admin-page h4, body.admin-page .font-serif,
body.admin-page .table-responsive > table.table,
body.admin-page .form-control-plaintext {
  font-variant-numeric: tabular-nums;
}

/* Opt into fixed-width digits anywhere, public pages included (unscoped on
   purpose — it does nothing until an element asks for it). */
.tnum { font-variant-numeric: tabular-nums; }

/* ── App-wide grid style (neutral header) ─────────────────────────────────────
   Applies to every admin grid (the standard `.table-responsive > table.table`
   pattern). Bootstrap-native since the 2026-08-03 theme adoption: light
   header a touch larger than the body text, rounded card, subtle zebra
   striping, Bootstrap's own hover tint. */
body.admin-page .table-responsive > table.table {
  border-collapse: separate;
  border-spacing: 0;
  overflow: hidden;
  border-radius: 10px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .06);
}
body.admin-page .table-responsive > table.table > thead > tr > th {
  background: var(--bs-tertiary-bg, #f8f9fa) !important;
  color: var(--bs-emphasis-color, #000);
  border: 0;
  box-shadow: none;
  font-size: .95rem;          /* a bit bigger than the grid body text */
  font-weight: 600;
  letter-spacing: .02em;
  padding: .6rem .8rem;
}
/* sort-arrow icons read muted on the light header */
body.admin-page .table-responsive > table.table > thead > tr > th i { color: var(--bs-secondary-color, #6c757d) !important; opacity: .9; }
body.admin-page .table-responsive > table.table > tbody > tr > td { border-top: 0; border-bottom: 1px solid var(--bs-border-color-translucent, #f0f1f2); }
body.admin-page .table-responsive > table.table > tbody > tr:nth-child(even) > td { background: var(--bs-tertiary-bg, #f8f9fa); }
body.admin-page .table-responsive > table.table > tbody > tr:last-child > td { border-bottom: 0; }

/* Master-detail selected row (services.html): the row whose Items fill the
   subgrid below. Painted like Bootstrap's hover (inset shadow, so it wins over
   the zebra background) + a left accent bar; a touch deeper than the hover
   tint so the selection stays readable while hovering other rows. */
body.admin-page .table-responsive > table.table > tbody > tr.svc-row-selected > td {
  box-shadow: inset 0 0 0 9999px var(--bs-primary-bg-subtle, #cfe2ff);
}
body.admin-page .table-responsive > table.table > tbody > tr.svc-row-selected > td:first-child {
  box-shadow: inset 3px 0 0 var(--bs-primary, #0d6efd), inset 0 0 0 9999px var(--bs-primary-bg-subtle, #cfe2ff);
}

/* Bootstrap tab bars (e.g. tenant-detail, the user modal) — bold labels; the
   active tab uses the primary tint + accent underline instead of a white box. */
.nav-tabs { border-bottom-color: var(--bs-border-color); }
.nav-tabs .nav-link {
  font-weight: 600;
  color: var(--bs-secondary-color);
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.nav-tabs .nav-link:hover { color: var(--bs-primary); border-bottom-color: var(--bs-border-color); }
.nav-tabs .nav-link.active {
  color: var(--bs-primary);
  background: var(--bs-primary-bg-subtle);
  border: none;
  border-bottom: 2px solid var(--bs-primary);
  border-radius: .375rem .375rem 0 0;
  font-weight: 700;
}

/* Contextual help "?" affordance */
.help-dot {
  border: 0;
  background: none;
  padding: 0;
  margin-left: .4rem;
  line-height: 1;
  color: var(--bs-primary, #0d6efd);
  cursor: pointer;
  font-size: 1.1rem;
  vertical-align: middle;
  transition: color .15s, transform .1s;
}
.help-dot:hover { color: var(--bs-link-hover-color, #0a58ca); transform: scale(1.12); }
/* On the dark topbar the sage help-dot vanishes — lighten it there. */
.admin-topbar .help-dot { color: rgba(255,255,255,.65); }
.admin-topbar .help-dot:hover { color: #fff; }
.admin-pane .card h6 {
  color: var(--bs-secondary-color, #6c757d);
}
.admin-pane .form-control,
.admin-pane .form-select,
.modal .form-control,
.modal .form-select,
/* Read-only field VALUES are fields too (2026-08-03): .form-control-plaintext
   kept Bootstrap's 1rem while every input beside it ran .875rem, so a plain
   value — and much more visibly a linked one, being blue and underlined —
   rendered a size larger than the form around it. Same size, same field.
   (A value that is deliberately big, e.g. the quote Total, pins its own
   font-size inline and still wins.) */
.admin-pane .form-control-plaintext,
.modal .form-control-plaintext {
  font-size: .875rem;
}
/* Public product forms (onboarding) — match the page's .875rem text so inputs
   don't render at Bootstrap's larger default. */
.product-form .form-control,
.product-form .form-select,
.product-form .input-group-text {
  font-size: .875rem;
}
.pd-field-label {
  font-size: .875rem;
  font-weight: 400;
  color: #6c757d;
  display: block;
  margin-bottom: .25rem;
}
#adminSidebar .nav-link {
  color: rgba(255,255,255,.7);
  padding: .75rem 1.5rem;
  font-size: .9375rem;
  transition: background .15s, color .15s;
  border-radius: 0;
  display: flex;
  align-items: center;
  gap: .625rem;
}
#adminSidebar .nav-link:hover,
#adminSidebar .nav-link.active {
  background: rgba(255,255,255,.1);
  color: #fff;
}

.admin-slot-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: .5rem .75rem;
  border-radius: .4375rem;
  border: none;
  font-size: .8rem;
  font-weight: 500;
  margin-bottom: .375rem;
  cursor: pointer;
  transition: opacity .15s;
  border-left: 3px solid transparent;
  text-align: left;
}
.admin-slot-btn:hover { opacity: .85; }
.admin-slot-btn.dur-30    { background: var(--slot-30-bg);        color: var(--slot-30-text);        border-left-color: var(--slot-30); }
.admin-slot-btn.dur-45    { background: var(--slot-45-bg);        color: var(--slot-45-text);        border-left-color: var(--slot-45); }
.admin-slot-btn.dur-60    { background: var(--slot-60-bg);        color: var(--slot-60-text);        border-left-color: var(--slot-60); }
.admin-slot-btn.dur-75    { background: var(--slot-75-bg);        color: var(--slot-75-text);        border-left-color: var(--slot-75); }
.admin-slot-btn.pending   { background: var(--slot-pending-bg);    color: var(--slot-pending-text);    border-left-color: var(--slot-pending); }
.admin-slot-btn.requested { background: var(--slot-requested-bg);  color: var(--slot-requested-text);  border-left-color: var(--slot-requested); }
.admin-slot-btn.confirmed { background: var(--slot-booked-bg);    color: var(--slot-booked-text);    border-left-color: var(--slot-booked); }
.admin-slot-btn.blocked           { background: #E5E7EB; color: var(--slot-blocked-text); border-left-color: var(--slot-blocked); }
.admin-slot-btn.cancelled         { background: #F9FAFB; color: #9CA3AF; border-left-color: #E5E7EB; font-style: italic; opacity: .75; }
.admin-slot-btn.cancelled-admin   { background: repeating-linear-gradient(135deg, #E5E7EB 0px, #E5E7EB 6px, #D1D5DB 6px, #D1D5DB 12px); color: var(--slot-blocked-text); border-left-color: var(--slot-blocked); font-style: italic; opacity: .75; }

/* === Utility === */
.bg-warm      { background-color: var(--warm-100) !important; }
.bg-surface   { background-color: var(--surface) !important; }  /* tenant-aware "white" — follows a dark preset */
.text-sage    { color: var(--sage-500) !important; }
.text-gold    { color: var(--gold-500) !important; }
.border-warm  { border-color: var(--warm-200) !important; }

/* === Rich text (Quill output rendered on public pages) === */
/* Graduated, close-together heading scale — deliberately NOT far apart, so the
   two-size jump we had with Trix is gone. h2/h3 come from Quill's header
   dropdown; h1/h4-h6 covered for pasted/legacy content. */
.rich-text > *:first-child { margin-top: 0; }
.rich-text > *:last-child  { margin-bottom: 0; }
.rich-text h1 { font-size: 1.3rem;  font-weight: 600; margin: .4rem 0; }
.rich-text h2 { font-size: 1.15rem; font-weight: 600; margin: .4rem 0; }
.rich-text h3 { font-size: 1.02rem; font-weight: 600; margin: .4rem 0; }
.rich-text h4, .rich-text h5, .rich-text h6 { font-size: .95rem; font-weight: 600; margin: .4rem 0; }
.rich-text ul, .rich-text ol { padding-left: 1.25rem; margin-bottom: .5rem; }
.rich-text blockquote {
  border-left: 3px solid var(--sage-200, #b8d4b8);
  padding-left: .75rem; margin: .5rem 0;
}
.rich-text pre { white-space: pre-wrap; }

/* Quill editors in the admin (every .rich-editor field) — the editing area is a
   resizable container: it opens at a comfortable height and the admin can drag
   the bottom edge down for more real-estate (overflow scrolls once content
   passes the dragged height / the viewport cap).

   Quill's own CSS pins .ql-container and .ql-editor to height:100%, which
   COLLAPSES when the parent has no fixed height — the editor then overflows its
   card. Force the container to auto so it grows with the (resizable) editor.
   Quill keeps the .rich-editor class on the container after init, so these
   selectors target every enhanced field. */
.rich-editor.ql-container { height: auto; }
.rich-editor .ql-editor {
  height: auto;          /* override Quill's 100% so min/max-height drive size */
  min-height: 12rem;     /* comfortable starting size */
  max-height: 80vh;      /* never taller than the viewport */
  overflow-y: auto;      /* scroll tall content + enables the resize grip */
  resize: vertical;      /* drag the bottom edge for more room */
}

/* === Month Calendar === */
.month-nav {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.month-nav .month-label {
  min-width: 160px;
  text-align: center;
  font-weight: 600;
  font-size: 1rem;
  color: var(--bs-secondary-color, #6c757d);
}

.month-cal-wrap {
  overflow-x: auto;
}
.month-cal-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 700px;
  table-layout: fixed;
}
.month-cal-th {
  background: var(--bs-tertiary-bg, #f8f9fa);
  border: 1px solid var(--bs-border-color, #dee2e6);
  text-align: center;
  padding: .4rem;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--bs-secondary-color, #6c757d);
}
.month-cal-cell {
  border: 1px solid var(--bs-border-color, #dee2e6);
  vertical-align: top;
  padding: .375rem .4rem;
  min-height: 90px;
  background: #fff;
}
.month-cal-cell--other   { background: #f9fafb; }
.month-cal-cell--weekend { background: #f4f6f4; }
.month-cal-cell--holiday { background: var(--slot-blocked-bg); }
.month-cal-cell--today   { outline: 2px solid var(--bs-primary); outline-offset: -2px; }

.month-cal-date {
  font-size: .95rem;
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
  margin-bottom: .25rem;
  line-height: 1;
}
.month-cal-cell--today .month-cal-date {
  color: var(--bs-primary);
}
.month-cal-cell--other .month-cal-date {
  opacity: .4;
}

.month-holiday-label {
  font-size: .7rem;
  font-weight: 500;
  color: var(--slot-blocked-text);
  background: var(--slot-blocked-bg);
  border-left: 3px solid var(--slot-blocked);
  padding: .2rem .4rem;
  border-radius: .25rem;
  margin-top: .15rem;
}

.month-no-slots {
  font-size: .75rem;
  color: var(--bs-secondary-color, #6c757d);
  opacity: .5;
  text-align: center;
  padding: .25rem 0;
}

/* Compact slot button for month view */
.admin-slot-btn--compact {
  padding: .2rem .4rem;
  font-size: .7rem;
  margin-bottom: .2rem;
  line-height: 1.3;
}
.admin-slot-btn--compact:last-child { margin-bottom: 0; }

/* === Booking: vertical day rows === */
.day-row {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  background: var(--surface);
  border: 1px solid var(--warm-200);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: .875rem 1rem;
  margin-bottom: .625rem;
}
.day-row--muted  { opacity: .5; }
.day-row--today  { border-color: var(--sage-500); box-shadow: 0 0 0 2px rgba(91,122,90,.18); }

.day-row-label {
  width: 64px;
  flex-shrink: 0;
  text-align: center;
  padding-top: .125rem;
}
.day-row-short {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.day-row-num {
  font-family: 'Playfair Display', serif;
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--sage-700);
  line-height: 1;
}
.day-row-month {
  font-size: .7rem;
  color: var(--text-muted);
  margin-top: .125rem;
}

.day-row-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  padding-top: .25rem;
}

.day-row-action {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .375rem;
  min-width: 140px;
  text-align: right;
}

.day-row-closed {
  font-size: .8125rem;
  font-weight: 500;
  color: var(--slot-blocked-text);
}

/* === Booking: booked slot pills === */
.booked-pill {
  display: inline-flex;
  flex-direction: column;
  padding: .3rem .65rem;
  border-radius: .375rem;
  background: var(--slot-booked-bg);
  border-left: 3px solid var(--slot-booked);
  line-height: 1.3;
}
.booked-pill-time {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--slot-booked-text);
}
.booked-pill-dur {
  font-size: .7rem;
  color: var(--slot-booked-text);
  opacity: .7;
}

/* Booked pill status variants */
.booked-pill--pending   { background: #FEF3C7; border-left-color: #F59E0B; }
.booked-pill--pending   .booked-pill-time,
.booked-pill--pending   .booked-pill-dur,
.booked-pill--pending   .booked-pill-status { color: #92400E; }

.booked-pill--requested { background: var(--slot-requested-bg); border-left-color: var(--slot-requested); }
.booked-pill--requested .booked-pill-time,
.booked-pill--requested .booked-pill-dur,
.booked-pill--requested .booked-pill-status { color: var(--slot-requested-text); }

.booked-pill--confirmed { background: var(--slot-confirmed-bg); border-left-color: var(--slot-confirmed); }
.booked-pill--confirmed .booked-pill-time,
.booked-pill--confirmed .booked-pill-dur,
.booked-pill--confirmed .booked-pill-status { color: var(--slot-confirmed-text); }

.booked-pill-status {
  font-size: .7rem;
  font-style: italic;
  opacity: .85;
}
.booked-pill-cancel-btn {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  margin-top: .25rem;
  font-size: .7rem;
  font-weight: 500;
  color: #DC2626;
  background: none;
  border: 1px solid #DC2626;
  border-radius: .375rem;
  padding: .2rem .55rem;
  cursor: pointer;
  opacity: .85;
  transition: background .15s, color .15s, opacity .15s;
}
.booked-pill-cancel-btn:hover { opacity: 1; background: #DC2626; color: #fff; text-decoration: none; }

/* === Booking: day card open state === */
.day-hours-info {
  font-size: .8125rem;
  color: var(--text-secondary);
  margin-bottom: .125rem;
}

/* === Booking: duration picker === */
.dur-pick {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: .625rem .5rem;
  border: 2px solid var(--warm-200);
  border-radius: .5rem;
  background: var(--surface);
  cursor: pointer;
  transition: border-color .15s, background .15s, color .15s;
  gap: .125rem;
}
.dur-pick:hover { border-color: var(--sage-500); background: var(--sage-50); }
.dur-pick-min   { font-size: .9375rem; font-weight: 600; }
.dur-pick-price { font-size: .8125rem; color: var(--text-muted); }
.dur-pick.active .dur-pick-price { color: inherit; opacity: .8; }

.dur-pick.dur-30.active { border-color: var(--slot-30); background: var(--slot-30-bg); color: var(--slot-30-text); }
.dur-pick.dur-45.active { border-color: var(--slot-45); background: var(--slot-45-bg); color: var(--slot-45-text); }
.dur-pick.dur-60.active { border-color: var(--slot-60); background: var(--slot-60-bg); color: var(--slot-60-text); }
.dur-pick.dur-75.active { border-color: var(--slot-75); background: var(--slot-75-bg); color: var(--slot-75-text); }

/* === Booking: dropdown selects === */
.booking-select {
  border: 2px solid var(--warm-200);
  border-radius: .5rem;
  padding: .625rem 2.5rem .625rem 1rem;
  font-size: .9rem;
  cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
}
.booking-select:hover { border-color: var(--sage-500); }
.booking-select:focus {
  border-color: var(--sage-500);
  box-shadow: 0 0 0 .25rem var(--sage-100);
  outline: none;
}

/* === Booking: time slot buttons === */
.time-slot-btn {
  padding: .35rem .75rem;
  border-radius: .375rem;
  border: 1.5px solid var(--sage-200);
  background: var(--surface);
  color: var(--sage-700);
  font-size: .8125rem;
  font-weight: 500;
  cursor: pointer;
  transition: all .15s;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
}
.time-slot-btn:hover                   { border-color: var(--sage-500); background: var(--sage-50); }
.time-slot-btn.selected                { border-color: var(--sage-500); background: var(--sage-500); color: var(--on-accent); }

.ts-meta {
  font-size: .75rem;
  font-weight: 400;
  opacity: .75;
  margin-left: .2rem;
}

/* === Admin Help / Flow Diagram === */
.flow-node {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  padding: .875rem 1.25rem;
  border-radius: var(--radius);
  border: 1.5px solid;
  width: 100%;
}
.flow-node--neutral   { background: #F9FAFB; border-color: #D1D5DB; color: #374151; }
.flow-node--pending   { background: var(--slot-pending-bg);   border-color: var(--slot-pending);   color: var(--slot-pending-text); }
.flow-node--requested { background: var(--slot-requested-bg); border-color: var(--slot-requested); color: var(--slot-requested-text); }
.flow-node--confirmed { background: var(--slot-confirmed-bg); border-color: var(--slot-confirmed); color: var(--slot-confirmed-text); }
.flow-node--blocked   { background: var(--slot-blocked-bg);   border-color: var(--slot-blocked);   color: var(--slot-blocked-text); }

.flow-connector {
  display: flex;
  flex-direction: column;
  align-items: center;
  color: #9CA3AF;
  padding: .2rem 0;
  gap: .1rem;
}
.flow-connector i    { font-size: 1.1rem; }
.flow-connector span { font-size: .72rem; text-align: center; max-width: 220px; }

/* Vertical flow (fits the narrow help popup; reusable on the Help page) */
.flow-vert { display: flex; flex-direction: column; align-items: stretch; gap: .15rem; }
.flow-vert .flow-node { align-items: center; }
.flow-vert .flow-node i { font-size: 1.05rem; }
.flow-vert .flow-node strong { display: block; font-size: .85rem; }
.flow-vert .flow-node .fn-sub { display: block; font-size: .75rem; opacity: .85; margin-top: .1rem; }
.flow-node--success { background: var(--slot-confirmed-bg); border-color: var(--slot-confirmed); color: var(--slot-confirmed-text); }
.flow-node--danger  { background: #FEE2E2; border-color: #FCA5A5; color: #991B1B; }
.flow-node--branch  { border-style: dashed; }
.flow-branch-label  { font-size: .72rem; color: #9CA3AF; text-align: center; margin: .55rem 0 .15rem; }

/* Loop group: a run of steps that can repeat, with a bracket down the right
   side arrowed back into the first step (quote -> revised quote -> a quote
   again). The rail stretches to the group's height, so it never needs to know
   how tall the nodes are; the 1.6rem inset just lands its ends inside the
   first and last node instead of on their edges. */
.flow-loop       { display: flex; align-items: stretch; gap: .3rem; }
.flow-loop-steps { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .15rem; }
.flow-loop-rail  {
  flex: 0 0 1.5rem;
  position: relative;
  margin: 1.6rem 0;
  border: 1.5px dashed var(--slot-pending);
  border-left: 0;
  border-radius: 0 .5rem .5rem 0;
}
.flow-loop-rail::before {          /* arrowhead, pointing back into the first step */
  content: "";
  position: absolute;
  left: -.56rem;
  top: -.28rem;
  border: .28rem solid transparent;
  border-right-color: var(--slot-pending);
}

.flow-dot {
  width: .7rem;
  height: .7rem;
  border-radius: 50%;
  flex-shrink: 0;
  margin-top: .2rem;
}

.help-color-swatch {
  width: 1rem;
  height: 1rem;
  border-radius: .25rem;
  flex-shrink: 0;
  border: 1px solid rgba(0,0,0,.1);
}

/* === Timeline View === */
.tl-wrap { overflow-x: visible; min-width: 0; }

.tl-header {
  display: flex;
  align-items: center;
  padding: .4rem 0 .3rem;
  border-bottom: 1px solid #E5E7EB;
  position: sticky;
  top: 0;
  background: #fff;
  z-index: 10;
  box-shadow: 0 2px 6px rgba(0,0,0,.06);
}

.tl-row {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid #F3F4F6;
  min-height: 54px;
}

.tl-row--today { background: #FEF9C3; box-shadow: inset 4px 0 0 var(--bs-primary); }

.tl-label {
  width: 76px;
  flex-shrink: 0;
  padding: 6px 10px;
  font-size: .78rem;
  line-height: 1.3;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.tl-label--today .tl-day-name { color: var(--bs-primary); font-size: .85rem; }
.tl-label--today .tl-day-date { color: var(--bs-primary); font-weight: 500; }
.tl-day-name  { font-weight: 600; color: #374151; }
.tl-day-date  { color: #9CA3AF; font-size: .72rem; }
.tl-today-badge { display: inline-block; margin-top: 3px; font-size: .6rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: #fff; background: var(--bs-primary); padding: 1px 5px; border-radius: 3px; }

.tl-axis {
  flex: 1;
  position: relative;
  height: 28px;
  min-width: 520px;
}

.tl-hour-tick {
  position: absolute;
  font-size: .68rem;
  color: #9CA3AF;
  transform: translateX(-50%);
  top: 7px;
  white-space: nowrap;
  pointer-events: none;
}

.tl-track {
  flex: 1;
  position: relative;
  min-width: 520px;
}

.tl-grid-line {
  position: absolute;
  top: 0; bottom: 0;
  width: 1px;
  background: #F3F4F6;
  pointer-events: none;
}

.tl-working-bg {
  position: absolute;
  top: 5px; bottom: 5px;
  background: #F0FDF4;
  border-radius: 4px;
  pointer-events: none;
}

.tl-closed-overlay {
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(135deg,#EBEBEB 0,#EBEBEB 4px,#D4D4D4 4px,#D4D4D4 8px);
  pointer-events: none;
}

.tl-closed-label {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%,-50%);
  font-size: .72rem;
  color: #555;
  font-style: italic;
  font-weight: 500;
  pointer-events: none;
  white-space: nowrap;
}

.tl-appt {
  position: absolute;
  top: 5px; bottom: 5px;
  border-radius: 4px;
  cursor: pointer;
  overflow: hidden;
  font-size: .69rem;
  display: flex;
  align-items: center;
  padding: 0 5px;
  border: none;
  min-width: 6px;
  transition: opacity .15s, box-shadow .15s;
  text-align: left;
}

.tl-appt:hover    { opacity: .85; box-shadow: 0 2px 6px rgba(0,0,0,.15); }
.tl-appt-label    { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.tl-pending   { background: var(--slot-pending-bg);   border: 1.5px solid var(--slot-pending);   color: var(--slot-pending-text); }
.tl-requested { background: var(--slot-requested-bg); border: 1.5px solid var(--slot-requested); color: var(--slot-requested-text); }
.tl-confirmed { background: var(--slot-booked-bg);    border: 1.5px solid var(--slot-booked);    color: var(--slot-booked-text); }
.tl-paid             { background: #DCFCE7; border: 1.5px solid #4ADE80; color: #14532D; }
.tl-no-show          { background: #FEF9C3; border: 1.5px solid #FACC15; color: #713F12; font-style: italic; }
.tl-blocked          { background: #E5E7EB; border: 1.5px solid #9CA3AF; color: #374151; }
.tl-cancelled        { background: repeating-linear-gradient(135deg,#DBEAFE 0,#DBEAFE 4px,#BFDBFE 4px,#BFDBFE 8px); border: 1.5px solid #93C5FD; color: #1E3A8A; font-style: italic; }
.tl-cancelled-admin  { background: repeating-linear-gradient(135deg,#E5E7EB 0,#E5E7EB 4px,#D1D5DB 4px,#D1D5DB 8px); border: 1.5px solid #6B7280; color: #374151; font-style: italic; }

/* === Timeline: split (All Providers) view === */
.tl-day-group {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid #E5E7EB;
}
.tl-day-group.tl-row--today { background: #FEF9C3; box-shadow: inset 4px 0 0 var(--bs-primary); }
.tl-day-group > .tl-label {
  border-right: 1px solid #F3F4F6;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.tl-provider-rows {
  flex: 1;
  display: flex;
  flex-direction: column;
}
.tl-provider-row {
  display: flex;
  align-items: stretch;
  min-height: 44px;
  border-bottom: 1px solid #F3F4F6;
}
.tl-provider-row:last-child { border-bottom: none; }
.tl-prov-name {
  width: 52px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2px 4px;
  border-right: 1px solid #F3F4F6;
}
.tl-prov-name--hdr { background: #fff; }

/* === Work Order Calendar === */
/* Phase 4 (docs/field-service-model.md): the request-mode Timeline is an
   Outlook-style month/week grid — the .month-cal-* table above supplies the
   chrome; this section adds the WO bars. A bar segment lives inside its
   START day's cell and spans forward with a calc() width. ⚠ .wo-cal-lanes
   ALREADY bleeds over the cell's side padding, so its 100% is one whole
   column minus the shared border: a span of N is N*100% + (N-1)*1px, and
   nothing more. (Adding the .8rem padding per boundary on top — the first
   cut — overshot by ~13px per extra day and the bar spilled into the day
   after its end.) table-layout:fixed keeps every column equal. */
.wo-cal-cell { padding-bottom: .3rem; }
.wo-cal-lanes {
  /* Lane canvas. The negative side margins must exactly cancel
     .month-cal-cell's .4rem side padding so bars run edge to edge. */
  position: relative;
  margin: 0 -.4rem;
  min-height: 2px;              /* real height set inline: laneCount * 26px */
}
/* Two lines by design: the job (number + CLIENT) over the CREW — the two
   things a dispatcher reads off the board. One run-on line could not be
   scanned. Keep the height in sync with _WO_LANE_H in admin-timeline.js. */
.wo-cal-bar {
  position: absolute;
  left: 0;
  height: 34px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 1px;
  padding: .15rem .4rem;
  border-radius: 4px;
  border: 1.5px solid transparent;
  font-size: .7rem;
  line-height: 1.15;
  text-align: left;
  overflow: hidden;
  white-space: nowrap;
  cursor: pointer;
  z-index: 2;
  /* The bar is a double-click target (opens the record) — without this every
     double click paints a text selection across the label first. */
  -webkit-user-select: none;
  user-select: none;
}
.wo-cal-bar:hover { box-shadow: 0 2px 6px rgba(0,0,0,.18); z-index: 3; }
.wo-cal-bar-main,
.wo-cal-bar-crew {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wo-cal-bar-crew { font-size: .64rem; opacity: .82; }
/* An unassigned job says so on the board — that IS the dispatch signal. */
.wo-cal-bar-crew--none { font-style: italic; opacity: .6; }
/* Status skins — same palette family as the appointment timeline above.
   Planning is deliberately dashed + italic: the dates are tentative. */
.wo-cal-bar--planning    { background: #F3F4F6; border: 1.5px dashed #9CA3AF; color: #374151; font-style: italic; }
.wo-cal-bar--scheduled   { background: #DBEAFE; border-color: #3B82F6; color: #1E3A8A; }
.wo-cal-bar--in_progress { background: #DCFCE7; border-color: #4ADE80; color: #14532D; }
.wo-cal-bar--completed_pending_payment { background: #FEF9C3; border-color: #FACC15; color: #713F12; }
.wo-cal-bar--completed_paid            { background: #E5E7EB; border-color: #6B7280; color: #374151; }
.wo-cal-bar--cancelled_by_client { background: repeating-linear-gradient(135deg,#DBEAFE 0,#DBEAFE 4px,#BFDBFE 4px,#BFDBFE 8px); border-color: #93C5FD; color: #1E3A8A; font-style: italic; }
.wo-cal-bar--cancelled_by_admin  { background: repeating-linear-gradient(135deg,#E5E7EB 0,#E5E7EB 4px,#D1D5DB 4px,#D1D5DB 8px); border-color: #6B7280; color: #374151; font-style: italic; }
/* A bar clipped by the week edge squares the cut corner (continues next row). */
.wo-cal-bar--contl { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.wo-cal-bar--contr { border-top-right-radius: 0; border-bottom-right-radius: 0; }
/* Drag affordances (write privilege + active band only) */
.wo-cal-bar--draggable { cursor: grab; touch-action: none; }
.wo-cal-resize {
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: 8px;
  cursor: ew-resize;
}
.wo-cal-dragging { cursor: grabbing; -webkit-user-select: none; user-select: none; }
/* During a drag the bars go inert so elementFromPoint reaches the day cells. */
.wo-cal-dragging .wo-cal-bar { pointer-events: none; }
.month-cal-cell--droptarget { background: #E0EAFF; outline: 2px dashed var(--bs-primary); outline-offset: -2px; }
/* Legend swatch reuses the bar status skins for its colours. */
.wo-legend-swatch { width: 2.5rem; height: 1.4rem; border-radius: 4px; flex-shrink: 0; }
/* Holiday name sits inline beside the date number — the block
   .month-holiday-label would collide with lane 0. */
.wo-cal-holiday-inline {
  font-size: .62rem;
  font-weight: 500;
  color: var(--slot-blocked-text);
  margin-left: .25rem;
  white-space: nowrap;
}

/* === Provider avatar === */
.provider-avatar-initials {
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  color: #fff;
  -webkit-user-select: none;
  user-select: none;
  flex-shrink: 0;
  letter-spacing: .02em;
}
.provider-avatar-photo {
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  display: inline-block;
}
.provider-avatar-wrap {
  position: relative;
  display: inline-flex;
  cursor: pointer;
  border-radius: 50%;
}
.provider-avatar-wrap:hover .provider-avatar-cam {
  opacity: 1;
}
.provider-avatar-cam {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: rgba(0,0,0,.45);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: .75rem;
  opacity: 0;
  transition: opacity .15s;
  pointer-events: none;
}

/* === Provider filter dropdown === */
.prov-filter-dropdown {
  position: relative;
  min-width: 160px;
}
.prov-filter-btn {
  display: flex;
  align-items: center;
  gap: .45rem;
  padding: .28rem .6rem;
  border: 1px solid #D1D5DB;
  border-radius: .375rem;
  background: #fff;
  cursor: pointer;
  font-size: .8rem;
  color: #374151;
  width: 100%;
  white-space: nowrap;
  transition: border-color .15s;
}
.prov-filter-btn:hover { border-color: #9CA3AF; }
#provFilterSelected {
  display: flex;
  align-items: center;
  gap: .4rem;
  flex: 1;
  min-width: 0;
}
#provFilterSelected span:last-child {
  overflow: hidden;
  text-overflow: ellipsis;
}
.prov-filter-caret { font-size: .6rem; color: #9CA3AF; flex-shrink: 0; }
.prov-filter-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 100%;
  background: #fff;
  border: 1px solid #E5E7EB;
  border-radius: .375rem;
  box-shadow: 0 4px 14px rgba(0,0,0,.12);
  z-index: 200;
  overflow: hidden;
}
.prov-filter-option {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .45rem .7rem;
  font-size: .8rem;
  color: #374151;
  cursor: pointer;
  white-space: nowrap;
}
.prov-filter-option:hover { background: #F9FAFB; }
.prov-filter-option--all { border-bottom: 1px solid #E5E7EB; margin-bottom: .25rem; padding-bottom: .55rem; }
.prov-filter-done { border-top: 1px solid #E5E7EB; margin-top: .25rem; padding: .5rem .6rem .3rem; }
.prov-filter-label {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  cursor: pointer;
  margin: 0;
}
.prov-filter-chk { flex-shrink: 0; accent-color: var(--bs-primary); width: 14px; height: 14px; cursor: pointer; }
.prov-filter-all-icon {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--bs-primary-bg-subtle, #cfe2ff);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--bs-primary);
  font-size: .68rem;
  flex-shrink: 0;
}

/* === Client identity bar === */
.client-identity-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
  padding: .625rem 1rem;
  border-radius: var(--radius);
  font-size: .875rem;
  background: #F9FAFB;
  border: 1px solid #E5E7EB;
  color: var(--text-secondary);
}
.client-identity-bar--on {
  background: #F0FDF4;
  border-color: #86EFAC;
  color: #166534;
}
.client-identity-bar--on a { color: #166534; font-weight: 500; }

/* === My Appointments (booking page) === */
.my-appointments {
  border-left: 4px solid var(--sage-500);
  background: var(--surface);
  border-radius: var(--radius);
}
.my-appointments .card-body { padding: 1rem 1.125rem; }

.appt-status {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .3rem .65rem;
  border-radius: .375rem;
  border-left: 3px solid;
  font-size: .8rem;
  font-weight: 500;
  white-space: nowrap;
  line-height: 1.3;
}
.appt-status--pending   { background: var(--slot-pending-bg);   border-color: var(--slot-pending);   color: var(--slot-pending-text); }
.appt-status--requested { background: var(--slot-requested-bg); border-color: var(--slot-requested); color: var(--slot-requested-text); }
.appt-status--confirmed { background: var(--slot-confirmed-bg); border-color: var(--slot-confirmed); color: var(--slot-confirmed-text); }

/* === My Appointment Pills (booking page vertical list) === */
.my-appt-pill {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: .75rem 1rem;
  border-radius: var(--radius);
  border: 1px solid #E5E7EB;
  background: var(--surface);
  margin-bottom: .5rem;
}

.my-appt-pill.booked-pill--pending   { border-left: 4px solid #F59E0B; background: #FFFBEB; }
.my-appt-pill.booked-pill--requested { border-left: 4px solid var(--slot-requested); background: var(--slot-requested-bg); }
.my-appt-pill.booked-pill--confirmed { border-left: 4px solid var(--slot-confirmed); background: var(--slot-confirmed-bg); }

.my-appt-pill-main {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  font-size: .875rem;
  flex: 1;
  min-width: 0;
}

.my-appt-pill-date     { font-weight: 600; color: #111827; }
.my-appt-pill-time     { color: #374151; }
.my-appt-pill-provider { color: #6B7280; font-size: .8125rem; }
.my-appt-pill-price    { font-weight: 600; color: var(--sage-700); font-size: .8125rem; }

.my-appt-pill-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .35rem;
  flex-shrink: 0;
}

.my-appt-pill-status {
  font-size: .75rem;
  font-style: italic;
  font-weight: 600;
  color: #6B7280;
  text-align: right;
  white-space: nowrap;
}

.my-appt-pill.booked-pill--pending   .my-appt-pill-status { color: #92400E; }
.my-appt-pill.booked-pill--confirmed .my-appt-pill-status { color: var(--slot-confirmed-text); }

/* === Social Icons === */
.social-icon-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  transition: opacity .2s, transform .15s;
  line-height: 1;
}
.social-icon-link:hover { opacity: .7; transform: translateY(-2px); }

/* === Availability Map === */
.tl-action {
  flex-shrink: 0;
  width: 84px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px 8px;
}

.av-unavailable {
  background: var(--slot-requested-bg);
  border: 1.5px solid var(--slot-requested);
  color: var(--slot-requested-text);
}

/* === Availability — date range label === */
#avDateRange {
  font-size: .95rem;
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: .01em;
}

/* === Availability — Provider card selector === */
.av-pcard {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .35rem;
  padding: .625rem .75rem;
  border: 2px solid var(--warm-200);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  transition: border-color .15s, background .15s, box-shadow .15s;
  min-width: 82px;
  max-width: 110px;
  text-align: center;
}
.av-pcard:hover {
  border-color: var(--bs-border-color);
  background: var(--bs-tertiary-bg);
}
.av-pcard.selected {
  border-color: var(--bs-primary);
  background: var(--bs-primary-bg-subtle);
  box-shadow: 0 0 0 3px rgba(13,110,253,.14);
}
.av-pcard-avatar {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}
.av-pcard-avatar--all,
.av-pcard-avatar--init {
  display: flex;
  align-items: center;
  justify-content: center;
}
.av-pcard-avatar--all {
  background: var(--bs-secondary-bg);
  font-size: 1.35rem;
  color: var(--bs-primary);
}
.av-pcard-avatar--init {
  background: var(--bs-primary-bg-subtle);
  color: var(--bs-link-hover-color, #0a58ca);
  font-weight: 600;
  font-size: .9rem;
}
.av-pcard-name {
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.25;
  max-width: 90px;
  word-break: break-word;
}
.av-pcard-spec {
  font-size: .7rem;
  color: var(--text-muted);
  line-height: 1.2;
  max-width: 90px;
  word-break: break-word;
}

/* Small avatar variant — used inside the dropdown trigger */
.av-pcard-avatar--sm {
  width: 28px !important;
  height: 28px !important;
  font-size: .72rem !important;
}

/* === Availability — Provider dropdown trigger === */
.av-psel-wrap {
  position: relative;
  flex-shrink: 0;
}
.av-psel-trigger {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .35rem .65rem .35rem .45rem;
  border: 1px solid var(--bs-border-color);
  border-radius: 8px;
  background: var(--surface);
  cursor: pointer;
  min-width: 190px;
  transition: border-color .15s, box-shadow .15s;
}
.av-psel-trigger:hover {
  border-color: var(--bs-primary);
}
.av-psel-trigger--open {
  border-color: var(--bs-primary);
  box-shadow: 0 0 0 3px rgba(13,110,253,.14);
}
.av-psel-label {
  flex: 1;
  text-align: left;
  font-size: .85rem;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.av-psel-chevron {
  font-size: .7rem;
  color: var(--text-muted);
  flex-shrink: 0;
  transition: transform .2s;
}
.av-psel-trigger--open .av-psel-chevron {
  transform: rotate(180deg);
}

/* === Availability — Provider dropdown panel === */
.av-psel-panel {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 200;
  background: var(--surface);
  border: 1px solid var(--bs-border-color);
  border-radius: 10px;
  box-shadow: 0 8px 28px rgb(0 0 0 / .13);
  padding: .6rem;
  min-width: 230px;
  max-width: 520px;
}

/* === Availability — Provider bio box === */
.av-pbio {
  border-left: 2px solid var(--bs-border-color);
  padding-left: 1.25rem;
}
.av-pbio-name {
  font-size: .9rem;
  font-weight: 600;
  color: var(--bs-body-color);
  margin-bottom: .3rem;
}
.av-pbio-cred {
  font-weight: 400;
  color: var(--text-muted);
  font-size: .82rem;
  margin-left: .35rem;
}
.av-pbio-exp {
  font-weight: 400;
  color: var(--bs-secondary-color);
  font-size: .78rem;
  margin-left: .4rem;
}
.av-pbio-exp::before {
  content: "\00B7";  /* middot separator from the name / credential */
  margin-right: .4rem;
  color: var(--text-muted);
}
.av-pbio-text {
  font-size: .875rem;
  color: var(--text-secondary);
  line-height: 1.6;
  margin: 0;
}

/* === Responsive === */
/* Sidebar backdrop for mobile overlay */
.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.45);
  z-index: 1045;
  cursor: pointer;
}
.sidebar-backdrop.show { display: block; }

@media (max-width: 767.98px) {
  .hero-section { min-height: 32.4vh; }

  /* Sidebar: off-canvas overlay on mobile */
  #adminSidebar {
    position: fixed !important;
    left: -260px;
    top: 0;
    bottom: 0;
    height: 100% !important;
    width: 240px !important;
    z-index: 1050;
    transition: left .22s ease;
  }
  #adminSidebar.sidebar--open { left: 0; }
  #adminSidebar.sidebar--collapsed { width: 240px !important; left: -260px; }
  #adminSidebar.sidebar--collapsed.sidebar--open { left: 0; }
  #adminSidebar.sidebar--collapsed .nav-text { display: inline !important; }
  #adminSidebar.sidebar--collapsed .nav-link  { justify-content: flex-start !important; padding: .75rem 1.5rem !important; }
  #adminSidebar.sidebar--collapsed .sidebar-header { align-items: stretch !important; padding: .85rem 1rem .7rem 1.25rem !important; }
  /* Off-canvas drawer: the icon-rail flatten doesn't apply — show group headers so
     the collapsible groups work normally on mobile (v238). The rail's companion
     rule (collapsed groups stay open, since a 58px rail has no headers) must go
     with it: here the drawer is a full 240px WITH headers, so a group the user
     collapsed has to actually collapse — otherwise the header click looked dead. */
  #adminSidebar.sidebar--collapsed .nav-group-header { display: flex !important; }
  #adminSidebar.sidebar--collapsed .nav-group.collapsed .nav-group-items { display: none; }
  /* Desktop rail toggle + drag divider hidden on mobile; the hamburger and the
     off-canvas drawer own the menu there. */
  #sidebarToggleBtn { display: none !important; }
  .sidebar-resizer  { display: none !important; }

  /* Topbar: compact, hide email and person icon */
  .admin-topbar { padding: .625rem 1rem !important; gap: .5rem !important; }
  #adminEmailTopbar { display: none !important; }
  .admin-topbar .bi-person-circle { display: none !important; }
  .admin-user-sep { border-left: none !important; padding-left: 0 !important; }

  /* Stats row: stack vertically on small screens */
  #statsRow > div { flex: 0 0 100%; max-width: 100%; }

  /* Content area: tighter padding */
  .admin-pane { padding: .875rem !important; }

  /* Day row action column: allow shrinking */
  .day-row-action { min-width: 80px; }

  /* Month nav label: compact */
  .month-nav .month-label { min-width: 110px; font-size: .875rem; }
}

/* =============================================================================
   DESIGN SYSTEM — apply these classes consistently across all admin UI
   (2026-08-03 theme adoption: the admin wears STOCK BOOTSTRAP colors)
   ─────────────────────────────────────────────────────────────────────────────
   Buttons (inside modals and admin panels):
     Primary action   → btn btn-primary btn-sm
     Secondary action → btn btn-sm btn-outline-secondary
     Ribbon / subgrid-toolbar commands → btn btn-outline-primary btn-sm
   Never use w-100 or inline colour styles on admin buttons. (btn-sage /
   btn-outline-sage are PUBLIC-page classes — tenant brand palettes — and must
   not appear in the admin portal.)

   Tabs (inside modals):
     Add class "admin-tabs" to any <ul class="nav nav-tabs"> in the admin.
   ============================================================================= */

/* === Admin modal tabs — pill style === */
.admin-tabs.nav-tabs {
  border-bottom: none;
  background: var(--bs-tertiary-bg);
  border-radius: .5rem;
  padding: .25rem;
  display: flex;
  gap: .25rem;
}
.admin-tabs .nav-link {
  border: none;
  border-radius: .375rem;
  color: var(--bs-body-color);
  font-size: .875rem;
  padding: .375rem .875rem;
  transition: background .15s, color .15s;
  background: transparent;
}
.admin-tabs .nav-link.active {
  background: var(--bs-primary);
  /* --kylo-on-primary: a skin whose accent can't carry white text (Carbon's
     mint) sets it dark; every stock/Bootswatch skin falls back to white. */
  color: var(--kylo-on-primary, #fff);
  font-weight: 600;
  box-shadow: 0 1px 3px rgba(0,0,0,.15);
}
.admin-tabs .nav-link:hover:not(.active) {
  background: var(--bs-secondary-bg);
  color: var(--bs-emphasis-color);
}

/* -- "Continue with Google" button (Google branding guidelines: white fill,
   #747775 border, dark neutral text; the G logo is the vendored
   assets/img/google-g.svg -- no external fetch) ------------------------- */
.btn-google {
  background: #fff;
  color: #1f1f1f;
  border: 1px solid #747775;
  font-weight: 500;
}
.btn-google:hover,
.btn-google:focus {
  background: #f8f9fa;
  color: #1f1f1f;
  border-color: #747775;
  box-shadow: 0 1px 2px rgba(60, 64, 67, .3);
}
.btn-google img {
  vertical-align: -3px;
}

/* Dropdown menus: Bootstrap's default hover tint was too pale to follow (user
   call, 2026-08-03 theme adoption) — highlight with the primary-subtle token
   so the focused item is unmistakable in every admin menu (ribbon Status
   picker, account menu, grid menus). */
body.admin-page .dropdown-menu {
  --bs-dropdown-link-hover-bg: var(--bs-primary-bg-subtle, #cfe2ff);
  --bs-dropdown-link-active-bg: var(--bs-primary, #0d6efd);
}

/* A DISABLED COMMAND BUTTON MUST READ AS INERT. Bootstrap's `.btn:disabled`
   only drops opacity to .65 and keeps the accent colour, which on an outline
   button over a white card is nearly indistinguishable from a live command —
   worse when it sits beside a disabled INPUT, because `.form-control:disabled`
   paints a plainly grey field and the eye reads the contrast as "field locked,
   button available". Reported on the Service Request form (user, 2026-08-10):
   "New Client" is correctly disabled on a saved record — the customer is
   immutable from the first save (v280) — and still looked clickable.

   Same complaint and same answer as the segmented-toggle block below (user,
   2026-08-03: "disabled but there is no indication for it"): neutral grey.
   ⛔ Outline and link buttons only. A disabled SOLID button already reads as a
   faded fill, and repainting those would grey out ribbon commands mid-save.
   ⚠ Placed BEFORE the .btn-group block on purpose — those selectors carry
   higher specificity and must keep winning, so the lit side of a locked
   segmented toggle stays a legible state chip rather than fading to this. */
body.admin-page .btn[class*="btn-outline-"]:disabled,
body.admin-page .btn[class*="btn-outline-"].disabled,
body.admin-page .btn.btn-link:disabled,
body.admin-page .btn.btn-link.disabled {
  color: var(--bs-secondary-color, #6c757d);
  border-color: var(--bs-border-color, #dee2e6);
  background-color: transparent;
  text-decoration: none;
  opacity: .8;
}

/* Segmented toggles (btn-group of two): a DISABLED group still has to say
   something — the quote form's Source switch stays on screen once the source
   is fixed, to show which parent the record hangs off. Two problems to solve
   at once: Bootstrap's `.btn:disabled` is declared after `.btn.active` and
   greys BOTH sides identically (the state vanishes), while leaving the lit
   side in live primary blue reads as an operable control (user, 2026-08-03:
   "disabled but there is no indication for it"). So a locked group paints the
   lit side as a NEUTRAL GREY CHIP — legible state, obviously not a button —
   and fades the other side. The padlock beside it carries the reason. */
body.admin-page .btn-group > .btn.active:disabled,
body.admin-page .btn-group > .btn.active.disabled {
  color: var(--bs-body-color, #212529);
  background-color: var(--bs-secondary-bg, #e9ecef);
  border-color: var(--bs-border-color, #dee2e6);
  font-weight: 600;
  opacity: 1;
}
body.admin-page .btn-group > .btn:disabled:not(.active),
body.admin-page .btn-group > .btn.disabled:not(.active) {
  color: var(--bs-secondary-color, #6c757d);
  background-color: transparent;
  border-color: var(--bs-border-color, #dee2e6);
  opacity: .55;
}

/* --- v316: the Service Request Board (admin/index.html) ------------------- */
/* Eight fixed-width verticals in one horizontal scroller (the .month-cal-wrap
   idiom): 8 x 250px always exceeds a laptop pane, so the BOARD scrolls
   sideways while each column scrolls its own cards vertically. Colours ride
   the Bootstrap vars so every admin skin (v301) paints it natively.
   ⚠ Admin CSS — must sit ABOVE the public-skin block that ends this file:
   everything below its banner is pinned to body.trades-skin scoping, and the
   banner text itself is the split marker (trades-skin.test.js) — do not quote
   it here. */
.sr-board {
  display: flex;
  gap: .75rem;
  align-items: flex-start;
  overflow-x: auto;
  padding-bottom: .5rem;
}
/* ⚠ THE LANE IS THE DARKER SURFACE, THE CARD IS THE LIGHTER ONE. A white card
   on a near-white lane with a faint shadow read "too washed out" (user, live
   board 2026-08-12) — the fix is contrast between the two surfaces plus a real
   border on the card, not a heavier shadow. Kanban convention, and it survives
   the dark admin skins because both surfaces are Bootstrap vars. */
.sr-board-col {
  flex: 0 0 250px;
  max-width: 250px;
  border-radius: .5rem;
  background: var(--bs-secondary-bg, #e9ecef);
  border: 1px solid var(--bs-border-color, #dee2e6);
  padding: .5rem;
}
/* Each lane carries its stage colour in ONE variable — the header rule, the
   count chip and every card's stripe read it, so a stage is one line to
   retune. Deep tones: the chip paints white text on them. */
.sr-board-col[data-stage="active"]       { --sr-stage: #4F46E5; }  /* new work, nothing issued yet */
.sr-board-col[data-stage="q_created"]    { --sr-stage: #64748B; }  /* a draft nobody has seen — deliberately quiet */
.sr-board-col[data-stage="q_sent"]       { --sr-stage: #B45309; }  /* waiting on the customer */
.sr-board-col[data-stage="q_accepted"]   { --sr-stage: #059669; }  /* agreed, not yet a job */
.sr-board-col[data-stage="wo_created"]   { --sr-stage: #7C3AED; }  /* a job exists, no dates yet (Planning) */
.sr-board-col[data-stage="wo_scheduled"] { --sr-stage: #2563EB; }  /* the calendar's Scheduled blue */
.sr-board-col[data-stage="wo_inprog"]    { --sr-stage: #16A34A; }  /* the calendar's In Progress green */
.sr-board-col[data-stage="wo_done"]      { --sr-stage: #0F766E; }  /* settled — the calendar's two done states merge here */
/* v319 "full dress": the lane header is a Business Process Flow chevron — a
   stage-tinted band with a right-pointing head and a left notch, so the top of
   the board reads as one connected pipeline (the Dynamics BPF idea, never its
   artwork). The tint is the stage colour mixed into the BODY surface, so the
   header text keeps ordinary ink in every admin skin, light or dark; the SOLID
   stage colour stays where it always was — the count chip and the card stripe.
   clip-path clips borders away, which is why the band carries none: contrast
   comes from tint-on-lane. The plain var() line above each color-mix is the
   no-color-mix fallback (last-one-wins when supported). */
.sr-board-col-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  font-weight: 600;
  font-size: .78rem;
  padding: .45rem 1.15rem .45rem .95rem;
  margin-bottom: .5rem;
  background: var(--bs-tertiary-bg, #f1f3f5);
  background: color-mix(in srgb, var(--sr-stage, #6c757d) 16%, var(--bs-body-bg, #fff));
  clip-path: polygon(0 0, calc(100% - 11px) 0, 100% 50%, calc(100% - 11px) 100%, 0 100%, 11px 50%);
}
/* The first stage has nothing flowing into it — no notch. */
.sr-board-col:first-child .sr-board-col-head {
  clip-path: polygon(0 0, calc(100% - 11px) 0, 100% 50%, calc(100% - 11px) 100%, 0 100%);
  padding-left: .7rem;
}
.sr-board-col-note {
  font-size: .65rem;
  font-weight: 400;
  color: var(--bs-secondary-color, #6c757d);
}
.sr-board-count {
  background: var(--sr-stage, #6c757d);
  color: #fff;
  font-size: .68rem;
  border-radius: 10rem;
  padding: .2rem .45rem;
  min-width: 1.4rem;
}
.sr-board-col-body {
  overflow-y: auto;
  max-height: calc(100vh - 410px);   /* v319: the KPI band sits above the board */
}
.sr-board-empty {
  font-size: .75rem;
  font-style: italic;
  color: var(--bs-secondary-color, #6c757d);
  padding: .35rem .25rem;
}
/* The card: a real object on the lane — body-coloured face, its own border,
   and the stage colour as a left stripe so a card torn out of context still
   says where it came from. Own shadow, never .shadow-sm: that !important
   would out-rank the hover lift. */
.sr-card {
  background: var(--bs-body-bg, #fff);
  border: 1px solid var(--bs-border-color, #dee2e6);
  border-left: 3px solid var(--sr-stage, var(--bs-border-color, #dee2e6));
  border-radius: .5rem;
  padding: .45rem .55rem;
  margin-bottom: .5rem;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .06);
  transition: box-shadow .12s ease, transform .12s ease;
}
.sr-card:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, .15);
  transform: translateY(-1px);
}
.sr-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .4rem;
}
.sr-card-no { font-size: .8rem; }
/* The age chip stays NEUTRAL — it must not compete with the stage stripe, and
   colouring it by threshold would assert a "too long" policy no business has
   stated. */
.sr-card-age {
  flex-shrink: 0;
  font-size: .65rem;
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
  background: var(--bs-tertiary-bg, #f1f3f5);
  border: 1px solid var(--bs-border-color, #dee2e6);
  border-radius: 10rem;
  padding: .05rem .35rem;
  white-space: nowrap;
}
/* ⚠ Label and value sit CLOSE in size on purpose: at .6rem against Bootstrap's
   .small the links "looked too big compared to the labels" (user, same review).
   Keep the ratio gentle if either one is ever retuned. */
.sr-card-cell { margin-top: .3rem; }
.sr-card-label {
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--bs-secondary-color, #6c757d);
  line-height: 1.3;
}
.sr-card-value {
  font-size: .8rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* v319: the document links became icon pills — the Q-/WO- prefix already says
   what the number IS, the sidebar's own icon repeats it, and the full word
   stays on the pill's tooltip (qd.entity / wd.entity, translated). The link
   inside keeps the global link style: the pill is a container, not a button. */
.sr-card-docs {
  border-top: 1px solid var(--bs-border-color, #dee2e6);
  margin-top: .5rem;
  padding-top: .45rem;
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}
.sr-card-doc {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: .72rem;
  line-height: 1;
  padding: .28rem .55rem;
  border-radius: 10rem;
  background: var(--bs-tertiary-bg, #f1f3f5);
  border: 1px solid var(--bs-border-color, #dee2e6);
  white-space: nowrap;
}
.sr-card-doc i {
  font-size: .8rem;
  color: var(--bs-secondary-color, #6c757d);
}
/* The customer's initials — a neutral dot beside the name. Deliberately NOT
   stage-coloured: identity decoration must not compete with the one colour
   that means something on this board (the stripe). */
.sr-card-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.3rem;
  height: 1.3rem;
  border-radius: 50%;
  font-size: .56rem;
  font-weight: 700;
  letter-spacing: .02em;
  color: var(--bs-secondary-color, #6c757d);
  background: var(--bs-secondary-bg, #e9ecef);
  border: 1px solid var(--bs-border-color, #dee2e6);
  margin-right: .35rem;
  vertical-align: text-bottom;
}

/* --- v319: the KPI band above the board ----------------------------------- */
/* Four stat tiles derived from the SAME buckets the lanes render — no second
   query, no second truth. The tile follows the stat-tile contract: the value
   wears INK (never the data colour) in proportional figures; identity rides
   the icon chip beside it, tinted with the matching lane's stage colour so the
   band and the board agree on what a colour means. */
.sr-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: .75rem;
  margin-bottom: 1rem;
}
.sr-kpi {
  display: flex;
  align-items: center;
  gap: .75rem;
  background: var(--bs-body-bg, #fff);
  border: 1px solid var(--bs-border-color, #dee2e6);
  border-radius: .75rem;
  padding: .7rem .9rem;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
}
/* Open = the pipeline's entry indigo (everything on the board flows in through
   Active); the other three are their lane's own colour, verbatim. */
.sr-kpi[data-kpi="open"]    { --sr-kpi: #4F46E5; }
.sr-kpi[data-kpi="waiting"] { --sr-kpi: #B45309; }
.sr-kpi[data-kpi="inprog"]  { --sr-kpi: #16A34A; }
.sr-kpi[data-kpi="done"]    { --sr-kpi: #0F766E; }
.sr-kpi-icon {
  flex: 0 0 auto;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: .6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  color: var(--sr-kpi, #6c757d);
  background: var(--bs-tertiary-bg, #f1f3f5);
  background: color-mix(in srgb, var(--sr-kpi, #6c757d) 14%, var(--bs-body-bg, #fff));
}
.sr-kpi-value {
  font-family: 'Figtree', system-ui, -apple-system, sans-serif;
  font-size: 1.45rem;
  font-weight: 600;
  line-height: 1.1;
}
.sr-kpi-label {
  font-size: .72rem;
  font-weight: 600;
  color: var(--bs-secondary-color, #6c757d);
}
/* Deep stage tones sink into a dark surface — lift the icon toward white on
   the dark admin skins (same hook the sidebar/topbar borders use). */
:root[data-admin-skin-dark] .sr-kpi-icon {
  color: color-mix(in srgb, var(--sr-kpi, #adb5bd) 55%, #fff);
}

/* --- v319: the dashboard page header --------------------------------------- */
/* The selector IS the title — the Dynamics dashboards area reads as a heading
   with a caret, not a form row. The accessible name stays on the (visually
   hidden) label; the icon tile is decoration and says so with aria-hidden. */
.dash-header {
  display: flex;
  align-items: flex-start;
  gap: .85rem;
  margin-bottom: 1rem;
}
.dash-header-icon {
  flex: 0 0 auto;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: .75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.35rem;
  color: var(--bs-primary, #0d6efd);
  background: var(--bs-tertiary-bg, #f1f3f5);
  background: color-mix(in srgb, var(--bs-primary, #0d6efd) 12%, var(--bs-body-bg, #fff));
  border: 1px solid var(--bs-border-color, #dee2e6);
}
.dash-title-select {
  font-family: 'Figtree', system-ui, -apple-system, sans-serif;
  font-size: 1.15rem;
  font-weight: 600;
  border-color: transparent;
  background-color: transparent;
  padding-top: .1rem;
  padding-bottom: .1rem;
  padding-left: .25rem;
}
.dash-title-select:hover,
.dash-title-select:focus {
  border-color: var(--bs-border-color, #dee2e6);
}

/* =============================================================================
   TRADES SKIN (public tenant pages only)
   ─────────────────────────────────────────────────────────────────────────────
   Applied via <body class="trades-skin"> on the 13 tenant-facing pages ONLY.
   Admin portal and platform pages (welcome/onboard/legal/connect-domain) never
   carry the class and must render byte-identical — every selector in this
   block MUST be prefixed body.trades-skin (grep-auditable).
   Look: Figtree-only typography (weight = hierarchy), neutral stone canvas
   (tenant theme presets keep supplying --sage-* accents), image-led sections,
   ghost-pill buttons. See docs/trades-vertical.md "Public site: Trades skin".
   ============================================================================= */

/* --- Canvas: stone neutrals shadow the preset warm tints (body-level custom
       properties beat the #tenant-theme :root remap for everything inside) --- */
body.trades-skin {
  --warm-50:  #FBFBFA;
  --warm-100: #F5F5F4;
  --warm-200: #E7E5E4;
  background-color: var(--warm-50);
}
/* Gold retired as a canvas accent on public pages (stays for admin chrome) */
body.trades-skin .section-label { color: var(--sage-600); }
body.trades-skin hr.divider     { background: var(--sage-500); }

/* --- Typography: Figtree everywhere; weight does the hierarchy --- */
body.trades-skin h1, body.trades-skin h2, body.trades-skin h3,
body.trades-skin h4, body.trades-skin .font-serif {
  font-family: 'Figtree', system-ui, -apple-system, sans-serif;
}
body.trades-skin #mainNav .navbar-brand {
  font-family: 'Figtree', system-ui, sans-serif;
  font-weight: 700;
  letter-spacing: -.015em;
}
body.trades-skin .price-big,
body.trades-skin .day-card .day-num,
body.trades-skin .day-row-num,
body.trades-skin #site-footer h5,
body.trades-skin #site-footer h6 {
  font-family: 'Figtree', system-ui, sans-serif;
}

/* --- Hero: full-bleed photo behind a neutral layered scrim. The left band
       guarantees contrast behind the text column; the base dim tames bright
       skies. Big line is Figtree 300 — never use 300 below hero scale. --- */
body.trades-skin .hero-section {
  min-height: 62vh;
  background-color: #141719;
}
body.trades-skin .hero-bg { opacity: 1; }
body.trades-skin .hero-overlay {
  background:
    linear-gradient(90deg,  rgb(10 12 14 / .62) 0%, rgb(10 12 14 / .34) 55%, rgb(10 12 14 / .22) 100%),
    linear-gradient(180deg, rgb(10 12 14 / .15) 0%, rgb(10 12 14 / .35) 100%);
}
body.trades-skin .hero-content h1 {
  font-weight: 300;
  font-size: clamp(2.75rem, 6vw, 4.5rem);
  line-height: 1.08;
  text-shadow: 0 1px 24px rgb(0 0 0 / .35);
}
body.trades-skin .hero-content .lead {
  font-weight: 400;
  opacity: 1;
  color: rgba(255,255,255,.92);
}
@media (max-width: 575.98px) {
  body.trades-skin .hero-section { min-height: 46vh; }
}

/* Sub-page hero: denser scrim — the text sits directly on it */
body.trades-skin .page-hero { padding: 4rem 0; background-color: #141719; }
body.trades-skin .page-hero .hero-bg { opacity: 1; }
body.trades-skin .page-hero .hero-overlay {
  background: linear-gradient(90deg, rgb(10 12 14 / .68) 0%, rgb(10 12 14 / .42) 100%);
}
body.trades-skin .page-hero h1 {
  font-weight: 300;
  font-size: clamp(2rem, 4vw, 3rem);
}
body.trades-skin .page-hero p { color: rgba(255,255,255,.9); }

/* --- Ghost pill buttons --- */
body.trades-skin .btn-ghost-pill {                /* on-photo variant */
  border: 1.5px solid rgba(255,255,255,.85);
  color: #fff;
  background: rgba(255,255,255,.08);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  border-radius: 999px;
  padding: .625rem 1.75rem;
  font-weight: 500;
}
body.trades-skin .btn-ghost-pill:hover,
body.trades-skin .btn-ghost-pill:focus {
  background: rgba(255,255,255,.2);
  border-color: #fff;
  color: #fff;
}
body.trades-skin .btn-ghost-pill--accent {        /* on-white-card variant */
  border: 1.5px solid var(--sage-500);
  color: var(--sage-600);
  background: transparent;
  border-radius: 999px;
  font-weight: 500;
}
body.trades-skin .btn-ghost-pill--accent:hover,
body.trades-skin .btn-ghost-pill--accent:focus {
  background: var(--sage-500);
  color: #fff;
}
body.trades-skin .btn-sage,
body.trades-skin .btn-outline-sage { border-radius: 999px; }

/* --- Portfolio: image-led cards, title overlaid on a bottom scrim --- */
body.trades-skin .pf-cover {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius) var(--radius) 0 0;
}
body.trades-skin .pf-cover img {
  width: 100%;
  height: 280px;
  object-fit: cover;
  transition: transform .35s;
}
body.trades-skin .card:hover .pf-cover img { transform: scale(1.04); }
body.trades-skin .pf-cover-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 50%, rgb(0 0 0 / .62) 100%);
}
body.trades-skin .pf-title {
  position: absolute;
  left: 1rem;
  right: 1rem;
  bottom: .875rem;
  color: #fff;
  font-weight: 600;
  font-size: 1.05rem;
  line-height: 1.3;
  margin: 0;
}
body.trades-skin .pf-badge {                      /* category / +N ghost pills */
  border: 1px solid rgba(255,255,255,.6);
  background: rgba(0,0,0,.45);
  color: #fff;
  border-radius: 999px;
  font-size: .7rem;
  font-weight: 600;
  padding: .25rem .7rem;
}
body.trades-skin .pf-card-only-cover .pf-cover { border-radius: var(--radius); }

/* --- Nav phone --- */
body.trades-skin .nav-phone {
  font-weight: 600;
  color: var(--sage-700);
  text-decoration: none;
  white-space: nowrap;
}
body.trades-skin .nav-phone:hover { color: var(--sage-500); }
body.trades-skin .nav-phone .nav-phone-label {
  font-style: italic;
  font-weight: 500;
}

/* --- Stretch (cosmetic, public contact form only): underline inputs --- */
body.trades-skin .input-underline {
  border: 0;
  border-bottom: 1.5px solid var(--warm-200);
  border-radius: 0;
  background: transparent;
  padding-left: 0;
}
body.trades-skin .input-underline:focus {
  box-shadow: none;
  border-bottom-color: var(--sage-500);
}
