/* Roughley Mechanical — layout: shell, utility bar, header, nav, sections, footer.

   ┌─ BREAKPOINTS — the canonical set. Do not introduce others. ───────────┐
   │  30em   480px   button rows and stacked pairs go side-by-side         │
   │  34em   544px   urgency toggle goes 2-up                              │
   │  48em   768px   2-up grids; display line-height tightens to 0.92;     │
   │                 the sticky mobile call bar disappears                 │
   │  64em  1024px   nav goes inline; hero splits copy / form              │
   │  75em  1200px   full brand shell padding; display type hits 96px      │
   └───────────────────────────────────────────────────────────────────────┘
   These literals repeat here and in components.css because
   `@media (min-width: var(--bp-md))` is invalid CSS — custom properties are
   not usable in media conditions — and @custom-media needs PostCSS, which
   this no-build project excludes. This comment block is the only guard.
   assets/js/nav.js also hardcodes the 64em nav breakpoint; they must match. */

/* ── Skip link ───────────────────────────────────────────────────────── */

.skip-link {
  position: absolute;
  left: var(--space-8);
  top: var(--space-8);
  z-index: var(--z-skip);
  transform: translateY(-200%);
  background: var(--iron);
  color: var(--white);
  padding: var(--space-12) var(--space-20);
  text-decoration: none;
  font-stretch: var(--w-label);
  font-weight: var(--fw-label);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-button);
  text-transform: uppercase;
}
.skip-link:focus {
  transform: translateY(0);
  color: var(--white);
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* ── Shell ───────────────────────────────────────────────────────────── */

.shell {
  max-width: var(--shell-max);
  margin-inline: auto;
  padding-inline: var(--space-20);
  display: flex;
  flex-direction: column;
  gap: var(--gap-section);
}
.shell--flush { gap: 0; padding-block: var(--space-16) 0; }

/* A full-bleed band butts straight up against whatever follows it, because
   `.shell` carries padding-inline only. That left the first eyebrow sitting on
   the band's edge: under the trust bar on 2 pages, and under `.page-hero` on
   the other 30.

   Keyed on the FOLLOWING element rather than the band's own margin-bottom,
   deliberately — band → band must stay flush (the home hero and the trust bar
   meet edge to edge and should), while band → content must not.

   Structural rather than an enumeration of band classes, so a fourth band
   added later is covered without anyone having to remember this rule. The two
   other things wearing `.shell` are unaffected: `.shell--flush` (breadcrumbs)
   is always main's first child so `* +` cannot match it — the `:not()` is
   belt-and-braces for future edits — and `.hero__inner` / `.page-hero__inner`
   are children of their band, never adjacent siblings of one. */
main > * + .shell:not(.shell--flush) {
  padding-block-start: var(--gap-section);
}

/* Room for the fixed call bar so it never covers the last row. The bar is
   --callbar-h tall PLUS its 2px top border, so the reservation has to include
   the border or the final row sits 2px under it. */
main { padding-bottom: var(--space-56); }
body { padding-bottom: calc(var(--callbar-h) + var(--bw)); }
@media (min-width: 48em) {
  body { padding-bottom: 0; }
  .shell { padding-inline: var(--space-24); }
  /* The bump tokens.ext.css documents but never applied: section rhythm was
     56px at every width, which is why desktop read as cramped. */
  :root { --gap-section: var(--space-96); }
}
@media (min-width: 75em) {
  .shell { padding-inline: var(--space-32); }
}

/* ── Utility bar ─────────────────────────────────────────────────────────
   Scrolls away; the header below it is what sticks. */

.utility-bar {
  background: var(--iron);
  color: var(--white);
}
.utility-bar__inner {
  max-width: var(--shell-max);
  margin-inline: auto;
  padding: var(--space-8) var(--space-20);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-8) var(--space-24);
  font-size: var(--fs-micro);
  letter-spacing: 0.02em;
}
.utility-bar__phone,
.utility-bar__area {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
}
.utility-bar__phone {
  color: var(--copper-tint);   /* copper on Iron is 3.50:1 and fails AA */
  text-decoration: none;
  font-weight: 700;
  font-size: var(--fs-label);
}
.utility-bar__phone:hover { color: var(--white); text-decoration: underline; }
.utility-bar__area { color: var(--steel); }
.utility-bar__hours { color: var(--steel); margin-left: auto; }

