/* ==========================================================================
   site.css — per-site layout & components, built FROM tokens.

   band-rhythm (design-rules §7; brief §5): alternating full-width bands —
   light ground (bg) ↔ raised surface (surface) ↔ the one dark band (band),
   never two identical grounds adjacent. Every band opens with the same
   object, the painted seam (brief §5.1 rule 2) — one geometry, two jobs:
   the hero's own closing gesture (§8.2), flattened to a static rule on
   every section below it.
   ========================================================================== */

/* --- Layout primitives ---------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--layout-container);
  margin-inline: auto;
  padding-inline: var(--layout-gutter);
}

.section {
  padding-block: var(--section-gap);
}

.section--surface {
  background-color: var(--color-surface);
}

/* The one dark band — brief R3: exactly one element carries --color-band
   (the reviews section), plus the preview expiry bar (skeleton chrome,
   the one named exception). */
.section--band {
  background-color: var(--color-band);
  color: var(--color-band-ink);
}

/* On the dark band, the light-ground colour assumptions this site otherwise
   makes everywhere else don't hold, so the accent-carrying pieces of the
   section-head device swap to their already-brief-specified on-band
   siblings (tokens.css §3.2's own accent-onband/focus-on-band roles) —
   the same substitution pattern the brief itself applies to the focus ring
   on a dark ground, extended here to the seam and eyebrow that open every
   band, which read at 2.4:1 in barn-red against the dark ink band (below
   the 3:1 WCAG 1.4.11 floor for a meaningful graphical device) and are
   fully AA at 12.17:1 in --color-accent-onband. */
.section--band .section__head {
  border-block-start-color: var(--color-accent-onband);
}

.section--band .section__eyebrow {
  color: var(--color-accent-onband);
}

.section--band .section__title {
  color: var(--color-band-ink);
}

.section--band :focus-visible {
  outline-color: var(--color-focus-on-band);
}

.measure {
  max-width: var(--layout-measure);
}

/* --- Section head — the painted seam, brief §5.1 rule 2 / §5.4 -----------
   "Every band opens with the same object: the painted seam." Seam → eyebrow
   12px, eyebrow → h1/h2 12px (brief §5.5) — every section head, hero
   included. The seam is 3px at every width by construction; nothing yields
   it (brief §5.4). */

/* section__head wraps the seam's own two possible children — the eyebrow
   and the h2 — so the 12px seam-to-first-child and 12px-between-children
   gaps hold whether both are present (every section that has copy for
   both) or the wrapper carries only one (see the FAQ note below: copy.md
   supplies no distinct eyebrow text for any non-hero section, so §II-§V
   and §VII ship seam + h2 only, never an invented eyebrow phrase). */
.section__head {
  border-block-start: var(--rule-seam) solid var(--color-accent);
  padding-block-start: var(--space-xs);
}

.section__head > * + * {
  margin-block-start: var(--space-xs);
}

.section__eyebrow {
  margin: 0;
  font-family: var(--font-body-strong);
  font-weight: var(--font-weight-body-strong);
  font-size: var(--text-eyebrow);
  line-height: var(--leading-caps);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--color-ink-muted);
  white-space: nowrap;
}

/* Below 320px of available width the seam never yields (it has no larger
   state to shrink from — brief §5.2's yield order) — the eyebrow's own
   tracking is what gives, rather than wrapping mid-tracking. */
@media (max-width: 20em) {
  .section__eyebrow {
    /* @allow-literal: brief §5.4's exact yield value below 320px */
    letter-spacing: 0.08em;
  }
}

.section__title {
  margin: 0;
  font-size: var(--text-h2);
  color: var(--color-ink);
}

/* Generic "section head → content" gap — 24px, every section (brief §5.5).
   Applied to whatever the first content element after the head wrapper is,
   whether the wrapper carried an eyebrow+h2 pair or (FAQ; copy.md supplies
   no heading text for §VI either) only the bare seam. */
.section__head + * {
  margin-block-start: var(--space-md);
}

/* --- Header & navigation ---------------------------------------------------
   Brief §5.6: header is 60px at every width — padding-block 8px
   (--space-2xs) top and bottom around the 44px tel: CTA, the row's tallest
   element (8 + 44 + 8 = 60). Sticky beneath the expiry bar (css/preview.css,
   this site's own override — brief §5.6's call-first requirement). */

.site-header {
  position: relative;
  z-index: var(--z-header);
  padding-block: var(--space-2xs);
  border-bottom: var(--border-hairline) var(--border-style) var(--color-border);
  background-color: var(--color-bg);
}

