/* ============================================================
   Mission Home Solutions — Mock Site Design System
   Wave 14a-evolved with restrained, editorial aesthetic.
   ============================================================
   Tokens, base components, and the editing-surface overlay
   system. Each page mockup links to this file and adds only
   page-specific overrides in a <style> block in <head>.
   ============================================================ */

/* ============================================================
   CANONICAL RESPONSIVE BREAKPOINTS (Wave 5 lock — 2026-05-21)

   --bp-sm: 480px   — small phone landscape
   --bp-md: 600px   — large phone / small tablet portrait
   --bp-lg: 900px   — tablet landscape / small laptop
   --bp-xl: 1100px  — desktop wide
   (xl+ uses the existing --max-w container constraint)

   Migration map for legacy breakpoints in mockups:
   480, 540, 560 → 480
   640, 700, 760, 768, 800 → 600
   900, 950, 960, 980, 1000 → 900
   1050, 1100 → 1100
   ============================================================ */

/* ============================================================
   CHROME-PROMOTION TODO LIST (for build-engineer pickup)
   ------------------------------------------------------------
   Wave 6 / build-engineer pass: the following 18 chrome
   components are flagged for promotion from inline-per-mockup
   styles into this shared sheet. Promoting means: (1) lift the
   canonical definition here, (2) remove inline duplicates from
   every mockup, (3) reconcile any geometric drift along the way.
   Sourced from R&D/css-inventory.md (drift audit, 2026-05-20).

   PROMOTED IN THIS PASS (Wave 5 spike):
     - .content-key-chip            canonical defined below
     - .sticky-save-bar             canonical defined below
     - @keyframes caret-blink       renamed from caretBlink

   STILL INLINE — promote next pass:
     1.  .edit-field                multi-mockup (every admin page)
     2.  .edit-field .ef-label      multi-mockup
     3.  .edit-field .label-key     multi-mockup
     4.  .sketch-edit-pill          admin-* mockups
     5.  .surface-toggle-group      most admin mockups
     6.  .admin-data-table          admin-posts, admin-users,
                                    admin-services, admin-settings
     7.  .table-row-actions         same set as data-table
     8.  .empty-state               most admin mockups
     9.  .field-help                most admin mockups
     10. .status-dot                sticky-save-bar consumer
     11. .save-status               sticky-save-bar consumer
     12. .editing-toolbar           rich-text mockups
     13. .field-meta-row            most admin mockups
     14. .inline-add-button         section-items, faqs, services
     15. .reorder-grip              section-items, posts, faqs
     16. .move-button               section-items, posts, faqs
     17. .state-frame chrome        admin-dock canonical mockup +
                                    editing-experience walkthroughs
     18. .mobile-frame chrome       same set as state-frame

   Inline keyframe duplications still pending dedupe:
     - @keyframes spin              4 mockups
     - @keyframes shimmer           4 mockups
     - @keyframes pulse-orange      multiple
     - @keyframes pulse-amber       multiple
   ============================================================ */

/* ============================================================
   FONT FACES — Inter (body) + Montserrat (display).
   Preloaded in partials/head.ejs; declarations here let them
   actually render. Both files live in /public/fonts/.
   font-display: swap so the page renders in the system fallback
   chain immediately rather than waiting on the .woff2 fetch.
   ============================================================ */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
}

@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 200 700;
  font-display: swap;
  src: url('/fonts/oswald-latin.woff2') format('woff2');
}

/* W3-P2a (2026-06-04): display font reverted Oswald → Montserrat to match the
   approved mockups (styles.css:96 / css-inventory.md:65) — design-system audit
   FINDING 1. Variable face, weights 400–700 (mockup uses 500/600/700). woff2
   reused from the legacy MHS repo (verified, self-hosted per CSP font-src
   'self'). Oswald @font-face kept dormant above — no longer referenced by
   --font-display and not preloaded, so it never fetches. */
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/montserrat-var.woff2') format('woff2');
}

:root {
  /* Brand palette — black/cream/orange. Canonical per Wave 9 D6
     migration in legacy MHS 00-foundation.css (rebuild adopts the
     same tokens). Legacy --gold-* aliases removed (Wave 9 D6
     migration complete). Use --orange-* / --amber-* tokens. */
  --ink: #0a0a0a;
  --ink-soft: #2a2a2a;
  --ink-mute: #4a4a4a;
  --canvas: #faf7f0;
  --canvas-alt: #f3eedf;
  --orange: #e87a00;
  --orange-dark: #b55c00;
  --orange-light: #f59333;
  --orange-soft: rgba(232, 122, 0, 0.10);
  --orange-tint: #f4d4ad;
  --orange-flare: rgba(232, 122, 0, 0.18);
  --amber: #f5c800;
  --amber-light: #ffd944;
  --amber-soft: #fff5cc;
  --rule: #e6dfc8;
  --rule-strong: #cdc4a7;
  --muted: #6a655a;
  --shadow-card: 0 4px 16px rgba(10, 10, 10, 0.06);
  --shadow-lift: 0 12px 32px rgba(10, 10, 10, 0.10);

  /* Type stack */
  --font-display: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', sans-serif;
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', sans-serif;
  --font-mono: ui-monospace, 'SF Mono', 'Roboto Mono', Menlo, monospace;

  /* Spacing */
  --space-xs: 0.5rem;
  --space-sm: 1rem;
  --space-md: 1.75rem;
  --space-lg: 3rem;
  --space-xl: 5rem;
  --space-xxl: 8rem;

  /* Sizing */
  --max-w: 72rem;
  --max-w-prose: 38rem;
  --max-w-narrow: 56rem;
  /* Admin single-column form measures — one shared rhythm instead of the
     per-view 36/44/48/52rem inline literals the CSS audit flagged (P2).
     --max-w-form is the canonical edit-form width; --form-narrow is the
     tighter measure for short forms (invite-a-user, profile). */
  --max-w-form: 44rem;
  --max-w-form-narrow: 36rem;

  /* Motion */
  --ease: cubic-bezier(.2, .8, .2, 1);
  --dur: 0.3s;

  /* Header height (for sticky-offset anchors) */
  --header-h: 5.5rem;

  /* Canonical responsive breakpoints — see top-of-file block. */
  --bp-sm: 480px;
  --bp-md: 600px;
  --bp-lg: 900px;
  --bp-xl: 1100px;

  /* ===== STATE COLORS =====
     Canonical status palette per council (Wave 5).
     Use these tokens for any badge/pill/dot that signals
     publication state, save state, or row state. The triplet
     pattern is (solid / soft-tint / dark-text) so any state
     can render as full chip, soft-bg + colored-text, or just
     colored text — pick the variant that matches the density. */
  --state-live: var(--orange);
  --state-live-soft: var(--orange-soft);
  --state-live-text: var(--orange-dark);
  --state-pending: #4a73a8;
  --state-pending-soft: rgba(108, 143, 191, 0.12);
  --state-pending-text: #2e578a;
  --state-draft: #b88a00;
  --state-draft-soft: rgba(184, 138, 0, 0.10);
  --state-draft-text: #8a6800;
  --state-hidden: #6a655a;
  --state-hidden-soft: rgba(106, 101, 90, 0.10);
  --state-hidden-text: #4a4540;
  --state-trash: #c41e1e;
  --state-trash-soft: rgba(196, 30, 30, 0.08);
  --state-trash-text: #8a1818;
  --state-active: #2e8540;
  --state-active-soft: rgba(46, 133, 64, 0.12);
  --state-active-text: #1f5d2c;

  /* ===== Z-INDEX TIERS =====
     Named tiers to replace scattered numeric z-index values
     (current drift: 20, 50, 100, 200, 300, 999, 9000, 9999 —
     all mixed without a system). Always reach for a token. */
  --z-base: 1;
  --z-sticky: 100;
  --z-dock: 200;
  --z-overlay: 300;
  --z-modal: 400;
  --z-toast: 500;
  --z-top: 9999;

  /* ===== TYPE SCALE =====
     Canonical type tokens for chrome / admin / component
     contexts. Long-form content typography still uses the
     clamp() rules on h1–h4 above — these tokens are for the
     UI-density side of the system. */
  --type-xs: 0.75rem;
  --type-sm: 0.85rem;
  --type-base: 1rem;
  --type-md: 1.1rem;
  --type-lg: 1.25rem;
  --type-h3: 1.4rem;
  --type-h2: 1.8rem;
  --type-h1: 2.4rem;

  /* ===== SPACING SCALE (component-density addendum) =====
     The page-level spacing tokens (--space-xs through --space-xxl)
     above stay as-is — they govern section gutters / column gaps /
     hero padding. These additions fill in the *component-density*
     end of the scale (chip gaps, dock gaps, inline-flex gaps) where
     the existing 0.5rem floor was too coarse. */
  --space-3xs: 0.15rem;
  --space-2xs: 0.3rem;
  --space-2xl: 3rem;

  /* ===== RADIUS SCALE =====
     Standardized corner-radius tokens. Current drift uses raw
     values (2px / 3px / 999px / 50%) — canonicalize via tokens. */
  --radius-sm: 2px;
  --radius-md: 3px;
  --radius-pill: 999px;
  --radius-circle: 50%;

  /* ===== FORK-RESIDUE TOKEN ALIASES (compatibility shim) =====
     These 8 custom-property names are upstream-fork leftovers still
     referenced ~114× across views/admin/** inline styles. None were
     defined here, so every usage silently dropped its styling (red
     Delete/Remove buttons lost their color; contacts status chips lost
     their navy fill). Rather than introduce NEW fork tokens, this block
     NEUTRALIZES the residue by aliasing each name to the real MHS token,
     fixing all usages at once. Goal is deprecation: new code should use
     the canonical token on the right, not these aliases. Closes the open
     half of the design-system token-gap finding. */
  --error: var(--state-trash);    /* destructive red — #c41e1e */
  --success: var(--state-active); /* affirmative green — #2e8540 */
  --navy: var(--state-pending);   /* the fork "navy" → pending blue #4a73a8 */
  --white: #fff;                  /* literal surface white (no token exists) */
  --line: var(--rule);            /* hairline border — #e6dfc8 */
  --text: var(--ink);             /* body text — #0a0a0a */
  --text-muted: var(--muted);     /* muted text — #6a655a */
  --radius: var(--radius-md);     /* default corner radius — 3px */
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: var(--header-h);
}

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: 'ss01', 'cv01';
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; height: auto; display: block; }

/* ============================================================
   FOCUS MANAGEMENT — universal :focus-visible system
   ------------------------------------------------------------
   Per Accessibility Audit P0 (2026-05-21). The suite carries
   43 inline `outline: none` declarations and only two elements
   (.auth-submit + .toggle-switch) have proper focus rings. This
   block lands the canonical replacement: default outline
   suppressed on mouse-click, visible orange ring on keyboard
   focus. 3:1+ contrast against canvas/white/ink surfaces.
   Component rules below may override outline-offset or color
   where geometry requires it.
   ============================================================ */

/* Suppress default focus ring globally — we replace with our own. */
:focus { outline: none; }

/* Universal keyboard focus indicator — uses :focus-visible per WCAG. */
:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Components with their own borders/backgrounds need extra offset
   so the ring clears the rim and stays readable. */
.btn:focus-visible,
.btn-primary:focus-visible,
.btn-new:focus-visible,
.auth-submit:focus-visible,
button:focus-visible {
  outline-offset: 3px;
}

/* Dark surfaces (dock, ink-gradient hero) need a light-color ring
   to clear contrast against the dark background. */
.admin-dock :focus-visible,
.hub-hero :focus-visible,
.dark-bg :focus-visible {
  outline-color: var(--canvas);
}

/* Card-as-link focus — ring the whole card, not just inner text. */
.mockup-card:focus-visible,
.card:focus-visible,
.spec-link:focus-visible,
[role="listitem"] a:focus-visible {
  outline: 2px solid var(--orange);
  /* W3-P2a (FINDING 2): 4px (not 3px) pushes the focus ring clear of the
     solid-orange hover border so the two never visually merge. */
  outline-offset: 4px;
}

/* .btn group — orange-tinted button bg can swallow a thin orange
   ring; pair the outline with an orange-soft glow for distinction. */
.btn:focus-visible {
  /* W3-P2a (FINDING 3): a hard INK ring, not orange-on-orange "optical mud."
     Per color-discipline contract #1 — orange button needs a dark ring. */
  outline: 3px solid var(--ink);
  outline-offset: 3px;
}

/* Primary CTA + auth submit sit on .--orange backgrounds — a dark
   ring vanishes; swap to canvas with a dark glow for separation. */
.btn-primary:focus-visible,
.auth-submit:focus-visible {
  outline: 2px solid var(--canvas);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(10, 10, 10, 0.25);
}

/* ============================================================
   DISABLED STATES — universal treatment for non-interactive
   ------------------------------------------------------------
   Per Color Discipline Audit P0: zero [disabled] state was
   defined anywhere in the system. Buttons/toggles dim to 0.5
   opacity with not-allowed cursor; form fields stay full-
   opacity but adopt muted text + canvas-alt fill so they read
   as "present but not editable" rather than ghosted.
   ============================================================ */

button[disabled],
button[aria-disabled="true"],
.btn[disabled],
.btn[aria-disabled="true"],
input[disabled],
select[disabled],
textarea[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

.btn[disabled]:hover,
.btn[aria-disabled="true"]:hover {
  transform: none;
  box-shadow: none;
}

/* Form fields override the 0.5 dim — labels stay readable but the
   surface goes canvas-alt and text goes muted so editability is
   obviously absent without crushing readability. */
input[disabled],
select[disabled],
textarea[disabled] {
  background: var(--canvas-alt);
  color: var(--muted);
  opacity: 1;
}

/* ============================================================
   SKIP TO MAIN CONTENT — keyboard-only nav shortcut.
   ------------------------------------------------------------
   Per Accessibility Audit P0 (WCAG 2.4.1). Build-phase adds
   <a class="skip-to-main" href="#main">Skip to main content</a>
   as the first child of <body>; this rule keeps it off-screen
   until keyboard focus reveals it.
   ============================================================ */

.skip-to-main {
  position: absolute;
  left: -10000px;
  top: 1rem;
  background: var(--ink);
  color: var(--canvas);
  padding: 0.5rem 1rem;
  font-family: var(--font-display);
  font-weight: 600;
  text-decoration: none;
  border-radius: 3px;
  z-index: 10000;
}

.skip-to-main:focus,
.skip-to-main:focus-visible {
  left: 1rem;
  outline: 2px solid var(--orange);
  outline-offset: 2px;
}

/* ============================================================
   SCREEN-READER UTILITY — visually hide, keep accessible.
   ------------------------------------------------------------
   Per Accessibility Audit P0. Used for status-pill prefixes
   ("Status: Live"), icon-button aria-label fallbacks, and any
   text that exists solely for assistive tech.
   ============================================================ */

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

/* ============================================================
   TYPOGRAPHY
   ============================================================ */

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  margin: 0 0 var(--space-sm);
  letter-spacing: -0.015em;
  color: var(--ink);
}
h1 { font-size: clamp(2.2rem, 5vw, 3.8rem); letter-spacing: -0.025em; font-weight: 700; }
h2 { font-size: clamp(1.6rem, 3.2vw, 2.5rem); }
h3 { font-size: clamp(1.15rem, 2vw, 1.45rem); font-weight: 600; }
h4 { font-size: 0.95rem; text-transform: uppercase; letter-spacing: 0.1em; font-weight: 600; color: var(--orange); }

p { margin: 0 0 1em; max-width: var(--max-w-prose); }
p.lede { font-size: 1.2rem; line-height: 1.5; max-width: 50ch; }
p.muted { color: var(--muted); }
.kicker {
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--orange);
  margin: 0 0 var(--space-xs);
}

a { color: var(--orange-dark); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; transition: color var(--dur) var(--ease); }
a:hover { color: var(--ink); }

strong { font-weight: 600; }
em { font-style: italic; }

ul, ol { padding-left: 1.3em; margin: 0 0 1em; }
li { margin: 0.32em 0; }
ul li::marker { color: var(--orange); }
ol li::marker { color: var(--orange); font-weight: 600; }

blockquote {
  border-left: 4px solid var(--orange);
  margin: 0 0 1em;
  padding: 0.2em 0 0.2em 1.4em;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.25rem;
  line-height: 1.4;
  max-width: 60ch;
}

code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--orange-soft);
  color: var(--orange-dark);
  padding: 0.1em 0.36em;
  border-radius: 2px;
}

/* ============================================================
   LAYOUT
   ============================================================ */

.container { max-width: var(--max-w); margin: 0 auto; padding: 0 var(--space-md); }
.container--narrow { max-width: var(--max-w-narrow); }
.section { padding: var(--space-xl) 0; }
.section--alt { background: var(--canvas-alt); }

/* ============================================================
   HEADER + NAV
   ============================================================ */

.site-header {
  background: var(--canvas);
  border-bottom: 1px solid var(--rule);
  position: sticky;
  top: 0;
  z-index: 50;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-sm) var(--space-md);
  max-width: var(--max-w);
  margin: 0 auto;
  gap: var(--space-md);
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--ink);
}
.brand img { height: 2rem; width: auto; }
.brand-text {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: 0.01em;
}
.nav-primary, .nav-secondary {
  display: flex;
  gap: var(--space-md);
  list-style: none;
  padding: 0;
  margin: 0;
  align-items: center;
}
.nav-primary { font-family: var(--font-display); font-weight: 600; }
.nav-primary a, .nav-secondary a {
  color: var(--ink);
  text-decoration: none;
  font-size: 0.95rem;
  padding: 0.3em 0.1em;
  border-bottom: 2px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.nav-primary a:hover { border-bottom-color: var(--orange); }
.nav-secondary {
  border-top: 1px solid var(--rule);
  padding: var(--space-xs) var(--space-md);
  justify-content: center;
  gap: var(--space-lg);
  max-width: var(--max-w);
  margin: 0 auto;
}
.nav-secondary a { font-size: 0.84rem; color: var(--muted); font-weight: 500; }
.nav-secondary a:hover { color: var(--orange-dark); }

/* ===== REVIEW FILTER CHIPS (W2-P3 / P0-17) =====
   /reviews project-type filter nav. Ported from mockups/reviews.html.
   Wrapped as <nav> for a11y; each chip links to /reviews?project_type=…
   and the active chip carries aria-current="page". Mirrors the
   .category-jump chip pattern from the services index. */
.review-filter {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  justify-content: center;
  margin-top: var(--space-md);
}
.review-filter a {
  display: inline-flex;
  align-items: center;
  padding: 0.42em 1em;
  background: white;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.review-filter a:hover {
  border-color: var(--orange);
  background: var(--orange-soft);
  color: var(--orange-dark);
}
.review-filter a[aria-current="page"] {
  border-color: var(--orange);
  background: var(--orange);
  color: var(--ink);
}
.review-filter a .count {
  color: var(--muted);
  font-weight: 500;
  margin-left: 0.4em;
}
.review-filter a[aria-current="page"] .count { color: rgba(10, 10, 10, 0.65); }

/* Header phone CTA — icon-only at all widths.
   The phone number is announced to screen readers via aria-label;
   the visible button is a circular icon target. R&D-canonical
   pattern: keep the header chrome compact + lean. */
.header-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem; /* 44px — Apple touch-target floor (Wave 5 a11y) */
  height: 2.75rem;
  color: var(--ink);
  background: var(--canvas-alt);
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  text-decoration: none;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
  flex-shrink: 0;
}
.header-cta:hover {
  background: var(--orange);
  border-color: var(--orange-dark);
  color: var(--ink);
}
.header-cta .icon {
  width: 1.15rem;
  height: 1.15rem;
}

/* ============================================================
   HERO
   ============================================================ */

.hero {
  position: relative;
  min-height: 70vh;
  display: flex;
  align-items: center;
  background: var(--ink);
  color: var(--canvas);
  overflow: hidden;
}
.hero::before {
  content: '';
  position: absolute; inset: 0;
  background-image:
    linear-gradient(180deg, rgba(10, 10, 10, 0.40), rgba(10, 10, 10, 0.78)),
    var(--hero-bg, none);
  background-size: cover;
  /* --hero-bg-position consumes mhs_images.focal_point_x/y (per the
     Wave 5 hero-focal patch). Fallback 'center 55%' preserves the
     cedar-porch placeholder's deliberate vertical bias. */
  background-position: var(--hero-bg-position, center 55%);
  z-index: 0;
}
.hero-inner {
  position: relative;
  z-index: 1;
  padding: var(--space-xxl) var(--space-md) var(--space-xl);
  max-width: var(--max-w);
  margin: 0 auto;
  width: 100%;
}
.hero h1 {
  color: var(--canvas);
  max-width: 22ch;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
}
.hero p.lede {
  color: var(--canvas-alt);
  font-size: clamp(1.05rem, 1.5vw, 1.35rem);
  max-width: 44ch;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.4);
}
.hero-actions {
  display: flex;
  gap: var(--space-sm);
  margin-top: var(--space-md);
  flex-wrap: wrap;
}

/* .page-hero — for non-home pages */
.page-hero {
  background: var(--ink-soft);
  color: var(--canvas);
  padding: var(--space-lg) 0 var(--space-md);
  position: relative;
}
.page-hero.with-photo {
  background-image:
    linear-gradient(180deg, rgba(10, 10, 10, 0.50), rgba(10, 10, 10, 0.78)),
    var(--hero-bg, none);
  background-size: cover;
  background-position: var(--hero-bg-position, center);
  min-height: 38vh;
  display: flex;
  align-items: center;
}
.page-hero h1 { color: var(--canvas); }
.page-hero p.lede { color: var(--canvas-alt); max-width: 50ch; }
.page-hero .breadcrumb {
  font-size: 0.85rem;
  color: var(--canvas-alt);
  opacity: 0.7;
  margin-bottom: 0.5em;
  letter-spacing: 0.04em;
}
.page-hero .breadcrumb a { color: var(--canvas-alt); text-decoration: none; }
.page-hero .breadcrumb a:hover { color: var(--orange); }

/* ────────────────────────────────────────────────────────────────
   .page-hero.amber-grade — warm radial wash over a photo hero.
   Lifted from mockup epoxy.html in-page styles. Use alongside
   .with-photo for the epoxy detail page.
   ──────────────────────────────────────────────────────────────── */
.page-hero.amber-grade {
  overflow: hidden;
  position: relative;
}
.page-hero.amber-grade .container { position: relative; z-index: 2; }
.page-hero.amber-grade::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 75% 40%, rgba(232, 122, 0, 0.30) 0%, transparent 55%);
  pointer-events: none;
  z-index: 1;
  mix-blend-mode: screen;
}

/* ────────────────────────────────────────────────────────────────
   .page-hero.post-hero — image-over-text banner for /blog/:slug.
   Heavier gradient than the generic .with-photo so title + byline
   stay legible regardless of the post hero's brightness; uses
   --hero-bg-position to honor each image's stored focal point.
   ──────────────────────────────────────────────────────────────── */
.page-hero.post-hero.with-photo {
  background-image:
    linear-gradient(to bottom, rgba(10, 10, 10, 0.50), rgba(10, 10, 10, 0.78)),
    var(--hero-bg, none);
  background-position: var(--hero-bg-position, center);
  min-height: 44vh;
}

/* ============================================================
   CARDS + GRIDS
   ============================================================ */

.card-grid {
  display: grid;
  gap: var(--space-md);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.card-grid--tight { gap: var(--space-sm); }
.card-grid--wide { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }

.card {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 3px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
  text-decoration: none;
  color: inherit;
}
.card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lift);
  /* W3-P2a (FINDING 2): solid orange, not --orange-soft (0.10α), so the
     hover border reads distinctly from the focus-visible orange ring instead
     of layering two faint oranges (color-discipline collision #2, CRITICAL). */
  border-color: var(--orange);
}
.card-image {
  aspect-ratio: 4/3;
  background: var(--canvas-alt) center/cover no-repeat;
  width: 100%;
}
/* Visible "add a photo" fallback for any card whose entity has no image_id yet.
   The :not selector cleanly hands off when the EJS inlines a real background-image. */
.card-image:not([style*="background-image"]) {
  background-image: url('/images/placeholders/placeholder-card.svg');
}
.card-body { padding: var(--space-md); display: flex; flex-direction: column; flex: 1; }
.card-body h3 { margin: 0 0 0.3em; font-size: 1.15rem; }
.card-body p { margin: 0; color: var(--muted); font-size: 0.95rem; flex: 1; }
.card-meta {
  margin-top: var(--space-sm);
  font-size: 0.82rem;
  color: var(--orange-dark);
  font-weight: 600;
  letter-spacing: 0.04em;
}
.card-meta::after { content: ' →'; }

/* Owner-only per-card image-slot wrapper (W2-P6b, /remodeling category cards).
   The category cards are anchors, so the "Change photo" pill can't nest inside
   them (invalid HTML + the <a> would hijack the click). The wrapper is the grid
   item + positioning context; the <a class="card"> fills it, and the pill is an
   absolutely-positioned sibling overlay. Only rendered when a card is owner-
   editable, so public markup is untouched. */
.card-slot-wrap {
  position: relative;
  display: flex;
}
.card-slot-wrap > .card {
  flex: 1;
  min-width: 0;
}
/* Tighter pill seated over the card thumbnail (vs the 1rem hero inset). */
.change-pill--card {
  top: 0.5rem;
  right: 0.5rem;
  font-size: 0.78rem;
  padding: 0.4em 0.8em;
  min-height: 36px;
}

/* ------------------------------------------------------------------
   Post-detail neighbor nav (prev/next) — note.ejs:73-94.
   Two thumbnail cards ("Newer post" / "Older post") at the foot of an
   article. Borrows the .card idiom (white panel, hairline rule, hover
   lift) so it sits coherently with the blog-card grid above it. With a
   single Live post the route suppresses this block entirely; it becomes
   visible the instant a 2nd post goes Live (Chain H — ships together).
   ------------------------------------------------------------------ */
.note-nav-pair {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-sm);
}
.note-nav {
  display: flex;
  align-items: stretch;
  gap: var(--space-sm);
  background: white;
  border: 1px solid var(--rule);
  border-radius: 3px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  padding: 0;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.note-nav:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lift);
  border-color: var(--orange-soft);
}
/* Older-post card lives in the right column and reads right-to-left:
   text then thumb, label/title right-aligned, so the pair mirrors. */
