/* ==========================================================================
   tokens.css — SOURCE. Project-specific. Replace per client.

   Palette grounded in the actual materials of the trade: copper pipe,
   cast-iron/slate ironmongery, galvanised steel, invoice paper. This is
   NOT a neutral starting point — do real art direction for the next
   client rather than reusing these values (see README.md).
   ========================================================================== */

:root {
  /* ---- Palette (name every value, don't leave it as a raw hex) ---- */
  --ink:          #1c2422; /* body text, headings — cast-iron */
  --ink-deep:     #121917; /* footer / dark section background */
  --copper:       #b5622f; /* primary accent — copper pipe */
  --copper-light: #d98a54; /* hover state on copper */
  --brass:        #a9843f; /* secondary accent — brass fittings */
  --steel:        #5b6b6e; /* muted text, borders — galvanised steel */
  --steel-light:  #c7cfd0; /* hairline borders on light backgrounds */
  --paper:        #f2efe7; /* page background — invoice/job-sheet paper */
  --white:        #ffffff;

  /* Alias every build's own accent onto this name — base.css focus
     rings and any shared component key off --accent, not a specific
     brand color, so this line is the only thing a new build changes
     to keep those working. */
  --accent: var(--copper);

  /* ---- Type ---- */
  /* Display: condensed, upright, a bit industrial — the kind of face
     that already lives on van livery and site boards, used here on
     purpose rather than a soft editorial serif. Body: a workmanlike
     grotesque that stays legible small. Mono: quotes, reg numbers,
     job-ticket data — reads like a stamped/typed detail. */
  --font-display: 'Oswald', 'Arial Narrow', sans-serif;
  --font-body: 'Inter', -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', 'Courier New', monospace;

  --fs-h1: clamp(2.25rem, 1.4rem + 3.5vw, 3.75rem);
  --fs-h2: clamp(1.75rem, 1.3rem + 1.8vw, 2.5rem);
  --fs-h3: 1.25rem;
  --fs-lede: clamp(1.05rem, 1rem + 0.3vw, 1.2rem);
  --fs-body: 1rem;
  --fs-small: 0.875rem;

  --lh-tight: 1.1;
  --lh-normal: 1.6;

  /* ---- Spacing scale ---- */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4.5rem;

  /* ---- Layout ---- */
  --container-max: 72rem;
  /* Floor + ceiling so this never collapses to nothing on a narrow
     phone or blows out to nothing on an ultra-wide screen. */
  --container-pad: clamp(1.25rem, 1rem + 3vw, 5rem);
  --radius: 0.5rem;
  --radius-lg: 1rem;
  --nav-height: 4.5rem;

  /* ---- Generic alias layer ----
     If this site ever grows an internal/admin page built against the
     kit's generic template names (--color-accent, --space-1..8, .card,
     .form-field, .btn--ghost, etc.) it should render correctly with
     zero extra work. Keep this block present in every client's
     tokens.css from the start rather than discovering it's missing
     after an admin page is already built and unstyled. */
  --color-accent: var(--copper);
  --color-bg: var(--paper);
  --color-bg-alt: var(--white);
  --color-text: var(--ink);
  --color-text-muted: var(--steel);
  --color-border: var(--steel-light);
  --color-white: var(--white);
  --text-sm: var(--fs-small);
}
/* ==========================================================================
   base.css — SOURCE. Reusable as-is across every build.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Tied to the nav's actual height so every anchor jump (fragment
     nav, scrollIntoView, skip links) lands below the sticky header
     instead of flush underneath it. */
  scroll-padding-top: var(--nav-height);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-normal);
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: var(--lh-tight);
  text-wrap: balance;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.01em;
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }

p { text-wrap: pretty; }

a { color: inherit; }

img, svg { max-width: 100%; display: block; }
img { height: auto; }

ul, ol { list-style: none; padding: 0; }

button, input, select, textarea {
  font: inherit;
  color: inherit;
}
button { cursor: pointer; background: none; border: none; }

/* Every design system tends to grow a shared flex/card utility that
   sets display:flex on its children — that silently beats the
   browser's own [hidden]{display:none} default on any element that
   carries both. Baked in here from the start rather than discovered
   as a live bug later. pointer-events:none is a CSS-only fallback so
   a hidden element can never intercept clicks/scroll even if the
   class logic driving visibility regresses. */