.site-header__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.site-header__brand {
  font-family: var(--font-display);
  font-weight: var(--font-weight-display);
  font-size: var(--text-lead);
  color: var(--color-ink);
  text-decoration: none;
  letter-spacing: var(--tracking-display);
}

.nav-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs) var(--space-xs);
  /* The nav-toggle's only shape is this hairline, so it is a CONTROL
     boundary (WCAG 1.4.11, >= 3:1), not a decorative one. */
  border: var(--border-hairline) var(--border-style) var(--color-border-strong);
  border-radius: var(--radius-none);
  font-family: var(--font-body-strong);
  font-size: var(--text-small);
  font-weight: var(--font-weight-body-strong);
  color: var(--color-ink);
}

.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav__link {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  font-family: var(--font-body-strong);
  font-size: var(--text-small);
  font-weight: var(--font-weight-body-strong);
  color: var(--color-ink);
}

.site-nav__link:hover,
.site-nav__link:focus-visible {
  text-decoration: underline;
  text-underline-offset: var(--space-3xs);
}

/* QA r3 FIX perf/cls (house pattern, kept from the skeleton): closed is the
   plain CSS default below 48em, un-gated by [data-nav-ready], so the header
   never collapses AFTER first paint. JS-off visitors get the nav back via
   the <noscript> stylesheet override in @shared:head-boilerplate. */
.site-nav {
  display: none;
}

[data-nav-ready] .site-nav[data-nav-open='true'] {
  display: block;
  flex-basis: 100%;
}

@media (min-width: 48em) {
  .site-nav {
    display: block;
  }

  [data-nav-ready] .nav-toggle {
    display: none;
  }
}

/* --- Buttons ---------------------------------------------------------------
   Two roles. Radius is --radius-none everywhere (brief §3.2) — the only
   radius on this site. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  padding: var(--space-xs) var(--space-md);
  border: var(--border-hairline) var(--border-style) transparent;
  border-radius: var(--radius-none);
  font-family: var(--font-body-strong);
  font-weight: var(--font-weight-body-strong);
  font-size: var(--text-small);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  line-height: var(--leading-snug);
  text-align: center;
  text-decoration: none;
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}

.btn--primary {
  background-color: var(--color-accent);
  color: var(--color-accent-ink);
}

.btn--quiet {
  border-color: var(--color-border-strong);
  color: var(--color-ink);
}

/* --- Hero — §I hero-call ----------------------------------------------------
   DOM order (brief §5.3): section rule -> eyebrow -> h1 -> primary CTA ->
   field -> lead -> facts. Never a reveal target — it is the LCP element. */

.hero {
  padding-block-start: var(--hero-pad-top);
  padding-block-end: var(--section-gap);
}

.hero h1 {
  margin-block-start: var(--space-xs);
  margin-block-end: 0;
  font-size: var(--text-hero);
  max-width: var(--h1-max);
  color: var(--color-ink);
}

.hero__cta {
  display: flex;
  width: 100%;
  margin-block-start: var(--space-sm);
}

@media (min-width: 48em) {
  .hero__cta {
    display: inline-flex;
    width: auto;
    min-width: var(--hero-cta-min-width);
  }
}

/* The hero field — image slot 1, the LCP element. Full-bleed to the
   viewport edge below 48rem (breaking out of .container's own gutter);
   contained to --hero-field-max, centred, at 48rem and up (brief §5.1
   rule 3). aspect-ratio is CONSTANT at every width (brief §5.2). */
.hero__field-wrap {
  position: relative;
  margin-block-start: var(--space-md);
  aspect-ratio: var(--hero-field-ratio);
  overflow: hidden;
  /* @allow-literal: full-bleed breakout, structural geometry not a design value */
  width: 100vw;
  /* @allow-literal: full-bleed breakout, structural geometry not a design value */
  margin-inline-start: calc(50% - 50vw);
}

@media (min-width: 48em) {
  .hero__field-wrap {
    width: 100%;
    max-width: var(--hero-field-max);
    margin-inline: auto;
  }
}

.hero__field-wrap picture,
.hero__field-wrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The signature move — "the seam closes" (brief §8.2). An aria-hidden
   broom silhouette completes one sweep down the illustration's own painted
   seam (which sits at the exact horizontal centre of the frame, brief
   §7.3 Block A clause 3) on load, then holds its final resting position
   for the rest of the visit. */