.note-nav-pair .note-nav:last-child:nth-child(2) {
  flex-direction: row-reverse;
  text-align: right;
}
.note-nav__thumb {
  flex: 0 0 5.5rem;
  align-self: stretch;
  min-height: 5rem;
  background: var(--canvas-alt) center/cover no-repeat;
}
.note-nav__thumb:not([style*="background-image"]) {
  background-image: url('/images/placeholders/placeholder-card.svg');
}
.note-nav__body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.25rem;
  padding: var(--space-sm);
  min-width: 0;
}
.note-nav__label {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--orange-dark);
}
.note-nav__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.98rem;
  line-height: 1.3;
  color: var(--ink);
}
@media (max-width: 640px) {
  .note-nav-pair { grid-template-columns: 1fr; }
  /* On a single column, un-mirror the older-post card so both read L-to-R. */
  .note-nav-pair .note-nav:last-child:nth-child(2) {
    flex-direction: row;
    text-align: left;
  }
}

/* ------------------------------------------------------------------
   Blog cards + category pill — ported from mockups/blog.html inline
   <style> (lines 126-159). The blog index grid (blog.ejs) and the
   post-detail related-posts grid (note.ejs) both use .card.blog-card
   with a .pill-category chip + .author-date line. The base .card /
   .card-image / .card-body rules already live above; these are the
   blog-specific overrides + the pill.
   ------------------------------------------------------------------ */
.pill-category {
  display: inline-block;
  padding: 0.25em 0.7em;
  border-radius: 999px;
  background: var(--canvas);
  color: var(--orange-dark);
  border: 1px solid var(--orange);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.4;
}
.blog-card .card-image { aspect-ratio: 16/9; }
.blog-card .card-meta-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
  flex-wrap: wrap;
}
.blog-card .author-date {
  font-size: 0.82rem;
  color: var(--muted);
  margin-top: var(--space-sm);
}

/* ------------------------------------------------------------------
   Related-posts heading + bottom inline-CTA box — ported from
   mockups/blog.html inline <style> (lines 290-334). Used at the foot
   of a post-detail article (note.ejs).
   ------------------------------------------------------------------ */
.related-heading {
  text-align: center;
  margin-bottom: var(--space-md);
}
.related-heading .kicker { text-align: center; }

/* ------------------------------------------------------------------
   QJ-8 (W3-P3): service-detail "More from MHS" related-services rail
   (service-detail.ejs). Reuses the canonical .card / .card-grid--wide
   idiom + the .related-heading chrome above (shared with note.ejs's
   related-posts rail). Only this scoping block is service-detail-
   specific: the sibling-service thumbnails take the wider 16/9 crop the
   services catalog cards use elsewhere, so the cross-promo cards read as
   service cards, not blog cards. Renders only when the route hands back
   ≥1 sibling service (cold/sparse catalog → no rail).
   ------------------------------------------------------------------ */
.related-services .card-image { aspect-ratio: 16/9; }

.inline-cta {
  max-width: 44rem;
  margin: var(--space-lg) auto 0;
  background: var(--ink);
  color: var(--canvas);
  border-radius: 4px;
  padding: var(--space-lg);
  text-align: center;
  position: relative;
  overflow: hidden;
}
.inline-cta::before {
  content: '';
  position: absolute;
  inset: -30%;
  background: radial-gradient(ellipse at center, var(--orange-flare) 0%, transparent 60%);
  pointer-events: none;
}
.inline-cta h3 {
  color: var(--orange);
  margin: 0 0 0.4em;
  font-size: 1.3rem;
  position: relative;
}
.inline-cta p {
  color: var(--canvas-alt);
  margin: 0 auto var(--space-md);
  max-width: 40ch;
  position: relative;
}
.inline-cta .inline-actions {
  display: inline-flex;
  gap: var(--space-sm);
  flex-wrap: wrap;
  justify-content: center;
  position: relative;
}

/* Surface 4: section-item card variants */
.section-card {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: var(--space-md);
  position: relative;
}
.section-card .illustration {
  aspect-ratio: 1/1;
  background: var(--canvas-alt);
  border-radius: 50%;
  width: 5rem;
  margin-bottom: var(--space-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--orange-dark);
  font-size: 1.5rem;
  font-family: var(--font-display);
}
.section-card h3 { margin: 0 0 0.3em; font-size: 1.05rem; }
.section-card p { margin: 0; font-size: 0.92rem; color: var(--muted); }

/* Process steps numbered */
.process-grid { counter-reset: step; }
.process-grid .section-card { padding-left: 4.5rem; min-height: 7rem; }
.process-grid .section-card::before {
  counter-increment: step;
  content: counter(step);
  position: absolute;
  left: 1rem;
  top: 1rem;
  font-family: var(--font-display);
  font-size: 2.2rem;
  font-weight: 700;
  color: var(--orange);
  line-height: 1;
  width: 2.5rem;
  text-align: center;
}

/* Team grid */
.team-grid .section-card .portrait {
  aspect-ratio: 1/1;
  background: var(--canvas-alt) center/cover no-repeat;
  border-radius: 50%;
  width: 6rem;
  margin-bottom: var(--space-sm);
}
.team-grid .role {
  font-size: 0.85rem;
  color: var(--orange-dark);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  margin-bottom: 0.3em;
}

/* Timeline */
.timeline { position: relative; padding-left: 2.5rem; border-left: 2px solid var(--rule); }
.timeline-beat { margin-bottom: var(--space-md); position: relative; }
.timeline-beat::before {
  content: '';
  position: absolute;
  left: -3rem;
  top: 0.4rem;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  background: var(--orange);
  border: 3px solid var(--canvas);
}
.timeline-beat .year {
  font-family: var(--font-display);
  font-size: 0.95rem;
  color: var(--orange-dark);
  font-weight: 700;
  letter-spacing: 0.04em;
}
.timeline-beat h3 { margin: 0.2em 0 0.3em; font-size: 1.15rem; }
.timeline-beat p { margin: 0; color: var(--muted); }

/* ============================================================
   BUTTONS
   ============================================================ */

.btn {
  display: inline-block;
  padding: 0.9em 1.7em;
  background: var(--orange);
  color: var(--ink);
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  border: 2px solid var(--orange);
  border-radius: 2px;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease), transform var(--dur) var(--ease);
  cursor: pointer;
  text-align: center;
}
.btn:hover {
  background: var(--orange-dark);
  border-color: var(--orange-dark);
  /* W3-P2a (FINDING 4): pure white (not --canvas #faf7f0) clears 4.5:1 on
     --orange-dark at the anti-aliased rim — color-discipline contract #1. */
  color: white;
  transform: translateY(-1px);
}
/* W3-P2a (FINDING 5): 100ms press depression — microinteractions-spec §10
   item 2 + contract #1. Without it the hover's -1px lift lingers on click. */
.btn:active {
  transform: translateY(0);
  background: var(--orange-dark);
}
.btn--secondary {
  background: transparent;
  color: var(--canvas);
  border-color: var(--canvas);
}
.btn--secondary:hover {
  background: var(--canvas);
  border-color: var(--canvas);
  color: var(--ink);
}
.btn--inverse {
  background: var(--ink);
  color: var(--canvas);
  border-color: var(--ink);
}
.btn--inverse:hover {
  background: var(--orange);
  border-color: var(--orange);
  color: var(--ink);
}

/* ============================================================
   CTA SECTION (Wave 14a V10 — gold glow)
   ============================================================ */

.cta-section {
  background: var(--ink);
  color: var(--canvas);
  padding: var(--space-xl) 0;
  position: relative;
  overflow: hidden;
  text-align: center;
}
.cta-section::before {
  content: '';
  position: absolute;
  inset: -20%;
  background: radial-gradient(ellipse at center, var(--orange-flare) 0%, transparent 55%);
  pointer-events: none;
}
.cta-section .container { position: relative; z-index: 1; }
.cta-section h2 { color: var(--orange); margin-bottom: var(--space-sm); width: fit-content; max-width: 22ch; margin-left: auto; margin-right: auto; }
.cta-section p { margin: 0 auto var(--space-md); color: var(--canvas-alt); max-width: 50ch; font-size: 1.1rem; }
.cta-section .btn--secondary { color: var(--canvas); border-color: var(--canvas); }
.cta-section .btn--secondary:hover { background: var(--canvas); color: var(--ink); }

/* ============================================================
   DIVIDER (Wave 14a V11 — Wave SVG)
   ============================================================ */

.divider-wave {
  display: block;
  width: 100%;
  height: 36px;
  background-color: var(--canvas-alt);
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 36' preserveAspectRatio='none'><path d='M0,18 C300,0 900,36 1200,18 L1200,36 L0,36 Z' fill='black'/></svg>") center/100% 100% no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 36' preserveAspectRatio='none'><path d='M0,18 C300,0 900,36 1200,18 L1200,36 L0,36 Z' fill='black'/></svg>") center/100% 100% no-repeat;
}
.divider-wave--orange { background-color: var(--orange); opacity: 0.65; }
.divider-wave--ink { background-color: var(--ink); opacity: 0.85; }

/* ============================================================
   EPOXY BRAND-VIDEO BAND
   Mockup spec at mhs-blueprint/marketing-site/mockups/epoxy.html:137-220.
   Thumbnail URL is injected inline via --video-thumb custom prop so the
   EJS can compute YouTube auto-thumbnails without per-deploy CSS edits.
   ============================================================ */
.video-band .video-frame {
  position: relative;
  max-width: 56rem;
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  background-image:
    linear-gradient(135deg, rgba(232, 122, 0, 0.15) 0%, rgba(10, 10, 10, 0) 60%),
    var(--video-thumb, url('/images/placeholders/placeholder-card.svg'));
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  background-color: var(--ink);
  border: 1px solid var(--rule);
  border-radius: 3px;
  overflow: hidden;
  box-shadow: var(--shadow-lift);
}
.video-band .video-frame::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(10, 10, 10, 0.30) 0%, rgba(10, 10, 10, 0.55) 100%);
  pointer-events: none;
}
.video-band .play-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  color: var(--canvas);
  text-decoration: none;
  z-index: 2;
  font-family: var(--font-display);
  font-weight: 600;
  transition: transform var(--dur) var(--ease);
}
.video-band .play-overlay:hover { transform: translateY(-2px); }
.video-band .play-button {
  width: 4.5rem;
  height: 4.5rem;
  background: var(--orange);
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow:
    0 0 0 10px rgba(232, 122, 0, 0.20),
    0 0 0 24px rgba(232, 122, 0, 0.08),
    var(--shadow-lift);
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.video-band .play-overlay:hover .play-button {
  background: var(--orange-light);
  transform: scale(1.04);
}
.video-band .play-button svg {
  width: 1.6rem;
  height: 1.6rem;
  color: var(--ink);
  transform: translateX(2px);
}
.video-band .play-caption {
  color: var(--canvas);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.6);
}
.video-band .video-meta {
  text-align: center;
  margin-top: var(--space-md);
  color: var(--muted);
  font-size: 0.85rem;
  max-width: 56rem;
  margin-left: auto;
  margin-right: auto;
  padding: 0 var(--space-md);
}
.video-band .video-meta code {
  background: rgba(10, 10, 10, 0.06);
  color: var(--ink-soft);
  font-size: 0.85em;
  padding: 0.15em 0.4em;
  border-radius: 2px;
}

/* ============================================================
   FINISHES GRID (S4) — /epoxy
   Ported from mockup epoxy.html in-page styles (~222-296). Each
   swatch is a real-ish epoxy finish rendered with layered CSS
   gradients — no photography, but reads as on-brand placeholder
   until real samples land. The five seeded families carry a
   meta.swatch_class that selects one of the gradient modifiers
   below; an owner-added finish with only a meta.swatch_color hex
   gets a flat inline background instead (handled in the view).
   ============================================================ */