[hidden] {
  display: none !important;
  pointer-events: none !important;
}

:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* ==========================================================================
   layout.css — SOURCE. Reusable as-is across every build.

   Three breakpoints, reused everywhere — don't introduce a fourth:
     max-width: 640px   mobile
     max-width: 960px   tablet & down
     min-width: 961px   desktop & up
   ========================================================================== */

.container {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

.container--narrow {
  max-width: 42rem;
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

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

.section--alt { background: var(--white); }

.section--dark {
  background: var(--ink-deep);
  color: var(--paper);
}

.section__head {
  max-width: 40rem;
  margin-bottom: var(--space-6);
}

.section__head--center {
  margin-inline: auto;
  text-align: center;
}

/* Vertical rhythm between children. */
.stack { display: flex; flex-direction: column; }
.stack > * + * { margin-top: var(--space-4); }
.stack--tight > * + * { margin-top: var(--space-2); }
.stack--loose > * + * { margin-top: var(--space-6); }
/* margin-top does nothing to inline elements — a stack of bare <a>
   tags (e.g. a footer link list) collapses onto one line without
   this, even though the markup itself is perfectly correct. */
.stack > a { display: block; }

/* Horizontal wrapping group. */
.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.cluster--between { justify-content: space-between; }
.cluster--center { justify-content: center; }

/* 50/50 two-column, collapses under the tablet breakpoint. */
.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-7);
  align-items: center;
}
.split--reverse .split__media { order: -1; }
@media (max-width: 960px) {
  .split { grid-template-columns: 1fr; gap: var(--space-6); }
  .split--reverse .split__media { order: 0; }
}

/* Self-wrapping card/image grid. */
.grid-auto {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--space-5);
}

/* Locked 3-column grid, e.g. testimonials or step lists. */
.grid-fixed-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-5);
}
@media (max-width: 960px) {
  .grid-fixed-3 { grid-template-columns: 1fr; }
}

.grid-fixed-2 {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-5);
}
@media (max-width: 640px) {
  .grid-fixed-2 { grid-template-columns: 1fr; }
}
/* ==========================================================================
   components.css — SOURCE.
   Nav / button / card / form mechanics are reusable as-is; colors,
   radius, and the pipe-line signature element are this build's own —
   swap those for a real design plan on the next client, don't just
   recolor this one (see README.md).
   ========================================================================== */

/* ---------------------------------------------------------------------
   Nav
   Mobile-first: base rules here are the mobile dropdown nav.
   @media (min-width: 961px) turns it into an inline desktop row.
   .nav__bar and .nav__panel are both children of .nav__inner (one flex
   row) rather than separate siblings — keeping them siblings is what
   caused misaligned nav links on an earlier build.
--------------------------------------------------------------------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--paper);
  border-bottom: 1px solid transparent;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.nav--scrolled {
  border-color: var(--steel-light);
  box-shadow: 0 4px 16px rgba(18, 25, 23, 0.06);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: relative;
  height: var(--nav-height);
}

.nav__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

.nav__logo {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-weight: 600;
  font-size: 1.15rem;
  letter-spacing: 0.02em;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
}
.nav__logo span { color: var(--copper); }

.nav__toggle {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
}
.nav__toggle-bar {
  display: block;
  width: 1.5rem;
  height: 2px;
  background: var(--ink);
  transition: transform 0.2s ease, opacity 0.2s ease;
}
.nav--open .nav__toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav--open .nav__toggle-bar:nth-child(2) { opacity: 0; }
.nav--open .nav__toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Dropdown panel, hidden via opacity/visibility (not display, and not
   the [hidden] attribute) so the SAME class the JS toggles is the
   only thing either state depends on — a mismatch between the two is
   what leaves an invisible-but-still-interactive overlay blocking the
   page on other sites that got this wrong. pointer-events:none is the
   fallback in case that ever regresses. */
.nav__panel {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4) var(--container-pad) var(--space-5);
  background: var(--white);
  box-shadow: 0 16px 32px rgba(18, 25, 23, 0.14);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(-0.5rem);
  transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
}
.nav__panel.open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: translateY(0);
}