.hero__broom {
  position: absolute;
  inset-block-end: 0;
  /* Just clear of centre, into the cleared (right) half — the cluttered
     half already carries its own dense geometry down to the floor, and a
     broom leaning into it reads as one more piece of clutter rather than
     as the tool that cleared the other side. */
  inset-inline-start: 54%;
  height: 28%;
  transform-origin: bottom center;
  animation: hero-seam-closes var(--duration-slow) var(--ease-out) 240ms both,
             hero-broom-sway 31s var(--ease-out) 760ms infinite;
}

@keyframes hero-seam-closes {
  0% {
    /* @allow-literal: the sweep's own start offset, brief §8.2's "traces the seam from top to bottom" */
    transform: translateX(-50%) translateY(-120%) rotate(5deg);
    opacity: 0;
  }
  100% {
    transform: translateX(-50%) translateY(0) rotate(5deg);
    opacity: 1;
  }
}

@keyframes hero-broom-sway {
  0%, 100% { transform: translateX(-50%) rotate(5deg); }
  50%      { transform: translateX(-50%) rotate(3.5deg); }
}

/* Ambient satellite motion — the hero field only (brief §8.3). Three loops,
   no two durations shared (19/23/31s, pairwise coprime), so the set never
   re-synchronises. */
.hero__dust {
  position: absolute;
  border-radius: 50%;
  background-color: var(--color-accent-ink);
  opacity: 0.4;
}

.hero__dust--1 {
  inset-block-start: 28%;
  inset-inline-start: 62%;
  /* @allow-literal: dust mote size, brief §8.3 bespoke ambient device */
  width: 5px;
  /* @allow-literal: dust mote size, brief §8.3 bespoke ambient device */
  height: 5px;
  animation: hero-dust-drift 19s var(--ease-out) infinite;
}

.hero__dust--2 {
  inset-block-start: 46%;
  inset-inline-start: 40%;
  /* @allow-literal: dust mote size, brief §8.3 bespoke ambient device */
  width: 4px;
  /* @allow-literal: dust mote size, brief §8.3 bespoke ambient device */
  height: 4px;
  animation: hero-dust-drift 23s var(--ease-out) infinite;
  animation-delay: -11s;
}

@keyframes hero-dust-drift {
  0%   { transform: translate(0, 0); opacity: 0.4; }
  33%  {
    /* @allow-literal: brief §8.3's exact dust-mote motion value */
    transform: translate(7px, -9px);
    opacity: 0.6;
  }
  66%  {
    /* @allow-literal: brief §8.3's exact dust-mote motion value */
    transform: translate(-4px, -15px);
    opacity: 0.75;
  }
  100% { transform: translate(0, 0); opacity: 0.4; }
}

@media (prefers-reduced-motion: reduce) {
  .hero__broom {
    animation: none;
    transform: translateX(-50%) rotate(5deg);
    opacity: 1;
  }

  .hero__dust {
    animation: none;
    transform: translate(0, 0);
    opacity: 0.4;
  }
}

.hero__lead {
  margin-block-start: var(--space-md);
  font-size: var(--text-lead);
  line-height: var(--leading-snug);
  color: var(--color-ink);
}

.hero__facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm) var(--space-md);
  margin: 0;
  margin-block-start: var(--space-sm);
  padding: 0;
  padding-block-start: var(--space-sm);
  border-block-start: var(--border-hairline) var(--border-style) var(--color-border);
  list-style: none;
  font-size: var(--text-small);
  color: var(--color-ink-muted);
}

.hero__facts li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
}

.hero__facts svg {
  flex: none;
  fill: var(--color-accent);
}

/* --- Services — §II, a hairline index, never a card grid ------------------ */

.service-list {
  margin: 0;
  /* the largest intra-section gap, 40px (brief §5.5) — before the rows begin */
  margin-block-start: var(--space-lg);
  padding: 0;
  list-style: none;
  border-block-start: var(--border-hairline) var(--border-style) var(--color-border);
}

.service-list li {
  padding-block: var(--space-sm);
  border-block-end: var(--border-hairline) var(--border-style) var(--color-border);
  font-size: var(--text-body);
  color: var(--color-ink);
}

/* The hairline yields entirely below 240px of content width (brief §5.2's
   yield order) — every row is still fully readable without the divider. */
@media (max-width: 15em) {
  .service-list {
    border-block-start: 0;
  }

  .service-list li {
    border-block-end: 0;
  }
}