.finishes-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-md);
}
.finishes-grid .section-card { padding: 0; overflow: hidden; }
.finishes-grid .finish-swatch {
  aspect-ratio: 4 / 3;
  width: 100%;
  background-size: cover;
  background-position: center;
  position: relative;
}
.finishes-grid .finish-swatch::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 35% 30%, rgba(255, 255, 255, 0.18) 0%, transparent 50%);
  pointer-events: none;
}
.finishes-grid .finish-swatch--metallic-silver {
  background:
    radial-gradient(ellipse at 30% 35%, rgba(255, 255, 255, 0.55) 0%, transparent 38%),
    radial-gradient(ellipse at 70% 70%, rgba(220, 220, 230, 0.5) 0%, transparent 45%),
    linear-gradient(135deg, #4a4a52 0%, #8c8c95 35%, #2e2e34 100%);
}
.finishes-grid .finish-swatch--metallic-bronze {
  background:
    radial-gradient(ellipse at 35% 30%, rgba(245, 200, 100, 0.45) 0%, transparent 40%),
    radial-gradient(ellipse at 75% 75%, rgba(180, 92, 0, 0.35) 0%, transparent 50%),
    linear-gradient(135deg, #5a3008 0%, #b56a1a 40%, #2a1a08 100%);
}
.finishes-grid .finish-swatch--broadcast-quartz {
  background:
    radial-gradient(circle at 20% 30%, #f5e6c8 0.5px, transparent 1.5px),
    radial-gradient(circle at 60% 50%, #c89a5a 0.4px, transparent 1.4px),
    radial-gradient(circle at 80% 25%, #6a4a28 0.5px, transparent 1.6px),
    radial-gradient(circle at 35% 75%, #e8d4a0 0.4px, transparent 1.4px),
    radial-gradient(circle at 70% 85%, #8a6a3a 0.5px, transparent 1.5px),
    linear-gradient(135deg, #d4b886 0%, #b89358 100%);
  background-size: 8px 8px, 6px 6px, 10px 10px, 7px 7px, 9px 9px, 100% 100%;
}
.finishes-grid .finish-swatch--decorative-flake {
  background:
    radial-gradient(ellipse 3px 1.5px at 20% 25%, #0a0a0a 0%, transparent 100%),
    radial-gradient(ellipse 2.5px 1.5px at 65% 40%, #e87a00 0%, transparent 100%),
    radial-gradient(ellipse 3px 1px at 80% 75%, #4a4a4a 0%, transparent 100%),
    radial-gradient(ellipse 2px 1px at 35% 70%, #faf7f0 0%, transparent 100%),
    radial-gradient(ellipse 3px 2px at 50% 15%, #0a0a0a 0%, transparent 100%),
    radial-gradient(ellipse 2.5px 1.5px at 15% 85%, #e87a00 0%, transparent 100%),
    linear-gradient(135deg, #2a2a2a 0%, #4a4a4a 100%);
  background-size: 16px 16px, 14px 14px, 18px 18px, 12px 12px, 20px 20px, 15px 15px, 100% 100%;
}
.finishes-grid .finish-swatch--solid-color {
  background:
    linear-gradient(135deg, #c75a00 0%, #e87a00 50%, #b55c00 100%);
}
.finishes-grid .section-card .finish-body { padding: var(--space-md); }
.finishes-grid .section-card h3 { margin: 0 0 0.3em; font-size: 1.05rem; }
.finishes-grid .section-card .finish-meta {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--orange-dark);
  font-weight: 600;
  margin-bottom: 0.4em;
}
.finishes-grid .section-card p { margin: 0; font-size: 0.92rem; color: var(--muted); }

/* ============================================================
   GALLERY PIPELINE LIST (S4: gallery/pipeline_items)
   Ported verbatim from mockup gallery.html in-page styles
   (~53-103). A small "what's coming" list under the empty-state
   card — admin-editable as the photo-shoot details firm up.
   2-col auto-fit grid with an orange leader bullet; restrained,
   no per-item card chrome. Lives inside the .empty-state card.
   ============================================================ */
.pipeline {
  max-width: 56rem;
  margin: var(--space-md) auto 0;
  padding-top: var(--space-md);
  border-top: 1px solid var(--rule);
  text-align: left;
}
.pipeline-label {
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--orange);
  margin: 0 0 var(--space-sm);
  text-align: center;
}
.pipeline-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0.6em var(--space-md);
}
.pipeline-list li {
  margin: 0;
  padding-left: 1.2em;
  position: relative;
  color: var(--ink);
  font-size: 0.95rem;
  line-height: 1.5;
}
.pipeline-list li::before {
  content: '◉';
  position: absolute;
  left: 0;
  top: 0;
  color: var(--orange);
  font-size: 0.7em;
  line-height: 1.7;
}
.pipeline-list li .pipeline-where {
  color: var(--muted);
  font-size: 0.88rem;
}

/* ============================================================
   PROPERTY-MANAGEMENT CAPABILITY CARDS (S4: capabilities_grid)
   Ported verbatim from mockup property-management.html in-page
   styles (~45-94). Six cards, each with a line-art SVG icon in an
   orange-soft disc, a name, and a one-sentence description. The
   icon is load-bearing brand visual (restored W2 — the rebuild had
   dropped all six). Used with .card-grid on the public page.
   ============================================================ */
.capability-grid { list-style: none; padding: 0; margin: 0; }
.capability-card {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.capability-card:hover {
  border-color: var(--orange-soft);
  box-shadow: var(--shadow-card);
  transform: translateY(-2px);
}
.capability-card .cap-icon {
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--orange-soft);
  color: var(--orange-dark);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--space-sm);
  flex-shrink: 0;
  border: 1px solid var(--orange-flare);
}
.capability-card .cap-icon svg {
  width: 1.4rem;
  height: 1.4rem;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.capability-card h3 {
  font-size: 1.08rem;
  margin: 0 0 0.4em;
  letter-spacing: -0.01em;
}
.capability-card p {
  margin: 0;
  color: var(--ink-mute);
  font-size: 0.94rem;
  line-height: 1.5;
  max-width: none;
}

/* ============================================================
   PROPERTY-MANAGEMENT SERVICE-AREA + WHY-CARD (W3-P2c)
   Ported verbatim from mockup property-management.html in-page
   styles (130-201). Two-column block: left = city pill list,
   right = "why it works" card. The view previously inlined all
   of this, which (a) lost the mobile stack breakpoint — the bare
   inline `grid-template-columns: 1.1fr 1fr` never collapsed on
   phones — and (b) carried the region-highlight pill + check-mark
   bullets only as one-off inline styles. Classes restore the
   @media stack + the .area-pill--region accent + the why-card
   custom check bullets.
   ============================================================ */
.service-area-grid {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: var(--space-lg);
  align-items: start;
}
@media (max-width: 768px) {
  .service-area-grid { grid-template-columns: 1fr; }
}
.area-pill-list {
  list-style: none;
  padding: 0;
  margin: var(--space-sm) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.area-pill-list li {
  margin: 0;
  background: white;
  border: 1px solid var(--rule);
  color: var(--ink);
  padding: 0.4em 0.95em;
  border-radius: 999px;
  font-size: 0.88rem;
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: 0.01em;
}
.area-pill-list li::marker { content: none; }
.area-pill-list li.area-pill--region {
  background: var(--orange-soft);
  color: var(--orange-dark);
  border-color: var(--orange-flare);
  font-weight: 600;
}
.why-card {
  background: white;
  border-left: 4px solid var(--orange);
  padding: var(--space-md) var(--space-md) var(--space-sm);
  box-shadow: var(--shadow-card);
  border-radius: 0 3px 3px 0;
}
.why-card h3 {
  margin: 0 0 var(--space-sm);
  font-size: 1.15rem;
}
.why-card ul {
  list-style: none;
  padding: 0;
  margin: 0;
}
.why-card li {
  margin: 0 0 0.7em;
  padding-left: 1.5em;
  position: relative;
  color: var(--ink);
  font-size: 0.96rem;
  line-height: 1.45;
}
.why-card li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 0.7em;
  height: 0.35em;
  border-left: 2px solid var(--orange);
  border-bottom: 2px solid var(--orange);
  transform: rotate(-45deg);
}
.why-card li strong { color: var(--ink); font-weight: 600; }

/* ============================================================
   TESTIMONIAL
   ============================================================ */

.testimonial {
  background: white;
  border-left: 4px solid var(--orange);
  padding: var(--space-lg);
  max-width: 56rem;
  margin: 0 auto;
  box-shadow: var(--shadow-card);
}
.testimonial blockquote {
  margin: 0 0 var(--space-sm);
  border: 0;
  padding: 0;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.35rem;
  line-height: 1.45;
  color: var(--ink);
  max-width: none;
}
.testimonial blockquote::before { content: '“'; color: var(--orange); font-size: 1.4em; line-height: 0; vertical-align: -0.15em; }
.testimonial cite {
  display: block;
  font-style: normal;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink);
  margin-top: var(--space-sm);
}
.testimonial cite::before {
  content: '— ';
  color: var(--orange);
}
.testimonial .project-type {
  font-size: 0.82rem;
  color: var(--muted);
  margin-left: 0.4em;
}

/* ============================================================
   STATS
   ============================================================ */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--space-md);
  text-align: center;
  margin: var(--space-lg) 0;
  padding: var(--space-md) 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.stat .num {
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 4.5vw, 3.2rem);
  font-weight: 700;
  color: var(--orange);
  line-height: 1;
  letter-spacing: -0.02em;
}
.stat .label {
  font-size: 0.78rem;
  color: var(--muted);
  margin-top: 0.5em;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
}

/* ============================================================
   FAQ
   ============================================================ */

.faq-list { max-width: 56rem; margin: 0 auto; }
.faq-item {
  border-bottom: 1px solid var(--rule);
  padding: var(--space-sm) 0;
}
.faq-item summary {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.1rem;
  cursor: pointer;
  list-style: none;
  position: relative;
  padding-right: 2rem;
  color: var(--ink);
}
.faq-item summary::after {
  content: '+';
  position: absolute;
  right: 0;
  top: 0;
  font-size: 1.5rem;
  color: var(--orange);
  font-weight: 400;
  line-height: 1;
}
.faq-item[open] summary::after { content: '–'; }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item-body {
  padding-top: var(--space-sm);
  color: var(--ink-mute);
  max-width: 64ch;
}

/* ============================================================
   FOOTER
   ============================================================ */

.site-footer {
  background: var(--ink);
  color: var(--canvas);
  padding: var(--space-lg) 0 var(--space-md);
  position: relative;
  overflow: hidden;
}
.site-footer::after {
  content: '';
  position: absolute;
  bottom: -4rem;
  right: -4rem;
  width: 20rem;
  height: 20rem;
  background-color: var(--canvas);
  opacity: 0.06;
  /* W3-P2a (FINDING 10): absolute path. This sheet serves from /css/, so a
     relative 'images/…' resolved to /css/images/… (404) — the footer
     watermark silently failed. Pointing at the 18KB mhs-mark-200.png (not
     the 1.5MB full-res) since it's an alpha mask at 0.06 opacity — identical
     visually, 1.5MB lighter on every page. */
  -webkit-mask: url('/images/mhs-mark-200.png') no-repeat center/contain;
  mask: url('/images/mhs-mark-200.png') no-repeat center/contain;
  pointer-events: none;
}
.footer-grid {
  display: grid;
  gap: var(--space-md);
  grid-template-columns: 2fr 1fr 1fr 1fr;
  max-width: var(--max-w);
  margin: 0 auto;
  padding: 0 var(--space-md);
  position: relative;
  z-index: 1;
}
.footer-grid h4 { color: var(--canvas); margin-bottom: var(--space-sm); }
.footer-grid a {
  color: var(--canvas-alt);
  text-decoration: none;
  display: block;
  padding: 0.2em 0;
  font-size: 0.92rem;
}
.footer-grid a:hover { color: var(--orange); }
.footer-grid p { color: var(--canvas-alt); font-size: 0.92rem; margin: 0.2em 0; max-width: none; }
.footer-bottom {
  border-top: 1px solid rgba(250, 247, 240, 0.15);
  margin-top: var(--space-md);
  padding: var(--space-sm) var(--space-md) 0;
  max-width: var(--max-w);
  margin-left: auto;
  margin-right: auto;
  font-size: 0.82rem;
  color: rgba(250, 247, 240, 0.55);
  display: flex;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
  position: relative;
  z-index: 1;
}

/* ============================================================
   EDITING-SURFACE OVERLAY SYSTEM
   ----------------------------------------------------------
   When body has .show-surfaces, every [data-surface="N"]
   element gets a colored dashed outline + label badge.
   Toggle via the .surface-toggle button.
   ============================================================ */

body.show-surfaces [data-surface] {
  position: relative;
  outline-offset: 3px;
  outline-width: 2px;
  outline-style: dashed;
  transition: outline-color var(--dur) var(--ease);
}
body.show-surfaces [data-surface="1"] { outline-color: rgba(232, 122, 0, 0.6); }
body.show-surfaces [data-surface="2"] { outline-color: rgba(40, 140, 220, 0.6); }
body.show-surfaces [data-surface="3"] { outline-color: rgba(170, 60, 200, 0.6); }
body.show-surfaces [data-surface="4"] { outline-color: rgba(50, 170, 90, 0.6); }
/* S6 derived = read-only computed values (review aggregates, counts, copyright year).
   Muted gray outline signals "informational, not editable" — distinct from the four
   editable surfaces above. */
body.show-surfaces [data-surface="6"] { outline-color: rgba(106, 101, 90, 0.45); }

/* Surface-number chip — always visible when overlay is ON, inset top-left.
   Small + bounded inside the annotated element so it never collides with
   chips on adjacent/stacked annotations (e.g. hero kicker + h1 + lede). */
body.show-surfaces [data-surface]::before {
  content: 'S' attr(data-surface);
  position: absolute;
  top: 0.25em;
  left: 0.25em;
  background: var(--ink);
  color: var(--canvas);
  min-width: 1.4em;
  height: 1.4em;
  padding: 0 0.35em;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
  pointer-events: none;
  box-shadow: 0 1px 3px rgba(10, 10, 10, 0.3);
}
body.show-surfaces [data-surface="1"]::before { background: #b85a00; }
body.show-surfaces [data-surface="2"]::before { background: #1c6da8; }
body.show-surfaces [data-surface="3"]::before { background: #7a2890; }
body.show-surfaces [data-surface="4"]::before { background: #1e7a40; }
body.show-surfaces [data-surface="6"]::before { background: #6a655a; }

/* Settings-class S1 chip — when the surface-label starts with "S1: settings.",
   the chip shows "S1" followed by an inline globe glyph to signal "global,
   edit in /admin/settings — propagates everywhere". The chip widens to fit.
   SVG is inlined as a data URI for crisp rendering and zero network cost; explicit
   width/height keeps the glyph sized to match the chip's text. */
body.show-surfaces [data-surface="1"][data-surface-label^="S1: settings."]::before {
  content: 'S1 ' url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 16 16' fill='none' stroke='%23faf7f0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><circle cx='8' cy='8' r='6'/><path d='M2 8h12'/><path d='M8 2a9 9 0 010 12'/><path d='M8 2a9 9 0 000 12'/></svg>");
  padding-right: 0.5em;
  gap: 0.25em;
}

/* Full label appears on hover/focus as a fixed-position tooltip in the
   viewport bottom-left, away from the .surface-toggle dock (bottom-right).
   Only one full label is visible at a time.
   Default rule: show the dev-key (data-surface-label) — fallback for elements
   that don't yet carry a plain-English name. */
body.show-surfaces [data-surface]:hover::after,
body.show-surfaces [data-surface]:focus-within::after {
  content: attr(data-surface-label);
  position: fixed;
  bottom: calc(7rem + env(safe-area-inset-bottom));
  left: 1rem;
  background: var(--ink);
  color: var(--canvas);
  padding: 0.45em 0.85em;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  border-radius: 3px;
  z-index: 300;
  pointer-events: none;
  max-width: 70vw;
  white-space: normal;
  line-height: 1.3;
  box-shadow: 0 4px 16px rgba(10, 10, 10, 0.35);
}

/* When data-surface-name is present, lead with the plain-English name (for Doug)
   and append the dev-key in parentheses (for engineering context). More specific
   selector wins the cascade. */
body.show-surfaces [data-surface][data-surface-name]:hover::after,
body.show-surfaces [data-surface][data-surface-name]:focus-within::after {
  content: attr(data-surface-name) '  (' attr(data-surface-label) ')';
}

.surface-toggle {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  background: var(--ink);
  color: var(--canvas);
  padding: 0.7em 1.2em;
  border: 2px solid var(--ink);
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  cursor: pointer;
  z-index: 999;
  box-shadow: 0 4px 16px rgba(10, 10, 10, 0.25);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.surface-toggle:hover { background: var(--orange); border-color: var(--orange); color: var(--ink); transform: translateY(-2px); }
.surface-toggle::before {
  content: '◉ ';
  color: var(--orange);
}
body.show-surfaces .surface-toggle::before { color: var(--canvas); }

/* ============================================================
   PROMOTED SHARED CHROME (Wave 5)
   ------------------------------------------------------------
   Components promoted from per-mockup inline styles into this
   shared sheet. Inline duplicates in individual mockups are
   NOT yet removed (separate Wave 6 cleanup); these canonicals
   define the contract so new edits inherit the shared rule.
   ============================================================ */

/* Content-key chip — surfaces the underlying db table.column for
   any editable field. Monospace, orange-soft chip aesthetic so it
   reads as "developer/engineering metadata" without overpowering
   the field label. Used across ~98 sites in the mockup surface. */
.content-key-chip {
  display: inline-block;
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: var(--type-xs);
  background: rgba(232, 122, 0, 0.08);
  color: var(--orange-dark);
  padding: 0.1em 0.5em;
  border-radius: var(--radius-sm);
  margin-left: 0.4em;
  letter-spacing: 0.01em;
  font-weight: 500;
}

/* Sticky save bar — fixed-bottom save-status surface for edit
   forms. Lives above the admin-dock (4.5rem clearance + safe-area
   inset) so the two never collide. .is-dirty tints the bar amber
   to signal "unsaved changes pending". */
.sticky-save-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(4.5rem + env(safe-area-inset-bottom));
  z-index: var(--z-sticky);
  background: white;
  border-top: 1px solid var(--rule);
  padding: var(--space-sm) var(--space-md);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  box-shadow: 0 -2px 10px rgba(10, 10, 10, 0.06);
}
.sticky-save-bar.is-dirty { background: var(--amber-soft); }
.sticky-save-bar .save-status {
  font-size: var(--type-sm);
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
}
.sticky-save-bar .save-actions {
  display: flex;
  gap: var(--space-sm);
  align-items: center;
}

/* ============================================================
   UTILITIES
   ============================================================ */

.center { text-align: center; }
.center .lede, .center p { margin-left: auto; margin-right: auto; }
/* P2 fit-finish: a centered heading with no width cap draws a full-container
   dashed edit-outline while its text floats in the middle (reads "off-center").
   Cap centered headings to a readable measure so the [data-editable] box hugs
   the text. Scoped to headings only — centered paragraphs keep their own caps. */
h2.center, .center > h2,
h3.center, .center > h3 { width: fit-content; max-width: 24ch; margin-left: auto; margin-right: auto; }
.mt-0 { margin-top: 0; }
.mt-sm { margin-top: var(--space-sm); }
.mt-md { margin-top: var(--space-md); }
.mt-lg { margin-top: var(--space-lg); }

.pill {
  display: inline-block;
  padding: 0.25em 0.7em;
  border-radius: 999px;
  font-size: 0.78rem;
  background: var(--orange-soft);
  color: var(--orange-dark);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.pill--gated {
  background: rgba(106, 101, 90, 0.15);
  color: var(--muted);
}

/* ============================================================
   RESPONSIVE
   ============================================================ */

@media (max-width: 900px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 768px) {
  body { font-size: 16px; }
  :root { --header-h: 4.5rem; }
  .header-inner { padding: 0.75rem var(--space-sm); }
  /* Pre-drawer wrap-stack rule removed (W3-P4, 2026-06-03, chrome-nav.md
     [P1] §"Stale pre-drawer 768px nav rules"). The Wave 6 drawer owns all
     sub-900 nav sizing via `#site-nav .nav-primary` / `#site-nav .nav-primary a`
     (gap:0 + 1.15rem), so the old `.nav-primary { gap; font-size; flex-wrap;
     justify-content }` here was dead weight: flex-wrap/justify-content are inert
     against the drawer's flex-direction:column, and gap/font-size were silently
     overridden by the higher-specificity drawer rules — a drift trap if the
     drawer sizing were later edited. Sole source of truth for sub-900 nav is
     now the drawer block below. */
  /* Pre-drawer rule: hid the standalone nav-secondary bar at small
     widths. With the Wave 6 drawer refactor (2026-06-03) both nav
     lists live inside #site-nav, so this rule is scoped to
     direct-child case to avoid double-hiding inside the drawer. */
  .site-header > .nav-secondary { display: none; }
  .hero { min-height: 56vh; }
  .hero-inner { padding: var(--space-xl) var(--space-sm) var(--space-lg); }
  .section { padding: var(--space-lg) 0; }
}

@media (max-width: 560px) {
  .footer-grid { grid-template-columns: 1fr; }
  /* Pre-drawer rule used .header-inner { flex-direction: column } at narrow
     widths because the nav-primary needed its own row. With the Wave 6
     drawer refactor nav-primary lives in the off-flow drawer, so the
     header-inner stays a single row at every breakpoint. Padding tightened
     for the narrow viewport. */
  .header-inner { gap: var(--space-xs); padding: var(--space-xs) var(--space-sm); }
  .nav-primary { gap: var(--space-sm); font-size: 0.82rem; }
  .stats { grid-template-columns: repeat(2, 1fr); gap: var(--space-sm); }
  .surface-toggle { right: 0.75rem; bottom: 0.75rem; font-size: 0.78rem; padding: 0.5em 1em; }
}

/* ============================================================
   TOUCH-TARGET FLOOR (Wave 5 a11y — 2026-05-21)
   ------------------------------------------------------------
   Apple HIG / WCAG 2.5.5 — interactive targets ≥ 44×44px at
   mobile widths. Footer links carry generous vertical padding
   so taps stay accurate even with narrow link rows.
   ============================================================ */
@media (max-width: 600px) {
  .footer-grid a { padding: 0.5em 0; }
}

/* ============================================================
   PRINT
   ============================================================ */

@media print {
  .surface-toggle { display: none; }
  .site-header { position: static; }
  .hero { min-height: auto; page-break-inside: avoid; }
  body { font-size: 11pt; background: white; }
  .card { break-inside: avoid; }
}

/* ============================================================
   ADMIN CHROME — Floating Bottom Dock
   ------------------------------------------------------------
   The unified admin chrome for any logged-in session. Floats
   at the bottom of every page, decoupled from page DOM flow.
   Ink ground with orange reserved for edit affordances only.
   Council-approved (2026-05-20) replacing the v1 top banner.
   Production note: render in Shadow DOM / React Portal to
   escape CSS bleed + z-index wars. Mockup uses z-index: 9999.
   ============================================================ */

/* Body-class gate — pages opt-in by adding .admin-dock-visible.
   Padding-bottom reserves space at the page bottom so the floating
   dock doesn't permanently occlude the last bit of content. */
body.admin-dock-visible { padding-bottom: 7rem; }
.admin-dock { display: none; }
body.admin-dock-visible .admin-dock {
  position: fixed;
  bottom: calc(1rem + env(safe-area-inset-bottom));
  left: 50%;
  transform: translateX(-50%);
  z-index: 9999;

  /* Pill shape, translucent ink with strong backdrop-blur so content
     beneath stays faintly readable (tinted, not crisp). Preserves
     the always-visible chrome contract without blocking the read. */
  /* Opacity bumped 0.82 → 0.92 per Accessibility Audit P0
     (2026-05-21). Translucent dock over cream canvas was producing
     effective L ≈ 0.173, putting --canvas text at 4.13:1 (below
     body floor 4.5:1). 0.92 drops effective L to ~0.078, lifting
     dock pairs to 9:1+. Backdrop-filter preserved. */
  background: rgba(10, 10, 10, 0.92);
  color: var(--canvas);
  border-radius: 999px;
  padding: 0.55em 1.1em;
  box-shadow:
    0 14px 32px -8px rgba(10, 10, 10, 0.45),
    0 4px 10px -2px rgba(10, 10, 10, 0.28),
    0 0 0 1px rgba(255, 255, 255, 0.04) inset;
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);

  /* Layout. */
  display: inline-flex;
  align-items: center;
  gap: 0.85em;
  font-family: var(--font-body);
  font-size: 0.86rem;
  font-weight: 500;
  white-space: nowrap;
  max-width: calc(100% - 2rem);
}

/* State-card-pinned variant: editing-experience walkthroughs (S1-S4)
   and the admin-dock canonical mockup pin the dock per state-frame
   so all states render simultaneously. Same chrome, position: absolute. */
.state-frame .admin-dock,
.mobile-frame .admin-dock {
  display: inline-flex;
  position: absolute;
  bottom: 1rem;
  left: 50%;
  transform: translateX(-50%);
  top: auto;
  z-index: 20;
  /* Opacity bumped 0.82 → 0.92 per Accessibility Audit P0
     (2026-05-21). Translucent dock over cream canvas was producing
     effective L ≈ 0.173, putting --canvas text at 4.13:1 (below
     body floor 4.5:1). 0.92 drops effective L to ~0.078, lifting
     dock pairs to 9:1+. Backdrop-filter preserved. */
  background: rgba(10, 10, 10, 0.92);
  color: var(--canvas);
  border-radius: 999px;
  padding: 0.55em 1.1em;
  box-shadow:
    0 14px 32px -8px rgba(10, 10, 10, 0.45),
    0 4px 10px -2px rgba(10, 10, 10, 0.28),
    0 0 0 1px rgba(255, 255, 255, 0.04) inset;
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  align-items: center;
  gap: 0.85em;
  font-family: var(--font-body);
  font-size: 0.86rem;
  font-weight: 500;
  white-space: nowrap;
  max-width: calc(100% - 2rem);
}

/* Role chip — small uppercase pill inside the dock.
   Kept for /admin/users row labels and the help-page persona
   cards; the dock chip itself uses .role-icon + .dock-user-name
   now (no "Owner" word in the dock per council synthesis D8). */
.admin-dock .role-chip {
  display: inline-flex;
  align-items: center;
  background: rgba(255, 255, 255, 0.04);
  color: var(--canvas);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.34em 0.7em;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  flex-shrink: 0;
}

/* Identity label (Montserrat 600). Wraps role-icon + first name
   so the dock reads as one visually-grouped token. */
.admin-dock .dock-user {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--canvas);
  letter-spacing: 0.01em;
  flex-shrink: 0;
  text-decoration: none;
}
.admin-dock .dock-user:hover,
.admin-dock .dock-user:focus-visible {
  color: var(--canvas);
  text-decoration: none;
}

/* Role icon glyph — small monochrome marker that replaces the
   persistent "Owner" word in the dock chip. ~12px hollow ring
   with a center dot; color shifts by role variant. */
.admin-dock .role-icon {
  width: 0.85em;
  height: 0.85em;
  border-radius: 50%;
  flex-shrink: 0;
  position: relative;
  display: inline-block;
}
.admin-dock .role-icon--owner {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.55);
}
.admin-dock .role-icon--owner::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.32em;
  height: 0.32em;
  border-radius: 50%;
  background: var(--canvas);
  transform: translate(-50%, -50%);
}
.admin-dock .role-icon--editor {
  background: rgba(211, 180, 0, 0.18);
  border: 1px solid #d3b400;
}
.admin-dock .role-icon--editor::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.32em;
  height: 0.32em;
  border-radius: 50%;
  background: #d3b400;
  transform: translate(-50%, -50%);
}
/* Wave 6 color audit: helper role icon shifted from #4a8cb8 (blue) to #4a6e7a (slate-teal) to separate it from --state-pending #4a73a8. The two were only ~5 hex digits apart and would have read as the same hue side-by-side in the admin dock — a Helper viewing a pending entity would have seen two near-identical blues meaning different things (permission level vs. moderation state). Slate-teal reads as "role badge", not "status". */
.admin-dock .role-icon--helper {
  background: rgba(74, 110, 122, 0.2);
  border: 1px solid #4a6e7a;
}
.admin-dock .role-icon--helper::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.32em;
  height: 0.32em;
  border-radius: 50%;
  background: #4a6e7a;
  transform: translate(-50%, -50%);
}
.admin-dock .dock-user-name {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--canvas);
  letter-spacing: 0.01em;
}

/* Hairline vertical divider between dock sections. */
.admin-dock .dock-rule {
  width: 1px;
  height: 1.4em;
  background: rgba(255, 255, 255, 0.14);
  display: inline-block;
  flex-shrink: 0;
}

/* Primary admin nav inside the dock. */
.admin-dock .dock-nav {
  display: inline-flex;
  gap: 0.95em;
  align-items: center;
  flex-shrink: 0;
}
.admin-dock .dock-nav .nav-item {
  color: var(--canvas);
  text-decoration: none;
  cursor: default;
  display: inline-flex;
  align-items: center;
  gap: 0.22em;
  padding: 0.18em 0.05em;
  border-bottom: 2px solid transparent;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
  font-size: 0.86rem;
}
.admin-dock .dock-nav .nav-item:hover { border-bottom-color: var(--canvas); }
.admin-dock .dock-nav .nav-item[aria-current="page"] {
  color: var(--canvas);
  font-weight: 600;
  border-bottom-color: var(--orange);
}
.admin-dock .dock-nav .caret {
  font-size: 0.75em;
  line-height: 1;
  opacity: 0.7;
  transform: translateY(1px);
}
.admin-dock .dock-nav .nav-item--open .caret {
  transform: translateY(1px) rotate(180deg);
  opacity: 1;
}

/* ============================================================
   SAVE-PILL — ambient state indicator inside the dock.
   Five states (idle / editing / saving / saved-flash / error).
   ============================================================ */
.admin-dock .save-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.32em 0.85em 0.32em 0.7em;
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--canvas-alt);
  flex-shrink: 0;
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.admin-dock .save-pill:hover { background: rgba(255, 255, 255, 0.1); }
.admin-dock .save-pill .dot {
  width: 0.5em;
  height: 0.5em;
  border-radius: 50%;
  background: #8c8472;
  display: inline-block;
  flex-shrink: 0;
}

/* IDLE — gray dot, "Saved". */
.admin-dock .save-pill--idle .dot { background: #8c8472; }

/* EDITING — amber dot, "Editing…", subtle pulse. */
.admin-dock .save-pill--editing {
  background: rgba(245, 200, 0, 0.18);
  border-color: rgba(245, 200, 0, 0.45);
  color: var(--amber-light);
  animation: dock-pulse-amber 1.8s ease-in-out infinite;
}
.admin-dock .save-pill--editing .dot {
  background: var(--amber);
  box-shadow: 0 0 0 3px rgba(245, 200, 0, 0.18);
}
@keyframes dock-pulse-amber {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.78; }
}

/* SAVING — amber + spinner. */
.admin-dock .save-pill--saving {
  background: rgba(245, 200, 0, 0.18);
  border-color: rgba(245, 200, 0, 0.45);
  color: var(--amber-light);
}
.admin-dock .save-pill--saving .dot {
  background: transparent;
  border: 1.5px solid var(--amber);
  border-top-color: transparent;
  width: 0.65em;
  height: 0.65em;
  animation: dock-spin 0.8s linear infinite;
}
@keyframes dock-spin {
  to { transform: rotate(360deg); }
}

/* SAVED FLASH — green dot, "Saved ✓". */
.admin-dock .save-pill--saved-flash {
  background: rgba(31, 140, 77, 0.22);
  border-color: rgba(31, 140, 77, 0.55);
  color: #7ee0a4;
}
.admin-dock .save-pill--saved-flash .dot { background: #1f8c4d; }

/* ERROR — red dot, "Save failed — tap to retry". */
.admin-dock .save-pill--error {
  background: rgba(196, 30, 30, 0.22);
  border-color: rgba(196, 30, 30, 0.55);
  color: #ffb3b3;
}
.admin-dock .save-pill--error .dot { background: #ff5252; }

/* Help + Log out — small text links in the dock tail. */
.admin-dock .dock-tail {
  display: inline-flex;
  align-items: center;
  gap: 0.85em;
  flex-shrink: 0;
}
.admin-dock .dock-tail a {
  color: var(--canvas-alt);
  text-decoration: none;
  cursor: default;
  font-size: 0.82rem;
  transition: color var(--dur) var(--ease);
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
}
.admin-dock .dock-tail a:hover { color: var(--canvas); }
.admin-dock .dock-tail .help-icon {
  width: 14px;
  height: 14px;
  border: 1.4px solid currentColor;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6rem;
  font-weight: 700;
  font-family: var(--font-display);
  line-height: 1;
}

/* Narrow-viewport collapse — match canonical responsive rules. */
@media (max-width: 1100px) {
  body.admin-dock-visible .admin-dock,
  .state-frame .admin-dock,
  .mobile-frame .admin-dock {
    gap: 0.6em;
    padding: 0.5em 0.85em;
    font-size: 0.8rem;
  }
  .admin-dock .dock-nav { gap: 0.75em; }
}
@media (max-width: 700px) {
  .admin-dock .dock-rule.dock-rule--nav,
  .admin-dock .dock-rule.dock-rule--tail,
  .admin-dock .dock-nav,
  .admin-dock .dock-tail { display: none; }
}

/* Reduced-motion — kill the pulse + spinner animations. */
@media (prefers-reduced-motion: reduce) {
  .admin-dock .save-pill--editing { animation: none; }
  .admin-dock .save-pill--saving .dot { animation: none; }
}

@media print { .admin-dock { display: none !important; } }

/* ============================================================
   DOCK DROPDOWNS + button-as-nav-item reset
   ------------------------------------------------------------
   Wave 3 follow-up (2026-06-02 evening): Agent Y discovered the
   dropdown CSS lives INLINE in mockups/editing-admin-dock.html
   lines 325-450, not in mockups/styles.css. Y ported it into an
   inline <style nonce> block in admin-dock.ejs as a temporary
   measure; the CSP nonce wasn't resolving and the buttons
   rendered with UA defaults (white bg, rounded). This block is
   the permanent home — verbatim port from mockup HTML.

   Mockup source-of-truth:
     ~/Projects/mhs-blueprint/marketing-site/mockups/editing-admin-dock.html:325-397
   ============================================================ */

.admin-dock .nav-item-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}

/* Button-as-nav-item — strip UA defaults so trigger reads as the
   same flat text link as the anchor .nav-item. The .nav-item base
   above (around line 1527) targets anchors; this widens to button. */
.admin-dock .dock-nav button.nav-item {
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  margin: 0;
  font: inherit;
  color: var(--canvas);
  cursor: pointer;
  padding: 0.18em 0.05em;
  display: inline-flex;
  align-items: center;
  gap: 0.22em;
  font-size: 0.86rem;
  transition: border-color var(--dur, 180ms) var(--ease, ease),
              color var(--dur, 180ms) var(--ease, ease);
}
.admin-dock .dock-nav button.nav-item:hover {
  border-bottom-color: var(--canvas);
}
.admin-dock .dock-nav button.nav-item[aria-current="page"] {
  color: var(--canvas);
  font-weight: 600;
  border-bottom-color: var(--orange);
}

/* Dropdown card — hangs above the dock pointing down via ::after arrow. */
.dock-dropdown {
  position: absolute;
  bottom: calc(100% + 0.7rem);
  left: 50%;
  transform: translateX(-50%);
  min-width: 16rem;
  background: var(--ink);
  color: var(--canvas);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  box-shadow:
    0 18px 40px -10px rgba(10, 10, 10, 0.5),
    0 6px 14px -2px rgba(10, 10, 10, 0.3);
  padding: 0.4em 0;
  font-family: var(--font-body);
  font-size: 0.88rem;
  z-index: 220;
}
.dock-dropdown[hidden] { display: none; }
.dock-dropdown::after {
  content: '';
  position: absolute;
  bottom: -5px;
  left: 50%;
  transform: translateX(-50%) rotate(45deg);
  width: 9px;
  height: 9px;
  background: var(--ink);
  border-right: 1px solid rgba(255, 255, 255, 0.1);
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.dock-dropdown .dropdown-label {
  display: block;
  font-family: var(--font-display);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: rgba(250, 247, 240, 0.5);
  font-weight: 700;
  padding: 0.4em 1.1em 0.3em;
}
.dock-dropdown a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8em;
  padding: 0.5em 1.1em;
  color: var(--canvas);
  text-decoration: none;
  font-weight: 500;
  transition: background var(--dur, 180ms) var(--ease, ease);
}
.dock-dropdown a:hover,
.dock-dropdown a:focus-visible {
  background: rgba(255, 255, 255, 0.06);
  outline: none;
}
.dock-dropdown a.is-current {
  color: var(--orange-light);
  font-weight: 600;
  background: rgba(232, 122, 0, 0.10);
}
.dock-dropdown a .count {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: rgba(250, 247, 240, 0.4);
  font-weight: 500;
}
.dock-dropdown a .count.count--attention {
  color: var(--orange-light);
  background: rgba(232, 122, 0, 0.18);
  border-radius: 999px;
  padding: 0.05em 0.55em;
  font-weight: 600;
}
.dock-dropdown a.is-current .count { color: var(--orange-light); }
.dock-dropdown hr {
  margin: 0.35em 0;
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

/* Mobile hamburger trigger + sheet — v1 minimum-viable per Lens D §4.3.
   Hidden above 768px; visible only at narrow widths. */
.dock-mobile-trigger { display: none; }
@media (max-width: 768px) {
  .dock-mobile-trigger {
    display: inline-flex;
    position: fixed;
    bottom: calc(1rem + env(safe-area-inset-bottom));
    right: calc(1rem + env(safe-area-inset-right));
    z-index: 230;
    background: var(--ink);
    color: var(--canvas);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 999px;
    width: 2.75rem;
    height: 2.75rem;
    align-items: center;
    justify-content: center;
    font-size: 1.4rem;
    cursor: pointer;
    box-shadow: 0 14px 32px -8px rgba(10, 10, 10, 0.45);
  }
}
.dock-mobile-sheet[hidden] { display: none; }
.dock-mobile-sheet {
  position: fixed;
  inset: 0;
  background: rgba(10, 10, 10, 0.94);
  z-index: 240;
  overflow-y: auto;
  padding: 4rem 1.25rem 6rem;
}
/* Close X for the dock mobile sheet — Mark flagged 2026-06-03 the
   v1 sheet had no way to dismiss without picking an item. */
.dock-mobile-sheet__close {
  position: fixed;
  top: calc(0.85rem + env(safe-area-inset-top, 0px));
  right: calc(0.85rem + env(safe-area-inset-right, 0px));
  z-index: 250;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(250, 247, 240, 0.08);
  color: var(--canvas);
  border: 1px solid rgba(250, 247, 240, 0.18);
  border-radius: 999px;
  font-size: 1.8rem;
  line-height: 1;
  cursor: pointer;
}
.dock-mobile-sheet__close:hover,
.dock-mobile-sheet__close:focus-visible {
  background: rgba(250, 247, 240, 0.18);
  outline: none;
}
.dock-mobile-sheet__inner {
  max-width: 30rem;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.dock-mobile-sheet a {
  display: block;
  padding: 0.85rem 1rem;
  color: var(--canvas);
  text-decoration: none;
  border-radius: 8px;
  min-height: 44px;
  font-family: var(--font-body);
  font-size: 1rem;
}
.dock-mobile-sheet a:hover,
.dock-mobile-sheet a:focus-visible {
  background: rgba(255, 255, 255, 0.08);
  outline: none;
}
.dock-mobile-sheet a[aria-current="page"] {
  color: var(--orange-light);
  font-weight: 600;
}
.dock-mobile-sheet__header {
  font-family: var(--font-display);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: rgba(250, 247, 240, 0.5);
  font-weight: 700;
  padding: 1.25rem 1rem 0.4rem;
}

/* MOCKUP-ONLY META-AFFORDANCES (.logged-in-mode-note + .admin-dock-toggle)
   removed 2026-06-02 (Wave 3 / P0-9). Mockup styles.css:1645 explicitly
   said "Stripped in production builds"; the hand-port copied the whole
   chunk anyway. Closes Lens E #30 + #31. */

/* ============================================================
   S3 IMAGE-SLOT AFFORDANCE — "Change hero image" pill in the
   top-right of every [data-image-slot] when body.edit-mode is set.
   The outline-on-slot pattern (mockup editing-s3-image-slot.html)
   was redundant with the pill; dropped per Mark 2026-06-02.
   The position-relative below is purely the pill's positioning
   context; the slot itself has no visual edit indicator beyond
   the pill.
   ============================================================ */

body.edit-mode [data-image-slot] {
  position: relative;
}

/* Floating "Change hero image" pill — top-right corner. */
.change-pill {
  position: absolute;
  top: 1rem;
  right: 1rem;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  background: var(--ink);
  color: var(--canvas);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.02em;
  padding: 0.55em 1em;
  border-radius: 999px;
  border: 1px solid rgba(250, 247, 240, 0.15);
  box-shadow: 0 6px 18px rgba(10, 10, 10, 0.35);
  cursor: pointer;
  min-height: 44px;
  text-decoration: none;
  transition: background var(--dur, 180ms) var(--ease, ease),
              color var(--dur, 180ms) var(--ease, ease),
              transform var(--dur, 180ms) var(--ease, ease);
}
.change-pill:hover,
.change-pill:focus-visible {
  background: var(--orange);
  color: var(--ink);
  transform: translateY(-1px);
  outline: none;
}
.change-pill svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ============================================================
   REDUCED MOTION — universal honoring of OS preference
   ------------------------------------------------------------
   Per Accessibility Audit P0 (WCAG 2.3.3). Replaces the per-
   mockup neutralizers scattered across 10 files; new keyframes
   added during build automatically inherit. Covers hover-lift
   transforms, transitions, scroll-behavior, and named anims
   (caret-blink, dock-pulse, shimmer, spin, pulse-amber, etc).
   Static states preserved — visitors who request reduced
   motion still see every state, just without the motion.
   Placed last so component-level transitions surrender to it.
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Explicit hover-lift neutralizers — transforms aren't covered by
     transition-duration since they're often instant (no transition). */
  .mockup-card:hover { transform: none; }
  .spec-link:hover { transform: none; }
  .card:hover { transform: none; }
  .btn:hover { transform: none; }
  /* .admin-dock-toggle:hover dropped 2026-06-02 with the mockup-only
     meta-affordance strip (Wave 3 / P0-9). */
}

/* ============================================================
   Phase 6.3a admin chrome additions — breadcrumb strip, status
   card affordances, orderable list controls, activity timeline.
   Kept additive at the end of the sheet to avoid disturbing the
   pre-existing cascade.
   ============================================================ */

.admin-pagehead-wrap {
  background: var(--canvas, #f6f3eb);
  border-bottom: 1px solid var(--line, #e3ddc9);
  padding: 1rem 0 0.5rem;
}
.admin-breadcrumb {
  font-family: var(--font-display, "Montserrat", system-ui, sans-serif);
  font-size: 0.78rem;
  color: var(--text-muted, #6b6453);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
  margin: 0;
}
.admin-breadcrumb a {
  color: var(--text-muted, #6b6453);
  text-decoration: none;
}
.admin-breadcrumb a:hover {
  color: var(--orange-dark, #c25e1f);
}

/* Status / KPI cards — extended copy slots so the dashboard reads
   like the mockup (label + count + context + helper). */
.stat-card .stat-label {
  font-family: var(--font-display, "Montserrat", system-ui, sans-serif);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.78rem;
  color: var(--text-muted, #6b6453);
  margin: 0 0 0.35em;
}
.stat-card .stat-context {
  font-size: 0.88rem;
  color: var(--text, #2d2a22);
  margin: 0.3em 0 0;
  line-height: 1.45;
}
.stat-card .stat-helper {
  font-size: 0.76rem;
  color: var(--text-muted, #6b6453);
  font-style: italic;
  line-height: 1.45;
  margin: 0.4em 0 0;
}

/* Activity feed on dashboard. */
.admin-activity-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.admin-activity-row {
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--line, #e3ddc9);
}
.admin-activity-row a {
  display: block;
  text-decoration: none;
  color: inherit;
}
.admin-activity-row strong {
  color: var(--ink, #1a1a1a);
  display: block;
  margin-bottom: 0.15em;
}
.admin-activity-meta {
  display: block;
  font-size: 0.82rem;
  color: var(--text-muted, #6b6453);
}

/* Quick-action stack. */
.admin-quicklinks {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: stretch;
}
.admin-quicklinks .btn {
  text-align: center;
  width: 100%;
}

/* Orderable list controls — drag handle + Move ↑ / ↓ buttons.
   Replaces the raw sort_order numeric input per Mark's UX doctrine. */
.admin-orderable {
  --handle-color: var(--text-muted, #6b6453);
}
.admin-orderable-row {
  position: relative;
}
.admin-orderable-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  color: var(--handle-color);
  cursor: grab;
  flex-shrink: 0;
}
.admin-orderable-handle:active {
  cursor: grabbing;
}
.admin-orderable-row[aria-dragging="true"] {
  opacity: 0.6;
}
.admin-orderable .btn[disabled] {
  opacity: 0.35;
  pointer-events: none;
}

/* Flash messages — base + variants. Used on every admin page above
   the page-hero area (success on POST, error on validation, warn on
   forced-password-change prompts). */
.admin-flash {
  background: var(--canvas);
  color: var(--ink);
  padding: 0.85rem 1rem;
  border-radius: 4px;
  border: 1px solid var(--rule-strong);
  border-left: 4px solid var(--rule-strong);
  margin: var(--space-sm) 0 0;
  font-size: 0.95rem;
  line-height: 1.5;
}
.admin-flash--success {
  background: rgba(105, 168, 122, 0.12);
  border-color: rgba(105, 168, 122, 0.45);
  border-left-color: var(--state-active);
  color: var(--state-active-text);
}
.admin-flash--error {
  background: var(--state-trash-soft);
  border-color: var(--state-trash);
  border-left-color: var(--state-trash);
  color: var(--state-trash-text);
}
.admin-flash--warn {
  background: var(--amber-soft, #fef3c7);
  border-color: var(--amber);
  border-left-color: var(--amber);
  color: #846221;
}

/* ============================================================
   ADMIN LAYER — extracted from mhs-blueprint/marketing-site/mockups/
   admin-*.html scoped style blocks (2026-05-26 port).

   Source mockups (all read + extracted):
     admin-dashboard, admin-dashboard-helper, admin-denied,
     admin-faqs, admin-forgot-password, admin-help, admin-images,
     admin-login, admin-messages, admin-partners, admin-posts,
     admin-profile, admin-reset, admin-section-items,
     admin-services, admin-settings, admin-setup,
     admin-testimonials, admin-users.

   The views adopt a more compact BEM-flavored taxonomy
   (.page-hero__title, .stat-card, .admin-card, .kpi-card__row,
   etc.) than the legacy mockup naming. This layer defines the
   canonical rules using existing public-layer tokens
   (--canvas, --orange, --rule, --space-*, etc.).
   ============================================================ */

/* ------------------------------------------------------------
   BEM page-hero — view-side classes (.page-hero__inner / __title
   / __lede / __eyebrow). The parent .page-hero is ink-dark per
   the public layer; this layer adds the inner-grid + BEM kids.
   ------------------------------------------------------------ */
.page-hero__inner {
  max-width: var(--max-w);
  margin: 0 auto;
  padding: 0 var(--space-md);
  width: 100%;
}
.page-hero__eyebrow {
  font-family: var(--font-display);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--orange);
  font-weight: 600;
  margin: 0 0 0.4em;
}
.page-hero__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.7rem, 3.4vw, 2.4rem);
  letter-spacing: -0.018em;
  line-height: 1.15;
  color: var(--canvas);
  margin: 0 0 0.3em;
}
.page-hero__lede {
  color: var(--canvas-alt);
  font-size: 1.02rem;
  line-height: 1.55;
  margin: 0;
  max-width: 60ch;
}

/* Wrapper used in the admin breadcrumb row, which sits on the
   cream canvas (not the dark page-hero). Inner uses page-hero__inner. */
.admin-pagehead-wrap .page-hero__inner {
  padding-left: var(--space-md);
  padding-right: var(--space-md);
}

/* The .page-auth body class is set on auth views to override
   the dock-reserved bottom padding. */
body.page-auth { padding-bottom: 0; }

/* ------------------------------------------------------------
   Section helpers — .section already exists in the public layer;
   .section__inner is the BEM-flavored container.
   ------------------------------------------------------------ */
.section__inner {
  max-width: var(--max-w);
  margin: 0 auto;
  padding: 0 var(--space-md);
  width: 100%;
}
/* Single-column admin form column. Replaces the per-view inline
   `style="max-width: 44rem"` (and the 36/48/52rem variants) the CSS
   audit flagged — every edit/settings form now shares one measure via
   the --max-w-form token. --form-narrow is the tighter short-form width. */
.section__inner--form { max-width: var(--max-w-form); }
.section__inner--form-narrow { max-width: var(--max-w-form-narrow); }

/* ------------------------------------------------------------
   Button modifiers — .btn--primary / --ghost / --sm. The public
   layer's base .btn is already a chunky marketing-site CTA; the
   admin chrome wants tighter, system-font-flavored variants.
   ------------------------------------------------------------ */
.btn--primary {
  background: var(--orange);
  color: var(--ink);
  border-color: var(--orange-dark);
}
.btn--primary:hover {
  background: var(--orange-dark);
  border-color: var(--orange-dark);
  color: var(--canvas);
}
.btn--ghost {
  background: white;
  color: var(--ink);
  border: 1.5px solid var(--rule-strong);
  padding: 0.6em 1.1em;
  font-size: 0.9rem;
  letter-spacing: 0.02em;
}
.btn--ghost:hover {
  background: var(--canvas-alt);
  border-color: var(--orange);
  color: var(--orange-dark);
  transform: none;
}
.btn--sm {
  padding: 0.45em 0.9em;
  font-size: 0.8rem;
  letter-spacing: 0.02em;
}

/* ------------------------------------------------------------
   Admin stats grid + .stat-card chrome.
   The base .stat-card chrome (label + count + context + helper)
   already exists in the public layer; this adds the grid wrapper
   + variants (.stat-card--link, .stat-card--attention).
   ------------------------------------------------------------ */
.admin-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--space-sm);
}
.stat-card {
  display: flex;
  flex-direction: column;
  gap: 0.3em;
  background: white;
  border: 1px solid var(--rule);
  border-left: 4px solid var(--rule-strong);
  border-radius: 4px;
  padding: var(--space-sm) var(--space-md);
  box-shadow: var(--shadow-card);
  position: relative;
  min-height: 9rem;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.stat-card--link {
  text-decoration: none;
  color: var(--ink);
  cursor: pointer;
}
.stat-card--link:hover {
  border-left-color: var(--orange);
  box-shadow: var(--shadow-lift);
  transform: translateY(-2px);
}
.stat-card--attention {
  border-left-color: var(--orange);
  background: linear-gradient(180deg, var(--orange-soft) 0%, white 60%);
}
.stat-card--attention .stat-number { color: var(--orange-dark); }
.stat-number {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.7rem, 2.8vw, 2.1rem);
  line-height: 1.1;
  letter-spacing: -0.018em;
  color: var(--ink);
  margin: 0;
}

/* ------------------------------------------------------------
   Two-column admin split (recent activity + quick links).
   ------------------------------------------------------------ */
.admin-split {
  display: grid;
  gap: var(--space-md);
}
.admin-split--2col {
  grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
  align-items: start;
}
@media (max-width: 900px) {
  .admin-split--2col { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------------
   Admin card — generic surface card used on profile, settings,
   contacts detail. White panel + soft shadow + head row.
   ------------------------------------------------------------ */
.admin-card {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: var(--space-md);
  box-shadow: var(--shadow-card);
}
.admin-card-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  justify-content: space-between;
  margin-bottom: var(--space-sm);
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid var(--rule);
  flex-wrap: wrap;
}
.admin-card-head h2 {
  margin: 0;
  font-size: 1.1rem;
  letter-spacing: -0.01em;
}
.admin-card-subtitle {
  font-size: 0.84rem;
  color: var(--muted);
  font-style: italic;
  line-height: 1.45;
  flex-basis: 100%;
}

/* ------------------------------------------------------------
   Admin form fields — .admin-field + .admin-field-label +
   .admin-field-hint. Used across profile, settings, posts/edit,
   testimonials/edit, faqs/edit, partners/edit, services/edit,
   section-items/edit, users.
   ------------------------------------------------------------ */
.admin-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.admin-form-row {
  display: grid;
  gap: var(--space-sm);
}
.admin-form-row--2col {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (max-width: 600px) {
  .admin-form-row--2col { grid-template-columns: 1fr; }
}
.admin-field {
  display: flex;
  flex-direction: column;
  gap: 0.35em;
}
.admin-field-label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink);
  letter-spacing: 0.01em;
}
.admin-field-hint {
  font-size: 0.82rem;
  color: var(--muted);
  font-style: italic;
  line-height: 1.45;
  margin: 0;
}
.admin-field input[type="text"],
.admin-field input[type="email"],
.admin-field input[type="password"],
.admin-field input[type="url"],
.admin-field input[type="tel"],
.admin-field input[type="number"],
.admin-field input[type="date"],
.admin-field input[type="datetime-local"],
.admin-field select,
.admin-field textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--ink);
  padding: 0.65em 0.85em;
  border: 1.5px solid var(--rule-strong);
  border-radius: 3px;
  background: white;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.admin-field input:focus,
.admin-field select:focus,
.admin-field textarea:focus {
  outline: 0;
  border-color: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-soft);
}
.admin-field textarea { resize: vertical; min-height: 6em; }
.admin-form-actions {
  display: flex;
  gap: 0.6em;
  align-items: center;
  flex-wrap: wrap;
  margin-top: var(--space-sm);
}
.admin-inline-form {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  margin: 0;
}

/* ------------------------------------------------------------
   Admin chip — small role/status pill used inline with names.
   Variants emit by tone via attribute selector pattern.
   ------------------------------------------------------------ */
.admin-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.2em 0.6em;
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--canvas-alt);
  border: 1px solid var(--rule);
  color: var(--ink-mute);
  line-height: 1.2;
}
.admin-chip[class*="--owner"],
.admin-chip[class*="--Owner"] {
  background: var(--orange-soft);
  border-color: var(--orange);
  color: var(--orange-dark);
}
.admin-chip[class*="--helper"],
.admin-chip[class*="--Helper"] {
  background: rgba(108, 143, 191, 0.12);
  border-color: rgba(108, 143, 191, 0.45);
  color: var(--state-pending-text);
}
.admin-chip[class*="--editor"],
.admin-chip[class*="--Editor"] {
  background: rgba(105, 168, 122, 0.14);
  border-color: rgba(105, 168, 122, 0.45);
  color: var(--state-active-text);
}
.admin-chip[class*="--success"],
.admin-chip[class*="--info"] {
  background: rgba(105, 168, 122, 0.12);
  border-color: rgba(105, 168, 122, 0.4);
  color: var(--state-active-text);
}
.admin-chip[class*="--warning"],
.admin-chip[class*="--warn"] {
  background: var(--amber-soft);
  border-color: var(--amber);
  color: #846221;
}
.admin-chip[class*="--danger"],
.admin-chip[class*="--error"] {
  background: var(--state-trash-soft);
  border-color: var(--state-trash);
  color: var(--state-trash-text);
}
.admin-chip[class*="--mute"],
.admin-chip[class*="--muted"] {
  background: var(--canvas-alt);
  border-color: var(--rule);
  color: var(--muted);
}

/* Legacy mockup role-chip (used on denied + welcome cards). */
.role-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.18em 0.55em;
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--orange-soft);
  border: 1px solid var(--orange);
  color: var(--orange-dark);
}

/* ------------------------------------------------------------
   Access-denied (403) card TYPOGRAPHY. The view was hand-rolling the
   card, role badge, and buttons inline (CSS audit P3); it now sits on
   the canonical .denied-card / .denied-card-wrap / .denied-actions block
   (further down, ported from admin-denied.html) + .role-chip + .btn.
   These rules only add the heading/lede/note typography that the
   shared card components don't cover. All token-based.
   ------------------------------------------------------------ */
.denied-card h1 {
  margin: 0 0 0.4em;
  font-size: clamp(1.4rem, 3vw, 1.9rem);
  letter-spacing: -0.015em;
  line-height: 1.2;
}
.denied-card .role-chip { margin-bottom: var(--space-sm); }
.denied-subtitle,
.denied-body { color: var(--ink-mute); line-height: 1.6; }
.denied-subtitle { font-size: 1rem; margin: 0 0 var(--space-sm); }
.denied-body { font-size: 0.95rem; line-height: 1.55; margin: 0 0 var(--space-md); }
.denied-subtitle strong,
.denied-body strong { color: var(--ink); }
.denied-note {
  display: flex;
  align-items: center;
  gap: 0.55em;
  padding: 0.7em 0.95em;
  background: var(--canvas);
  border: 1px dashed var(--rule-strong);
  border-radius: 4px;
  font-size: 0.85rem;
  color: var(--ink-mute);
  line-height: 1.5;
}
.denied-note svg { flex-shrink: 0; color: var(--muted); }
.denied-note code {
  background: #fff;
  border: 1px solid var(--rule);
  padding: 0.1em 0.4em;
  border-radius: 2px;
  font-family: var(--font-mono);
  font-size: 0.86em;
  color: var(--ink);
}

/* ------------------------------------------------------------
   Admin profile list — definition list for profile fields.
   ------------------------------------------------------------ */
.admin-profile-list {
  display: grid;
  grid-template-columns: 8rem 1fr;
  gap: 0.5em var(--space-sm);
  margin: 0;
  align-items: baseline;
}
.admin-profile-list dt {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.admin-profile-list dd {
  margin: 0;
  color: var(--ink);
}
@media (max-width: 600px) {
  .admin-profile-list { grid-template-columns: 1fr; gap: 0.15em var(--space-sm); }
  .admin-profile-list dd { margin-bottom: 0.5em; }
}

/* ------------------------------------------------------------
   Admin help — narrow prose container.
   ------------------------------------------------------------ */
.admin-help h2 { margin-top: var(--space-md); }
.admin-help h3 { margin-top: var(--space-sm); }
.admin-help table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--space-sm) 0;
  font-size: 0.92rem;
}
.admin-help th,
.admin-help td {
  padding: 0.5em 0.75em;
  border: 1px solid var(--rule);
  text-align: left;
  vertical-align: top;
}
.admin-help th {
  background: var(--canvas-alt);
  font-family: var(--font-display);
  font-weight: 600;
}

/* ------------------------------------------------------------
   Status tabs — segmented control above lists.
   ------------------------------------------------------------ */
.admin-status-tabs {
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  background: white;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-pill);
  padding: 0.25em;
  margin: 1.5rem 0 var(--space-sm);
  flex-wrap: wrap;
}
.admin-status-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.45em 0.95em;
  border-radius: var(--radius-pill);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.84rem;
  letter-spacing: 0.05em;
  color: var(--muted);
  text-decoration: none;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.admin-status-tab:hover { color: var(--ink); }
/* Active segment: solid navy fill + white text — the high-contrast
   "you are here" affordance (Mark must not click blind). */
.admin-status-tab--active {
  background: var(--state-pending);
  color: #fff;
}
.admin-status-tab--active:hover { color: #fff; }
.admin-status-tab-count { opacity: 0.7; }

/* ------------------------------------------------------------
   Status / state pills (badges).
   ------------------------------------------------------------ */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.2em 0.65em;
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--canvas-alt);
  border: 1px solid var(--rule);
  color: var(--ink-mute);
  line-height: 1.2;
}
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.18em 0.55em;
  border-radius: var(--radius-sm);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--canvas-alt);
  border: 1px solid var(--rule);
  color: var(--ink-mute);
  line-height: 1.2;
}

/* ------------------------------------------------------------
   Posts list — used on /admin/posts.
   ------------------------------------------------------------ */
.admin-post-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.admin-post-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-sm);
  align-items: start;
  padding: var(--space-sm);
  background: white;
  border: 1px solid var(--rule);
  border-radius: 4px;
  box-shadow: var(--shadow-card);
}
.admin-post-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--ink);
  margin: 0 0 0.2em;
  letter-spacing: -0.01em;
  line-height: 1.3;
}
.admin-post-title a {
  color: inherit;
  text-decoration: none;
}
.admin-post-title a:hover { color: var(--orange-dark); }
.admin-post-meta {
  font-size: 0.82rem;
  color: var(--muted);
  margin: 0;
  display: flex;
  gap: 0.5em;
  flex-wrap: wrap;
  align-items: center;
}
.admin-post-status {
  margin-left: 0.3em;
}
.admin-post-edit,
.admin-post-delete {
  white-space: nowrap;
}
@media (max-width: 600px) {
  .admin-post-row { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------------
   Users table — used on /admin/users.
   ------------------------------------------------------------ */
.admin-users-table {
  /* Div-based "table": flex column of grid rows (no <table> markup). */
  display: flex;
  flex-direction: column;
  background: white;
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
  box-shadow: var(--shadow-card);
  margin: 0 0 var(--space-md);
}
/* Row is a 5-column grid: name | role | active-toggle | last-login | actions */
.admin-user-row {
  display: grid;
  grid-template-columns: minmax(12rem, 2fr) auto auto minmax(6rem, 1fr) auto;
  align-items: center;
  gap: var(--space-sm);
  padding: 0.7em var(--space-sm);
  border-bottom: 1px solid var(--rule);
  transition: background var(--dur) var(--ease);
}
.admin-user-row:last-child { border-bottom: 0; }
.admin-user-row:hover { background: var(--canvas); }
.admin-user-row--inactive { opacity: 0.55; }
.admin-user-row--self { background: var(--orange-soft); }
.admin-user-row--self:hover { background: var(--orange-soft); }
.admin-user-cell {
  min-width: 0; /* let cell contents wrap inside the grid track */
}
.admin-user-cell--name {
  display: flex;
  align-items: center;
  gap: 0.7em;
  min-width: 12rem;
}
.admin-user-cell--actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4em;
  justify-content: flex-end;
  white-space: nowrap;
}
@media (max-width: 899px) {
  /* Narrow viewport: stack each cell as a card row — no horizontal scroll. */
  .admin-user-row {
    grid-template-columns: 1fr;
    gap: 0.5rem;
    padding: var(--space-sm);
  }
  .admin-user-cell--actions { justify-content: flex-start; }
}
.admin-user-avatar {
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  background: var(--orange-soft);
  color: var(--orange-dark);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.85rem;
  border: 1.5px solid var(--orange);
  flex-shrink: 0;
}
.admin-user-name {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink);
  font-size: 0.95rem;
}
.admin-user-meta {
  font-size: 0.82rem;
  color: var(--muted);
  display: block;
}
.admin-user-meta--warn {
  color: #846221;
  background: var(--amber-soft);
  padding: 0.1em 0.5em;
  border-radius: 3px;
  display: inline-block;
  border: 1px solid var(--amber);
}
.admin-user-you {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--orange-dark);
  margin-left: 0.4em;
}
.admin-role-select {
  font-family: var(--font-body);
  font-size: 0.92rem;
  padding: 0.35em 0.55em;
  border: 1px solid var(--rule-strong);
  border-radius: 3px;
  background: white;
}