/* Hours and the service-area line are the first things to go when tight.
   Hide the whole element, not just its text — hiding the span alone strands
   the map-pin icon on its own. */
@media (max-width: 47.99em) {
  .utility-bar__area,
  .utility-bar__hours { display: none; }
}
@media (min-width: 48em) { .utility-bar__inner { padding-inline: var(--space-24); } }
@media (min-width: 75em) { .utility-bar__inner { padding-inline: var(--space-32); } }

/* ── Site header ─────────────────────────────────────────────────────── */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--paper);
  border-bottom: var(--border);
}
.site-header__inner {
  max-width: var(--shell-max);
  margin-inline: auto;
  padding: var(--space-12) var(--space-20);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-16);
}
@media (min-width: 48em) { .site-header__inner { padding-inline: var(--space-24); } }
@media (min-width: 75em) { .site-header__inner { padding-inline: var(--space-32); } }

.site-header__brand { display: block; line-height: 0; flex: none; }
.site-header__brand:focus-visible { outline-offset: 6px; }

/* The lockup is 2.098:1 with a 140px brand minimum, so it can never render
   shorter than ~67px at full width. There is no compliant smaller option —
   this is a horizontal-only raster lockup with no mark-only variant. */
.site-header__logo {
  height: 52px;
  width: auto;
  transition: height var(--dur) linear;
}
@media (min-width: 64em) { .site-header__logo { height: 64px; } }

/* Condensed state, toggled by nav.js after ~120px of scroll. */
.site-header.is-condensed .site-header__logo { height: 44px; }
@media (min-width: 64em) { .site-header.is-condensed .site-header__logo { height: 48px; } }

.site-header__actions { display: none; gap: var(--space-8); align-items: center; }
/* Header CTAs must never wrap — a two-line button in a sticky header eats
   vertical space on every page and reads as broken. */
.site-header__actions .btn { white-space: nowrap; }

/* Six nav items plus two buttons do not fit until ~1360px. Below that the
   header carries the phone only — the primary CTA is still one scroll away in
   the hero, and on phones it is pinned in the call bar. */
@media (min-width: 64em) {
  .site-header__actions { display: flex; }
  .site-header__actions .btn--primary { display: none; }
}
@media (min-width: 85em) {
  .site-header__actions .btn--primary { display: inline-flex; }
}

/* ── Primary nav ─────────────────────────────────────────────────────── */

.site-nav { margin-left: auto; }
@media (min-width: 64em) { .site-nav { margin-left: 0; } }

.site-nav__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  background: transparent;
  border: var(--border);
  color: var(--iron);
  padding: var(--space-10) var(--space-14);
  cursor: pointer;
  font-stretch: var(--w-label);
  font-weight: var(--fw-label);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-button);
  text-transform: uppercase;
  min-height: 44px;
}
.site-nav__toggle:hover { background: var(--iron); color: var(--white); }

.site-nav__bars { display: block; width: 16px; height: 2px; background: currentColor; position: relative; }
.site-nav__bars::before,
.site-nav__bars::after {
  content: ""; position: absolute; left: 0; width: 16px; height: 2px; background: currentColor;
}
.site-nav__bars::before { top: -5px; }
.site-nav__bars::after  { top: 5px; }

/* Mobile: the panel drops below the header as a full-width sheet. */
.site-nav__panel {
  display: none;
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  background: var(--paper);
  border-bottom: var(--border);
  padding: var(--space-8) var(--space-20) var(--space-20);
  max-height: calc(100vh - var(--header-h));
  overflow-y: auto;
}
.site-nav__panel.is-open { display: block; }

.site-nav__list { display: flex; flex-direction: column; }
.site-nav__item { position: relative; }

.site-nav__link {
  display: flex;
  align-items: center;
  min-height: 44px;   /* 13px text alone fails WCAG 2.2 SC 2.5.8 */
  padding: var(--space-12) 0;
  color: var(--iron);
  text-decoration: none;
  border-bottom: var(--border-fine);
  font-stretch: var(--w-label);
  font-weight: var(--fw-label);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}