/* --- Section-foot figures — slots 2, 3, 4 (brief §7.2) ---------------------
   A single-column supporting accent, contained rather than full-bleed
   (unlike the hero field, which is the one full-bleed device on the site). */

.section-figure {
  margin-block-start: var(--space-lg);
  max-width: var(--figure-max-width);
}

.section-figure img {
  width: 100%;
  height: auto;
}

/* --- Pricing — §III --------------------------------------------------------- */

.pricing__body p + p {
  margin-block-start: var(--space-sm);
}

/* --- Reviews — §V, the one dark band ---------------------------------------- */

.reviews__stat {
  margin: 0;
  margin-block-start: var(--space-sm);
  font-family: var(--font-body-strong);
  font-weight: var(--font-weight-body-strong);
}

.review-list {
  display: grid;
  gap: var(--space-lg);
  margin: 0;
  margin-block-start: var(--space-lg);
  padding: 0;
  list-style: none;
}

.review {
  margin: 0;
}

.review__quote {
  margin: 0;
  font-size: var(--text-body);
  line-height: var(--leading-body);
}

.review__attribution {
  display: block;
  margin-block-start: var(--space-xs);
  font-family: var(--font-body-strong);
  font-weight: var(--font-weight-body-strong);
  font-size: var(--text-small);
  font-style: normal;
  color: var(--color-accent-onband);
}

/* --- FAQ — §VI, native disclosure, no numeral ------------------------------- */

.faq-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.faq-list li + li {
  margin-block-start: var(--space-lg);
}

.faq-item {
  border-block-start: var(--border-hairline) var(--border-style) var(--color-border);
  padding-block-start: var(--space-sm);
}

.faq-item summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-sm);
  font-family: var(--font-body-strong);
  font-weight: var(--font-weight-body-strong);
  font-size: var(--text-body);
  color: var(--color-ink);
  cursor: pointer;
  list-style: none;
}

.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary::after {
  content: '+';
  flex: none;
  color: var(--color-accent);
  font-family: var(--font-body-strong);
  font-weight: var(--font-weight-body-strong);
}

.faq-item[open] summary::after {
  content: '\2212';
}

.faq-item p {
  margin: 0;
  margin-block-start: var(--space-sm);
  color: var(--color-ink-muted);
}

/* --- Form -------------------------------------------------------------------
   One form per site. name / phone / message only (brief §6.9, R10). */

.form {
  display: grid;
  gap: var(--space-md);
  margin-block-start: var(--space-md);
  max-width: var(--layout-measure);
}

.field {
  display: grid;
  gap: var(--space-3xs);
}

.field__label {
  font-family: var(--font-body-strong);
  font-size: var(--text-small);
  font-weight: var(--font-weight-body-strong);
  color: var(--color-ink);
}

.field__control {
  width: 100%;
  min-height: var(--layout-tap-min);
  padding: var(--space-2xs) var(--space-xs);
  background-color: var(--color-surface);
  color: var(--color-ink);
  /* 1.4.11-bound control edge — never the decorative --color-border. */
  border: var(--border-hairline) var(--border-style) var(--color-border-strong);
  border-radius: var(--radius-none);
  font-family: var(--font-body);
}

textarea.field__control {
  min-height: var(--space-3xl);
  resize: vertical;
}

.field__hint {
  font-size: var(--text-small);
  color: var(--color-ink-muted);
}

.form__trap {
  position: absolute;
  /* @allow-literal: off-canvas parking position, not a design value */
  left: -9999px;
  opacity: 0;
  pointer-events: none;
}

.form__status {
  font-size: var(--text-small);
  color: var(--color-ink-muted);
}

.form__status[data-state='error'] {
  color: var(--color-ink);
  font-weight: var(--font-weight-body-strong);
}

/* --- Footer ------------------------------------------------------------------ */

.site-footer {
  padding-block: var(--space-xl);
  border-top: var(--border-hairline) var(--border-style) var(--color-border);
  font-size: var(--text-small);
  color: var(--color-ink-muted);
}

.site-footer a {
  color: var(--color-ink);
  text-underline-offset: var(--space-3xs);
}

.site-footer__nap {
  font-style: normal;
  color: var(--color-ink);
}

.site-footer__nap strong {
  font-family: var(--font-display);
  font-weight: var(--font-weight-display);
  font-size: var(--text-lead);
}

/* --- thanks.html — brief §5.6, "space-sm" (16px) head → tel control ------- */

.section__head + .thanks__cta {
  margin-block-start: var(--space-sm);
}