/* Password reset callouts on users page. */
.admin-password-callout {
  background: var(--amber-soft);
  border: 1px solid var(--amber);
  border-left: 4px solid var(--amber);
  border-radius: 4px;
  padding: var(--space-sm);
  margin: 0 0 var(--space-sm);
}
.admin-password-callout-head {
  font-family: var(--font-display);
  font-weight: 700;
  color: #846221;
  margin: 0 0 0.3em;
}
.admin-password-callout-warn {
  font-size: 0.85rem;
  color: #846221;
  margin: 0.3em 0 0;
  font-style: italic;
}
.admin-password-row {
  display: flex;
  align-items: center;
  gap: 0.6em;
  flex-wrap: wrap;
  margin: 0.5em 0;
}
.admin-password-pill {
  font-family: var(--font-mono);
  font-size: 0.95rem;
  background: white;
  border: 1px dashed var(--orange);
  padding: 0.3em 0.7em;
  border-radius: 3px;
  color: var(--ink);
  letter-spacing: 0.04em;
}
.admin-password-hand-off {
  font-size: 0.8rem;
  color: var(--muted);
  font-style: italic;
}

/* Contact photo (in messages list). */
.admin-contact-photo {
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  background: var(--canvas-alt);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--ink-mute);
  flex-shrink: 0;
  border: 1px solid var(--rule);
  overflow: hidden;
}
.admin-contact-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ------------------------------------------------------------
   Image picker (used on section-items, services, posts edit).
   ------------------------------------------------------------ */
.admin-image-picker {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-sm);
  padding: var(--space-sm);
  background: var(--canvas);
  border: 1px dashed var(--rule-strong);
  border-radius: 4px;
  align-items: start;
}
.admin-image-picker-thumb {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 5.5rem;
  height: 5.5rem;
  background: white;
  border: 1px solid var(--rule);
  border-radius: 3px;
  overflow: hidden;
  flex-shrink: 0;
}
.admin-image-picker-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.admin-image-picker-thumb-icon {
  width: 1.5rem;
  height: 1.5rem;
  color: var(--muted);
}
.admin-image-picker-label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--ink);
}
.admin-image-picker-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.92rem;
  margin: 0 0 0.2em;
  color: var(--ink);
}
.admin-image-picker-hint {
  font-size: 0.82rem;
  color: var(--muted);
  font-style: italic;
  margin: 0.2em 0 0;
  line-height: 1.45;
}
.admin-image-picker-clear {
  background: transparent;
  border: 0;
  color: var(--orange-dark);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.84rem;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
  padding: 0.2em 0;
}
.admin-image-picker-clear:hover { color: var(--ink); }

/* ------------------------------------------------------------
   Orderable Move ↑ / ↓ buttons — extend base .admin-orderable
   that already exists in the public layer.
   ------------------------------------------------------------ */
.admin-orderable-up,
.admin-orderable-down {
  /* Inherit base .btn--ghost.btn--sm; ensure consistent width. */
  min-width: 2.4em;
}

/* ------------------------------------------------------------
   Audit log table — used on /admin/audit.
   ------------------------------------------------------------ */
/* Column-header strip — shares the SAME grid as the rows below so
   headers and cells align on one axis. (Was display:flex, which spread
   the 5 titles evenly over a vertical pile of cells.) */
.admin-audit-head {
  display: grid;
  grid-template-columns: 7rem minmax(8rem, 1fr) minmax(9rem, auto) minmax(7rem, 1fr) minmax(8rem, 1.4fr);
  gap: var(--space-sm);
  align-items: baseline;
  padding: 0.55em 0.75em;
  background: var(--canvas-alt);
  border-bottom: 1px solid var(--rule);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.admin-audit-meta {
  font-size: 0.84rem;
  color: var(--muted);
  font-style: italic;
}
.admin-audit-filters {
  display: flex;
  gap: 0.6em;
  flex-wrap: wrap;
  align-items: flex-end;
  padding: var(--space-sm);
  background: var(--canvas-alt);
  border: 1px solid var(--rule);
  border-radius: 4px;
  margin-bottom: var(--space-sm);
}
.admin-audit-col-label {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.25em;
}
.admin-audit-filter-actions {
  display: inline-flex;
  gap: 0.5em;
  align-items: center;
}
.admin-audit-table {
  /* Div-based "table": flex column of grid rows (no <table> markup). */
  display: flex;
  flex-direction: column;
  background: white;
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
  box-shadow: var(--shadow-card);
  font-size: 0.92rem;
}
/* Data row — same 5-column grid as .admin-audit-head so cells align
   to their column titles. (Previously had no layout, so its five child
   divs stacked vertically.) */
.admin-audit-row {
  display: grid;
  grid-template-columns: 7rem minmax(8rem, 1fr) minmax(9rem, auto) minmax(7rem, 1fr) minmax(8rem, 1.4fr);
  gap: var(--space-sm);
  align-items: baseline;
  padding: 0.55em 0.75em;
  border-bottom: 1px solid var(--rule);
}
.admin-audit-row:last-child { border-bottom: 0; }
.admin-audit-row:hover { background: var(--canvas); }
/* The per-cell mini-labels are the mobile-card pattern — hide them on
   desktop where the column-header strip carries the labels. */
@media (min-width: 900px) {
  .admin-audit-col-label { display: none; }
}
@media (max-width: 899px) {
  /* Narrow viewport: header strip hides, each row stacks single-column
     and the mini-labels reappear inline above each value. */
  .admin-audit-head { display: none; }
  .admin-audit-row {
    grid-template-columns: 1fr;
    gap: 0.3rem;
    padding: var(--space-sm);
  }
}
.admin-audit-when {
  font-family: var(--font-display);
  font-size: 0.84rem;
  white-space: nowrap;
  color: var(--ink);
}
.admin-audit-who {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink);
}
.admin-audit-what {
  color: var(--ink);
}
.admin-audit-sub {
  display: block;
  font-size: 0.8rem;
  color: var(--muted);
  margin-top: 0.15em;
}
.admin-audit-on {
  font-family: var(--font-mono);
  font-size: 0.84rem;
  color: var(--ink-mute);
}
.admin-audit-muted {
  opacity: 0.55;
}
.admin-audit-muted .admin-audit-who,
.admin-audit-muted .admin-audit-what { color: var(--muted); font-style: italic; }
.admin-audit-pager {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  justify-content: space-between;
  margin-top: var(--space-sm);
  font-size: 0.85rem;
  flex-wrap: wrap;
}