.site-nav__link:hover { color: var(--copper); }
.site-nav__link[aria-current="page"] { box-shadow: inset 0 -2px 0 0 var(--copper); }

@media (min-width: 64em) {
  .site-nav__toggle { display: none; }
  .site-nav__panel {
    display: block;
    position: static;
    border-bottom: 0;
    padding: 0;
    max-height: none;
    overflow: visible;
    background: transparent;
  }
  .site-nav__list { flex-direction: row; align-items: center; gap: var(--space-18); }
  .site-nav__link { border-bottom: 0; padding: var(--space-10) 0; }
}

/* ── Nav dropdowns ───────────────────────────────────────────────────────
   The trigger is a real link to the hub PLUS a separate toggle button, so
   with JS off the hub is still reachable and the panel opens on :focus-within.
   With JS the button drives aria-expanded. */

.nav-drop { display: flex; flex-wrap: wrap; align-items: center; }
.nav-drop > .site-nav__link { flex: 1; }

.nav-drop__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  min-height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  border-bottom: var(--border-fine);
  color: var(--iron);
  cursor: pointer;
}
.nav-drop__toggle:hover { color: var(--copper); }
.nav-drop__chev { transition: transform var(--dur) linear; }
.nav-drop__toggle[aria-expanded="true"] .nav-drop__chev { transform: rotate(180deg); }

.nav-drop__panel { display: none; width: 100%; }
.nav-drop__panel.is-open { display: block; }

.nav-drop__list {
  display: flex;
  flex-direction: column;
  border-left: var(--bw) solid var(--copper);
  margin: var(--space-4) 0 var(--space-12);
  padding-left: var(--space-14);
}
.nav-drop__list a {
  display: flex;
  align-items: center;
  min-height: 40px;
  padding: var(--space-6) 0;
  color: var(--iron);
  text-decoration: none;
  font-size: var(--fs-support);
}
.nav-drop__list a:hover { color: var(--copper); }
.nav-drop__all a {
  font-stretch: var(--w-label);
  font-weight: var(--fw-label);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

@media (min-width: 64em) {
  .nav-drop { flex-wrap: nowrap; }
  .nav-drop > .site-nav__link { flex: none; }
  .nav-drop__toggle { width: 24px; min-height: 0; height: 24px; border-bottom: 0; }

  .nav-drop__panel {
    position: absolute;
    top: calc(100% + var(--space-10));
    left: 0;
    z-index: var(--z-drop);
    width: max-content;
    min-width: 220px;
    background: var(--white);
    border: var(--border);
    padding: var(--space-12) var(--space-16);
  }
  /* Bridging the gap the pointer has to cross to reach the panel.
     TWO bridges are needed, and it is worth saying why, because the obvious
     one alone is useless.

     The panel sits --space-10 below the trigger row. That strip belongs to
     .site-header__inner, not to .nav-drop, so a pointer leaving the trigger
     dropped :hover, the panel went display:none — and a pseudo-element of a
     display:none element does not hit-test, so the panel's own ::before
     bridge disappeared at exactly the moment it was needed. It could only
     ever help someone already across the gap. The menu was unusable with a
     real mouse; only a synthetic pointer that jumps straight from trigger to
     panel could reach it.

     So the load-bearing bridge is this one, on .nav-drop itself, materialised
     by the same :hover that opens the panel. It exists exactly when it is
     needed and never intercepts clicks the rest of the time. min-width keeps
     it at least as wide as the panel so a diagonal approach stays covered. */
  .nav-drop:hover::after,
  .nav-drop:focus-within::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 0;
    width: 100%;
    min-width: 220px;
    height: var(--space-10);
  }

  /* The second bridge, spanning the panel's full width — wider than the nav
     item — for a pointer approaching diagonally. Only works while the panel
     is open, which is precisely what the rule above guarantees. */
  .nav-drop__panel::before {
    content: "";
    position: absolute;
    left: 0; right: 0;
    top: calc(var(--space-10) * -1);
    height: var(--space-10);
  }
  .nav-drop__list { border-left: 0; margin: 0; padding-left: 0; }
  .nav-drop__all { border-top: var(--border-fine); margin-top: var(--space-6); padding-top: var(--space-6); }

  /* Open on hover, on keyboard focus anywhere inside (the no-JS path), or
     when JS has set the state. */
  .nav-drop:hover > .nav-drop__panel,
  .nav-drop:focus-within > .nav-drop__panel,
  .nav-drop__panel.is-open { display: block; }

  /* The 15-town menu runs in two columns rather than one very tall list. */
  #nav-drop-locations .nav-drop__list { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--space-24); }
  #nav-drop-locations .nav-drop__all { grid-column: 1 / -1; }
}

