/* ==========================================================================
   site.css — Western Landscaping & Decorative Curbing (Pocatello, ID)
   Archetype: sidebar-anchor (brief §4). Mobile (<1024): single column,
   fixed bottom CTA bar. Desktop (>=1024): true sticky left rail, 320px.
   Tokens only — no raw hex/px/font literals (house-tech-spec §3).
   ========================================================================== */

/* --- 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);
}

/* Brief §4.2: gutter and section-gap step up at the house 64em breakpoint. */
@media (min-width: 64em) {
  :root {
    --layout-gutter: var(--space-lg);   /* 40px */
    --section-gap: var(--space-2xl);    /* 96px */
    --hero-pad-start: var(--space-2xl); /* 96px */
  }
}

/* Anchor targets clear the sticky chrome stack (header + border, plus the
   preview expiry bar while status: preview — preview.css adds that on top). */
section[id] {
  scroll-margin-block-start: var(--chrome-height);
}

/* --- Header & navigation ---------------------------------------------------
   Fixed 56px + 1px border-bottom AT REST at every breakpoint (brief §4.4
   step 1), sticky at every breakpoint (copy.md §1.1). Preview.css adds the
   expiry bar's height on top of the offset below (buyer-inherited default:
   0). "At rest" = nav collapsed — see the QA r2 FIX note below
   `.site-header__inner` for the one deliberate exception. */

.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-header);
  min-height: calc(var(--header-height) + var(--border-hairline));
  padding-block: 0;
  border-bottom: var(--border-hairline) var(--border-style) var(--color-border);
  background-color: var(--color-bg);
}

.site-header__inner {
  display: flex;
  min-height: var(--header-height);
  /* QA r2 FIX clarity/5s: was `flex-wrap: nowrap` with both heights fixed
     (not min-), so a revealed `.site-nav` (JS toggle, or the JS-off
     `<noscript>` override in `@shared:head-boilerplate`, which
     unconditionally sets `.site-nav{display:block}`) had nowhere to go but
     overflow onto the hero below — the Critic's clarity/5s BLOCKER.
     `min-height` here and on `.site-header` above keeps 56px exact whenever
     nav is collapsed (every closed state; every state at >=48em, unchanged)
     while letting the header grow to fit the nav's own wrapped line the
     moment it is genuinely revealed — the skeleton's own original fix for
     this (`position: relative` + auto-height + `flex-wrap: wrap`),
     reapplied without losing the sticky/56px-at-rest brief requires. */
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.site-header__brand {
  /* "Western Landscaping & Decorative Curbing" does not fit one line at
     375px at any reasonable display-face size alongside the nav toggle;
     the brief does not address this case, so it truncates with an ellipsis
     rather than wrapping to a second line or overflowing. Sized down from
     the display-h2 scale for the same reason — this is a 56px-tall
     persistent bar, not a second headline.

     QA r2 FIX regression guard: `flex-basis: 0`, not `auto`. Now that
     `.site-header__inner` wraps (above), a `white-space: nowrap` text
     node's hypothetical main size under `flex-basis: auto` is its full
     unbroken content width — wider than 375px on its own — which wrapped
     the nav-toggle to its own line even with the nav itself still
     `display: none`. `flex-basis: 0` starts the row-fitting math from
     zero, so the toggle stays on the brand's line and `flex-grow` alone
     decides how much room the brand gets before its own ellipsis. */
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: var(--font-display);
  font-size: var(--text-body);
  font-weight: var(--font-weight-display-strong);
  text-decoration: none;
  letter-spacing: var(--tracking-tight);
}

.nav-toggle {
  flex: 0 0 auto;
  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-none);
  font-size: var(--text-small);
  font-weight: var(--font-weight-body-strong);
}

.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-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);
}

.site-nav {
  display: none;
  /* Below 48em, whenever revealed (either trigger below), always its own
     full-width row under the brand/toggle row rather than however much
     space happens to be left on their line — a deterministic panel, not an
     accident of how much the two other items shrank. Reset at >=48em
     (below), where the nav sits inline in the header's own row instead. */
  flex-basis: 100%;
}

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

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

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

