/* ==========================================================================
   site.css — bonneville-lawn-care-idaho-falls-id, built FROM tokens.
   Tokens only (house-tech-spec §3), plus the two house escape hatches
   (breakpoint conditions, `@allow-literal:` comments).

   Archetype: band-rhythm (brief §4). Signature move: the living-hero
   (field/atmosphere/plate) + the season-strip's current-month tint (§7).

   Contact form's field labels/hint/honeypot/status strings are
   Builder-supplied (copy.md §10 gives only heading/intro/two CTA labels) —
   flagged in README.md; see index.html's contact-section comment.
   ========================================================================== */

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

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

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

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

/* A section that sits on the local-character band image (trust-strip) needs
   its own stacking context so the low-opacity image + scrim sit below its
   text without a second element. */
.section--band {
  position: relative;
  isolation: isolate;
}

/* --- Header & navigation ---------------------------------------------------
   Brief §4.1: tel: visible at 375 without opening the menu; height fixed at
   56px+1px at every breakpoint. tel: sits outside the collapsible nav; only
   the 4 anchor links collapse. Collapse threshold is 64em, not the house
   default 48em — at 48em brand+tel:+4 links do not fit one line without
   wrapping, which the fixed-height rule forbids. Below 64em the nav opens as
   an absolutely-positioned overlay panel, so it never changes header height. */

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

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

.site-header__brand {
  overflow: hidden;
  flex-shrink: 1;
  min-width: 0;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: var(--font-display);
  font-size: var(--text-small);
  font-weight: var(--font-weight-display);
  text-decoration: none;
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
}

.site-header__phone {
  flex-shrink: 0;
  white-space: nowrap;
  font-size: var(--text-small);
  font-weight: var(--font-weight-body-strong);
  color: var(--color-accent);
  text-decoration: none;
}

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

.nav-toggle {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs) var(--space-xs);
  border: var(--border-hairline) var(--border-style) var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--text-small);
  font-weight: var(--font-weight-body-strong);
  background-color: var(--color-surface);
}

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

.site-nav__link {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  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);
}

/* Panel positioning is UNCONDITIONAL (not gated behind [data-nav-ready]):
   gating it meant the nav sat in normal static flow for the instant between
   first paint and script execution, at full multi-line height — a measured
   CLS 0.10 against the ≈0 budget (CDP layout-shift trace), the nav
   collapsing OUT of flow once JS ran. Making out-of-flow the default state
   removes the shift: a JS-off visitor sees the nav as an always-visible
   absolute panel (readable, clickable, never dead) rather than a plain
   inline list — one nicety traded for the harder budget. Only OPEN/CLOSED
   needs JS and stays gated behind data-nav-ready. */
/* Right-anchored, content-width — not full-bleed. The hero plate is
   left-aligned (brief §2), so a narrow dropdown clears the eyebrow/H1/CTA a
   JS-off visitor needs to read, where a full-width bar would sit on them. */
.site-nav {
  position: absolute;
  inset-block-start: 100%;
  inset-inline-end: var(--layout-gutter);
  inline-size: max-content;
  max-inline-size: var(--nav-panel-max-width);
  z-index: var(--z-nav-panel);
  background-color: var(--color-bg);
  border: var(--border-hairline) var(--border-style) var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: var(--space-md);
}

[data-nav-ready] .site-nav[data-nav-open='false'] {
  display: none;
}

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

.site-nav__list {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-sm);
}

@media (min-width: 64em) {
  .site-nav {
    position: static;
    display: block;
    background-color: transparent;
    border-bottom: 0;
    box-shadow: var(--shadow-none);
    padding: 0;
  }

  .site-nav__list {
    flex-direction: row;
    align-items: center;
  }

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

  .site-header__brand {
    font-size: var(--text-h3);
  }
}

/* --- Buttons ---------------------------------------------------------------- */

.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-sm);
  font-weight: var(--font-weight-body-strong);
  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--primary:hover,
.btn--primary:focus-visible {
  background-color: var(--color-ink);
}

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

.btn--quiet:hover,
.btn--quiet:focus-visible {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

/* --- Section heads -----------------------------------------------------
   House pattern: eyebrow (small, wide-tracked, accent) + h2. Reused across
   every band below the hero. */

.section-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  margin-block-end: var(--space-lg);
}

.eyebrow {
  font-size: var(--text-eyebrow);
  font-weight: var(--font-weight-body-strong);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-accent);
}