/* ------------------------------------------------------------
   Settings accordion (used on /admin/settings).
   ------------------------------------------------------------ */
.settings-accordion {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 4px;
  margin-bottom: var(--space-sm);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.settings-accordion > summary {
  list-style: none;
  cursor: pointer;
  padding: var(--space-sm) var(--space-md);
  background: var(--canvas-alt);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.02rem;
  color: var(--ink);
  border-bottom: 1px solid var(--rule);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.settings-accordion > summary::-webkit-details-marker { display: none; }
.settings-accordion > summary::after {
  content: '+';
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.2rem;
  color: var(--muted);
  transition: transform var(--dur) var(--ease);
}
.settings-accordion[open] > summary::after { content: '−'; }
.settings-accordion-body {
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

/* ------------------------------------------------------------
   KPI cards + trend tiles (analytics page).
   ------------------------------------------------------------ */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--space-sm);
}
.kpi-card {
  display: flex;
  flex-direction: column;
  gap: 0.25em;
  background: white;
  border: 1px solid var(--rule);
  border-left: 4px solid var(--orange);
  border-radius: 4px;
  padding: var(--space-sm) var(--space-md);
  box-shadow: var(--shadow-card);
  color: var(--ink);
  text-decoration: none;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.kpi-card--link:hover {
  border-color: var(--orange);
  box-shadow: var(--shadow-lift);
  transform: translateY(-2px);
}
.kpi-card__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}
.kpi-card__row {
  display: flex;
  align-items: baseline;
  gap: 0.5em;
  flex-wrap: wrap;
}
.kpi-card__value {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 2.6vw, 1.95rem);
  line-height: 1.1;
  letter-spacing: -0.018em;
  color: var(--ink);
  margin: 0;
}
.kpi-card__delta {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.82rem;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 0.2em;
}
.kpi-card__delta--up { color: var(--state-active-text); }
.kpi-card__delta--down { color: var(--state-trash-text); }
.kpi-card__spark {
  width: 100%;
  max-width: 100%;
  height: 1.6rem;
  margin: 0.2em 0;
}
.kpi-card__hint {
  font-size: 0.78rem;
  color: var(--muted);
  font-style: italic;
  margin: 0.15em 0 0;
  line-height: 1.4;
}

.trend-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: var(--space-md);
}
.trend-tile {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: var(--space-sm) var(--space-md);
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.trend-tile__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5em;
  flex-wrap: wrap;
}
.trend-tile__title {
  margin: 0;
  font-size: 1rem;
  letter-spacing: -0.01em;
}
.trend-tile__window {
  font-family: var(--font-display);
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}
.trend-tile__caption {
  font-size: 0.84rem;
  color: var(--ink-mute);
  margin: 0;
  line-height: 1.45;
}
.trend-tile__empty {
  font-size: 0.88rem;
  color: var(--muted);
  font-style: italic;
  margin: 0;
}
.trend-tile__legend {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  gap: var(--space-sm);
  font-size: 0.82rem;
  color: var(--ink-mute);
  flex-wrap: wrap;
}
.trend-tile__legend li {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  margin: 0;
}
.trend-tile__swatch {
  width: 0.85em;
  height: 0.85em;
  border-radius: 2px;
  display: inline-block;
  flex-shrink: 0;
}
.trend-tile__swatch--orange { background: var(--orange); }
.trend-tile__swatch--navy { background: #4a73a8; }

.trend-bars {
  display: flex;
  align-items: flex-end;
  gap: 0.2em;
  height: 5rem;
  padding: 0.2em 0;
}
.trend-bars__slot {
  flex: 1;
  display: flex;
  align-items: flex-end;
}
.trend-bars__bar {
  width: 100%;
  background: var(--orange);
  border-radius: 1px 1px 0 0;
  min-height: 2px;
  transition: background var(--dur) var(--ease);
}
.trend-bars__slot:hover .trend-bars__bar { background: var(--orange-dark); }

.trend-line { width: 100%; height: 5rem; }

.trend-rank {
  list-style: none;
  padding: 0;
  margin: 0;
  counter-reset: rank;
  display: flex;
  flex-direction: column;
  gap: 0.45em;
}
.trend-rank__row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 0.6em;
  padding: 0.3em 0;
  font-size: 0.92rem;
}
.trend-rank__name {
  color: var(--ink);
  text-decoration: none;
  font-weight: 500;
}
.trend-rank__name:hover { color: var(--orange-dark); }
.trend-rank__bar {
  display: block;
  height: 0.6em;
  background: var(--canvas-alt);
  border-radius: 1px;
  width: 7rem;
  position: relative;
  overflow: hidden;
}
.trend-rank__bar > span {
  display: block;
  height: 100%;
  background: var(--orange);
  border-radius: inherit;
}
.trend-rank__num {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.86rem;
  color: var(--ink);
  min-width: 2em;
  text-align: right;
}

/* Activity grid (analytics tier 3). */
.activity-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--space-md);
}
.activity-tile {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: var(--space-sm) var(--space-md);
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.activity-tile__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5em;
  flex-wrap: wrap;
}
.activity-tile__title { margin: 0; font-size: 1rem; }
.activity-tile__window {
  font-family: var(--font-display);
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}
.activity-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
.activity-table th,
.activity-table td {
  padding: 0.45em 0.4em;
  text-align: left;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
.activity-table tbody tr:last-child td { border-bottom: 0; }
.activity-table th {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.activity-table__cell-grow {
  text-align: left;
}
.activity-table__cell-num {
  text-align: right;
  font-family: var(--font-display);
  font-weight: 600;
  white-space: nowrap;
}
.activity-table__cell--mute {
  color: var(--muted);
  font-weight: 500;
}
.activity-table__path {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--muted);
  margin-top: 0.15em;
}

.activity-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.45em;
}
.activity-list__row {
  display: flex;
  flex-direction: column;
  gap: 0.1em;
  padding: 0.45em 0;
  border-bottom: 1px solid var(--rule);
}
.activity-list__row:last-child { border-bottom: 0; }
.activity-list__title {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  font-size: 0.94rem;
}
.activity-list__title:hover { color: var(--orange-dark); }
.activity-list__meta {
  font-size: 0.82rem;
  color: var(--ink-mute);
  margin: 0;
}
.activity-list__sub {
  font-size: 0.86rem;
  color: var(--ink);
  margin: 0;
}
.activity-list__when {
  font-size: 0.78rem;
  color: var(--muted);
  margin: 0;
  font-style: italic;
}

.analytics-footer {
  text-align: right;
  font-size: 0.78rem;
  color: var(--muted);
  font-style: italic;
  margin: var(--space-md) 0 0;
}
.analytics-preview-banner {
  background: var(--amber-soft);
  border: 1px solid var(--amber);
  border-left: 4px solid var(--amber);
  border-radius: 4px;
  padding: 0.7em 1em;
  color: #846221;
  font-size: 0.9rem;
  line-height: 1.5;
  margin: var(--space-sm) 0 0;
}
.analytics-preview-banner strong { color: #6b4f0a; font-weight: 700; }

/* ============================================================
   AUTH SURFACES — login / forgot / reset / setup / denied.
   The auth views already inline these per-page, but the layer
   defines canonical fallbacks so the chrome holds if a view
   ever forgets to inline them. Extracted from admin-login.html
   + admin-forgot-password.html + admin-reset.html +
   admin-setup.html + admin-denied.html scoped styles.
   ============================================================ */

.auth-brandband {
  background: var(--canvas);
  border-bottom: 1px solid var(--rule);
  padding: var(--space-md);
  text-align: center;
}
.auth-brandband .brand {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  text-decoration: none;
  color: var(--ink);
}
.auth-brandband .brand-mark { height: 2.4rem; width: auto; }
.auth-brandband .brand-wordmark { height: 2rem; width: auto; }

.auth-pagehead {
  text-align: center;
  padding: var(--space-lg) var(--space-md) var(--space-md);
  max-width: 36rem;
  margin: 0 auto;
}
.auth-pagehead h1 {
  font-size: clamp(1.7rem, 3.4vw, 2.4rem);
  letter-spacing: -0.02em;
  margin: 0 0 0.5em;
  line-height: 1.15;
}
.auth-subtitle {
  color: var(--ink-mute);
  font-size: 1.02rem;
  line-height: 1.55;
  margin: 0;
  max-width: 36ch;
  margin-left: auto;
  margin-right: auto;
}

.auth-main {
  padding: var(--space-md) var(--space-md) var(--space-xl);
  max-width: 36rem;
  margin: 0 auto;
  width: 100%;
}

.auth-card {
  background: white;
  border: 1px solid var(--rule-strong);
  border-radius: 6px;
  padding: var(--space-md);
  box-shadow: var(--shadow-card);
  max-width: 28rem;
  margin: 0 auto;
}

.auth-callout {
  border-radius: 4px;
  padding: 0.85em 1em;
  margin: 0 0 var(--space-sm);
  font-size: 0.92rem;
  line-height: 1.55;
  display: flex;
  align-items: flex-start;
  gap: 0.7em;
  border: 1px solid;
}
.auth-callout svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  margin-top: 0.15em;
}
.auth-callout .callout-body { min-width: 0; }
.auth-callout .callout-body strong { font-weight: 700; }
.auth-callout .callout-body a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 600;
}
.auth-callout--error {
  background: #fceeee;
  border-color: #e7a8a8;
  color: #6e2020;
}
.auth-callout--error svg { color: #c43838; }
.auth-callout--info {
  background: var(--orange-soft);
  border-color: var(--orange);
  color: var(--orange-dark);
}
.auth-callout--info svg { color: var(--orange-dark); }

.auth-field { margin: 0 0 var(--space-sm); }
.auth-field .field-label {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink);
  margin-bottom: 0.4em;
  letter-spacing: 0.01em;
}
.auth-field input[type="email"],
.auth-field input[type="password"],
.auth-field input[type="text"] {
  width: 100%;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--ink);
  padding: 0.75em 0.85em;
  border: 1.5px solid var(--rule-strong);
  border-radius: 3px;
  background: white;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.auth-field input:focus {
  outline: none;
  border-color: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-soft);
}
.auth-field .helper-text {
  display: block;
  margin: 0.45em 0 0;
  color: var(--ink-mute);
  font-size: 0.82rem;
  line-height: 1.5;
  font-style: italic;
}
.auth-field .helper-text strong {
  color: var(--ink);
  font-weight: 600;
  font-style: normal;
}
.helper-text {
  font-size: 0.82rem;
  color: var(--ink-mute);
  font-style: italic;
  line-height: 1.5;
}
.field-label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink);
  margin-bottom: 0.4em;
  display: block;
  letter-spacing: 0.01em;
}

/* Password input + show/hide eye toggle. */
.pw-input-wrap { position: relative; }
.pw-input-wrap input { padding-right: 3em; }
.pw-eye-btn {
  position: absolute;
  top: 50%;
  right: 0.55em;
  transform: translateY(-50%);
  background: transparent;
  border: 0;
  width: 2.4em;
  height: 2.4em;
  border-radius: 3px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.pw-eye-btn:hover { color: var(--orange-dark); background: var(--orange-soft); }
.pw-eye-btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pw-eye-btn .eye-off { display: none; }
.pw-eye-btn[aria-pressed="true"] .eye-on { display: none; }
.pw-eye-btn[aria-pressed="true"] .eye-off { display: block; }

/* Password-strength meter (setup + reset flows). */
.pw-strength {
  display: flex;
  align-items: center;
  gap: 0.5em;
  margin: 0.55em 0 0;
}
.pw-strength-bar {
  display: inline-flex;
  flex: 1;
  gap: 0.15em;
}
.pw-strength-seg {
  flex: 1;
  height: 0.4em;
  background: var(--canvas-alt);
  border-radius: 1px;
  transition: background var(--dur) var(--ease);
}
.pw-strength-seg.is-on { background: var(--orange); }
.pw-strength[data-strength="weak"] .pw-strength-seg.is-on { background: #c43838; }
.pw-strength[data-strength="ok"] .pw-strength-seg.is-on { background: var(--amber); }
.pw-strength[data-strength="strong"] .pw-strength-seg.is-on { background: var(--state-active); }
.pw-strength-label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  min-width: 4.5em;
}

/* Match indicator (confirm-password row on setup + reset). */
.match-indicator {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  font-size: 0.82rem;
  color: var(--muted);
  font-style: italic;
  margin: 0.4em 0 0;
}
.match-indicator .match-glyph {
  width: 0.9em;
  height: 0.9em;
  border-radius: 50%;
  background: var(--canvas-alt);
  border: 1.5px solid var(--rule-strong);
  display: inline-block;
  flex-shrink: 0;
}
.match-indicator[data-match="yes"] { color: var(--state-active-text); }
.match-indicator[data-match="yes"] .match-glyph {
  background: var(--state-active);
  border-color: var(--state-active);
}
.match-indicator[data-match="no"] { color: var(--state-trash-text); }
.match-indicator[data-match="no"] .match-glyph {
  background: var(--state-trash);
  border-color: var(--state-trash);
}

/* Auth primary submit button (full-width orange). */
.auth-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  background: var(--orange);
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: 0.04em;
  padding: 0.85em 1.4em;
  border: 1.5px solid var(--orange-dark);
  border-radius: 3px;
  cursor: pointer;
  min-height: 48px;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.auth-submit:hover {
  background: var(--orange-dark);
  border-color: var(--orange-dark);
  color: var(--canvas);
}

/* Auth link rows + support note. */
.auth-links {
  margin: var(--space-sm) 0 0;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 0.55em;
}
.auth-links a {
  color: var(--orange-dark);
  text-decoration: underline;
  text-underline-offset: 3px;
  font-family: var(--font-display);
  font-weight: 600;
}
.auth-links a:hover { color: var(--ink); }
.link-secondary { font-size: 0.92rem; }
.link-tertiary {
  font-size: 0.84rem;
  color: var(--muted);
  font-weight: 500;
  text-decoration: none;
}

.auth-support-note {
  max-width: 28rem;
  margin: var(--space-sm) auto 0;
  text-align: center;
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.55;
}
.auth-support-note a {
  color: var(--orange-dark);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.auth-footer {
  background: var(--canvas-alt);
  border-top: 1px solid var(--rule);
  padding: var(--space-md);
  font-size: 0.84rem;
  color: var(--muted);
  margin-top: auto;
}
.auth-footer-inner {
  max-width: 36rem;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  flex-wrap: wrap;
}
.auth-footer a {
  color: var(--ink-mute);
  text-decoration: none;
  font-weight: 500;
}
.auth-footer a:hover { color: var(--orange-dark); }

/* State / welcome / confirm card variants on auth surfaces. */
.auth-state-card,
.welcome-card,
.confirm-card,
.denied-card,
.state-card {
  background: white;
  border: 1px solid var(--rule-strong);
  border-radius: 6px;
  padding: var(--space-md);
  box-shadow: var(--shadow-card);
  max-width: 32rem;
  margin: 0 auto;
}
.welcome-card { text-align: center; }
.confirm-card { text-align: center; }
.confirm-icon {
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--orange-soft);
  color: var(--orange-dark);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto var(--space-sm);
  border: 1.5px solid var(--orange);
}
.confirm-icon svg {
  width: 1.5rem;
  height: 1.5rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.confirm-lede {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.2rem;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin: 0 0 0.4em;
}
.confirm-meta {
  font-size: 0.9rem;
  color: var(--ink-mute);
  line-height: 1.5;
  margin: 0 0 var(--space-sm);
}
.confirm-fine {
  font-size: 0.8rem;
  color: var(--muted);
  font-style: italic;
  margin: var(--space-sm) 0 0;
  line-height: 1.5;
}

.state-icon {
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  background: var(--canvas-alt);
  color: var(--ink-mute);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--space-sm);
  border: 1.5px solid var(--rule);
}
.state-lede {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.1rem;
  margin: 0 0 0.3em;
}
.state-meta {
  font-size: 0.92rem;
  color: var(--ink-mute);
  margin: 0 0 var(--space-sm);
  line-height: 1.5;
}
.state-cta {
  margin-top: var(--space-sm);
}
.state-fine {
  font-size: 0.8rem;
  color: var(--muted);
  font-style: italic;
  margin: var(--space-sm) 0 0;
}

/* Denied page — same chrome + extra wrap. */
.denied-frame {
  min-height: 70vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-lg) var(--space-md);
  background: var(--canvas);
}
.denied-card-wrap {
  width: 100%;
  max-width: 32rem;
  /* Center within the standard .section__inner (the view uses the regular
     admin section wrapper now, not the .denied-frame flex centerer). */
  margin: 0 auto;
  text-align: center;
}
.denied-card {
  text-align: center;
  border-left: 4px solid var(--orange);
}
.denied-actions {
  display: flex;
  gap: 0.6em;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: var(--space-sm);
}

/* Identity badge (setup / reset show the invited account). */
.identity-badge-wrap {
  display: flex;
  align-items: center;
  gap: 0.7em;
  padding: 0.7em;
  background: var(--canvas);
  border: 1px solid var(--rule);
  border-radius: 4px;
  margin: 0 0 var(--space-sm);
}
.identity-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  flex: 1;
  min-width: 0;
}
.identity-avatar {
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  background: var(--orange-soft);
  color: var(--orange-dark);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.95rem;
  flex-shrink: 0;
  border: 1.5px solid var(--orange);
}
.identity-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.identity-name {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink);
  font-size: 0.95rem;
  letter-spacing: -0.005em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.identity-email {
  font-size: 0.84rem;
  color: var(--ink-mute);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.email-readonly {
  font-family: var(--font-mono);
  font-size: 0.9rem;
  padding: 0.55em 0.7em;
  background: var(--canvas-alt);
  border: 1px solid var(--rule);
  border-radius: 3px;
  color: var(--ink);
  word-break: break-all;
}
.invite-summary {
  font-size: 0.86rem;
  color: var(--ink-mute);
  line-height: 1.5;
  background: var(--orange-soft);
  border: 1px solid var(--orange);
  border-left: 4px solid var(--orange);
  border-radius: 4px;
  padding: 0.7em 0.9em;
  margin: 0 0 var(--space-sm);
}
.invite-summary strong { color: var(--ink); font-weight: 700; }

.summary-greeting {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--ink);
  margin: 0 0 0.3em;
}

/* ============================================================
   IMAGE LIBRARY — extracted from admin-images.html scoped block.
   Production views renamed mockup selectors (.images-wrap →
   .image-library-*, .img-tile → .image-card) so this layer
   defines fresh rules under the view's taxonomy.
   ============================================================ */

.image-upload-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  background: white;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: var(--space-md);
  box-shadow: var(--shadow-card);
  margin: 0 0 var(--space-md);
  max-width: 38rem;
}
.image-upload-field {
  display: flex;
  flex-direction: column;
  gap: 0.35em;
}
.image-upload-label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--ink);
}
.image-upload-field input[type="file"],
.image-upload-field input[type="text"] {
  font: inherit;
  padding: 0.55em 0.75em;
  border: 1.5px solid var(--rule-strong);
  border-radius: 3px;
  background: white;
}
.image-upload-progress {
  width: 100%;
  height: 6px;
  background: var(--canvas-alt);
  border-radius: 999px;
  overflow: hidden;
}
.image-upload-progress-bar {
  height: 100%;
  width: 0%;
  background: var(--orange);
  transition: width 0.2s ease;
}
.image-upload-status {
  font-size: 0.85rem;
  color: var(--ink-mute);
  margin: 0;
  font-style: italic;
  min-height: 1.2em;
}
.image-upload-status.is-error { color: var(--state-trash-text); font-style: normal; }
.image-upload-status.is-info { color: var(--state-pending-text); }

.image-library-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-sm);
  margin: var(--space-md) 0 var(--space-sm);
  flex-wrap: wrap;
}
.image-library-header h2 { margin: 0; font-size: 1.15rem; }
.image-library-count {
  font-size: 0.85rem;
  color: var(--muted);
  margin: 0;
  font-style: italic;
}
.image-library-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-sm);
}
@media (max-width: 600px) {
  .image-library-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
  .image-library-grid { grid-template-columns: 1fr; }
}
.image-card {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-card);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
  margin: 0;
}
.image-card:hover {
  border-color: var(--orange);
  box-shadow: var(--shadow-lift);
}
.image-card img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: contain;
  background: var(--canvas);
  display: block;
}
.image-card figcaption {
  padding: 0.55em 0.7em;
  display: flex;
  flex-direction: column;
  gap: 0.25em;
}
.image-card-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.86rem;
  color: var(--ink);
  letter-spacing: -0.005em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.image-card-dims {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--muted);
}
.image-card-actions {
  display: flex;
  gap: 0.4em;
  margin-top: 0.3em;
}
.image-card-edit,
.image-card-delete {
  flex: 1;
  padding: 0.35em 0.6em;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.78rem;
  border: 1px solid var(--rule-strong);
  border-radius: 3px;
  background: white;
  color: var(--ink);
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.image-card-edit:hover {
  border-color: var(--orange);
  background: var(--orange-soft);
  color: var(--orange-dark);
}
.image-card-delete:hover {
  border-color: var(--state-trash);
  background: var(--state-trash-soft);
  color: var(--state-trash-text);
}

/* Image editor modal. */
.image-editor {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal, 400);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-sm);
}
.image-editor[hidden] { display: none; }
.image-editor-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(10, 10, 10, 0.55);
  backdrop-filter: blur(4px);
}
.image-editor-panel {
  position: relative;
  background: white;
  border: 1px solid var(--rule-strong);
  border-radius: 6px;
  box-shadow: var(--shadow-lift);
  max-width: 42rem;
  width: 100%;
  max-height: calc(100vh - var(--space-md));
  overflow: auto;
}
.image-editor-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-sm) var(--space-md);
  border-bottom: 1px solid var(--rule);
  background: var(--canvas-alt);
}
.image-editor-head h2 { margin: 0; font-size: 1.05rem; }
.image-editor-close {
  background: transparent;
  border: 0;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  padding: 0.2em 0.5em;
  border-radius: 3px;
}
.image-editor-close:hover { color: var(--ink); background: var(--canvas); }
.image-editor-body {
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.image-editor-preview-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.5em;
}
.image-editor-preview {
  position: relative;
  background: var(--canvas);
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
  cursor: crosshair;
  max-height: 22rem;
}
.image-editor-preview img {
  width: 100%;
  height: 100%;
  max-height: 22rem;
  object-fit: contain;
  display: block;
}
.image-editor-focal {
  position: absolute;
  width: 1.2rem;
  height: 1.2rem;
  border-radius: 50%;
  background: var(--orange);
  border: 2px solid white;
  box-shadow: 0 0 0 1.5px var(--orange-dark), 0 2px 6px rgba(10, 10, 10, 0.35);
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.image-editor-hint {
  font-size: 0.82rem;
  color: var(--muted);
  font-style: italic;
  margin: 0;
  line-height: 1.45;
}
.image-editor-hint-inline {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--muted);
  margin-top: 0.3em;
  word-break: break-all;
}
.image-editor-field {
  display: flex;
  flex-direction: column;
  gap: 0.35em;
}
.image-editor-label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.88rem;
  color: var(--ink);
}
.image-editor-field textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.55em 0.75em;
  border: 1.5px solid var(--rule-strong);
  border-radius: 3px;
  resize: vertical;
  min-height: 4em;
}
.image-editor-field textarea:focus {
  outline: 0;
  border-color: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-soft);
}
.image-editor-actions {
  display: flex;
  gap: 0.6em;
  flex-wrap: wrap;
  margin-top: 0.4em;
}
.image-editor-status {
  font-size: 0.85rem;
  color: var(--ink-mute);
  margin: 0;
  font-style: italic;
  min-height: 1.2em;
}
.image-editor-status.is-error { color: var(--state-trash-text); font-style: normal; }
.image-editor-status.is-info { color: var(--state-pending-text); }

/* ============================================================
   MISC UTILITIES + ZERO-STATES.
   ============================================================ */

.placeholder-note {
  background: var(--canvas-alt);
  border: 1px dashed var(--rule-strong);
  border-radius: 4px;
  padding: var(--space-sm) var(--space-md);
  color: var(--ink-mute);
  font-style: italic;
  line-height: 1.5;
  margin: var(--space-sm) 0;
}
.placeholder-note a { color: var(--orange-dark); font-weight: 600; }

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

.breadcrumb {
  font-family: var(--font-display);
  font-size: 0.78rem;
  color: var(--muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
  margin: 0;
}
.breadcrumb a {
  color: var(--muted);
  text-decoration: none;
}
.breadcrumb a:hover { color: var(--orange-dark); }

.is-empty { opacity: 0.65; }
.is-error { color: var(--state-trash-text); }
.is-info { color: var(--state-pending-text); }
.label-state {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* JS-driven auto-submit hint cursor. */
.js-auto-submit { cursor: pointer; }

/* ============================================================
   END OF ADMIN LAYER.
   ============================================================ */

/* ============================================================
   POST-PORT GAP FIXES (2026-05-27)
   - .skip-link            — keyboard a11y; visible only on focus
   - .nav-toggle           — mobile hamburger; hidden ≥768px
   - .edit-banner family   — top strip when logged in (carry-over
                             from HTS scaffold; absent from mockups)
   ============================================================ */

/* --- Skip link --- */
.skip-link {
  position: absolute;
  top: -100px;
  left: 0;
  background: var(--ink);
  color: var(--canvas);
  padding: 0.5rem 1rem;
  z-index: 200;
  text-decoration: none;
  font-size: 0.9rem;
}
.skip-link:focus { top: 0; }

/* --- Mobile nav toggle (hamburger) --- */
.nav-toggle {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0.625rem 0.75rem;
  background: transparent;
  border: 0;
  cursor: pointer;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 5px;
  border-radius: 6px;
}
.nav-toggle:hover { background: rgba(0,0,0,0.05); }
.nav-toggle:focus-visible { outline: 2px solid var(--orange-dark); outline-offset: 2px; }
.nav-toggle__line {
  display: block;
  width: 100%;
  height: 2px;
  background: var(--ink);
  border-radius: 2px;
  transition: transform 0.18s ease, opacity 0.18s ease;
}
/* Hamburger morphs into an X when the drawer is open.
   public/js/nav.js flips aria-expanded on the toggle. */
.nav-toggle[aria-expanded="true"] .nav-toggle__line:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] .nav-toggle__line:nth-child(2) {
  opacity: 0;
}
.nav-toggle[aria-expanded="true"] .nav-toggle__line:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* Close X button — only shown inside the open mobile drawer. */
.nav-close {
  display: none;
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--ink);
  z-index: 1;
}
.nav-close:hover { background: rgba(0, 0, 0, 0.05); }
.nav-close:focus-visible { outline: 2px solid var(--orange-dark); outline-offset: 2px; }