/* --- Section head — the page's spine (brief §4.1 rule 4) -------------------
   A caps eyebrow in --color-ink-muted, and an h2 in --font-display 700.
   Every section on this page opens with this pair. */

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

.section h2 {
  margin: 0 0 var(--space-md);
}

h2 {
  font-family: var(--font-display);
  font-weight: var(--font-weight-display);
  font-size: var(--text-h2);
  line-height: var(--leading-h2);
  letter-spacing: var(--tracking-tight);
}

/* thanks.html's confirmation heading is an <h1> at h2 scale (brief §4.7/§5:
   "Confirmation heading (single line at both widths)", arithmetic table
   labels it "H1(h2-scale)") — this page spends no hero moment of its own
   (brief §7: exactly one spectacular moment, already spent on index.html). */
#thanks-title {
  margin: 0 0 var(--space-md);
  font-family: var(--font-display);
  font-weight: var(--font-weight-display);
  font-size: var(--text-h2);
  line-height: var(--leading-h2);
  letter-spacing: var(--tracking-tight);
}

/* base.css zeroes every block margin (its reset), so sibling paragraphs
   inside a section need their own rhythm token or they sit flush against
   each other (the exact "buy.html had no vertical rhythm" defect preview.css
   documents and fixes for that page — this is the same relationship,
   answered here for every other page). Heading-to-paragraph gaps are
   already carried by the heading's own bottom margin above and collapse
   normally in block flow. */
.section .container > p + p {
  margin-block-start: var(--space-md);
}

/* --- Hero (brief §3.4, §4.4 step 2) -----------------------------------------
   The gradient ground: computed against its own darkest stop at 375px
   (brief §3.4). Content column at >=1024 (brief §4.1 rule 2). */

.hero {
  padding-block-start: var(--hero-pad-start);
  padding-block-end: var(--section-gap);
  background: linear-gradient(155deg, var(--color-atmos-hi) 0%, var(--color-atmos-lo) 100%);
}

.hero h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--font-weight-display-strong);
  font-size: var(--text-h1);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

/* --- Primary CTA / bottom bar (brief §4.4 step 2, §5) -----------------------
   Below 1024: the ONLY rendering of the primary CTA, fixed to the viewport
   bottom, present at every scroll position by construction. The tel: link
   is redundant with the header's tel: link at this width, so it's hidden.
   At >=1024: relocates into the sticky rail (grid placement below); the
   tel: link becomes visible, stacked beneath the CTA. */

.cta-bar {
  position: fixed;
  inset-block-end: 0;
  inset-inline: 0;
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--header-height);
  padding-inline: var(--layout-gutter);
  background-color: var(--color-accent-strong);
  border-block-start: var(--border-hairline) var(--border-style) var(--color-accent-hover);
}

/* The bar IS the button below 1024 (brief §3.3 row 7 pairs the bar's own
   fill with the label directly, one pairing, not two stacked fills): the
   bar already carries --color-accent-strong, so the inner control's own
   fill is transparent here or it sits on itself at 1.00:1 and disappears
   (WCAG 1.4.11) — the exact failure preview.css's own history records for
   buy.html's button, one page over. Restored to a real fill at >=1024,
   where the control stands on --color-bg instead (below). */
.cta-bar .btn--primary {
  width: 100%;
  background-color: transparent;
}

.cta-bar__tel {
  display: none;
}

/* --- Hero field — the bed-edge-grows device (brief §4.3) ------------------- */

.hero-field {
  background: linear-gradient(155deg, var(--color-atmos-hi) 0%, var(--color-atmos-lo) 100%);
  padding-block-end: var(--section-gap);
}

.curb-svg {
  display: block;
  width: 100%;
  aspect-ratio: 375 / 240;
}

.curb-svg__turf {
  fill: var(--color-accent);
  opacity: 0.12;
}