.section-head h2 {
  font-size: var(--text-h2);
  color: var(--color-ink);
}

/* ==========================================================================
   HERO — the living-hero signature move (brief §1/§7). Three stacked layers:
   field (the LCP image, absolute, out of flow) < atmosphere (two radial
   gradients + the leaf/seed satellites, brief §2/§7) < plate (opaque
   --color-bg card carrying eyebrow/h1/CTA — every contrast pair in brief §2's
   table is measured against THIS flat surface, never against the photo).
   ========================================================================== */

.hero {
  position: relative;
  isolation: isolate;
  padding-block-end: var(--section-gap);
}

.hero__field {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 0;
  block-size: var(--hero-field-height);
  overflow: clip;
  z-index: var(--z-base);
}

.hero__field picture,
.hero__field img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

.hero__field img {
  object-fit: cover;
  object-position: center top;
}

/* Brief §2's gradient-vs-flat-token measurement: both radials contribute 0
   additional alpha wherever the plate or the field-chip sit, because both
   sit on their own opaque surfaces. No text is ever painted directly on
   this layer. */
.hero__atmosphere {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 0;
  block-size: var(--hero-field-height);
  z-index: var(--z-atmosphere);
  pointer-events: none;
  background-image: var(--hero-gradient-clay), var(--hero-gradient-sage);
}

/* The two leaf marks + two seed motes (brief §7/§8, ref-001's physics only).
   Independent, non-synchronised drift: each keyframe is scaled by a
   different multiplier of --duration-slow, so no two loops share a period. */
.hero__satellite {
  position: absolute;
  fill: var(--color-sage);
  opacity: 0.55;
  animation: hero-drift var(--duration-slow) var(--ease-in-out) infinite alternate;
}

.hero__satellite--leaf-1 {
  inset-block-start: 12%;
  inset-inline-end: 8%;
  inline-size: var(--space-xl);
  animation-duration: calc(var(--duration-slow) * 11);
}

.hero__satellite--leaf-2 {
  inset-block-start: 34%;
  inset-inline-end: 20%;
  inline-size: var(--space-lg);
  animation-duration: calc(var(--duration-slow) * 8);
  animation-direction: alternate-reverse;
}

.hero__satellite--seed-1 {
  inset-block-start: 22%;
  inset-inline-end: 30%;
  inline-size: var(--space-sm);
  animation-duration: calc(var(--duration-slow) * 13);
}

.hero__satellite--seed-2 {
  inset-block-start: 6%;
  inset-inline-end: 42%;
  inline-size: var(--space-xs);
  animation-duration: calc(var(--duration-slow) * 9);
  animation-direction: alternate-reverse;
}

@keyframes hero-drift {
  from { transform: translateY(0) rotate(0deg); }
  /* @allow-literal: keyframe drift distance is motion geometry, not a token-scale size */
  to   { transform: translateY(-0.6em) rotate(8deg); }
}

.hero__inner {
  position: relative;
  z-index: var(--z-plate);
  display: flow-root;
  width: 100%;
  max-width: var(--layout-container);
  margin-inline: auto;
}

/* THE PLATE. Opaque, always — brief §2's contrast table is measured against
   --color-bg, and a translucent plate would turn every flat pair there into
   an unmeasured gradient pair. */
.hero__plate {
  background-color: var(--color-bg);
  max-width: var(--hero-plate-width);
  padding: var(--space-md);
  margin-block-start: var(--space-lg);
  border-inline-start: var(--border-thick) var(--border-style) var(--color-accent);
  border-radius: var(--radius-md);
}

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

.hero h1 {
  max-width: var(--hero-h1-max-mobile);
  font-size: var(--text-hero);
}

.hero__cta {
  margin-block-start: var(--space-md);
}

/* THE FIELD CHIP — the season-strip teaser (brief §2 hero row). Opaque
   sage-tint surface, insulated from the atmosphere layer entirely (brief §2:
   "a chip on a solid colour is not text over a gradient in the first
   place"). */
.hero__field-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  margin-block-start: var(--space-md);
  padding: var(--space-xs) var(--space-md);
  background-color: var(--color-sage-tint);
  color: var(--color-ink);
  font-size: var(--text-small);
  font-weight: var(--font-weight-body-strong);
  text-decoration: none;
  border-radius: var(--radius-pill);
}

.hero__field-chip:hover,
.hero__field-chip:focus-visible {
  color: var(--color-accent);
}