/* The mobile nav links need their own scoping so the "Call now" CTA
   button dropped in alongside them keeps its full button treatment —
   without :not(.btn) here, the plain-link rule below wins on
   specificity and flattens the button back to plain text. */
.nav__panel a:not(.btn) {
  display: block;
  padding: var(--space-2) 0;
  font-weight: 600;
  text-decoration: none;
  color: var(--ink);
  border-bottom: 1px solid var(--steel-light);
}
.nav__panel a:not(.btn):hover { color: var(--copper); }
.nav__panel .btn { margin-top: var(--space-3); }

@media (min-width: 961px) {
  .nav__toggle { display: none; }
  .nav__bar { width: auto; }
  .nav__panel {
    position: static;
    flex-direction: row;
    align-items: center;
    gap: var(--space-6);
    padding: 0;
    background: none;
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
  }
  .nav__panel a:not(.btn) {
    padding: 0;
    border-bottom: none;
  }
  .nav__panel .btn { margin-top: 0; }
}

/* ---------------------------------------------------------------------
   Buttons
--------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center; /* without this, a full-width button in a
                               flex column pins its label to the left */
  gap: 0.5rem;
  padding: 0.9rem 1.6rem;
  border-radius: var(--radius);
  border: 2px solid transparent;
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.btn--primary { background: var(--copper); color: var(--white); }
.btn--primary:hover { background: var(--copper-light); }
.btn--outline { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn--outline:hover { border-color: var(--copper); color: var(--copper); }
.btn--block { width: 100%; }
.btn--sm { padding: 0.6rem 1.1rem; font-size: 0.85rem; }

/* ---------------------------------------------------------------------
   Eyebrow + signature "pipe-line" element
   One straight line + one flange mark — a single flat shape with its
   own border, not two independently-curved shapes layered on top of
   each other, which is what caused a hairline color-bleed at the
   corner seams on an earlier build. Used once, under the hero
   headline, not repeated through every section.
--------------------------------------------------------------------- */
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--steel);
}

.pipe-line {
  position: relative;
  width: 7rem;
  height: 3px;
  background: var(--copper);
  margin-block: var(--space-4);
}
.pipe-line::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 68%;
  width: 0.85rem;
  height: 0.85rem;
  background: var(--paper);
  border: 2px solid var(--copper);
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

/* ---------------------------------------------------------------------
   Hero
--------------------------------------------------------------------- */
.hero__grid {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: var(--space-7);
  align-items: center;
}
@media (max-width: 960px) {
  .hero__grid { grid-template-columns: 1fr; gap: var(--space-6); }
}

.hero__lede {
  font-size: var(--fs-lede);
  color: var(--steel);
  max-width: 34rem;
}

.hero__actions { margin-top: var(--space-6); }

.hero__media { position: relative; }

.hero__image {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--radius-lg);
  /* A single box-shadow gives the offset/depth effect without a
     second curved shape sitting behind it to keep in sync. */
  box-shadow: 0 24px 48px rgba(18, 25, 23, 0.28);
}

.ticket-card {
  position: absolute;
  left: -1.25rem;
  bottom: -1.5rem;
  max-width: 15rem;
  background: var(--paper);
  border: 1px solid var(--steel-light);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  box-shadow: 0 14px 28px rgba(18, 25, 23, 0.18);
}
.ticket-card__label {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--copper);
  margin-bottom: var(--space-2);
}
.ticket-card__list > div {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: 0.8rem;
  padding-block: 0.3rem;
  border-top: 1px dashed var(--steel-light);
}
.ticket-card__list > div:first-child { border-top: none; }
.ticket-card__list dt { color: var(--steel); }
.ticket-card__list dd { font-family: var(--font-mono); font-weight: 600; }

@media (max-width: 960px) {
  .ticket-card {
    position: static;
    max-width: none;
    margin-top: -2rem;
    margin-inline: var(--space-4);
  }
}

/* ---------------------------------------------------------------------
   Trust strip
--------------------------------------------------------------------- */
.trust-strip {
  background: var(--ink-deep);
  color: var(--paper);
  padding-block: var(--space-4);
}
.trust-strip__item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--fs-small);
  font-weight: 600;
}
.trust-strip__icon { color: var(--copper-light); flex-shrink: 0; }