.curb-svg__bed {
  fill: var(--color-ink);
  opacity: 0.06;
}

.curb-svg__line {
  fill: none;
  stroke: var(--color-accent-strong);
  stroke-width: 4;
  stroke-linecap: round;
  /* Settled/drawn by default — the reduced-motion- and JS-off-safe state.
     pathLength="1" normalises the dash math to a 0..1 range regardless of
     the curve's real length. */
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
}

.curb-svg__plant {
  stroke: var(--color-accent-strong);
  stroke-width: 2.5;
  stroke-linecap: round;
  fill: none;
  /* Upright, fully visible by default — the reduced-motion- and JS-off-safe
     resting state (house-tech-spec §8: reduced motion still reads as a
     finished, considered illustration). */
  transform: rotate(0deg);
}

.curb-svg__bud {
  fill: var(--color-accent-2);
  stroke: none;
}

/* Motion is additive only, under prefers-reduced-motion: no-preference — the
   default styles above already are the settled, reduced-motion-safe state,
   so nothing needs to be undone inside this query (house-tech-spec §8, brief
   §7). One spectacular moment, spent once, here (brief §0/§4.1 rule 5). */
@media (prefers-reduced-motion: no-preference) {
  .curb-svg__line {
    animation: curb-pour var(--duration-pour) var(--ease-out) forwards;
  }

  .curb-svg__plant {
    animation: curb-sway var(--duration-sway-1) var(--ease-in-out) infinite;
    animation-delay: 0s;
  }

  .curb-svg__plant--2 {
    animation-duration: var(--duration-sway-2);
    animation-delay: 0.35s;
  }

  .curb-svg__plant--3 {
    animation-duration: var(--duration-sway-3);
    animation-delay: 0.7s;
  }

  @keyframes curb-pour {
    from { stroke-dashoffset: 1; }
    to { stroke-dashoffset: 0; }
  }

  @keyframes curb-sway {
    0%, 100% { transform: rotate(-3deg); }
    50% { transform: rotate(3deg); }
  }
}

/* --- Service index (brief §4.4 step 3, LOAD-BEARING) ------------------------
   No numerals (brief §2.6) — a small hand-drawn leaf-glyph beside each item
   (ref-005 move). */

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

.service-list__item {
  display: flex;
  gap: var(--space-sm);
  align-items: flex-start;
}

.service-list__icon {
  flex: 0 0 auto;
  width: var(--space-md);
  height: var(--space-md);
  margin-block-start: var(--space-3xs);
  stroke: var(--color-accent);
  stroke-width: 1.6;
  stroke-linecap: round;
  fill: none;
}

.service-list__name {
  margin: 0 0 var(--space-3xs);
  font-family: var(--font-body);
  font-weight: var(--font-weight-body-strong);
  color: var(--color-ink);
}

.service-list__desc {
  margin: 0;
  color: var(--color-ink-muted);
  font-size: var(--text-small);
}

.section__accent-img {
  margin-block-start: var(--space-lg);
  border-radius: var(--radius-none);
}

/* --- Curb Shapes & Colors chip row (brief §4.4 step 4, ref-008 move) ------- */

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin: var(--space-lg) 0 0;
  padding: 0;
  list-style: none;
}

.chip {
  padding: var(--space-2xs) var(--space-md);
  background-color: var(--color-surface);
  color: var(--color-ink);
  border: var(--border-hairline) var(--border-style) var(--color-accent-2-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-small);
  font-weight: var(--font-weight-body-strong);
}

/* --- Material spec (brief §4.4 step 5) -------------------------------------- */

.material-spec__statement {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--font-weight-display);
  font-size: var(--text-h2);
  line-height: var(--leading-h2);
  color: var(--color-ink);
}

/* --- Trust-strip (brief §4.4 step 6) ---------------------------------------- */

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

@media (min-width: 48em) {
  .fact-list {
    grid-template-columns: repeat(3, 1fr);
  }
}