@media (min-width: 48em) {
  .hero__field,
  .hero__atmosphere {
    block-size: var(--hero-field-height-md);
  }

  .hero__plate {
    padding: var(--space-lg);
    margin-block-start: var(--space-2xl);
  }

  .hero h1 {
    max-width: var(--hero-h1-max-desktop);
  }
}

/* --- SERVICES [LOAD-BEARING] — 5 rows, CSS-only material-tint swatch per
   row (brief §1 ref-008: repeating-linear-gradient hatch, never an image). --- */

.services-list {
  display: grid;
  gap: var(--space-lg);
  margin-block-start: var(--space-lg);
  counter-reset: service;
}

.service-row {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: var(--space-md);
  padding-block-end: var(--space-lg);
  border-bottom: var(--border-hairline) var(--border-style) var(--color-border);
}

.service-row:last-child {
  border-bottom: 0;
  padding-block-end: 0;
}

.service-row__swatch {
  inline-size: var(--space-xl);
  block-size: var(--space-xl);
  border-radius: var(--radius-lg);
  background-color: var(--color-sage-tint);
  background-image: repeating-linear-gradient(
    135deg,
    var(--service-tint) 0 var(--space-3xs),
    transparent var(--space-3xs) var(--space-2xs)
  );
}

.service-row:nth-of-type(1) .service-row__swatch { --service-tint: rgb(177 80 47 / 0.5); }
.service-row:nth-of-type(2) .service-row__swatch { --service-tint: rgb(107 127 94 / 0.55); }
.service-row:nth-of-type(3) .service-row__swatch { --service-tint: rgb(177 80 47 / 0.35); }
.service-row:nth-of-type(4) .service-row__swatch { --service-tint: rgb(107 127 94 / 0.35); }
.service-row:nth-of-type(5) .service-row__swatch { --service-tint: rgb(177 80 47 / 0.65); }

.service-row__name {
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--font-weight-display);
  color: var(--color-ink);
}

.service-row__desc {
  margin-block-start: var(--space-3xs);
  color: var(--color-ink-muted);
}

/* --- SEASON-STRIP — signature device (brief §4/§7). Four cards, one shared
   macro texture tinted per card; the card matching today's month is the only
   one whose sage-tint fill animates in (main.js initSeasonStrip()). Every
   card renders full/static/equal weight with JS off or reduced motion. --- */

.season-grid {
  display: grid;
  gap: var(--space-md);
  margin-block-start: var(--space-lg);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--season-card-min)), 1fr));
}

.season-card {
  position: relative;
  overflow: clip;
  padding: var(--space-md);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  border: var(--border-hairline) var(--border-style) var(--color-border);
}

.season-card__texture {
  position: absolute;
  inset: 0;
  z-index: var(--z-base);
  opacity: 0.16;
}

.season-card__texture img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.season-card__body {
  position: relative;
  z-index: var(--z-atmosphere);
}

.season-card__window {
  display: block;
  font-size: var(--text-eyebrow);
  font-weight: var(--font-weight-body-strong);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-accent);
}

.season-card__heading {
  margin-block-start: var(--space-2xs);
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--font-weight-display);
  color: var(--color-ink);
}

.season-card__desc {
  margin-block-start: var(--space-2xs);
  color: var(--color-ink-muted);
}

/* Static base state (no JS, or reduced motion off-loop): every card equal.
   The active card's sage-tint fill is a background-colour transition sitting
   BELOW the texture layer, never a size/position change (native UX
   integrity, house-tech-spec §8 — nothing shifts). */
.season-card {
  background-color: var(--color-surface);
  transition: background-color var(--duration-base) var(--ease-out);
}

.season-card.is-active {
  background-color: var(--color-sage-tint);
  border-color: var(--color-sage);
}

/* accent-on-sage-tint measures 4.19:1 (not one of brief §2's pairs) — under
   the 4.5:1 floor. ink-on-sage-tint is measured safe (12.71:1). */
.season-card.is-active .season-card__window {
  color: var(--color-ink);
}

@media (prefers-reduced-motion: reduce) {
  .season-card {
    transition: none;
  }
}

/* ==========================================================================
   TRUST-STRIP — two V-tier facts, on the low-opacity local-character band
   image (imagery slot 5, brief §6/§8).
   ========================================================================== */

.trust-band__image {
  position: absolute;
  inset: 0;
  z-index: var(--z-base);
  opacity: 0.22;
}

