/* ==========================================================================
   site.css — Shedhorn Plumbing, Helena MT. sidebar-anchor archetype,
   "the valve opens" living hero. Built from tokens.css only — no raw hex,
   px/rem size literal, or font-name literal below (house-tech-spec §3). The
   two escape hatches are the house breakpoints and an explicit
   `@allow-literal:` comment on the preceding line.
   ========================================================================== */

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

/* --- The valve-dial signature glyph ---------------------------------------
   brief §6: the hero's settled end-state, reused as a fixed 20px outer-ring
   mark beside every rail item and section lead-in. Fixed px, never em
   (design-rules §5's em rule does not attach to a device never positioned
   relative to type). `vector-effect: non-scaling-stroke` keeps stroke width
   a literal device-px value independent of the viewBox's CSS resize, so the
   brief's 2px -> 1.5px step is real, not a scaling side effect. Minimum
   (brief §6): 20px >= 360px, shrinking to 16px down to the 320px floor with
   one spoke dropped and stroke 2px -> 1.5px — the ring itself never drops. */

.dial {
  flex: none;
  width: var(--dial-size);
  height: var(--dial-size);
}

.dial__ring,
.dial__spokes line {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

@media (max-width: 22.5em) {
  /* 360px floor down to the 320px minimum, per brief §6 */
  .dial {
    width: var(--dial-size-min);
    height: var(--dial-size-min);
  }
  .dial__ring,
  .dial__spokes line {
    stroke-width: 1.5;
  }
  .dial__spoke-drop {
    display: none;
  }
}

/* --- Header: sticky, house-shape precedent ---------------------------------
   brief §4.1's sticky-chrome term (101/117px) needs both the bar and the
   header position:sticky; this site's preview.css carries that override. */

.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-header);
  /* targets brief §4.1's 56/72px; renders 67.3/72px (button padding) --
     primary CTA still clears the fold with margin, see README. */
  min-height: var(--header-h-mobile);
  display: flex;
  align-items: center;
  border-bottom: var(--border-hairline) var(--border-style) var(--color-border);
  background-color: var(--color-bg);
}

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

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

.site-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

@media (min-width: 60em) {
  .site-header {
    min-height: var(--header-h-desktop);
  }
}

.nav-toggle {
  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-strong);
  border-radius: var(--radius-sm);
  font-size: var(--text-small);
  font-family: var(--font-body);
  font-weight: var(--font-weight-body-strong);
  color: var(--color-ink);
  /* Reserves its box from first paint (README's Build notes); JS-off
     contract unchanged -- functional.mjs's visible() treats this as hidden. */
  visibility: hidden;
}

[data-nav-ready] .nav-toggle {
  visibility: visible;
}

/* --- The rail (sidebar-anchor, brief §4) -----------------------------------
   Below 960px: a collapsible mobile panel behind the header's toggle, the
   house nav-toggle contract (JS-off shows the plain list via the <noscript>
   override in @shared:head-boilerplate — unchanged, same `.site-nav` class).
   At and above 960px: a PERSISTENT, viewport-pinned rail beside the
   scrolling content — nav + a foot-of-rail Call button, unornamented
   (ref-011's borrowed restraint: a plain link list, never a card). */

.site-nav {
  display: none;
}

[data-nav-ready] .site-nav[data-nav-open='true'] {
  display: block;
  position: absolute;
  inset-inline: 0;
  z-index: var(--z-nav-panel);
  background-color: var(--color-surface);
  border-bottom: var(--border-hairline) var(--border-style) var(--color-border);
  padding: var(--space-md) var(--layout-gutter) var(--space-lg);
}

.site-nav__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

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

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

.rail__call {
  margin-block-start: var(--space-md);
  width: 100%;
}