/* ── Sections ────────────────────────────────────────────────────────── */

.section { display: flex; flex-direction: column; gap: var(--space-20); }
.section > .t-label { color: var(--accent); }

/* Grounds. Each remaps the accent locally so copper-on-Iron (3.50:1, fails
   AA for normal text) cannot be reached by accident. */
.section--dark {
  background: var(--ground-dark);
  color: var(--text-inverse);
  --accent: var(--copper-tint);
  --text: var(--text-inverse);
  --text-body: var(--steel);
  --text-meta: var(--steel);
  padding: var(--space-32) var(--space-20);
}
.section--dark > .t-label { color: var(--copper-tint); }
@media (min-width: 48em) { .section--dark { padding: var(--space-56) var(--space-40); } }

/* ── Generic helpers ─────────────────────────────────────────────────── */

.stack { display: flex; flex-direction: column; gap: var(--stack-gap, var(--space-24)); }

.grid-auto {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--grid-min, 260px), 1fr));
  gap: var(--grid-gap, var(--space-32));
}

.actions { display: flex; flex-wrap: wrap; gap: var(--space-12); align-items: center; }

/* ── CTA band ────────────────────────────────────────────────────────── */

.cta-band {
  background: var(--ground-dark);
  color: var(--text-inverse);
  --accent: var(--copper-tint);
  --text: var(--text-inverse);
  --text-body: var(--steel);
  padding: var(--space-32) var(--space-20);
  display: flex;
  flex-direction: column;
  gap: var(--space-16);
}
.cta-band__logo { height: 40px; width: auto; align-self: flex-start; }
@media (min-width: 48em) { .cta-band { padding: var(--space-56) var(--space-40); gap: var(--space-20); } }

/* ── Footer ──────────────────────────────────────────────────────────── */

.site-footer {
  background: var(--ground-dark);
  color: var(--text-inverse);
  --accent: var(--copper-tint);
  --text: var(--text-inverse);
  margin-top: var(--space-56);
  padding: var(--space-40) var(--space-20);
}
.site-footer__inner {
  max-width: var(--shell-max);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-40);
}
.site-footer__cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-32);
}
.site-footer__logo { height: 56px; width: auto; margin-bottom: var(--space-16); }
.site-footer__tagline { color: var(--steel); max-width: 24ch; }

.site-footer__heading {
  font-stretch: var(--w-label);
  font-weight: var(--fw-label);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--steel);
  margin-bottom: var(--space-14);
}
.site-footer__heading--spaced { margin-top: var(--space-28); }

.site-footer__list { display: flex; flex-direction: column; gap: var(--space-10); }
.site-footer__list--tight { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-10) var(--space-16); }
.site-footer__list a {
  color: var(--white);
  text-decoration: none;
  font-size: var(--fs-support);
  overflow-wrap: anywhere;
}
.site-footer__list a:hover { color: var(--copper-tint); text-decoration: underline; }
.site-footer__meta { color: var(--steel); font-size: var(--fs-support); }

.site-footer__legal {
  border-top: var(--border-hair-dark);
  padding-top: var(--space-20);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-16) var(--space-24);
  align-items: center;
  justify-content: space-between;
}
.site-footer__legal p { font-size: var(--fs-micro); color: var(--steel); letter-spacing: 0.02em; }
.site-footer__credits { color: var(--steel); }
.site-footer__credits:hover { color: var(--copper-tint); }

@media (min-width: 48em) { .site-footer { padding: var(--space-56) var(--space-40); } }