.fact-list__label {
  margin: 0 0 var(--space-3xs);
  font-family: var(--font-display);
  font-weight: var(--font-weight-display);
  font-size: var(--text-h2);
  color: var(--color-accent-strong);
}

.fact-list__desc {
  margin: 0;
  color: var(--color-ink-muted);
}

/* --- 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-none);
  font-family: var(--font-body);
  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-strong);
  color: var(--color-accent-ink);
}

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

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

/* --- Form -------------------------------------------------------------------- */

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

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

.field__label {
  font-family: var(--font-body);
  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-none);
}

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 strong {
  color: var(--color-ink);
}

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

/* WCAG 2.5.8 target size: the phone and email links stack on their own
   lines with no surrounding text, so neither qualifies for the inline-text
   exception, and bare text glyphs alone don't clear the 24x24px minimum
   (Lighthouse target-size, measured at 18px tall with 0 spacing). Padding
   both grows the target and creates real space between the two stacked
   links, rather than the site's own body text setting the boundary. */
.site-footer__nap a {
  display: inline-block;
  padding-block: var(--space-3xs);
}

.site-footer__nap {
  font-style: normal;
  margin: 0 0 var(--space-sm);
}

/* ============================================================================
   SIDEBAR-ANCHOR RAIL — brief §4.1 rules 1-2, §4.2, §5. >=1024 only: the
   fixed bottom bar disengages and a true sticky left rail engages.

   Six content-column items (hero text, hero field, curb-shapes,
   material-spec, trust-strip, contact) become an explicit 6-row grid so the
   rail's two items (service index, cta-bar) can each declare
   `grid-row: 1 / -1` and span the full column height for sticky purposes,
   independent of how tall any individual content row is.
   ============================================================================ */

@media (min-width: 64em) {
  .page {
    display: grid;
    grid-template-columns: var(--rail-width) 1fr;
    grid-template-rows: repeat(6, auto);
    column-gap: var(--space-lg);
  }

  .hero            { grid-column: 2; grid-row: 1; }
  .cta-bar         { grid-column: 1; grid-row: 2; }
  .hero-field      { grid-column: 2; grid-row: 2; }
  #services        { grid-column: 1; grid-row: 3; }
  #curb-shapes     { grid-column: 2; grid-row: 3; }
  #material-spec   { grid-column: 2; grid-row: 4; }
  #trust-strip     { grid-column: 2; grid-row: 5; }
  #contact         { grid-column: 2; grid-row: 6; }

  /* Both rail items span the full grid height and align to its start, so
     each sticks independently of the content column's much taller rows. */
  .cta-bar,
  #services {
    grid-row: 1 / -1;
    align-self: start;
  }

  #services {
    position: sticky;
    inset-block-start: var(--chrome-height);
  }

  /* No longer a fixed bottom bar at this width: a normal, sticky, in-flow
     block placed directly beneath the service index (brief §5's rail
     arithmetic: eyebrow + list + gaps = --rail-services-block). */
  .cta-bar {
    position: sticky;
    inset-block-start: calc(var(--chrome-height) + var(--rail-services-block));
    inset-inline: auto;
    z-index: auto;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    height: auto;
    padding-inline: 0;
    margin-block-start: var(--rail-services-block);
    background-color: transparent;
    border-block-start: none;
  }

  .cta-bar .btn--primary {
    /* Restored: at this width the control stands on --color-bg (the rail's
       own ground), not on another accent-strong fill, so its own fill is
       visible again (brief §3.3 row 7, 10.19:1). */
    background-color: var(--color-accent-strong);
  }

  .cta-bar__tel {
    display: inline-flex;
    justify-content: center;
    margin-block-start: var(--space-sm);
    color: var(--color-accent);
    font-weight: var(--font-weight-body-strong);
    text-decoration: none;
  }

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

  /* Rail text sits on --color-bg's own gradient-free ground; the page's
     stock focus ring (--color-focus, 5.72:1 on bg) already clears AA here,
     so no band-safe override is needed for this rail. */
}