@media (min-width: 60em) {
  .site-nav {
    display: flex;
    flex-direction: column;
    position: fixed;
    inset-inline-start: 0;
    /* sticky-chrome total: --expiry-height (44px, preview.css) + desktop header
       (72px) + 1px border = 117px. --expiry-height does not exist once
       css/preview.css is deleted at purchase (house-tech-spec §5); the 0px
       fallback below is that sold-site default, not a design value.
       @allow-literal: var() fallback for a token that is absent post-purchase */
    inset-block-start: calc(var(--expiry-height, 0px) + var(--header-h-desktop) + var(--border-hairline));
    inset-block-end: 0;
    width: var(--layout-rail-w);
    padding: var(--space-lg) var(--space-lg) var(--space-lg) var(--layout-gutter);
    overflow-y: auto;
    background-color: transparent;
    border-bottom: 0;
  }

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

  .page-main {
    margin-inline-start: var(--layout-rail-w);
  }
}

/* --- 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-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);
  color: var(--color-accent-ink);
}

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

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

.cta-row {
  display: flex;
  /* Column, not width-triggered wrap: two labels sharing a row can flip
     from one line to two on the font swap alone (measured CLS 0.169 --
     README's Build notes). Fixed at the layout level, not the fallback. */
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-sm);
}

@media (min-width: 60em) {
  .cta-row {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-md);
  }
}

.link-strong {
  font-weight: var(--font-weight-body-strong);
  color: var(--color-ink);
  text-underline-offset: var(--space-3xs);
}

/* --- Section lead-in: kicker + dial + heading ------------------------------
   The reused signature mark beside every section's lead-in (brief §6). The
   kicker reuses the rail's own nav-item words verbatim — no new copy.
   Newsreader 600, authored in natural case, uppercased by CSS (spec §8). */

.section__lead {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin-block-end: var(--space-sm);
  color: var(--color-accent);
}

.section__label {
  font-family: var(--font-display);
  font-size: var(--text-eyebrow);
  font-weight: var(--font-weight-display-strong);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

.section__head {
  margin-block-end: var(--space-md);
}

/* --- Hero -------------------------------------------------------------------
   DOM order (design-rules §7.2 rule 1, brief §4.1): eyebrow -> h1 -> primary
   CTA (+secondary) -> living-hero field -> lead -> facts. Atmosphere is two
   radial gradients over --color-bg (brief §2); no text ever sits over the
   photographic field -- it is a separate boxed element. */

.hero {
  position: relative;
  padding-block-start: var(--space-hero-top);
  padding-block-end: var(--space-hero-bottom);
  background-image:
    radial-gradient(ellipse 70% 55% at 15% 10%, var(--color-hero-atmos-near) 0%, transparent 60%),
    radial-gradient(ellipse 80% 65% at 95% 100%, var(--color-hero-atmos-far) 0%, transparent 70%);
  background-color: var(--color-bg);
  overflow: hidden;
}

.hero__grid {
  display: grid;
  gap: var(--space-sm);
  position: relative;
}

.hero__eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-eyebrow);
  font-weight: var(--font-weight-body-strong);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-accent);
  margin-block-end: var(--space-2xs);
}

.hero h1 {
  font-size: var(--text-hero);
  margin-block-end: var(--space-sm);
  /* No max-width here: a `ch`-unit cap is face-relative and a tight one
     flips the h1's own line count on the font swap (fallback -> webfont),
     which is a full-line CLS event, not the ~11px metrics wobble the
     fallback pair is tuned for. The grid column / container width already
     governs the wrap, matching the brief's own 335px content-width
     mechanism (§3's H1 budget) with no second constraint layered on it. */
}

.hero h1 em {
  font-family: var(--font-emphasis);
  font-style: italic;
  font-weight: var(--font-weight-display);
}

.hero .cta-row {
  margin-block-end: var(--space-sm);
}

.hero__lead {
  font-size: var(--text-lead);
  line-height: var(--leading-snug);
  margin-block-start: var(--space-sm);
  max-width: var(--hero-field-w-desktop);
}

.hero__facts {
  font-family: var(--font-body);
  font-size: var(--text-small);
  color: var(--color-ink-muted);
  margin-block-start: var(--space-xs);
}

@media (min-width: 60em) {
  .hero__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--hero-field-w-desktop));
    align-items: start;
    column-gap: var(--space-2xl);
  }
  .hero__eyebrow,
  .hero h1,
  .hero .cta-row {
    grid-column: 1;
  }
  .hero__field {
    grid-column: 2;
    grid-row: 1 / span 4;
  }
  .hero__lead,
  .hero__facts {
    grid-column: 1;
  }
}