.trust-band__image img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.trust-band__scrim {
  position: absolute;
  inset: 0;
  z-index: var(--z-atmosphere);
  background-color: var(--color-bg);
  opacity: 0.72;
}

.trust-strip {
  position: relative;
  z-index: var(--z-plate);
  display: grid;
  gap: var(--space-md);
  margin-block-start: var(--space-sm);
}

.trust-strip p {
  font-family: var(--font-display);
  font-size: var(--text-lead);
  font-weight: var(--font-weight-display);
  color: var(--color-ink);
}

/* --- PROCESS — 3 steps, numeral treatment distinct from the services list
   (brief §4/§8). Imagery slot 3 sits beside the heading. --- */

.process-head {
  display: grid;
  gap: var(--space-lg);
  align-items: center;
  grid-template-columns: 1fr;
}

.process-head__image {
  border-radius: var(--radius-lg);
  overflow: clip;
}

.process-head__image img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.process-steps {
  display: grid;
  gap: var(--space-lg);
  margin-block-start: var(--space-lg);
}

.process-step {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-md);
  align-items: start;
}

.process-step__num {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  font-weight: var(--font-weight-display);
  color: var(--color-accent);
  line-height: 1;
}

.process-step__title {
  font-weight: var(--font-weight-body-strong);
  color: var(--color-ink);
}

.process-step__desc {
  margin-block-start: var(--space-3xs);
  color: var(--color-ink-muted);
}

@media (min-width: 48em) {
  .process-head {
    grid-template-columns: 1fr minmax(var(--process-image-min), var(--process-image-max));
  }
}

/* ==========================================================================
   ABOUT / MISSION — short band, seedling accent image (imagery slot 4).
   ========================================================================== */

.about-grid {
  display: grid;
  gap: var(--space-lg);
  align-items: center;
  grid-template-columns: 1fr;
}

.about-grid__image {
  inline-size: var(--space-3xl);
  block-size: var(--space-3xl);
  border-radius: var(--radius-lg);
  overflow: clip;
}

.about-grid__image img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.about-quotes {
  display: grid;
  gap: var(--space-md);
}

.about-quotes p {
  font-size: var(--text-lead);
  color: var(--color-ink);
  border-inline-start: var(--border-thick) var(--border-style) var(--color-sage);
  padding-inline-start: var(--space-md);
}

@media (min-width: 48em) {
  .about-grid {
    grid-template-columns: auto 1fr;
  }
}

/* --- Service area: one honest line. --- */

.service-area p {
  font-family: var(--font-display);
  font-size: var(--text-lead);
  font-weight: var(--font-weight-display);
  color: var(--color-ink);
}

/* --- FAQ — native <details>/<summary>, zero JS. --- */

.faq-list {
  display: grid;
  gap: var(--space-sm);
  margin-block-start: var(--space-lg);
}

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

.faq-item summary {
  cursor: pointer;
  padding-block: var(--space-xs);
  font-weight: var(--font-weight-body-strong);
  color: var(--color-ink);
}

.faq-item summary::-webkit-details-marker {
  color: var(--color-accent);
}

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

/* ==========================================================================
   FINAL CTA / CONTACT — phone CTA + quote form (house form contract,
   house-tech-spec §6). POSTs to the shared house endpoint; works as a plain
   HTML POST with JS off.
   ========================================================================== */

.contact-ctas {
  margin-block: var(--space-md);
}

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

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

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

.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);
  border: var(--border-hairline) var(--border-style) var(--color-border);
  border-radius: var(--radius-sm);
}

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

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

/* Honeypot: present in the DOM for bots, unreachable for humans and
   assistive tech. Not display:none — some bots skip those. */
.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);
}

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

.site-footer__nap {
  font-style: normal;
}

/* --- Reduced motion (brief §7): satellites freeze at keyframe MIDPOINT (not
   hidden); active season-card tint applies with no transition (above). --- */

@media (prefers-reduced-motion: reduce) {
  .hero__satellite {
    animation: none;
    /* The keyframe midpoint is half of hero-drift's own to-state
       (translateY(-0.6em) rotate(8deg)); a duration token cannot express a
       transform value, so this one pair of numbers is fixed here rather
       than mistakenly left riding a collapsed-to-~0 animation. */
    /* @allow-literal: keyframe drift distance is motion geometry, not a token-scale size */
    transform: translateY(-0.3em) rotate(4deg);
  }
}