/* ---------------------------------------------------------------------
   Cards — services, steps, reviews
--------------------------------------------------------------------- */
.card {
  background: var(--white);
  border: 1px solid var(--steel-light);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}

.service-card__icon {
  width: 2.75rem;
  height: 2.75rem;
  color: var(--copper);
  margin-bottom: var(--space-4);
}
.service-card h3 { margin-bottom: var(--space-2); font-size: 1.1rem; }
.service-card p { color: var(--steel); font-size: var(--fs-small); }

.step {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
}
.step__number {
  flex-shrink: 0;
  width: 2.75rem;
  height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 2px solid var(--copper);
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--copper);
}
.step h3 { margin-bottom: var(--space-1); font-size: 1.05rem; }
.step p { color: var(--steel); font-size: var(--fs-small); }

.review-card__stars {
  display: flex;
  gap: 0.2rem;
  color: var(--brass);
  margin-bottom: var(--space-3);
}
.review-card__stars svg { width: 1rem; height: 1rem; }
.review-card p { font-style: italic; margin-bottom: var(--space-4); }
.review-card__author {
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  color: var(--steel);
  font-style: normal;
}

/* ---------------------------------------------------------------------
   Area chips
--------------------------------------------------------------------- */
.chip-list { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.chip {
  font-size: var(--fs-small);
  font-weight: 600;
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--steel-light);
  border-radius: 999px;
  background: var(--white);
}

/* ---------------------------------------------------------------------
   Contact form
--------------------------------------------------------------------- */
.field { position: relative; margin-bottom: var(--space-4); }
.field label {
  display: block;
  font-size: var(--fs-small);
  font-weight: 600;
  margin-bottom: var(--space-2);
}
.field input,
.field select,
.field textarea {
  width: 100%;      /* without this a field sizes to its own intrinsic
                        width instead of filling its column, and can
                        overflow the card entirely on a narrow layout */
  min-width: 0;
  padding: 0.75rem;
  border: 1.5px solid var(--steel);
  border-radius: var(--radius);
  background: var(--white);
  font-size: 1rem;
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--copper);
}
.field textarea { resize: vertical; min-height: 8rem; }

.contact-card {
  background: var(--ink-deep);
  color: var(--paper);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}
.contact-card h3 { margin-bottom: var(--space-4); }
.contact-card__row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-block: var(--space-3);
  border-top: 1px solid rgba(242, 239, 231, 0.15);
}
.contact-card__row:first-of-type { border-top: none; }
.contact-card__row a { text-decoration: none; font-weight: 600; }
.contact-card__row a:hover { color: var(--copper-light); }
.contact-card__icon { flex-shrink: 0; width: 1.3rem; height: 1.3rem; color: var(--copper-light); }

/* ---------------------------------------------------------------------
   Footer
--------------------------------------------------------------------- */
.footer {
  background: var(--ink-deep);
  color: var(--paper);
  padding-block: var(--space-6);
  border-top: 1px solid rgba(242, 239, 231, 0.1);
}
.footer a { text-decoration: none; }
.footer a:hover { color: var(--copper-light); }
.footer__meta { font-size: var(--fs-small); color: var(--steel-light); }
.footer__social {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  border: 1.5px solid rgba(242, 239, 231, 0.3);
}
.footer__social svg { width: 1.1rem; height: 1.1rem; }

/* ---------------------------------------------------------------------
   Scroll reveal
   Default state is fully visible. JS adds .reveal-pending itself
   before animating — the CSS never sets opacity:0 unconditionally, so
   content attached to this never vanishes permanently if the script
   fails to load or run.
--------------------------------------------------------------------- */
[data-reveal] { opacity: 1; transform: none; }
.reveal-pending { opacity: 0; transform: translateY(1rem); }
.revealed {
  opacity: 1;
  transform: none;
  transition: opacity 0.6s ease, transform 0.6s ease;
}
@media (prefers-reduced-motion: reduce) {
  .reveal-pending, .revealed { opacity: 1; transform: none; transition: none; }
}