/* --- The living-hero field: "the valve opens" ------------------------------
   Two-layer asset (brief §5, ref-002): slot 1 is the LCP plate, slot 2 the
   independently-rotated wheel. Fixed aspect-ratio 4/3 box at content width
   (design-rules §7.2 rule 4) -- never a viewport-filled flex:1 box. */

.hero__field {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-none);
  overflow: hidden;
  margin-block-start: var(--space-md);
}

.hero__bg,
.hero__bg img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__handle {
  display: block;
  position: absolute;
  inset-inline-start: 14.8%;
  inset-block-start: 26.5%;
  width: 20.4%;
  height: auto;
  transform-origin: 52% 48%;
  animation: valve-rotate var(--duration-signature) var(--ease-out) 1 both;
}

@keyframes valve-rotate {
  from { transform: rotate(-70deg); }
  to   { transform: rotate(0deg); }
}

/* The flow-highlight line: draws once along the pipe run at 2.1s, settles
   static. Approximate trace over the hero plate's own right-hand pipe run
   (percentage coordinates against the field box, not a literal decal). */
.hero__flowline {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.hero__flowline path {
  fill: none;
  stroke: var(--color-hero-atmos-near);
  stroke-width: 0.6%;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  pathLength: 1;
  animation: flow-draw var(--duration-signature-draw) var(--ease-out) var(--duration-signature-delay) 1 both;
}

@keyframes flow-draw {
  to { stroke-dashoffset: 0; }
}

/* The joint-glint: a soft pulse at the fitting joint, independent slow loop
   (~6s, non-synchronised with the draw) -- the ambient satellite motion
   the living-hero convention requires (brief §0, ref-001). */
.hero__glint {
  position: absolute;
  inset-inline-start: 44%;
  inset-block-start: 58%;
  width: 8%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, var(--color-hero-atmos-near) 0%, transparent 70%);
  opacity: 0.35;
  animation: joint-glint var(--duration-glint) var(--ease-in-out) infinite;
}

@keyframes joint-glint {
  0%, 100% { opacity: 0.2; transform: scale(0.9); }
  50%      { opacity: 0.55; transform: scale(1.15); }
}

/* Reduced motion (house-tech-spec §8, brief §6): the hero renders in its
   fully-settled end-state on load -- valve open, line drawn, joint static.
   base.css already collapses the house duration tokens; these four are the
   signature move's own and are collapsed here alongside them. */
@media (prefers-reduced-motion: reduce) {
  .hero__handle {
    animation: none;
    transform: rotate(0deg);
  }
  .hero__flowline path {
    animation: none;
    stroke-dashoffset: 0;
  }
  .hero__glint {
    animation: none;
    opacity: 0.3;
  }
}

/* --- Services (#services) --------------------------------------------------
   Five clusters, an editorial index of lists, not an icon card grid
   (design-rules §4 bans the three-card icon/title/blurb pattern). */

.clusters {
  display: grid;
  gap: var(--space-lg) var(--space-xl);
  margin-block-start: var(--space-md);
}