/* ============================================================
   MOBILE DRAWER — site-nav becomes a fixed side-sheet on screens
   below 900px (matches the breakpoint in public/js/nav.js). Slides
   in from the right with a scrim. nav-primary + nav-secondary both
   live inside the drawer so all site navigation is in one place.
   ============================================================ */
@media (max-width: 899px) {
  /* W4-P3b (chrome-nav.md [P0]): the side-sheet drawer is a HARD JS feature
     (nav.js toggles `.is-open`/`inert`/scroll-lock). Gate every drawer-chassis
     rule behind `html.js` (set synchronously in head.ejs before this CSS
     paints) so the off-screen drawer + the hamburger that can't open without
     JS only exist when JS is confirmed. The no-JS fallback (`html:not(.js)`
     block at the end of this media query) keeps #site-nav static + visible and
     hides the dead .nav-toggle/.nav-scrim/.nav-close. The list-styling rules
     below (#site-nav .nav-primary/.nav-secondary + their links) stay UNGATED:
     they render the stacked links and are exactly what the no-JS fallback
     wants too. */
  .js .nav-toggle { display: flex; }

  /* Drawer chassis — explicit top/right/bottom + 100dvh because iOS
     Safari address-bar collapse + body.position:fixed (Wave 6 scroll-lock)
     made `inset: 0 0 0 auto` collapse vertically. dvh (dynamic viewport
     height) honors the live address-bar state. */
  .js #site-nav {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    height: 100dvh;
    width: min(85vw, 22rem);
    background: var(--canvas);
    color: var(--ink);
    box-shadow: -18px 0 40px rgba(10, 10, 10, 0.18);
    transform: translateX(100%);
    transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
    z-index: 1001;
    overflow-y: auto;
    padding: 3.5rem 1.5rem 2.5rem;
    display: flex;
    flex-direction: column;
    gap: 0;
  }
  @media (prefers-reduced-motion: reduce) {
    .js #site-nav { transition: none; }
  }
  .js #site-nav.is-open {
    transform: translateX(0);
  }
  .js .nav-close { display: inline-flex; align-items: center; justify-content: center; }

  /* Scrim — explicit sibling div [data-nav-scrim] instead of body::before
     because the latter disappears when body becomes position:fixed +
     top:-Npx (the scroll-lock pattern). Toggled visible by JS adding
     `is-open` class when nav-open fires. */
  .js .nav-scrim {
    position: fixed;
    inset: 0;
    height: 100dvh;
    background: rgba(10, 10, 10, 0.5);
    z-index: 1000;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease-out;
  }
  .js .nav-scrim.is-open {
    opacity: 1;
    pointer-events: auto;
  }
  .js body.nav-open {
    overflow: hidden;
    position: fixed;
    width: 100%;
  }

  /* Lists inside drawer — stacked vertical, no horizontal flex */
  #site-nav .nav-primary,
  #site-nav .nav-secondary {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    list-style: none;
    padding: 0;
    margin: 0;
  }
  #site-nav .nav-primary {
    padding-bottom: 0.85rem;
    margin-bottom: 0.85rem;
    border-bottom: 1px solid var(--rule);
  }
  #site-nav .nav-primary a,
  #site-nav .nav-secondary a {
    display: block;
    padding: 0.85rem 0.4rem;
    color: var(--ink);
    text-decoration: none;
    border: 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
    min-height: 44px;
    font-size: 1.05rem;
  }
  #site-nav .nav-primary a {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.15rem;
  }
  #site-nav .nav-secondary a {
    font-size: 1rem;
    color: var(--muted);
  }
  #site-nav .nav-primary a:hover,
  #site-nav .nav-secondary a:hover {
    color: var(--orange-dark);
    background: rgba(232, 122, 0, 0.06);
    outline: none;
  }
  /* Keyboard focus keeps the hover tint BUT also shows a real focus ring —
     previously these were grouped with :hover under `outline: none`, so
     tab-focus on a drawer link was invisible (focus looked like hover).
     Fit-finish: restore a distinct, token-based focus ring on nav links. */
  #site-nav .nav-primary a:focus-visible,
  #site-nav .nav-secondary a:focus-visible {
    color: var(--orange-dark);
    background: rgba(232, 122, 0, 0.06);
    outline: 2px solid var(--orange);
    outline-offset: 2px;
  }
  #site-nav a.is-current,
  #site-nav a[aria-current="page"] {
    color: var(--orange-dark);
    font-weight: 700;
  }
  /* Override desktop .nav-secondary border-top + center-align inside drawer */
  #site-nav .nav-secondary {
    border-top: 0;
    padding: 0;
    margin: 0;
    justify-content: stretch;
  }

  /* ----------------------------------------------------------------
     NO-JS FALLBACK (W4-P3b, chrome-nav.md [P0]).
     When JS is off/blocked/errored, `html` never gets the `.js` class,
     so none of the `.js`-gated drawer-chassis rules above apply. Without
     this block #site-nav would inherit only its (unset) static defaults
     and the hamburger would be a dead button. So: pin #site-nav back into
     normal flow, visible + full-width below the header, with the links
     stacked (the ungated #site-nav .nav-primary/.nav-secondary list rules
     above already style them as a vertical stack). Hide the toggle (a
     control that can't work is worse than none), the scrim, and the close
     X. Mirrors the mockup's always-reachable CSS-only nav. Scoped inside
     the ≤899px media query so desktop (≥900px) is untouched. */
  html:not(.js) .nav-toggle,
  html:not(.js) .nav-scrim,
  html:not(.js) .nav-close { display: none; }
  html:not(.js) #site-nav {
    position: static;
    transform: none;
    width: 100%;
    height: auto;
    box-shadow: none;
    overflow: visible;
    background: transparent;
    padding: 0 0 var(--space-sm);
  }
}

/* Desktop layout — #site-nav contains both nav-primary + nav-secondary
   after the Wave 6 restructure (single source of truth for both lists).
   Render them as a stacked column on the right side of header-inner. */
@media (min-width: 900px) {
  #site-nav {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.35rem;
  }
  #site-nav .nav-primary {
    display: flex;
    flex-direction: row;
    gap: var(--space-md);
  }
  #site-nav .nav-secondary {
    display: flex;
    flex-direction: row;
    list-style: none;
    padding: 0.35rem 0 0;
    margin: 0;
    gap: var(--space-lg);
    justify-content: flex-end;
    border-top: 1px solid var(--rule);
    width: 100%;
  }
  #site-nav .nav-secondary a {
    font-size: 0.84rem;
    color: var(--muted);
    font-weight: 500;
    text-decoration: none;
    padding: 0.2em 0;
  }
  #site-nav .nav-secondary a:hover { color: var(--orange-dark); }
  /* Current-page indicator on the desktop top nav (W3-P4, 2026-06-03,
     design-system.md FINDING 6). The active item reads as "permanently
     hovered": the primary nav gets the same orange underline as
     `.nav-primary a:hover`, the secondary nav gets the same --orange-dark
     as `.nav-secondary a:hover`. The build's primary links carry
     `.is-current` (header.ejs) and the secondary links carry
     `aria-current="page"`; both selectors are matched so either signal
     lights up, and `[aria-current]` is future-proofed on the primary too.
     Scoped to >=900px so the mobile-drawer rule (#site-nav a.is-current /
     [aria-current]) stays the source of truth below the drawer breakpoint. */
  #site-nav .nav-primary a.is-current,
  #site-nav .nav-primary a[aria-current="page"] { border-bottom-color: var(--orange); }
  #site-nav .nav-secondary a.is-current,
  #site-nav .nav-secondary a[aria-current="page"] { color: var(--orange-dark); }
  .nav-close { display: none; }
}

/* --- Edit banner (top strip when logged in; spans every page) --- */
.edit-banner {
  background: var(--ink);
  color: var(--canvas);
  /* P0-3 (cartography 2026-06-02): honor safe-area-inset-top so the banner
     content clears the iPhone notch / status bar in portrait. `viewport-fit=cover`
     is set in partials/head.ejs:5, so env() resolves on notched iPhones. */
  padding: max(0.5rem, env(safe-area-inset-top, 0.5rem)) 1rem 0.5rem;
  font-family: var(--font-body, system-ui, sans-serif);
  font-size: 0.85rem;
  line-height: 1.4;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 1rem;
  position: sticky;
  top: 0;
  z-index: 120;
}
.edit-banner-text {
  flex: 1 1 24rem;
  min-width: 0;
}
.edit-banner-me {
  color: var(--orange);
  text-decoration: none;
  font-weight: 600;
}
.edit-banner-me:hover { text-decoration: underline; }
.edit-banner-links {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  flex-wrap: wrap;
}
.edit-banner-links > a {
  color: var(--canvas);
  text-decoration: none;
  padding: 0.25rem 0.6rem;
  border-radius: 4px;
  font-size: 0.85rem;
  white-space: nowrap;
}
.edit-banner-links > a:hover { background: rgba(255,255,255,0.08); color: var(--orange); }

/* --- Banner dropdown (Content / Manage) --- */
.banner-dropdown {
  position: relative;
}
.banner-dropdown-trigger {
  background: transparent;
  color: var(--canvas);
  border: 0;
  font: inherit;
  font-size: 0.85rem;
  padding: 0.25rem 0.6rem;
  cursor: pointer;
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  white-space: nowrap;
}
.banner-dropdown-trigger:hover { background: rgba(255,255,255,0.08); color: var(--orange); }
.banner-dropdown-trigger[aria-expanded="true"] {
  background: rgba(255,255,255,0.14);
  color: var(--orange);
}
.banner-dropdown-caret {
  font-size: 0.7em;
  line-height: 1;
  transition: transform 0.18s ease;
}
.banner-dropdown-trigger[aria-expanded="true"] .banner-dropdown-caret {
  transform: rotate(180deg);
}
.banner-dropdown-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  background: var(--ink);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 6px;
  min-width: 220px;
  padding: 0.4rem 0;
  box-shadow: 0 8px 24px rgba(0,0,0,0.35);
  z-index: 130;
}
.banner-dropdown-menu[hidden] { display: none; }
.banner-dropdown-menu a {
  display: block;
  padding: 0.5rem 1rem;
  color: var(--canvas);
  text-decoration: none;
  font-size: 0.875rem;
}
.banner-dropdown-menu a:hover {
  background: rgba(255,255,255,0.08);
  color: var(--orange);
}


/* ============================================================
   PHASE 7B — admin widget layer
   filter-strip / sticky-save-bar / admin-dock
   ============================================================ */

/* ============================================================
   FILTER STRIP — search + select filters on admin list views.
   Horizontal card sitting between page-hero and the list body.
   Mined from mockups/admin-posts.html (canonical scoped CSS).
   ============================================================ */
.admin-filter-strip {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-xs) var(--space-sm);
  background: #fff;
  border: 1px solid var(--rule);
  border-radius: 4px;
  box-shadow: var(--shadow-card);
  margin: 0 auto var(--space-sm);
  max-width: var(--max-w);
  flex-wrap: wrap;
}

.admin-filter-strip__search {
  flex: 1 1 14rem;
  min-width: 13rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  background: var(--canvas);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-md);
  padding: 0.45em 0.8em;
}
.admin-filter-strip__search:focus-within {
  border-color: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-soft);
}
.admin-filter-strip__search-icon {
  flex-shrink: 0;
  width: 14px;
  height: 14px;
  stroke: var(--muted);
  fill: none;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.admin-filter-strip__search input {
  flex: 1;
  border: 0;
  background: transparent;
  font-family: var(--font-body);
  font-size: 0.9rem;
  color: var(--ink);
  padding: 0;
  min-width: 0;
}
.admin-filter-strip__search input:focus { outline: 0; }

.admin-filter-strip__control {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  font-family: var(--font-display);
  font-size: 0.78rem;
  color: var(--muted);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.admin-filter-strip__control-label { white-space: nowrap; }
.admin-filter-strip__control select {
  font-family: var(--font-body);
  font-size: 0.88rem;
  padding: 0.4em 2em 0.4em 0.7em;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-md);
  background: #fff url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%230a0a0a' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>") no-repeat right 0.6em center;
  appearance: none;
  -webkit-appearance: none;
  color: var(--ink);
  text-transform: none;
  font-weight: 500;
  letter-spacing: normal;
}
.admin-filter-strip__control select:focus {
  outline: 0;
  border-color: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-soft);
}

.admin-filter-strip__view-toggle {
  display: inline-flex;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-left: auto;
}
.admin-filter-strip__view-btn {
  background: #fff;
  color: var(--muted);
  border: 0;
  padding: 0.4em 0.75em;
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
}
.admin-filter-strip__view-btn + .admin-filter-strip__view-btn {
  border-left: 1px solid var(--rule);
}
.admin-filter-strip__view-btn.is-active {
  background: var(--ink);
  color: var(--canvas);
}
.admin-filter-strip__view-btn:hover:not(.is-active) {
  background: var(--canvas);
  color: var(--ink);
}

.admin-filter-strip__submit {
  background: var(--orange);
  color: var(--ink);
  border: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.82rem;
  padding: 0.5em 1em;
  border-radius: var(--radius-md);
  cursor: pointer;
}

.admin-filter-strip__clear {
  font-size: 0.82rem;
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 2px;
  align-self: center;
  white-space: nowrap;
}
.admin-filter-strip__clear:hover { color: var(--orange-dark); }

@media (max-width: 600px) {
  .admin-filter-strip {
    padding: var(--space-xs);
    gap: var(--space-xs);
  }
  .admin-filter-strip__search { flex-basis: 100%; }
  .admin-filter-strip__view-toggle { margin-left: 0; }
}

/* ============================================================
   STICKY SAVE BAR — bottom-of-viewport save chrome.
   Sits ABOVE the admin-dock (which lives at the screen floor)
   so both are reachable without occlusion.
   ------------------------------------------------------------
   Chassis lives at lines ~1214 above (mockup-canonical port from
   mockups/styles.css:1156-1183). The duplicate Phase 7B `.sticky-save-bar`
   chassis declaration that previously lived here (drifted background +
   backdrop-filter + heavier shadow vs canonical white + no-filter
   + lighter shadow) was deleted 2026-06-02 (Wave 3 / P0-1) per
   Lens E #21. The mockup-canonical now wins the cascade.
   The `.sticky-save-bar__*` BEM children below are emitted by
   views/partials/sticky-save-bar.ejs as functional additions
   with no mockup-canonical equivalent; Agent Z (P0-2 + P0-5)
   will reconcile them in their wave-3 PR.
   ============================================================ */