@media (min-width: 40em) {
  .clusters {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

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

.cluster__name {
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--font-weight-display);
  margin-block-end: var(--space-2xs);
}

.cluster__list {
  display: grid;
  gap: var(--space-3xs);
  list-style: none;
  margin: 0;
  padding: 0;
}

.cluster__list li {
  font-size: var(--text-body);
  color: var(--color-ink-muted);
}

.services__plate {
  margin-block-start: var(--space-lg);
  border-radius: var(--radius-none);
  overflow: hidden;
}

.services__plate img {
  display: block;
  width: 100%;
  height: auto;
}

/* --- Trust & Licensing (#trust) --------------------------------------------
   Typographic facts, never badge graphics (copy.md: "Not a badge wall.").
   A texture band carries the atmosphere ref-007's value-badge idea adapts
   as plain fact rows instead of an icon row. */

.trust {
  position: relative;
  background-color: var(--color-surface);
}

.trust__texture {
  position: relative;
  width: 100%;
  height: var(--trust-texture-h);
  overflow: hidden;
  margin-block-end: var(--space-lg);
}

.trust__texture img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.trust__facts {
  display: grid;
  gap: var(--space-sm);
  margin-block: var(--space-md);
}

@media (min-width: 40em) {
  .trust__facts {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.trust__fact {
  border-block-start: var(--border-thick) var(--border-style) var(--color-accent);
  padding-block-start: var(--space-2xs);
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--font-weight-display);
}

/* --- Reviews (#reviews) ----------------------------------------------------
   Verbatim quotes, italic setting (the ref-007 emphasis move, reused here
   per brief §3). */

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

.review {
  border-inline-start: var(--border-thick) var(--border-style) var(--color-border);
  padding-inline-start: var(--space-md);
}

.review blockquote {
  margin: 0;
  font-family: var(--font-emphasis);
  font-style: italic;
  font-size: var(--text-lead);
  line-height: var(--leading-snug);
  color: var(--color-ink);
}

.review figcaption {
  margin-block-start: var(--space-xs);
  font-family: var(--font-body);
  font-size: var(--text-small);
  color: var(--color-ink-muted);
}

/* --- How It Works (#process) ------------------------------------------------
   Three steps, numerals distinguished from the section-level rail/dial
   system by digit + weight rather than roman numerals or the dial glyph
   (design-rules §5's "two counters, one costume" rule: different glyph set,
   face and colour role). */

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

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

.step__num {
  display: block;
  font-family: var(--font-body);
  font-size: var(--text-small);
  font-weight: var(--font-weight-body-strong);
  color: var(--color-ink-muted);
  letter-spacing: var(--tracking-wide);
  margin-block-end: var(--space-2xs);
}

.step__name {
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--font-weight-display);
  margin-block-end: var(--space-2xs);
}

.step__line {
  color: var(--color-ink-muted);
}

/* --- Where We Work (#service-area) -----------------------------------------
   Kept light per brief §4 row 5 -- one heading, one line, no map. */

.service-area p {
  font-size: var(--text-lead);
  max-width: var(--layout-measure);
}

/* --- Send the Details (#contact) -------------------------------------------
   The house form, plus the divider motif before it. */

.contact__divider {
  width: var(--contact-divider-size);
  aspect-ratio: 1;
  margin-block-end: var(--space-md);
  border-radius: 50%;
  overflow: hidden;
}

.contact__divider img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.contact__intro {
  font-size: var(--text-lead);
  max-width: var(--layout-measure);
  margin-block-end: var(--space-md);
}

.contact__secondary {
  margin-block-start: var(--space-md);
  color: var(--color-ink-muted);
}

.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-strong);
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
}

textarea.field__control {
  min-height: var(--field-textarea-min);
  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);
}

/* --- Common Questions (#faq) ------------------------------------------------
   Native <details>/<summary>: keyboard-standard, works with JS off. The
   disclosure triangle is the item's own ornament, so it carries no numeral
   (design-rules §4/§5's nested-enumeration rule -- a sub-list that already
   has a marker of its own does not also get a counter). */

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

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

.faq__item:last-child {
  border-block-end: var(--border-hairline) var(--border-style) var(--color-border);
}

.faq__q {
  display: flex;
  align-items: baseline;
  gap: var(--space-2xs);
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--font-weight-display);
  cursor: pointer;
  list-style: none;
}

.faq__q::-webkit-details-marker {
  display: none;
}

.faq__q::before {
  content: '+';
  color: var(--color-accent);
  font-weight: var(--font-weight-body-strong);
  transition: transform var(--duration-fast) var(--ease-out);
}

.faq__item[open] .faq__q::before {
  content: '\2212';
}

.faq__a {
  margin-block-start: var(--space-2xs);
  color: var(--color-ink-muted);
  max-width: var(--layout-measure);
}

/* --- 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);
  margin-block-end: var(--space-2xs);
}

.site-footer p {
  margin-block-end: var(--space-2xs);
}

@media (min-width: 60em) {
  .site-footer {
    margin-inline-start: var(--layout-rail-w);
  }
}