.sticky-save-bar__inner {
  max-width: var(--max-w);
  margin: 0 auto;
  padding: 0.65em var(--space-sm);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  flex-wrap: wrap;
}
.sticky-save-bar__status {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.86rem;
  color: var(--ink);
}
.sticky-save-bar__status--placeholder { visibility: hidden; }
.sticky-save-bar__dot {
  width: 0.6em;
  height: 0.6em;
  border-radius: var(--radius-circle);
  background: var(--muted);
  flex-shrink: 0;
}
.sticky-save-bar__status.is-idle .sticky-save-bar__dot { background: var(--state-active); }
.sticky-save-bar__status.is-saved .sticky-save-bar__dot { background: var(--state-active); }
.sticky-save-bar__status.is-dirty .sticky-save-bar__dot {
  background: var(--amber);
  box-shadow: 0 0 0 3px rgba(245, 200, 0, 0.2);
}
.sticky-save-bar__status.is-saving .sticky-save-bar__dot {
  background: transparent;
  border: 1.5px solid var(--amber);
  border-top-color: transparent;
  width: 0.7em;
  height: 0.7em;
  animation: mhs-ssb-spin 0.8s linear infinite;
}
@keyframes mhs-ssb-spin {
  to { transform: rotate(360deg); }
}
.sticky-save-bar__status-meta {
  color: var(--muted);
  font-weight: 500;
  font-size: 0.8rem;
  margin-left: 0.35em;
  font-style: italic;
}
.sticky-save-bar__actions {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  flex-wrap: wrap;
}
.sticky-save-bar__cancel,
.sticky-save-bar__secondary {
  background: transparent;
  border: 1px solid transparent;
  color: var(--muted);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.82rem;
  padding: 0.5em 0.95em;
  border-radius: var(--radius-md);
  text-decoration: none;
}
.sticky-save-bar__cancel:hover,
.sticky-save-bar__secondary:hover { color: var(--ink); }
.sticky-save-bar__destructive-form { margin: 0; display: inline-flex; }
.sticky-save-bar__destructive {
  background: transparent;
  border: 1px solid transparent;
  color: var(--state-trash);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.82rem;
  padding: 0.5em 0.95em;
  border-radius: var(--radius-md);
  cursor: pointer;
}
.sticky-save-bar__destructive:hover {
  background: var(--state-trash-soft);
  color: var(--state-trash-text);
}
.sticky-save-bar__save {
  background: var(--orange);
  color: var(--ink);
  border: 1.5px solid var(--orange);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.86rem;
  padding: 0.55em 1.2em;
  border-radius: var(--radius-md);
  cursor: pointer;
  letter-spacing: 0.04em;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.sticky-save-bar__save:hover {
  background: var(--orange-dark);
  border-color: var(--orange-dark);
  color: var(--canvas);
}

@media (max-width: 600px) {
  .sticky-save-bar__inner {
    gap: 0.4em;
    padding: 0.55em var(--space-xs);
  }
  .sticky-save-bar__cancel,
  .sticky-save-bar__secondary { padding: 0.45em 0.7em; font-size: 0.78rem; }
  .sticky-save-bar__save { padding: 0.5em 0.9em; font-size: 0.8rem; }
}

/* Inline edit-banner + dock stay above the sticky-save-bar; when the
   user hides chrome the bar still sticks but the dock dismisses. */
/* Chrome-hidden state: keep ONLY the toggle button visible so the
   owner can always click it again to bring chrome back. Hiding the
   whole dock (the prior pattern) stranded users without an escape
   hatch — surfaced 2026-06-02 when Mark hit it on first try. */
body.admin-dock-hidden .edit-banner { display: none; }
body.admin-dock-hidden .admin-dock > *:not([data-admin-dock-toggle]) { display: none; }
body.admin-dock-hidden .admin-dock {
  background: transparent;
  box-shadow: none;
  border: none;
  padding: 0;
  gap: 0;
}
body.admin-dock-hidden [data-admin-dock-toggle] {
  background: rgba(10, 10, 10, 0.78);
  color: white;
  border-radius: 999px;
  min-width: 44px;
  min-height: 44px;
  padding: 0.55rem;
  opacity: 0.85;
  box-shadow: 0 4px 14px rgba(10, 10, 10, 0.25);
  transition: opacity 0.15s, transform 0.15s;
}
body.admin-dock-hidden [data-admin-dock-toggle]:hover,
body.admin-dock-hidden [data-admin-dock-toggle]:focus-visible {
  opacity: 1;
  transform: scale(1.05);
}

/* PHASE 7B BEM-FORK ADMIN DOCK BLOCK REMOVED 2026-06-02 (Wave 3 / P0-1).
   Was at lines 4686-4932 in commit 49ff9ed. Re-forked the verbatim
   mockup-canonical port that already lived at lines 1336-1696 of this
   file (faithful copy of ~/Projects/mhs-blueprint/marketing-site/
   mockups/styles.css:1281-1638). The fork drifted on every load-bearing
   axis: right-pinned vs centered, opaque var(--ink) vs rgba(10,10,10,0.92),
   backdrop blur(10px) vs blur(20px) saturate(140%), padding/gap drift,
   missing role-icon system, missing 5-state save-pill, council-overruled
   `+ Post` accent, mobile breakpoints 900px vs canonical 1100px+700px tiers.
   Closes Lens E rows E1, E2, E4, E6, E8, E10, E11, E13, E17, E18, E19
   + Lens A rows A1, A3, A4, A5, A7, A8, A11.
   Print-hide for .sticky-save-bar + .admin-filter-strip preserved as
   sensible defaults (the canonical mockup already hides .admin-dock for
   print at line 1696 of this file). */
@media print {
  .sticky-save-bar,
  .admin-filter-strip { display: none !important; }
}

/* ============================================================
   PHASE 7.1 — INLINE EDITOR VISUAL LAYER
   The click-to-edit pattern: every [data-editable] element with
   body.edit-mode gets a dashed outline + hover state; click swaps
   to an inline edit form with toolbar + save/cancel + toast.
   JS lives at public/js/inline-editor.js (added in Phase 5 scaffold
   but its companion CSS never shipped — surfaced by Mark 2026-06-02
   while logged in on /). Mined from the HTS canonical pattern with
   the navy palette swapped to MHS orange-dark.
   ============================================================ */

body.edit-mode [data-editable].mhs-editable {
  outline: 1px dashed rgba(184, 90, 0, 0.45);
  outline-offset: 2px;
  cursor: pointer;
  border-radius: 2px;
}
body.edit-mode [data-editable].mhs-editable:hover {
  outline: 2px dashed var(--orange-dark);
  outline-offset: 3px;
  background: rgba(184, 90, 0, 0.04);
}
/* Keyboard focus gets a distinct SOLID ring (not the dashed hover style)
   so tab-focus reads differently from mouse-hover — the editables carry
   role=button/tabindex=0 in JS, so they're keyboard targets. Public
   fit-finish P3: focus-vs-hover was previously indistinguishable. */
body.edit-mode [data-editable].mhs-editable:focus-visible {
  outline: 2px solid var(--orange-dark);
  outline-offset: 3px;
  background: rgba(184, 90, 0, 0.04);
}
body.edit-mode [data-editable].mhs-editing {
  outline: none;
  background: none;
}
body.edit-mode [data-editable].mhs-editable-locked {
  outline: 1px dashed rgba(122, 122, 122, 0.4);
  outline-offset: 2px;
  cursor: not-allowed;
  opacity: 0.7;
}

.mhs-edit-wrapper {
  display: flex; flex-direction: column; gap: 0.4rem;
  margin: 0.4rem 0;
  padding: 0.6rem;
  /* Cap the active single-field editor so it doesn't stretch to the full
     container under a short centered heading (public fit-finish P3). A
     comfortable single-field measure; the textarea inside still fills it. */
  max-width: 42rem;
  background: var(--canvas-alt, #efece3);
  border-radius: var(--radius, 6px);
  border: 1px solid var(--orange);
  box-shadow: 0 2px 8px rgba(184, 90, 0, 0.1);
}
/* In centered contexts (CTA bands, .center headings) the capped wrapper
   centers under the element being edited instead of left-anchoring. */
.center .mhs-edit-wrapper,
.cta-section .mhs-edit-wrapper { margin-left: auto; margin-right: auto; }

.mhs-edit-input {
  font: inherit;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--rule, #d6cfbe);
  border-radius: var(--radius, 6px);
  background: var(--canvas, #f8f7f2);
  width: 100%;
  box-sizing: border-box;
  color: var(--ink);
}
.mhs-edit-input:focus {
  outline: none;
  border-color: var(--orange-dark);
  box-shadow: 0 0 0 3px rgba(184, 90, 0, 0.15);
}
.mhs-edit-textarea {
  resize: vertical;
  min-height: 4rem;
  line-height: 1.5;
  font-family: inherit;
}

.mhs-edit-toolbar { display: flex; gap: 0.25rem; flex-wrap: wrap; }
.mhs-edit-tb-btn {
  appearance: none;
  background: var(--canvas, #f8f7f2);
  border: 1px solid var(--rule, #d6cfbe);
  border-radius: var(--radius, 6px);
  cursor: pointer;
  padding: 0.3rem 0.65rem;
  font: 600 0.85rem var(--font-display);
  color: var(--ink);
  min-height: 32px;
}
.mhs-edit-tb-btn:hover {
  background: var(--canvas-alt, #efece3);
  border-color: var(--orange);
}
/* Active-format state (P8 a11y): aria-pressed=true is set from
   document.queryCommandState on selectionchange, so Bold/Italic/•List/1.List
   visibly light up when the caret sits inside that formatting. */
.mhs-edit-tb-btn[aria-pressed="true"] {
  background: var(--orange);
  border-color: var(--orange-dark);
  color: var(--canvas, #f8f7f2);
}
.mhs-edit-tb-btn[aria-pressed="true"]:hover {
  background: var(--orange-dark);
}
/* Keyboard focus ring for the roving-tabindex toolbar (Tab to the bar, then
   arrows between buttons). Visible only for keyboard users. */
.mhs-edit-tb-btn:focus-visible {
  outline: 2px solid var(--orange-dark);
  outline-offset: 1px;
}

/* ── WYSIWYG (rich) editor: contenteditable surface + toolbar ───────────
   The rich paragraph editor (ctMd blocks). The owner sees formatted text —
   real headings, bold, lists, links — never raw Markdown. Storage stays
   Markdown (HTML↔MD via Turndown + /api/preview); these styles are the
   editing chrome only. Token-based to match the .mhs-edit-* visual layer. */
.mhs-rte-toolbar {
  align-items: center;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--rule, #d6cfbe);
  margin-bottom: 0.1rem;
}
.mhs-rte-tb-sep {
  display: inline-block;
  width: 1px;
  align-self: stretch;
  min-height: 1.4em;
  margin: 0 0.15rem;
  background: var(--rule, #d6cfbe);
}
.mhs-rte {
  min-height: 5rem;
  max-height: 60vh;
  overflow-y: auto;
  line-height: 1.55;
  text-align: left;
  cursor: text;
}
/* Tame the rendered markup inside the editing surface so headings/lists
   read sensibly while editing without inheriting full page hero scale. */
.mhs-rte:focus {
  outline: none;
  border-color: var(--orange-dark);
  box-shadow: 0 0 0 3px rgba(184, 90, 0, 0.15);
}
.mhs-rte > :first-child { margin-top: 0; }
.mhs-rte > :last-child { margin-bottom: 0; }
.mhs-rte h2 {
  font-family: var(--font-display);
  font-size: 1.3rem;
  line-height: 1.25;
  margin: 0.6rem 0 0.4rem;
  color: var(--ink);
}
.mhs-rte h3 {
  font-family: var(--font-display);
  font-size: 1.1rem;
  line-height: 1.3;
  margin: 0.55rem 0 0.35rem;
  color: var(--ink);
}
.mhs-rte p { margin: 0 0 0.6rem; }
.mhs-rte ul,
.mhs-rte ol { margin: 0 0 0.6rem; padding-left: 1.4rem; }
.mhs-rte li { margin: 0.15rem 0; }
.mhs-rte a {
  color: var(--orange-dark);
  text-decoration: underline;
}

/* ── Link popover (P8) ──────────────────────────────────────────────────
   Replaces the old window.prompt link flow. Two fields (text + address) plus
   Save/Remove/Cancel, built in JS (CSP-safe, no inline handlers). Lives inside
   the edit wrapper, anchored to the editor's normal flow so it never fights
   the mobile keyboard. Token-styled to match the .mhs-edit-* chrome. */
.mhs-link-pop {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-top: 0.4rem;
  padding: 0.6rem;
  background: var(--canvas, #f8f7f2);
  border: 1px solid var(--orange);
  border-radius: var(--radius, 6px);
  box-shadow: 0 2px 10px rgba(184, 90, 0, 0.14);
}
.mhs-link-pop-field {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.mhs-link-pop-label {
  font: 600 0.72rem var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted, #6a655a);
}
.mhs-link-pop-input {
  font: inherit;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--rule, #d6cfbe);
  border-radius: var(--radius, 6px);
  background: var(--canvas-alt, #efece3);
  color: var(--ink);
  width: 100%;
  box-sizing: border-box;
}
.mhs-link-pop-input:focus {
  outline: none;
  border-color: var(--orange-dark);
  box-shadow: 0 0 0 3px rgba(184, 90, 0, 0.15);
}
.mhs-link-pop-error {
  font-size: 0.8rem;
  color: #b91c1c;
  min-height: 0;
}
.mhs-link-pop-error:empty {
  display: none;
}
.mhs-link-pop-actions {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.mhs-link-pop-save,
.mhs-link-pop-cancel,
.mhs-link-pop-remove {
  appearance: none;
  cursor: pointer;
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius, 6px);
  font: 600 0.8rem var(--font-display);
  border: 1px solid transparent;
  min-height: 34px;
}
.mhs-link-pop-save {
  background: var(--orange-dark);
  color: var(--canvas, #f8f7f2);
  border-color: var(--orange-dark);
}
.mhs-link-pop-save:hover {
  background: #8f4400;
  border-color: #8f4400;
}
.mhs-link-pop-cancel {
  background: transparent;
  color: var(--ink);
  border-color: var(--rule, #d6cfbe);
}
.mhs-link-pop-cancel:hover {
  background: var(--canvas-alt, #efece3);
}
.mhs-link-pop-remove {
  background: transparent;
  color: #b91c1c;
  border-color: rgba(185, 28, 28, 0.4);
  margin-left: auto;
}
.mhs-link-pop-remove:hover {
  background: rgba(220, 38, 38, 0.08);
}
.mhs-link-pop-save:focus-visible,
.mhs-link-pop-cancel:focus-visible,
.mhs-link-pop-remove:focus-visible {
  outline: 2px solid var(--orange-dark);
  outline-offset: 1px;
}

.mhs-edit-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.mhs-edit-save, .mhs-edit-cancel {
  appearance: none;
  cursor: pointer;
  padding: 0.45rem 1rem;
  border-radius: var(--radius, 6px);
  font: 500 0.85rem var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border: 2px solid transparent;
  min-height: 36px;
}
.mhs-edit-save {
  background: var(--orange-dark);
  color: var(--canvas, #f8f7f2);
  border-color: var(--orange-dark);
}
.mhs-edit-save:hover {
  background: #8f4400;
  border-color: #8f4400;
}
.mhs-edit-save:disabled {
  background: var(--muted, #a99c89);
  border-color: var(--muted, #a99c89);
  cursor: wait;
}
.mhs-edit-cancel {
  background: transparent;
  color: var(--ink);
  border-color: var(--rule, #d6cfbe);
}
.mhs-edit-cancel:hover {
  background: var(--canvas-alt, #efece3);
}

.mhs-edit-error {
  font-size: 0.85rem;
  color: #b91c1c;
  margin-top: 0.2rem;
  padding: 0.4rem 0.6rem;
  background: rgba(220, 38, 38, 0.08);
  border-radius: var(--radius, 6px);
}

.mhs-toast {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  z-index: 9999;
  background: var(--ink);
  color: var(--canvas, #f8f7f2);
  padding: 0.75rem 1.2rem;
  border-radius: var(--radius, 6px);
  font-family: var(--font-display);
  font-size: 0.92rem;
  letter-spacing: 0.04em;
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity 200ms ease, transform 200ms ease;
  pointer-events: none;
}
.mhs-toast.visible {
  opacity: 1;
  transform: translateY(0);
}

/* ============================================================
   PHASE 7.2 — INLINE EDITOR MOBILE LAYER (2026-06-02)
   Click-to-edit doctrine #4: tap = click, form swaps in place,
   action chrome stays above mobile keyboards. Match desktop
   behavior; tighten touch targets to the iOS/MD min (44px).
   ============================================================ */

@media (max-width: 640px) {
  /* Editor wrapper expands edge-to-edge of its rendering container so
     the textarea isn't a sliver next to the dashed outline. The 0
     side-padding lets the textarea inherit the container's gutter
     instead of double-padding on top of paragraph margins. */
  .mhs-edit-wrapper {
    padding: 0.55rem 0.5rem;
    gap: 0.55rem;
    margin: 0.4rem 0;
    border-radius: 4px;
  }

  /* Inputs scale to viewport. 16px font-size prevents iOS Safari from
     auto-zooming on focus (the silent UX failure that makes inline
     editing feel broken on iPhone). */
  .mhs-edit-input {
    font-size: 16px;
    padding: 0.65rem 0.75rem;
  }
  .mhs-edit-textarea {
    min-height: 5.5rem;
    font-size: 16px;
  }
  /* Rich (contenteditable) surface — 16px to dodge iOS focus-zoom, like the
     textarea. The toolbar wraps in normal flow above it (not fixed) so it
     never fights the on-screen keyboard. */
  .mhs-rte {
    min-height: 6rem;
    font-size: 16px;
  }

  /* Action row docks at the bottom of the wrapper with the iOS safe-area
     + keyboard inset honored. Buttons hit the 44px touch-target floor. */
  .mhs-edit-actions {
    gap: 0.5rem;
    /* Honor safe-area on home-indicator iPhones AND keyboard inset on
       browsers that publish it (Safari 17.4+ / Chrome iOS via virtual
       keyboard API fallback). env() with a 0 fallback is safe on every
       browser — falls through to safe-area-inset-bottom alone elsewhere. */
    padding-bottom: max(env(safe-area-inset-bottom, 0px), 0px);
  }
  .mhs-edit-save,
  .mhs-edit-cancel {
    min-height: 44px;
    padding: 0.7rem 1.1rem;
    font-size: 0.9rem;
    flex: 1 1 auto;
  }

  /* Toolbar buttons (bold/italic etc.) — bump to 40px so they're
     thumb-tappable; leave one row max + wrap so we don't blow the
     container width on tiny screens. */
  .mhs-edit-tb-btn {
    min-height: 40px;
    padding: 0.5rem 0.8rem;
    font-size: 0.92rem;
  }

  /* Link popover: 16px inputs to dodge iOS focus-zoom (same rule as the
     editor inputs); buttons hit the 44px touch floor. */
  .mhs-link-pop-input {
    font-size: 16px;
    padding: 0.6rem 0.7rem;
  }
  .mhs-link-pop-save,
  .mhs-link-pop-cancel,
  .mhs-link-pop-remove {
    min-height: 44px;
    padding: 0.6rem 1rem;
    font-size: 0.9rem;
  }

  /* Toast moves to bottom-center so it doesn't collide with the
     keyboard or the admin-dock overflow scroll. */
  .mhs-toast {
    left: 1rem;
    right: 1rem;
    bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
    text-align: center;
  }
}

/* ============================================================
   CARTOGRAPHY P0 CSS BUNDLE (2026-06-02)
   Refs: R&D/audit-2026-06-02/cartography/{MASTER-CARTOGRAPHY-PUNCH-LIST.md,
         03-mobile-walkthrough.md}
   - P0-1 MhsImagePicker styling (closes ~12 unstyled S3 paths)
   - P0-2 .hero-edit-pill canonical class (unblocks Pattern A spread)
   - P0-9 Touch-target ≥44px floor on admin chrome (mobile)
   P0-3 lives inline at the .edit-banner ruleset above (safe-area-inset-top).
   ============================================================ */

/* ----- P0-1: MhsImagePicker modal styling ------------------- */
/* Class names match exactly the DOM emitted by public/js/image-picker.js:25-53
   plus the dynamic subclasses added by renderLibrary() + setUploadStatus(). */

.mhs-picker-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 10, 10, 0.6);
  z-index: var(--z-toast, 500); /* above admin-dock (200) + sticky-save-bar (100) */
  display: flex;
  align-items: center;
  justify-content: center;
  padding:
    env(safe-area-inset-top, 1rem)
    1rem
    env(safe-area-inset-bottom, 1rem);
  overscroll-behavior: contain;
}

/* Optional body class set by image-picker.js:56 — lock background scroll. */
body.mhs-picker-open {
  overflow: hidden;
}

.mhs-picker-modal {
  background: white;
  width: 100%;
  max-width: 720px;
  max-height: 85vh;
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-lift);
}

.mhs-picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem;
  border-bottom: 1px solid var(--rule);
}

.mhs-picker-header h2 {
  margin: 0;
  font-size: 1.15rem;
  font-family: var(--font-display);
  color: var(--ink);
}

.mhs-picker-close {
  min-width: 44px;
  min-height: 44px;
  padding: 0 0.7rem;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--ink-mute);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.mhs-picker-close:hover {
  background: var(--canvas-alt);
  color: var(--ink);
}
.mhs-picker-close:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 2px;
}

.mhs-picker-upload {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--rule);
  background: var(--canvas);
}

.mhs-picker-upload-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
}

.mhs-picker-upload-label {
  flex: 1 1 200px;
  display: inline-flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.85rem;
  color: var(--ink-mute);
}

.mhs-picker-upload-label > span {
  font-weight: 600;
  color: var(--ink);
}

.mhs-picker-upload-label input[type="file"] {
  font-size: 16px; /* iOS no-zoom floor */
  padding: 0.4rem 0;
  min-height: 44px;
}

.mhs-picker-alt {
  flex: 1 1 200px;
  padding: 0.6rem 0.75rem;
  font-size: 16px; /* iOS no-zoom floor */
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: white;
  color: var(--ink);
  min-height: 44px;
}
.mhs-picker-alt:focus {
  outline: none;
  border-color: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-soft);
}

.mhs-picker-upload-status {
  flex: 1 0 100%;
  margin: 0;
  font-size: 0.85rem;
  color: var(--ink-mute);
  min-height: 1.2em;
}
.mhs-picker-upload-status--success { color: var(--orange-dark); }
.mhs-picker-upload-status--error { color: #b00020; }

.mhs-picker-search {
  /* Search field is reserved by the spec (P0-1) for a future filter; the
     current JS doesn't emit it but we ship the rule so when it lands the
     visual is consistent with the upload field. */
  width: 100%;
  padding: 0.75rem;
  font-size: 16px; /* iOS no-zoom floor */
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: white;
  min-height: 44px;
}

.mhs-picker-library {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0; /* allow flex child to scroll inside .mhs-picker-grid */
}

.mhs-picker-library-header {
  padding: 0.85rem 1.25rem 0.35rem;
}
.mhs-picker-library-header h3 {
  margin: 0;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-mute);
  font-weight: 600;
}

.mhs-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.75rem;
  padding: 1rem 1.25rem;
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
  -webkit-overflow-scrolling: touch;
}

.mhs-picker-tile {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0.4rem;
  background: white;
  border: 2px solid transparent;
  border-radius: 3px;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  transition: border-color 0.15s, background 0.15s, transform 0.15s;
}
.mhs-picker-tile:hover {
  border-color: var(--orange-dark);
  background: var(--canvas-alt);
}
.mhs-picker-tile:focus-visible {
  outline: none;
  border-color: var(--orange-dark);
  box-shadow: 0 0 0 3px var(--orange-soft);
}
.mhs-picker-tile.is-selected,
.mhs-picker-tile--current {
  border-color: var(--orange-dark);
  background: var(--orange-soft);
}

.mhs-picker-tile-img,
.mhs-picker-tile > img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 2px;
  display: block;
  background: var(--canvas-alt);
}

.mhs-picker-tile-broken {
  width: 100%;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--canvas-alt);
  color: var(--ink-mute);
  border-radius: 2px;
  font-size: 1.5rem;
}

.mhs-picker-tile-meta,
.mhs-picker-tile-name {
  font-size: 0.7rem;
  color: var(--ink-mute);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mhs-picker-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 1rem 1.25rem;
  border-top: 1px solid var(--rule);
  background: var(--canvas);
}
.mhs-picker-actions > * {
  min-height: 44px;
}

.mhs-picker-upload-btn,
button.mhs-picker-upload {
  min-height: 44px;
  min-width: 44px;
  padding: 0.6rem 1rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--orange-dark);
  color: white;
  border: 0;
  border-radius: 3px;
  font-weight: 600;
  cursor: pointer;
}

.mhs-picker-empty,
.mhs-picker-loading,
.mhs-picker-error {
  grid-column: 1 / -1;
  padding: 2rem 1rem;
  text-align: center;
  color: var(--ink-mute);
  font-size: 0.9rem;
}
.mhs-picker-error {
  color: #b00020;
}

@media (max-width: 600px) {
  .mhs-picker-overlay {
    /* Edge-to-edge on small screens — but still honor safe-area insets so
       Brian's iPhone notch + home-indicator don't clip the modal chrome. */
    padding:
      env(safe-area-inset-top, 0)
      env(safe-area-inset-right, 0)
      env(safe-area-inset-bottom, 0)
      env(safe-area-inset-left, 0);
  }
  .mhs-picker-modal {
    max-width: 100%;
    max-height: 100vh;
    height: 100%;
    border-radius: 0;
  }
  .mhs-picker-header {
    padding: 1rem;
  }
  .mhs-picker-upload {
    padding: 0.85rem 1rem;
  }
  .mhs-picker-grid {
    padding: 0.85rem 1rem;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 0.6rem;
  }
  .mhs-picker-actions {
    padding: 0.85rem 1rem;
  }
}

/* ----- P0-2: .hero-edit-pill canonical class ---------------- */
/* Previously inline-styled on views/about.ejs:147,152 as ~58×21px underlined
   anchor. Pill chrome below makes it a proper 44px+ tap target and unblocks
   Pattern A spread across the top 5 visible S4 sections (P0-4). */

.hero-edit-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  min-height: 44px;
  min-width: 44px;
  padding: 0.5rem 0.9rem;
  background: var(--orange-dark);
  color: white;
  border: 0;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  box-shadow: 0 4px 12px rgba(10, 10, 10, 0.18);
  cursor: pointer;
  transition: background 0.15s, transform 0.15s, box-shadow 0.15s;
}
.hero-edit-pill:hover {
  background: var(--ink);
  color: white;
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(10, 10, 10, 0.25);
  text-decoration: none;
}
.hero-edit-pill:focus-visible {
  outline: 2px solid var(--orange-soft);
  outline-offset: 2px;
  text-decoration: none;
}
.hero-edit-pill:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(10, 10, 10, 0.2);
}

@media (max-width: 600px) {
  /* Hold the dimensions on mobile — these are touch targets, not chrome to
     shrink. The size IS the affordance. */
  .hero-edit-pill {
    min-height: 44px;
    min-width: 44px;
    font-size: 0.82rem;
    padding: 0.5rem 0.9rem;
  }
}

/* ----- P0-9: Touch-target ≥44px floor on admin chrome ------- */
/* Apple HIG + WCAG 2.5.5: 44×44 CSS px minimum on every interactive admin
   element. Selectors track the actual class names in this codebase (verified
   via grep against partials/admin-dock.ejs + sticky-save-bar.ejs + the row
   actions on admin/*/index.ejs).
   ------------------------------------------------------------
   2026-06-02 (Wave 3 / P0-1): Phase 7B BEM-fork selectors
   (.admin-dock__nav-item / __tail a / __hints / __chrome-toggle)
   removed — the canonical mockup-port uses compound-class selectors
   (.admin-dock .nav-item, .admin-dock .dock-tail a, .admin-dock
   .save-pill). The generic .admin-dock a + .admin-dock button rules
   below already cover every interactive child of the canonical dock,
   so no replacement listings are needed. */

@media (max-width: 900px) {
  .admin-dock a,
  .admin-dock button,
  .edit-banner-links > a,
  .edit-banner-me,
  .banner-dropdown-trigger,
  .banner-dropdown-menu a,
  .sticky-save-bar button,
  .sticky-save-bar a,
  .sticky-save-bar__save,
  .sticky-save-bar__cancel,
  .sticky-save-bar__secondary,
  .sticky-save-bar__destructive,
  .btn--ghost,
  .btn--ghost.btn--sm,
  .admin-orderable-up,
  .admin-orderable-down,
  .image-card-edit,
  .image-card-delete,
  .admin-image-picker,
  .admin-image-picker-clear,
  .filter-strip select,
  .filter-strip input,
  .table-actions a,
  .table-actions button {
    min-height: 44px;
    min-width: 44px;
    padding-inline: max(0.6rem, 0.9em);
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* Sticky-save-bar Save button is the highest-stakes tap of any form;
     give it visual weight in addition to the 44px floor. */
  .sticky-save-bar__save {
    min-height: 48px;
  }
}

/* ============================================================
   PARTNER / TRUSTED-TRADES — permission-gated cards (P0-8/9/10)
   Ported verbatim from mhs-blueprint mockups:
     about.html               → .trades-grid, .gated-preview,
                                 .portrait--placeholder, .name-row, .gating-note
     heating-and-cooling.html → .partner-feature, .blockquote-source,
                                 .attribution, .section-intro(--left)
   Every card defaults to the dashed REDACTED state until the matching
   permissions.<key> flag is flipped in /admin/settings.
   ============================================================ */

/* Section heading intros (muted under-text). Used by /about + /heating-and-cooling
   (and existing /epoxy, which referenced this class before it was defined). */
.section-intro {
  text-align: center;
  color: var(--muted);
  max-width: 56ch;
  margin: 0 auto var(--space-lg);
  font-size: 1.05rem;
}
.section-intro--left {
  text-align: left;
  margin: 0 0 var(--space-md);
}

/* ---- Trusted-trades grid: portrait + role + name + bio in section-card ---- */
.trades-grid { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.trades-grid .section-card {
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}
.trades-grid .portrait {
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  background: var(--canvas-alt) center/cover no-repeat;
  margin-bottom: var(--space-xs);
  position: relative;
}
.trades-grid .portrait--placeholder::before {
  content: '?';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--rule-strong);
  font-family: var(--font-display);
  font-size: 2rem;
  font-weight: 700;
}
.trades-grid .role {
  font-size: 0.78rem;
  color: var(--orange-dark);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  margin: 0;
}
.trades-grid h3 { margin: 0 0 0.2em; font-size: 1.1rem; }
.trades-grid .name-row {
  display: flex;
  align-items: center;
  gap: 0.5em;
  flex-wrap: wrap;
  margin-bottom: 0.2em;
}
.trades-grid .name-row h3 { margin: 0; }
.trades-grid .partner-business {
  font-size: 0.85rem;
  color: var(--ink-mute);
  font-weight: 600;
}
.trades-grid p {
  margin: 0;
  color: var(--ink-mute);
  font-size: 0.93rem;
}
/* Gated card variant — washed-out dashed preview of what the public sees while gated. */
.trades-grid .section-card.gated-preview {
  background: var(--canvas);
  border-style: dashed;
}
.trades-grid .gated-preview .portrait {
  background: repeating-linear-gradient(
    135deg,
    var(--rule) 0,
    var(--rule) 8px,
    var(--canvas-alt) 8px,
    var(--canvas-alt) 16px
  );
}
.trades-grid .gated-preview .portrait--placeholder::before { content: ''; }
.trades-grid .gated-preview h3,
.trades-grid .gated-preview p {
  color: var(--muted);
  font-style: italic;
}

/* ---- Gating-note callout explaining the mechanic ---- */
.gating-note {
  margin-top: var(--space-md);
  padding: var(--space-sm) var(--space-md);
  background: white;
  border-left: 3px solid var(--orange);
  border-radius: 0 3px 3px 0;
  font-size: 0.9rem;
  color: var(--ink-mute);
  max-width: 60ch;
}
.gating-note strong { color: var(--ink); }
.gating-note code { font-size: 0.82rem; }

/* ---- Wide partner feature card (/heating-and-cooling) ---- */
.partner-feature {
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: var(--space-md);
  align-items: center;
  background: white;
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: var(--space-md);
  max-width: 56rem;
  margin: 0 auto;
  box-shadow: var(--shadow-card);
}
/* Gated state: dashed canvas-tinted preview. */
.partner-feature[data-gated="true"] {
  background: var(--canvas);
  border: 1px dashed var(--rule-strong);
  box-shadow: none;
}
.partner-feature .portrait {
  aspect-ratio: 1/1;
  width: 100%;
  border-radius: 50%;
  background: var(--canvas-alt) center top/cover no-repeat;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: 0.78rem;
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  flex-shrink: 0;
}
.partner-feature[data-gated="true"] .portrait {
  background: repeating-linear-gradient(
    135deg,
    var(--rule) 0,
    var(--rule) 8px,
    var(--canvas-alt) 8px,
    var(--canvas-alt) 16px
  );
}
.partner-feature .role {
  font-size: 0.82rem;
  color: var(--orange-dark);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  margin-bottom: 0.4em;
}
.partner-feature h3 {
  margin: 0 0 0.4em;
  font-size: 1.4rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5em;
}
.partner-feature[data-gated="true"] h3 {
  font-style: italic;
  color: var(--muted);
}
.partner-feature h3 .partner-business {
  font-size: 1rem;
  font-weight: 600;
  font-style: normal;
  color: var(--ink-mute);
}
.partner-feature p {
  margin: 0;
  color: var(--ink-mute);
  max-width: none;
}
.partner-feature[data-gated="true"] p { font-style: italic; color: var(--muted); }
@media (max-width: 600px) {
  .partner-feature { grid-template-columns: 1fr; text-align: center; }
  .partner-feature .portrait { width: 8rem; margin: 0 auto; }
  .partner-feature h3 { justify-content: center; }
}

/* ---- Verbatim source quote (voice-canon protected blockquote) ---- */
.blockquote-source {
  background: white;
  border-left: 4px solid var(--orange);
  padding: var(--space-md) var(--space-md) var(--space-sm);
  margin: var(--space-md) 0;
  box-shadow: var(--shadow-card);
  max-width: 64ch;
}
.blockquote-source p {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.15rem;
  line-height: 1.5;
  color: var(--ink);
  margin: 0 0 0.5em;
  max-width: none;
}
.blockquote-source p strong { font-style: normal; color: var(--ink); }
.blockquote-source .attribution {
  display: block;
  font-family: var(--font-display);
  font-size: 0.78rem;
  color: var(--orange-dark);
  font-style: normal;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: var(--space-sm);
}
.blockquote-source .attribution::before { content: '— '; }

/* ============================================================
   /mission — gated-block visualizer + Honduras section (W2-P4)
   Ported from mhs-blueprint mockup mission.html in-page <style>
   (lines 25-327). The faith register is the explicit subject only
   on this page (voice canon Rule 8). Honduras + Christ Church +
   Doug-background blocks all default to their REDACTED state via
   the EJS gate guards (permissions.* default false); these styles
   cover BOTH the open (gate ON) and locked (gate OFF) renders.
   Tokens (--orange-soft, --rule-strong, --font-mono, --shadow-card,
   --ink-soft, etc.) are all defined in :root above.
   ============================================================ */

/* Type-heavy page hero — no photo, just a soft orange radial glow
   over the standard dark hero ground. .page-hero base supplies the
   light type colors. */
.page-hero--type-heavy {
  background:
    radial-gradient(ellipse at 80% 0%, rgba(232, 122, 0, 0.16) 0%, transparent 55%),
    var(--ink-soft);
  padding: var(--space-xl, 4rem) 0 var(--space-lg);
}
.page-hero--type-heavy h1 { max-width: 18ch; margin-bottom: var(--space-sm); }
.page-hero--type-heavy p.lede {
  max-width: 46ch;
  font-size: clamp(1.15rem, 1.7vw, 1.4rem);
  font-style: italic;
  line-height: 1.45;
}

/* Story prose — warm reading column. */
.mission-prose p {
  font-size: 1.08rem;
  line-height: 1.65;
  max-width: 56ch;
  margin: 0 auto 1.1em;
}
.mission-prose p:last-child { margin-bottom: 0; }
.mission-prose .lede { font-size: 1.2rem; color: var(--ink); line-height: 1.5; }

/* Honduras section — header tag-row + gate chip. */
.honduras-section .tag-row {
  display: flex;
  align-items: center;
  gap: 0.6em;
  flex-wrap: wrap;
  margin-bottom: var(--space-sm);
}
.honduras-tag {
  display: inline-block;
  padding: 0.18em 0.7em;
  border-radius: 999px;
  background: var(--orange-soft);
  color: var(--orange-dark);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.honduras-tag::before { content: '◉ '; color: var(--orange); }
/* OFF (gated) variant — muted, so the locked state reads "not public". */
.honduras-tag--off {
  background: rgba(106, 101, 90, 0.15);
  color: var(--muted);
}
.honduras-tag--off::before { color: var(--muted); }

.honduras-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: var(--space-lg);
  align-items: start;
  margin-top: var(--space-md);
}
@media (max-width: 800px) {
  .honduras-grid { grid-template-columns: 1fr; }
}
.honduras-grid .prose-col p { max-width: 52ch; line-height: 1.6; }
.honduras-grid .prose-col p:last-child { margin-bottom: 0; }

/* Honduras photo slot — S3. Real image fills as a background when
   mission.honduras_photo is set; otherwise the --pending placeholder
   shows the brand-tinted gradient + caption (no external URL — the
   mockup's placehold.co stand-in is replaced by an in-CSS placeholder). */
.honduras-photo {
  aspect-ratio: 4/3;
  background: var(--canvas-alt) center/cover no-repeat;
  border: 1px solid var(--rule);
  border-radius: 3px;
  box-shadow: var(--shadow-card);
  position: relative;
}
.honduras-photo--pending {
  background:
    linear-gradient(135deg, rgba(232, 122, 0, 0.14), rgba(10, 10, 10, 0.05));
}
.honduras-photo--pending::after {
  content: 'Photo pending — Doug to supply';
  position: absolute;
  bottom: 0.7rem;
  left: 0.7rem;
  background: rgba(10, 10, 10, 0.78);
  color: var(--canvas);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  padding: 0.18em 0.55em;
  border-radius: 2px;
  letter-spacing: 0.03em;
}

/* Honduras trip cards (S4) — year + where + blurb + verify pill. */
.trip-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-sm);
  margin-top: var(--space-md);
}
.trip-card {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: var(--space-sm) var(--space-md);
  position: relative;
}
.trip-card .year {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.4rem;
  color: var(--orange-dark);
  line-height: 1;
  letter-spacing: -0.01em;
}
.trip-card .where {
  font-size: 0.82rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-top: 0.4em;
  margin-bottom: 0.3em;
}
.trip-card p {
  margin: 0;
  font-size: 0.95rem;
  color: var(--ink-mute);
  line-height: 1.5;
  max-width: none;
}
.trip-card .verify-pill {
  display: inline-block;
  margin-top: 0.6em;
  padding: 0.12em 0.55em;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.trip-card .verify-pill.verified { background: rgba(31, 140, 77, 0.15); color: #1f7a40; }
.trip-card .verify-pill.approximate { background: rgba(245, 200, 0, 0.22); color: #8a6800; }

/* Gated-block card — locked-state preview for Christ Church + Doug
   background + (gate-off) Honduras. Restrained dashed border, washed
   ground, italic gray prose so it reads "not-yet-public". */
.gated-block {
  background: var(--canvas);
  border: 1px dashed var(--rule-strong);
  border-radius: 3px;
  padding: var(--space-md) var(--space-lg);
  max-width: 56rem;
}
.gated-block .gated-head {
  display: flex;
  align-items: center;
  gap: 0.6em;
  flex-wrap: wrap;
  margin-bottom: var(--space-xs);
}
.gated-block h3 { margin: 0; color: var(--ink-mute); font-size: 1.15rem; }
.gated-block p {
  margin: 0.3em 0 0;
  color: var(--muted);
  font-style: italic;
  max-width: 56ch;
}
.gated-block .lock-icon {
  width: 1rem;
  height: 1rem;
  color: var(--muted);
  flex-shrink: 0;
}
/* Open variant (gate ON) — solid border, normal ink, real content. */
.gated-block--open {
  background: white;
  border-style: solid;
  border-color: var(--rule);
  box-shadow: var(--shadow-card);
}
.gated-block--open p { color: var(--ink-mute); font-style: normal; }

/* Doug + Laura wedding aside (gate ON only). */
.mission-aside {
  margin-top: var(--space-md);
  max-width: 56ch;
  color: var(--ink-mute);
  font-style: italic;
}

/* Mission callout — tagline as a visual closer. Shared with /about's
   mission callout (the read-more link lives only on /about). */
.mission-callout { text-align: center; }
.mission-callout .kicker { margin-bottom: var(--space-sm); }
.mission-callout blockquote {
  border: 0;
  padding: 0;
  margin: var(--space-md) auto 0;
  max-width: 32ch;
  font-size: clamp(1.55rem, 3vw, 2.2rem);
  line-height: 1.3;
  font-family: var(--font-display);
  font-weight: 500;
  font-style: italic;
  color: var(--ink);
}
.mission-callout blockquote::before {
  content: '“';
  display: block;
  font-size: 3rem;
  line-height: 0.2;
  color: var(--orange);
  margin-bottom: 0.4em;
}
.mission-callout .attribution {
  font-family: var(--font-body);
  font-style: normal;
  font-size: 0.88rem;
  color: var(--muted);
  margin-top: var(--space-md);
  letter-spacing: 0.04em;
}
.mission-callout .read-more {
  display: inline-block;
  margin-top: var(--space-md);
  font-size: 0.92rem;
  color: var(--orange-dark);
}

/* CTA actions cluster (shared utility; home.ejs + mission.ejs use it). */
.cta-actions {
  display: flex;
  gap: var(--space-sm);
  justify-content: center;
  flex-wrap: wrap;
}

@media (max-width: 600px) {
  .gated-block { padding: var(--space-md); }
  .mission-prose p { max-width: none; }
}

/* ============================================================
   CONTACT PAGE (W3-P1) — ported from mockup contact.html:17-298.
   The /contact form is the only real form on the public site, so
   these field styles live page-scoped here rather than global.
   Variables (--orange*, --rule*, --space*, --font-*) are the
   canonical tokens defined at the top of this file.
   ============================================================ */

/* Two-column: form (3fr) + contact card (2fr). Stacks under 900px;
   the card drops its sticky position on narrow viewports (no sticky
   overlays on mobile — CLAUDE.md voice rules). */
.contact-grid {
  display: grid;
  grid-template-columns: 3fr 2fr;
  gap: var(--space-lg);
  align-items: start;
}
@media (max-width: 900px) {
  .contact-grid { grid-template-columns: 1fr; gap: var(--space-md); }
  .contact-card { position: static; }
}

/* Form panel — white card on canvas; the conversion surface gets the weight. */
.contact-form-wrap {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: var(--space-md);
  box-shadow: var(--shadow-card);
}
.contact-form-wrap h2 { margin: 0 0 var(--space-sm); }
.contact-form-intro {
  color: var(--ink-mute);
  margin: 0 0 var(--space-md);
  max-width: 52ch;
}
.contact-form-wrap .form-error {
  padding: 0.85rem 1rem;
  background: #fee2e2;
  color: #991b1b;
  border-radius: 3px;
  margin-bottom: var(--space-sm);
  font-size: 0.95rem;
}

/* Form fields — generous tap targets, canonical orange focus rings. */
.contact-form .form-row { margin-bottom: var(--space-md); }
.contact-form .form-row--split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-sm);
}
@media (max-width: 480px) {
  .contact-form .form-row--split { grid-template-columns: 1fr; }
}
.contact-form .form-row label,
.contact-form .label-as-legend {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--ink);
  margin-bottom: 0.4em;
  letter-spacing: 0.01em;
}
.contact-form .label-as-legend { margin-bottom: 0.5em; }
.contact-form .form-row label .req {
  color: var(--orange-dark);
  font-weight: 600;
  margin-left: 0.15em;
}
.contact-form .form-row label .optional {
  color: var(--muted);
  font-weight: 500;
  font-family: var(--font-body);
  font-size: 0.82rem;
  margin-left: 0.4em;
  letter-spacing: 0;
}
.contact-form .field-hint {
  font-size: 0.82rem;
  color: var(--muted);
  margin: 0.35em 0 0;
}
.contact-form input[type="text"],
.contact-form input[type="email"],
.contact-form input[type="tel"],
.contact-form select,
.contact-form textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--ink);
  background: var(--canvas);
  border: 1.5px solid var(--rule-strong);
  border-radius: 2px;
  padding: 0.75em 0.9em;
  line-height: 1.4;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
  -webkit-appearance: none;
  appearance: none;
}
.contact-form textarea {
  resize: vertical;
  min-height: 7rem;
}
.contact-form select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%230a0a0a' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 0.9em center;
  padding-right: 2.6em;
}
.contact-form input:focus,
.contact-form select:focus,
.contact-form textarea:focus {
  outline: 0;
  border-color: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-soft);
  background: white;
}
.contact-form input::placeholder,
.contact-form textarea::placeholder {
  color: #a39e90;
  opacity: 1;
}

/* Timeline radio group — pill buttons for a clear mutually-exclusive set. */
.contact-form .radio-group {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5em;
}
.contact-form .radio-group label {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.55em 1em;
  background: var(--canvas);
  border: 1.5px solid var(--rule-strong);
  border-radius: 999px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.92rem;
  color: var(--ink);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.contact-form .radio-group label:hover { border-color: var(--orange); }
.contact-form .radio-group input[type="radio"] {
  accent-color: var(--orange);
  margin: 0;
}
.contact-form .radio-group label:focus-within {
  box-shadow: 0 0 0 3px var(--orange-soft);
}
.contact-form .radio-group input[type="radio"]:checked + .radio-text {
  color: var(--orange-dark);
  font-weight: 600;
}
.contact-form .radio-group label:has(input:checked) {
  background: var(--orange-soft);
  border-color: var(--orange);
}

/* Submit + trust microcopy. */
.contact-form .form-submit-row { margin-top: var(--space-lg); }
.contact-form .form-submit-row .btn {
  width: 100%;
  padding: 1em 1.7em;
  font-size: 1rem;
}
.contact-form .trust-microcopy {
  margin: var(--space-sm) 0 0;
  text-align: center;
  font-size: 0.85rem;
  color: var(--muted);
}
.contact-form .trust-microcopy strong { color: var(--ink-mute); font-weight: 600; }

/* Contact card (right column) — sticky on desktop, static on mobile. */
.contact-card {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: var(--space-md);
  box-shadow: var(--shadow-card);
  position: sticky;
  top: calc(var(--header-h) + var(--space-sm));
}
.contact-card h3 {
  margin: 0 0 var(--space-sm);
  font-size: 1.15rem;
}
.contact-card .phone-block {
  display: block;
  text-decoration: none;
  color: var(--ink);
  padding: 0.75em 0;
  border-top: 1px solid var(--rule);
  transition: color var(--dur) var(--ease);
}
.contact-card .phone-block:first-of-type { border-top: 0; padding-top: 0; }
.contact-card .phone-block:hover { color: var(--orange-dark); }
.contact-card .phone-block .phone-loc {
  display: block;
  font-family: var(--font-display);
  font-size: 0.72rem;
  color: var(--orange-dark);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 700;
  margin-bottom: 0.2em;
}
.contact-card .phone-block .phone-num {
  display: block;
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
  line-height: 1.1;
}
.contact-card .email-block {
  display: block;
  text-decoration: none;
  color: var(--ink);
  padding: 0.75em 0;
  border-top: 1px solid var(--rule);
  font-family: var(--font-display);
  font-weight: 600;
  transition: color var(--dur) var(--ease);
  word-break: break-word;
}
.contact-card .email-block:hover { color: var(--orange-dark); }
.contact-card .email-block .email-label {
  display: block;
  font-family: var(--font-display);
  font-size: 0.72rem;
  color: var(--orange-dark);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 700;
  margin-bottom: 0.2em;
}
.contact-card .meta-block {
  padding: var(--space-sm) 0 0;
  border-top: 1px solid var(--rule);
  margin-top: var(--space-sm);
}
.contact-card .meta-label {
  font-family: var(--font-display);
  font-size: 0.72rem;
  color: var(--orange-dark);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 700;
  margin: 0 0 0.4em;
}
.contact-card .meta-block p,
.contact-card .meta-block ul {
  margin: 0;
  color: var(--ink-mute);
  font-size: 0.92rem;
  line-height: 1.5;
}
.contact-card .meta-block ul {
  list-style: none;
  padding: 0;
  columns: 2;
  column-gap: 1.2rem;
}
.contact-card .meta-block li {
  margin: 0.2em 0;
  break-inside: avoid;
}
.contact-card .meta-block li::before {
  content: '· ';
  color: var(--orange);
  margin-right: 0.1em;
}

/* ============================================================
   W3-P2b (2026-06-04): per-page visual fidelity — epoxy,
   heating-and-cooling, remodeling. CSS ported verbatim (token-
   normalized) from the mockup in-page <style> blocks named in
   each section header. CSP blocks inline <style>, so these
   chassis classes live here; the views reference them by name.
   ============================================================ */

/* ------------------------------------------------------------
   EPOXY — brand-video quote callout (C-1)
   The single most narrative-load-bearing element on /epoxy:
   orange top-hairline accent, oversized opening-quote glyph,
   --space-xl vertical rhythm, --canvas ground.
   Mockup: mockups/epoxy.html:441-446 + in-page styles ~80-133.
   ------------------------------------------------------------ */
.quote-callout {
  background: var(--canvas);
  padding: var(--space-xl) 0 var(--space-lg);
  position: relative;
}
.quote-callout::before {
  content: '';
  position: absolute;
  left: 50%;
  top: var(--space-md);
  width: 3.5rem;
  height: 1px;
  background: var(--orange);
  transform: translateX(-50%);
}
.quote-callout .quote-wrap {
  max-width: 56rem;
  margin: 0 auto;
  padding: 0 var(--space-md);
  text-align: center;
}
.quote-callout .lead-quote {
  border: 0;
  padding: 0;
  margin: 0 auto var(--space-md);
  max-width: 22ch;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 600;
  font-size: clamp(1.7rem, 4vw, 2.8rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.quote-callout .lead-quote::before {
  content: '“';
  display: block;
  font-family: var(--font-display);
  font-size: 4rem;
  line-height: 0.4;
  color: var(--orange);
  margin: 0.3em auto 0.2em;
  font-style: normal;
}
.quote-callout cite {
  display: block;
  font-style: normal;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
  font-weight: 600;
}
.quote-callout cite::before { content: ''; }

/* ------------------------------------------------------------
   EPOXY — 3-step process band (C-4)
   Larger decimal-leading-zero numerals (01/02/03) in a 5rem
   left gutter; matches the mini-split detail cadence pared down.
   Mockup: mockups/epoxy.html:585-598 + in-page styles ~302-334.
   ------------------------------------------------------------ */
.process-band {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-md);
  counter-reset: step;
  list-style: none;
  padding: 0;
  margin: 0;
  position: relative;
}
.process-band .process-step {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: var(--space-md) var(--space-md) var(--space-md) 5rem;
  position: relative;
  min-height: 8rem;
}
.process-band .process-step::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 1rem;
  top: 0.8rem;
  font-family: var(--font-display);
  font-size: 2.6rem;
  font-weight: 700;
  color: var(--orange);
  line-height: 1;
  letter-spacing: -0.02em;
}
.process-band .process-step h3 { margin: 0 0 0.3em; font-size: 1.1rem; }
.process-band .process-step p { margin: 0; font-size: 0.92rem; color: var(--muted); }

/* ------------------------------------------------------------
   HEATING & COOLING — "What we install" equipment grid (P1-4)
   Each tile leads with an .equip-illus gradient panel carrying
   a circular .glyph icon badge above the heading. Visual fidelity
   on the existing hardcoded grid; S4 wiring is a separate wave.
   Mockup: mockups/heating-and-cooling.html:419-445 + in-page
   styles ~91-127.
   ------------------------------------------------------------ */
.equipment-grid { list-style: none; padding: 0; margin: 0; }
.equip-illus {
  aspect-ratio: 4 / 3;
  background: var(--canvas-alt);
  border-radius: 3px;
  margin: 0 0 var(--space-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.4rem;
  color: var(--canvas);
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.equip-illus--heat-pump { background-image: linear-gradient(135deg, #2a2a2a 0%, #4a3c1a 100%); }
.equip-illus--furnace { background-image: linear-gradient(135deg, #0a0a0a 0%, #3a2a1a 100%); }
.equip-illus--mini-split { background-image: linear-gradient(135deg, #2a2a2a 0%, #5a4520 100%); }
.equip-illus--central-ac { background-image: linear-gradient(135deg, #1a1a1a 0%, #2a3a4a 100%); }
.equip-illus--hybrid { background-image: linear-gradient(135deg, #3a2a1a 0%, #2a2a2a 100%); }
.equip-illus .glyph {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  background: var(--orange);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  box-shadow: 0 0 0 6px rgba(232, 122, 0, 0.18);
}

/* ------------------------------------------------------------
   REMODELING — featured-testimonial section chassis (P2)
   Centers the H2 + intro via class instead of inline styles, so
   shared testimonial-section styling applies consistently.
   Mockup: mockups/remodeling.html:342-345 + in-page styles ~161-168.
   ------------------------------------------------------------ */
.testimonial-section h2 { text-align: center; margin-bottom: var(--space-md); width: fit-content; max-width: 30ch; margin-left: auto; margin-right: auto; }
.testimonial-section .testimonial-intro {
  text-align: center;
  color: var(--muted);
  margin: 0 auto var(--space-lg);
  max-width: 50ch;
}

/* ============================================================
   SUBSCRIPTION (MAINTENANCE PLAN) PRICING CARD (W3-P2c)
   Ported verbatim from mockup subscription.html in-page styles
   (19-206). The build previously reimplemented the whole card
   with inline styles, which structurally CANNOT carry three
   pseudo-element affordances: (1) the "The plan" ribbon over the
   card's top edge, (2) the circular orange check-badge on each
   feature bullet, and (3) the secondary-button ink-fill :hover
   invert. Restoring the class chassis brings all three back and
   removes the inline-style soup. Tokens only — no raw hex.
   ============================================================ */
.page-hero.subscription-hero {
  padding: var(--space-lg) 0 var(--space-xl);
  text-align: center;
}
.page-hero.subscription-hero .breadcrumb { text-align: left; }
.page-hero.subscription-hero h1 {
  max-width: 22ch;
  margin-left: auto;
  margin-right: auto;
}
.page-hero.subscription-hero p.lede {
  margin-left: auto;
  margin-right: auto;
}
.page-hero.subscription-hero .kicker { text-align: center; width: fit-content; max-width: 28ch; margin-left: auto; margin-right: auto; }

.pricing-wrap {
  display: flex;
  justify-content: center;
  margin-top: calc(-1 * var(--space-xl));
  position: relative;
  z-index: 2;
}
.pricing-card {
  background: white;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: var(--space-xl) var(--space-lg);
  max-width: 38rem;
  width: 100%;
  box-shadow: var(--shadow-lift);
  text-align: center;
  position: relative;
}
/* "The plan" ribbon straddling the top edge — restrained orange. */
.pricing-card::before {
  content: 'The plan';
  position: absolute;
  top: -0.85em;
  left: 50%;
  transform: translateX(-50%);
  background: var(--orange);
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.4em 1em;
  border-radius: 999px;
}
.price-headline {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--ink);
  font-size: clamp(3.2rem, 7.5vw, 5.2rem);
  line-height: 1;
  letter-spacing: -0.035em;
  margin: 0;
  display: inline-flex;
  align-items: baseline;
  gap: 0.15em;
  justify-content: center;
}
.price-headline .period {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1rem, 1.5vw, 1.15rem);
  color: var(--muted);
  letter-spacing: 0;
}
.price-sub {
  color: var(--muted);
  font-size: 0.95rem;
  margin: var(--space-xs) 0 var(--space-md);
  letter-spacing: 0.02em;
}
.price-sub strong {
  color: var(--orange-dark);
  font-weight: 600;
}
.pricing-features {
  list-style: none;
  padding: 0;
  margin: var(--space-md) auto;
  max-width: 28rem;
  text-align: left;
}
.pricing-features li {
  padding: 0.7em 0 0.7em 2rem;
  position: relative;
  border-bottom: 1px solid var(--rule);
  font-size: 1rem;
  color: var(--ink);
}
.pricing-features li:last-child { border-bottom: 0; }
/* Circular orange check-badge — the signature branded-checklist mark. */
.pricing-features li::before {
  content: '';
  position: absolute;
  left: 0.1em;
  top: 0.95em;
  width: 1.2rem;
  height: 1.2rem;
  border-radius: 50%;
  background: var(--orange-soft);
  border: 1.5px solid var(--orange);
}
.pricing-features li::after {
  content: '\2713';
  position: absolute;
  left: 0.36em;
  top: 0.85em;
  color: var(--orange-dark);
  font-weight: 700;
  font-family: var(--font-display);
  font-size: 0.85rem;
  line-height: 1.2;
}
.pricing-footnote {
  font-size: 0.82rem;
  color: var(--muted);
  margin: var(--space-md) auto 0;
  max-width: 36ch;
  line-height: 1.5;
}
.pricing-actions {
  display: flex;
  gap: var(--space-sm);
  justify-content: center;
  flex-wrap: wrap;
  margin-top: var(--space-md);
}
/* Secondary button needs an ink-friendly variant on the white card,
   plus the :hover invert that inline styles could never express. */
.pricing-card .btn--secondary {
  color: var(--ink);
  border-color: var(--ink);
  background: transparent;
}
.pricing-card .btn--secondary:hover {
  background: var(--ink);
  color: var(--canvas);
}
.long-description { max-width: 64ch; }
.long-description p { max-width: none; }
@media (max-width: 600px) {
  .pricing-card { padding: var(--space-lg) var(--space-md); }
  .pricing-wrap { margin-top: calc(-1 * var(--space-lg)); }
}

/* ============================================================
   SERVICES INDEX — catalog + category jumper (W3-P2c)
   Ported verbatim from mockup services-index.html in-page styles
   (12-112). The build rendered the catalog sections, count chips,
   jump-chips, and intro lead entirely with inline style="" — so
   the jump-chips had NO hover affordance (the mockup's
   border→orange / orange-soft fill). These classes restore the
   hover transition and de-brittle the markup. Single accent only
   (orange) — no per-category color system; the category signal is
   heading + hairline + spacing.
   ============================================================ */
.catalog-section { padding: var(--space-lg) 0; }
.catalog-section:first-of-type { padding-top: var(--space-xl); }
.catalog-section:last-of-type { padding-bottom: var(--space-xl); }
.catalog-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-sm);
  border-bottom: 1px solid var(--rule);
  padding-bottom: var(--space-sm);
  margin-bottom: var(--space-md);
  flex-wrap: wrap;
}
.catalog-head h2 { margin: 0; }
.catalog-head .catalog-count {
  font-family: var(--font-display);
  font-size: 0.82rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  flex-shrink: 0;
}
.catalog-head .catalog-count strong {
  color: var(--orange-dark);
  font-weight: 700;
}
.catalog-desc {
  color: var(--muted);
  margin: 0 0 var(--space-md);
  max-width: 56ch;
}
/* Intro lead under the page hero — short, centered, calmer than .lede. */
.services-lead {
  text-align: center;
  color: var(--ink-mute);
  margin: 0 auto;
  max-width: 56ch;
  font-size: 1.05rem;
}
/* In-page anchor jumper — skip-to-trade chips between intro + catalog. */
.category-jump {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  justify-content: center;
  margin-top: var(--space-md);
}
.category-jump a {
  display: inline-block;
  padding: 0.42em 1em;
  background: white;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.category-jump a:hover {
  border-color: var(--orange);
  background: var(--orange-soft);
  color: var(--orange-dark);
}
.category-jump a .count {
  color: var(--muted);
  font-weight: 500;
  margin-left: 0.3em;
}

/* ============================================================
   PRIVACY + TERMS — long-form legal-disclosure surfaces.
   Ported from the canonical mockup privacy.html:22-126 (its inline
   <style> block) — these classes were USED in views/privacy.ejs but
   never lived in mhs.css, so in production the TL;DR card and policy
   column rendered as bare full-width divs and every [data-editable]
   policy block drew its dashed outline at full container width.
   Two unique elements: the TL;DR summary card and the comfortable
   centered reading column. Raw mockup values mapped to design tokens.
   ============================================================ */

/* TL;DR summary card — sits under the page hero so any visitor sees
   the 5 promises before the legal-style prose. Radical-simplicity
   instinct on a legal-disclosure surface. */
.tldr-card {
  background: #fff;
  border: 1px solid var(--rule);
  border-left: 4px solid var(--orange);
  border-radius: var(--radius-md);
  padding: var(--space-lg);
  box-shadow: var(--shadow-card);
  margin: 0 auto;
  max-width: 46rem;
}
.tldr-card .tldr-kicker {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--orange-dark);
  margin: 0 0 var(--space-sm);
}
.tldr-card h2 {
  margin: 0 0 var(--space-sm);
  font-size: clamp(1.4rem, 2.5vw, 1.8rem);
}
.tldr-card ul {
  list-style: none;
  padding: 0;
  margin: 0;
}
.tldr-card ul li {
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  gap: var(--space-sm);
  padding: 0.65em 0;
  border-bottom: 1px solid var(--rule);
  margin: 0;
  line-height: 1.5;
}
.tldr-card ul li:last-child { border-bottom: 0; padding-bottom: 0; }
.tldr-card ul li::marker { content: ''; }
.tldr-card .tldr-label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--orange-dark);
  padding-top: 0.18em;
}
.tldr-card .tldr-value {
  color: var(--ink);
  font-size: 0.98rem;
}
@media (max-width: 560px) {
  .tldr-card { padding: var(--space-md); }
  .tldr-card ul li {
    grid-template-columns: 1fr;
    gap: 0.15em;
    padding: 0.85em 0;
  }
}

/* Detailed policy / legal-body column — comfortable reading measure.
   max-width: 42rem; margin: 0 auto gives the centered readable measure
   the audit calls for, so the policy text reads at a tidy width AND the
   [data-editable] outlines hug the text rather than the 56rem container.
   Also reused by views/terms.ejs for wrapper parity. */
.policy-prose { max-width: 42rem; margin: 0 auto; }
.policy-prose .policy-intro {
  color: var(--ink-mute);
  font-size: 1.08rem;
  margin: 0 0 var(--space-lg);
  max-width: none;
}
.policy-section {
  padding: var(--space-md) 0;
  border-bottom: 1px solid var(--rule);
}
.policy-section:last-of-type { border-bottom: 0; }
.policy-section h2 {
  font-size: clamp(1.25rem, 2.2vw, 1.55rem);
  margin: 0 0 var(--space-sm);
  scroll-margin-top: calc(var(--header-h) + 1rem);
}
/* max-width:none defeats the global p{max-width:38rem} default so policy
   paragraphs fill the 42rem prose column instead of wrapping narrower than
   their editable box (the "outline wider than text" leak the audit flagged). */
.policy-section p {
  max-width: none;
  color: var(--ink-soft);
  margin: 0 0 0.85em;
  line-height: 1.65;
}
.policy-section p:last-child { margin-bottom: 0; }
.policy-section ul {
  margin: 0.4em 0 0.9em;
  color: var(--ink-soft);
}
.policy-section ul li { margin: 0.3em 0; line-height: 1.5; }

/* terms.ejs renders its whole body as one ctMd block straight into
   .policy-prose (no .policy-section wrappers), so reset the global p cap
   there too — same reason as .policy-section p above. */
.policy-prose > [data-editable] p,
.policy-prose > [data-editable] ul { max-width: none; }
.policy-prose > [data-editable] p { color: var(--ink-soft); line-height: 1.65; }

/* "Last updated" line — small, muted, hairline-topped, centered at the
   foot of the prose column. */
.last-updated {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--rule);
  font-size: 0.85rem;
  color: var(--muted);
  text-align: center;
}
