/* ==========================================================================
   KW ELECTRICAL SERVICES — V2 stylesheet
   --------------------------------------------------------------------------
   Dark navy ground, orange heat, condensed display type.
   Mobile-first. Component-based: campaign landing pages can lift
   tokens + base + .site-header + .ticker + .trust-chips + .cta-band
   + .btn + .section/.container + .site-footer without the rest.
   --------------------------------------------------------------------------
   CONTENTS
   01 Design tokens          09 Feature split (Why KW)
   02 Base / reset           10 Process strip
   03 Utilities              11 CTA band (reusable)
   04 Buttons                12 Review cards
   05 Site header            13 Service area columns
   06 Hero                   14 Contact form
   07 Ticker marquee         15 Photo placeholders
   08 Stats band + cards     16 Site footer
   ========================================================================== */

/* Self-hosted brand faces. Subset to latin, woff2 only, swap so text is
   readable immediately on a slow connection. */
@font-face {
  font-family: "Archivo Black";
  font-style: normal; font-weight: 400; font-display: swap;
  src: url("../assets/fonts/archivo-black-400.woff2") format("woff2");
}
@font-face { font-family: "Inter"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("../assets/fonts/inter-400.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("../assets/fonts/inter-600.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("../assets/fonts/inter-700.woff2") format("woff2"); }

/* 01 — Design tokens ----------------------------------------------------- */
:root {
  /* Brand (from KW brand doc) */
  --navy: #032540;
  /* Kyle's brand orange is #ff6b00. What ships is two points darker in
     lightness, hue and saturation untouched (hsl 25, 100%, 48% instead of
     50%). Kyle's team found the original glared on some monitors, and the
     cause is the red channel sitting pinned at 255, which clips on
     wide-gamut screens. Side by side it reads as the same orange. */
  --orange: #f56600;
  /* Same hue again, dark enough to clear WCAG AA on a white ground. The
     brand orange only manages 3.1:1 there, this is 4.7:1. Used ONLY for
     small orange text on white. Anything on navy uses --orange. */
  --orange-ink: #c25100;
  --white: #ffffff;

  /* Derived surfaces */
  --bg: #041c31;             /* main dark ground */
  --bg-deep: #02121f;        /* footer / darkest */
  --panel: #0a3352;          /* raised navy panel */
  --line-dark: rgba(255, 255, 255, 0.10);

  /* Text on dark */
  --text: #eaf2f8;
  --muted: #9db3c5;

  /* Text on light */
  --ink: #10222f;
  --ink-soft: #4a5b6b;
  --tint: #f4f7fa;
  --line: #dde5ec;

  /* Type. Archivo Black: wide, open letterforms, matches the logo lettering
     and reads better than a condensed face at small sizes */
  --font-display: "Archivo Black", "Arial Black", sans-serif;
  --font-body: "Inter", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  /* Small-text floor lifted: primary audience skews older homeowners */
  --fs-base: 1.0625rem;
  --fs-sm: 0.9375rem;
  --fs-xs: 0.8125rem;
  --fs-lg: 1.1875rem;
  --fs-h1: clamp(2rem, 7.5vw, 4.1rem);
  --fs-h2: clamp(1.55rem, 4.6vw, 2.4rem);
  --fs-h3: 1.1rem;

  /* Rhythm (section padding scales down on small screens) */
  --space-1: 0.5rem;
  --space-2: 1rem;
  --space-3: 1.5rem;
  --space-4: clamp(1.75rem, 5vw, 2.5rem);
  --space-5: clamp(3rem, 9vw, 4.5rem);
  --radius: 10px;
  --radius-lg: 18px;
  --shadow: 0 10px 40px rgba(0, 0, 0, 0.35);

  --header-h: 56px;
  --container: 1140px;

  /* Motion. One easing curve and two durations across the whole site so every
     hover feels like it came from the same place. Killed entirely by the
     prefers-reduced-motion block in §02. */
  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);
  --dur: 0.18s;
  --dur-slow: 0.35s;
}
@media (min-width: 640px) { :root { --header-h: 68px; } }

/* 02 — Base ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 8px);
  /* stop Android Chrome inflating text sizes */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: 1.65;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

/* One visible focus ring for keyboard users across the whole site */
:where(a, button, summary, input, textarea):focus-visible {
  outline: 3px solid var(--orange);
  outline-offset: 3px;
  border-radius: 6px;
}
main:focus { outline: none; }

/* Skip link: first thing a keyboard or screen reader user hits, invisible
   until it's focused. Saves them tabbing through the header on every visit. */
.skip-link {
  position: absolute;
  left: var(--space-3);
  top: -100px;
  z-index: 200;
  padding: 0.85rem 1.4rem;
  background: var(--orange);
  color: #051a2b;
  font-family: var(--font-display);
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-decoration: none;
  border-radius: var(--radius);
  transition: top var(--dur) var(--ease);
}
.skip-link:focus { top: var(--space-2); }
h1, h2, h3 { margin: 0 0 var(--space-2); line-height: 1.05; }
p { margin: 0 0 var(--space-2); }
a { color: var(--orange); }

/* Display type: condensed caps, tight leading */
.display {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.005em;
  line-height: 1.08;
}
.display em { font-style: normal; color: var(--orange); }

/* Kicker label with orange dash — used above every section heading */
.kicker {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--muted);
  margin: 0 0 var(--space-2);
}
.kicker::before { content: ""; width: 34px; height: 2px; background: var(--orange); flex: none; }
.on-light .kicker { color: var(--ink-soft); }

/* Small orange text on a white ground uses --orange-ink so it clears WCAG AA.
   Anything on navy uses --orange. */
.on-light a:not(.btn),
.form-card a:not(.btn),
.form-note a,
.review-card a:not(.btn) { color: var(--orange-ink); }
/* Large orange display headings on white now measure 3.1:1, which clears the
   3:1 large-text threshold. They used to fail at 2.86:1 and were a knowing
   exception; softening the orange for Kyle fixed that as a side effect.
   One knowing exception remains: the same heading on the tinted panel
   (--tint) measures 2.88:1. It is a single italicised word inside a heading
   that is otherwise --ink, so the sentence still reads at full contrast.
   Fixing it would mean either a second, duller orange or washing the tint
   out to near-white, which would erase the white review cards sitting on it.
   Neither is worth it for one decorative word. */

/* 03 — Utilities ------------------------------------------------------------ */
.container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--space-3); }

.section { padding-block: var(--space-5); }
.section--panel { background: linear-gradient(180deg, #06294a 0%, var(--bg) 100%); }
.on-light { background: var(--white); color: var(--ink); }
.on-light.tinted { background: var(--tint); }

/* Branch-mark pattern (reusable). Sits behind the content as a low-contrast
   texture, never over body copy at full strength. Two tiles: light for dark
   grounds, dark for the orange band. Density and strength are per-instance:
     <section class="section pattern-bg pattern-bg--light">
   --pattern-size and --pattern-opacity override per block. */
.pattern-bg { position: relative; }
.pattern-bg > * { position: relative; z-index: 1; }
.pattern-bg::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-repeat: repeat;
  background-size: var(--pattern-size, 120px) var(--pattern-size, 120px);
  opacity: var(--pattern-opacity, 0.05);
}
.pattern-bg--light::before { background-image: url("../assets/pattern-light.webp"); }
.pattern-bg--dark::before { background-image: url("../assets/pattern-dark.webp"); }
/* Fade the texture out towards the bottom so it never fights the next section */
.pattern-bg--fade::before {
  mask-image: linear-gradient(180deg, #000 0%, #000 45%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 45%, transparent 100%);
}

/* 04 — Buttons --------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 54px;
  padding: 0.9rem 1.7rem;
  border: 2px solid transparent;
  border-radius: var(--radius);
  font-family: var(--font-display);
  font-size: 0.95rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.12s ease, background-color 0.12s ease, box-shadow 0.12s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0) scale(0.985); }
.btn .btn__icon { width: 1.15em; height: 1.15em; flex: none; }

.btn--call {
  background: var(--orange);
  color: #051a2b;
  box-shadow: 0 6px 24px rgba(245, 102, 0, 0.28);
}
.btn--call:hover { background: #ff7614; box-shadow: 0 10px 30px rgba(245, 102, 0, 0.38); }

.btn--dark { background: #05131f; color: var(--white); }
.btn--dark:hover { background: #0b2438; }

.btn--ghost { border-color: rgba(255, 255, 255, 0.55); color: var(--white); background: transparent; }
.btn--ghost:hover { border-color: var(--white); background: rgba(255, 255, 255, 0.08); }

.btn--block { width: 100%; }
@media (min-width: 640px) { .btn--block { width: auto; } }

/* 05 — Site header (reusable) -------------------------------------------------- */
/* Orange banner header. Kyle's pick over the navy one, 18 Aug 2026.
   Solid rather than translucent: orange over a moving photo background went
   muddy, and the black wordmark needs a stable ground to sit on. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--orange);
  border-bottom: 1px solid rgba(0, 0, 0, 0.18);
}
.site-header.is-scrolled { box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35); }
/* Dark pill on orange. White-on-orange fails contrast, near-black passes at 8.9:1
   and reads as a deliberate second brand colour rather than a washed-out button. */
.site-header .btn--call { background: #05131f; color: #ffffff; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28); }
.site-header .btn--call:hover { background: #0b2438; box-shadow: 0 10px 26px rgba(0, 0, 0, 0.35); }
.site-header :where(a, button):focus-visible { outline-color: #05131f; }
/* On phones the header and the bottom call bar swap places on scroll, so only
   one call CTA is ever pinned to the screen. Driven by js/main.js §4. */
.site-header { transition: transform var(--dur-slow) var(--ease); will-change: transform; }
.site-header.is-tucked { transform: translateY(-102%); }
@media (min-width: 640px) { .site-header.is-tucked { transform: none; } }

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  min-height: var(--header-h);
  padding-block: 6px;
}
/* Black wordmark, for the orange banner */
.site-header__logo { flex: none; }
.site-header__logo img { height: 34px; width: auto; transition: opacity var(--dur) var(--ease); }
.site-header__logo:hover img { opacity: 0.82; }
@media (min-width: 640px) { .site-header__logo img { height: 46px; } }

.site-header .btn {
  min-height: 42px;
  padding: 0.4rem 1rem;
  font-size: 0.9rem;
  white-space: nowrap;   /* never let the number wrap the button */
  flex: none;
}
@media (min-width: 640px) { .site-header .btn { min-height: 46px; padding: 0.5rem 1.15rem; font-size: 0.95rem; } }

/* Kyle asked (17 Aug) for the number to stay visible on the sticky bar, and
   dropped the word "CALL" from the header button. So the number is the button
   now and never hides. Tightened padding so it still fits a 320px screen. */
.site-header .btn__number { display: inline; }
@media (max-width: 380px) {
  .site-header .btn { padding-inline: 0.7rem; font-size: 0.85rem; gap: 0.4rem; }
  .site-header__logo img { height: 30px; }
}

/* 06 — Hero --------------------------------------------------------------------- */
/* Full-bleed dark hero. .hero__bg is the photo slot: a gradient stack over a
   background image, so the headline always has a dark ground to sit on. */
.hero { position: relative; overflow: hidden; }

/* The photo is the team shot, so the scrim is upside down compared with a
   texture hero: heaviest at the top where the headline sits, easing off over
   the crew so faces and orange shirts still read, then closing back to --bg at
   the very bottom so the hero joins the next section cleanly. The crop puts
   boots above that closing band, so the fade eats dirt, not people. */
/* Kyle's pick, 24 Aug 2026: the crew photo behind the hero copy.
   Two crops, because one does not serve both shapes. Desktop gets the close
   shot cropped hard onto the six of them, with the dead ute cut off either
   side so nobody is small. Phones and tablets get the wide shot, which has the
   room a narrow screen needs; the close crop at 390px would show two torsos.
   The scrim is heavier at the top, where the headline sits, and eases off over
   the crew before closing into --bg at the very bottom. */
:root { --hero-img: url("../assets/hero-sm.webp"); }
@media (min-width: 1000px) {
  :root { --hero-img: url("../assets/hero.webp"); }
}

.hero__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: #052642;
  background-image:
    linear-gradient(180deg,
      rgba(2, 18, 31, 0.92) 0%,
      rgba(2, 18, 31, 0.88) 38%,
      rgba(2, 18, 31, 0.70) 60%,
      rgba(2, 18, 31, 0.62) 86%,
      var(--bg) 100%),
    var(--hero-img);
  /* Phones sit the frame at 40% so the crew land under the copy. Desktop
     anchors to the top, which is where the close crop puts their heads. */
  background-position: center, center 40%;
  background-size: cover, cover;
  background-repeat: no-repeat;
}
/* From 1000px the copy occupies the left, so the scrim can be weighted that
   way: near solid under the words, easing off across the crew on the right.
   An even scrim heavy enough for the lead paragraph would flatten the whole
   photo, which is the thing this option exists to show. */
@media (min-width: 1000px) {
  .hero__bg {
    background-image:
      linear-gradient(90deg,
        rgba(2, 18, 31, 0.90) 0%,
        rgba(2, 18, 31, 0.86) 42%,
        rgba(2, 18, 31, 0.60) 58%,
        rgba(2, 18, 31, 0.42) 74%,
        rgba(2, 18, 31, 0.40) 100%),
      linear-gradient(180deg,
        rgba(2, 18, 31, 0.44) 0%,
        rgba(2, 18, 31, 0.30) 55%,
        rgba(2, 18, 31, 0.42) 86%,
        var(--bg) 100%),
      var(--hero-img);
    background-size: cover, cover, cover;
  }
}
@media (min-width: 1000px) {
  .hero__bg { background-position: center, center, center top; }
}
/* faint grid texture over the hero ground */
.hero__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px);
  background-size: 52px 52px;
  mask-image: radial-gradient(80% 70% at 50% 30%, #000 40%, transparent 100%);
}

.hero__inner { padding-block: var(--space-5) 0; }

.hero__title { font-size: var(--fs-h1); max-width: 9em; margin-bottom: var(--space-2); }

/* Location and category line lives inside the H1 so search engines read it,
   but sits small so the slogan stays the hero moment. */
.hero__title-sub {
  display: block;
  font-family: var(--font-body);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: clamp(0.8rem, 3vw, 1rem);
  line-height: 1.35;
  color: var(--muted);
  max-width: 22em;
  margin-bottom: 0.7rem;
}

.hero__lead { color: #c9d9e6; font-size: var(--fs-lg); max-width: 33em; margin-bottom: var(--space-3); }
.hero__lead strong { color: var(--white); }

.hero__actions { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: 0; }
/* Below 640px the hero card carries "Get a quote", so this one would be a
   straight duplicate. One call CTA and one quote CTA in the hero, no more. */
.hero__actions .btn--ghost { display: none; }
@media (min-width: 640px) { .hero__actions { flex-direction: row; align-items: center; } }
@media (min-width: 1120px) { .hero__actions .btn--ghost { display: inline-flex; } }

/* Floating guarantee card (Drain Unblockers move) */
.hero__card {
  background: var(--orange);
  color: #051a2b;
  border-radius: var(--radius-lg);
  padding: var(--space-3);
  max-width: 420px;
  box-shadow: var(--shadow);
  margin-block: var(--space-4) var(--space-5);
}
.hero__card-title { font-family: var(--font-display); text-transform: uppercase; font-size: 1.3rem; line-height: 1.15; margin: 0 0 var(--space-2); }
.hero__card .btn { width: 100%; }
@media (min-width: 1120px) {
  /* Card floats bottom-right. The hero text gets a hard right gutter the width
     of the card plus a gap, so the lead can never run underneath it. */
  .hero__inner { padding-block: var(--space-5); padding-right: calc(420px + var(--space-5)); }
  .hero__card { position: absolute; right: var(--space-3); bottom: var(--space-5); margin: 0; }
}

/* Featured social proof. Strongest single trust signal, so it gets its own
   treatment above the credential chips rather than sitting inside them. */
.trust-rating {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  background: rgba(255, 255, 255, 0.09);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 999px;
  padding: 0.55rem 1.15rem;
  margin-bottom: var(--space-2);
}
.trust-rating__stars { display: flex; gap: 2px; color: var(--orange); flex: none; }
.trust-rating__stars svg { width: 20px; height: 20px; }
.trust-rating__text { font-weight: 700; color: var(--white); font-size: var(--fs-sm); line-height: 1.2; }
.trust-rating__text span { color: var(--muted); font-weight: 600; }

/* Credential chips row (Powerhaus move), reusable on landing pages */
.trust-chips {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem 1.5rem;
  align-items: center;
}
.trust-chips li { display: flex; align-items: center; gap: 0.5rem; font-size: var(--fs-sm); color: #c9d9e6; font-weight: 600; }
.trust-chips svg { width: 18px; height: 18px; color: var(--orange); flex: none; }

/* 07 — Ticker marquee (reusable) --------------------------------------------------- */
.ticker { background: var(--orange); color: #051a2b; overflow: hidden; padding-block: 0.8rem; }
.ticker__track {
  display: flex;
  gap: 2.4rem;
  width: max-content;
  animation: ticker-scroll 28s linear infinite;
}
.ticker__item {
  display: flex;
  align-items: center;
  gap: 2.4rem;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
.ticker__item::after { content: "✦"; font-size: 0.8em; }
@keyframes ticker-scroll { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .ticker__track { animation: none; flex-wrap: wrap; width: auto; } }

/* 08 — Stats band + service cards ---------------------------------------------------- */
/* Always 3-across, Powerhaus style; scales down instead of stacking */
.stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2) var(--space-3);
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--line-dark);
  text-align: center;
}
@media (min-width: 640px) { .stats { text-align: left; } }

.stat__value { font-family: var(--font-display); font-size: clamp(1.5rem, 5.5vw, 3.2rem); color: var(--white); line-height: 1; margin: 0; }
.stat__value em { font-style: normal; color: var(--orange); }
.stat__label { color: var(--muted); font-size: clamp(0.72rem, 2.6vw, 0.875rem); margin: 0.4rem 0 0; line-height: 1.3; }

/* Numbered service cards (Powerhaus move). .card__media is the photo slot —
   swap the gradient for a real job photo per service. */
.card-grid { display: grid; grid-template-columns: 1fr; gap: var(--space-2); }
@media (min-width: 640px) { .card-grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1000px) { .card-grid { grid-template-columns: repeat(4, 1fr); gap: var(--space-3); } }

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 250px;
  container-type: inline-size;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--line-dark);
  background:
    linear-gradient(185deg, rgba(2, 18, 31, 0.15) 30%, rgba(2, 18, 31, 0.92) 82%),
    radial-gradient(420px 260px at 78% 8%, rgba(245, 102, 0, 0.20), transparent 60%),
    linear-gradient(150deg, #0b3a5e 0%, #062a48 55%, #04203a 100%);
  padding: var(--space-3) var(--space-2) var(--space-2);
  transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.card:hover {
  transform: translateY(-4px);
  border-color: rgba(245, 102, 0, 0.55);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.4);
}
.card__num, .card__title, .card__text { position: relative; z-index: 1; }
.card:hover .card__icon { transform: translateY(-3px) scale(1.05); opacity: 0.42; }
.card:hover .card__num { color: var(--orange); }

/* Photo cards.
   The image used to be passed in from the HTML as an inline --img custom
   property. Chrome resolves url() inside a custom property against the
   STYLESHEET, not the document, so every one of these was silently 404ing at
   css/assets/... and the cards had been rendering as plain gradients since V1.
   Declaring them here fixes the paths and keeps the markup clean. */
.card--solar       { --img: url("../assets/card-solar.webp"); }
.card--aircon      { --img: url("../assets/card-aircon.webp"); }
.card--switchboard { --img: url("../assets/card-switchboard.webp"); }
.card--ergon       { --img: url("../assets/pole.webp"); }
.card--rural       { --img: url("../assets/card-rural.webp"); }
/* Kyle's own job photos, supplied 18 and 20 Aug. */
.card--newbuilds   { --img: url("../assets/card-newbuilds.webp"); }
.card--cables      { --img: url("../assets/card-cables.webp"); }
.card--smoke       { --img: url("../assets/card-smoke.webp"); }

.card--photo {
  background:
    linear-gradient(185deg, rgba(2, 18, 31, 0.18) 0%, rgba(2, 18, 31, 0.38) 34%, rgba(2, 18, 31, 0.88) 62%, rgba(2, 18, 31, 0.97) 86%),
    var(--img) center / cover no-repeat,
    linear-gradient(150deg, #0b3a5e 0%, #04203a 100%);
}

.card__num {
  position: absolute;
  top: 0.9rem;
  left: 1rem;
  font-family: var(--font-display);
  font-size: 0.95rem;
  letter-spacing: 0.1em;
  color: rgba(255, 255, 255, 0.55);
  transition: color var(--dur) var(--ease);
}
/* Branded service icons: PNGs exported on a 200px canvas with the artwork
   scaled for equal optical mass, so a wide icon (aircon, cables) reads the
   same weight as a square one (smoke, new builds). */
/* Large icon treatment. Kyle's pick, 18 Aug 2026: the mark sits big and soft
   behind the card content instead of small in the corner. Sized as a
   percentage of the card so it scales with it instead of jumping between
   breakpoints, and capped so it never gets silly on a wide card. */
.card__icon {
  position: absolute;
  right: 3%;
  top: 5%;
  width: 46%;
  height: auto;
  aspect-ratio: 1;
  max-width: 132px;
  opacity: 0.30;
  margin: 0;
  pointer-events: none;
  z-index: 0;
  color: var(--orange);
  object-fit: contain;
  object-position: center;
  transition: transform var(--dur-slow) var(--ease), opacity var(--dur-slow) var(--ease);
}

.card__title {
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: var(--fs-h3);
  line-height: 1.2;
  color: var(--white);
  margin: var(--space-2) 0 0.3rem;
}
/* Titles wrap to two lines on the 4-across grid, so reserve the space and keep
   every title on the same baseline across a row. */
@media (min-width: 640px) { .card__title { min-height: 2.5em; display: flex; align-items: flex-end; } }
@media (min-width: 1000px) and (max-width: 1199px) { .card__title { min-height: 3.8em; } }
.card__text { font-size: var(--fs-sm); color: var(--muted); margin: 0; }
/* Reserved so the body copy starts at the same height right across a row.
   Sized off the longest description with a line of headroom, because the real
   Inter is a touch wider than the fallback these were measured in. */
@media (min-width: 640px)  { .card__text { min-height: 7.5em; } }
@media (min-width: 1000px) and (max-width: 1199px) { .card__text { min-height: 10.5em; } }
@media (min-width: 1200px) { .card__text { min-height: 8.8em; } }
/* Taller cards from the 4-across breakpoint up: the large icon and the job
   photo both need clear air above the copy, otherwise the card reads muddy. */
@media (min-width: 640px)  { .card { min-height: 300px; } }
@media (min-width: 1000px) { .card { min-height: 340px; } }

/* 09 — Feature split (Why KW) --------------------------------------------------------- */
.split { display: grid; gap: var(--space-4); align-items: center; }
@media (min-width: 900px) { .split { grid-template-columns: 1.05fr 0.95fr; } }

.checklist { list-style: none; margin: 0 0 var(--space-3); padding: 0; display: grid; gap: 1rem; }
.checklist li { display: flex; gap: 0.75rem; align-items: flex-start; }
.checklist__icon { width: 24px; height: 24px; flex: none; color: var(--orange); margin-top: 2px; }
.checklist p { margin: 0; color: var(--muted); }
.checklist strong { color: var(--white); }

/* Offset orange frame photo treatment (Powerhaus move) */
.framed { position: relative; }
.framed::after {
  content: "";
  position: absolute;
  inset: 14px -14px -14px 14px;
  border: 3px solid var(--orange);
  border-radius: var(--radius-lg);
  z-index: -1;
}

/* Real photos in split sections */
.split-photo {
  width: 100%;
  height: 100%;
  min-height: 300px;
  max-height: 480px;
  object-fit: cover;
  border-radius: var(--radius-lg);
}

/* Rotating stamp badge (Drain Unblockers move) */
.stamp {
  position: absolute;
  width: 118px;
  height: 118px;
  right: 2px;
  top: -26px;
  color: var(--white);
}
/* The stamp used to hang 18px outside its frame so it overlapped the photo
   edge. Below 1280px the frame sits close enough to the viewport edge that the
   overhang pushed past it, which gave the whole page 7 to 15px of sideways
   play depending on width. It now only hangs out where there is genuinely
   room, and shrinks on phones so it does not crowd the corner. */
@media (max-width: 559px) {
  .stamp { width: 96px; height: 96px; }
  .stamp .stamp__bolt svg { width: 28px; height: 28px; }
}
@media (min-width: 1280px) {
  .stamp { right: -18px; top: -32px; }
}
.stamp svg { width: 100%; height: 100%; animation: stamp-spin 22s linear infinite; }
.stamp .stamp__bolt { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
.stamp .stamp__bolt svg { width: 34px; height: 34px; animation: none; color: var(--orange); }
@keyframes stamp-spin { to { transform: rotate(360deg); } }

/* 10 — Process strip (on light) --------------------------------------------------------- */
.process { display: grid; gap: var(--space-3); counter-reset: step; }
/* Two-up in the middle, four-up only once the columns are genuinely wide enough
   for "STRAIGHT ESTIMATE" to sit on one line in Archivo Black. */
@media (min-width: 640px) { .process { grid-template-columns: 1fr 1fr; gap: var(--space-4) var(--space-3); } }
@media (min-width: 1040px) { .process { grid-template-columns: repeat(4, 1fr); gap: var(--space-3); } }

.process__step {
  position: relative;
  padding-top: var(--space-3);
  border-top: 3px solid var(--line);
  transition: transform var(--dur) var(--ease);
}
/* The rule above each step fills orange left-to-right on hover */
.process__step::after {
  content: "";
  position: absolute;
  top: -3px;
  left: 0;
  height: 3px;
  width: 100%;
  background: var(--orange);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-slow) var(--ease);
}
.process__step:hover { transform: translateY(-3px); }
.process__step:hover::after { transform: scaleX(1); }
.process__step:hover::before { color: var(--ink); }
.process__step:hover .process__title { color: var(--orange); }
.process__step::before {
  counter-increment: step;
  content: "0" counter(step);
  position: absolute;
  top: -0.95rem;
  left: 0;
  background: var(--white);
  padding-right: 0.7rem;
  font-family: var(--font-display);
  font-size: 1.25rem;
  color: var(--orange);
  z-index: 1;
  transition: color var(--dur) var(--ease);
}
.process__title {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: var(--fs-h3);
  color: var(--ink);
  margin: 0 0 0.35rem;
  transition: color var(--dur) var(--ease);
}
/* At four-up the columns are ~210px. Archivo Black is wide, so trim the size and
   tracking a touch to keep every title on a single line. */
@media (min-width: 1040px) {
  .process__title { font-size: 1rem; letter-spacing: -0.012em; }
}
.process__text { font-size: var(--fs-sm); color: var(--ink-soft); margin: 0; }

/* 11 — CTA band (reusable) --------------------------------------------------------------- */
.cta-band { background: var(--orange); color: #051a2b; padding-block: var(--space-4); }
.cta-band__inner { display: flex; flex-direction: column; gap: var(--space-2); align-items: flex-start; }
@media (min-width: 800px) { .cta-band__inner { flex-direction: row; align-items: center; justify-content: space-between; } }
.cta-band__title { font-size: var(--fs-h2); margin: 0; }
.cta-band__sub { margin: 0.3rem 0 0; font-weight: 600; }

/* 12 — Review cards (on light) ------------------------------------------------------------- */
.review-grid { display: grid; gap: var(--space-2); }
@media (min-width: 900px) { .review-grid { grid-template-columns: repeat(3, 1fr); gap: var(--space-3); } }

.review {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-3);
  box-shadow: 0 6px 24px rgba(3, 37, 64, 0.08);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.review:hover {
  transform: translateY(-4px);
  border-color: rgba(245, 102, 0, 0.4);
  box-shadow: 0 14px 34px rgba(3, 37, 64, 0.14);
}
.review__stars { display: flex; gap: 3px; color: var(--orange); margin-bottom: var(--space-1); }
.review__stars svg { width: 19px; height: 19px; }
.review__text { color: var(--ink); }
.review__name { font-weight: 700; color: var(--navy); margin: 0; }
.review__meta { font-size: var(--fs-sm); color: var(--ink-soft); margin: 0; }

/* 13 — Service area columns ------------------------------------------------------------------ */
.area-cols {
  columns: 2;
  column-gap: var(--space-4);
  list-style: none;
  margin: 0 0 var(--space-3);
  padding: 0;
  max-width: 520px;
}
.area-cols li {
  display: flex;
  align-items: baseline;
  gap: 0.8rem;
  padding-block: 0.55rem;
  border-bottom: 1px solid var(--line-dark);
  break-inside: avoid;
  font-weight: 600;
  color: var(--text);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), padding-left var(--dur) var(--ease);
}
.area-cols li:hover { color: var(--white); border-bottom-color: rgba(245, 102, 0, 0.6); padding-left: 0.35rem; }
.area-cols .num { font-family: var(--font-display); font-size: 0.8rem; color: var(--orange); letter-spacing: 0.08em; }

.area-callout {
  border-left: 4px solid var(--orange);
  background: rgba(245, 102, 0, 0.10);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: var(--space-2) var(--space-3);
  font-weight: 600;
  color: var(--text);
  max-width: 520px;
}

/* 13b — Licence badge cards (Pacific-style credential handling) -------------------
   .badge__logo is the slot for official accreditation artwork (QLD Electrical
   Safety, ARCTick, SAA marks). Drop the supplied logo files in and swap the
   text monogram for an <img>. */
.badge-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
@media (min-width: 900px) { .badge-grid { grid-template-columns: repeat(4, 1fr); gap: var(--space-3); } }

/* Official accreditation artwork sits on white so the marks keep their
   real brand colours (never recolour an accreditation mark). */
.badge {
  background: var(--white);
  border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-2);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.badge:hover { transform: translateY(-4px); box-shadow: 0 16px 36px rgba(0, 0, 0, 0.3); }
.badge__art { max-width: 180px; width: 100%; height: 96px; object-fit: contain; }
.badge__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 72px;
  height: 72px;
  margin-block: 12px;
  border-radius: 50%;
  border: 2.5px solid var(--navy);
  color: var(--navy);
}
.badge__label { font-size: var(--fs-sm); color: var(--ink-soft); font-weight: 600; margin: 0; line-height: 1.35; }

/* 13c — FAQ accordion (Done Right-style) ------------------------------------------- */
.faq-grid { display: grid; gap: var(--space-4); align-items: start; }
/* Left column widened from 0.85fr so the heading stops breaking mid-phrase. */
@media (min-width: 900px) { .faq-grid { grid-template-columns: 1fr 1.08fr; } }
@media (min-width: 1200px) { .faq-grid { grid-template-columns: 0.92fr 1.08fr; } }

/* The heading is two deliberate lines: "Straight answers," then "no runaround".
   Neither half may break, so it gets its own slightly tighter scale. */
.faq-title { font-size: clamp(1.45rem, 3.9vw, 2.15rem) !important; }
.faq-title em, .faq-title span { white-space: nowrap; }

.accordion { border-top: 1px solid var(--line-dark); counter-reset: faq; }

.accordion details { border-bottom: 1px solid var(--line-dark); }

.accordion summary {
  counter-increment: faq;
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 1.1rem 0;
  cursor: pointer;
  list-style: none;
  font-weight: 700;
  font-size: var(--fs-lg);
  color: var(--white);
  transition: color var(--dur) var(--ease), padding-left var(--dur) var(--ease);
}
.accordion summary:hover { color: var(--orange); padding-left: 0.3rem; }
.accordion summary:focus-visible { outline: 2px solid var(--orange); outline-offset: 3px; border-radius: 4px; }
.accordion summary::-webkit-details-marker { display: none; }
.accordion summary::before {
  content: "0" counter(faq);
  font-family: var(--font-display);
  font-size: 0.85rem;
  color: var(--orange);
  letter-spacing: 0.08em;
  flex: none;
}
.accordion summary::after {
  content: "+";
  margin-left: auto;
  font-family: var(--font-display);
  font-size: 1.4rem;
  color: var(--orange);
  line-height: 1;
  transition: transform var(--dur-slow) var(--ease);
  flex: none;
}
.accordion details[open] summary::after { transform: rotate(45deg); }
.accordion .accordion__body { padding: 0 0 1.2rem 2.4rem; color: var(--muted); }
.accordion .accordion__body p { margin: 0 0 0.6rem; }
.accordion .accordion__body p:last-child { margin-bottom: 0; }

/* 14 — Contact form ---------------------------------------------------------------------------- */
.contact-grid { display: grid; gap: var(--space-4); }
@media (min-width: 900px) { .contact-grid { grid-template-columns: 1.05fr 0.95fr; align-items: start; } }

.contact-details { display: grid; gap: var(--space-2); }
.contact-details__item { display: flex; gap: 0.8rem; align-items: flex-start; }
.contact-details__icon { width: 24px; height: 24px; flex: none; color: var(--orange); margin-top: 2px; }
/* Phone and email here are the primary conversion path on a phone, so the
   hit area gets padded out past the 24px minimum. */
.contact-details a { color: var(--white); font-weight: 700; text-decoration: none; transition: color var(--dur) var(--ease);
  display: inline-block; padding-block: 0.2rem; }
.contact-details a:hover { color: var(--orange); text-decoration: underline; text-underline-offset: 3px; }
.contact-details small { color: var(--muted); display: block; line-height: 1.55; margin-top: 0.15rem; }

.form-card { background: var(--white); color: var(--ink); border-radius: var(--radius-lg); padding: var(--space-3); box-shadow: var(--shadow); }

.form-field { margin-bottom: var(--space-2); }
.form-field label { display: block; font-weight: 600; color: var(--navy); margin-bottom: 0.35rem; font-size: var(--fs-sm); }
.form-field input,
.form-field textarea {
  width: 100%;
  padding: 0.8rem 0.9rem;
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  font: inherit;
  color: var(--ink);
  background: var(--white);
  min-height: 48px;
}
.form-field textarea { min-height: 110px; resize: vertical; }
.form-field input:focus,
.form-field textarea:focus { outline: 2px solid var(--orange); outline-offset: 1px; border-color: var(--orange); }

.form-note { font-size: var(--fs-sm); color: var(--ink-soft); margin-top: var(--space-2); margin-bottom: 0; }
.form-note a { color: var(--orange); }

.form-status { display: none; margin-top: var(--space-2); padding: var(--space-2); border-radius: var(--radius); font-weight: 600; }
.form-status.is-ok { display: block; background: #e8f6ec; color: #1c6b34; }
.form-status.is-error { display: block; background: #fdeaea; color: #a02020; }

/* 15 — Photo placeholders (swap for real images, keep the class) -------------------------------- */
.ph-photo {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  min-height: 300px;
  border: 2px dashed rgba(255, 255, 255, 0.35);
  border-radius: var(--radius-lg);
  background:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0.04) 12px, transparent 12px, transparent 24px),
    linear-gradient(160deg, #0a3352, #052642);
  color: var(--muted);
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: var(--space-3);
}

/* 15b — Service area map ------------------------------------------------------------------------
   Hand-built SVG so there's no map API key or third-party embed. Town positions
   are plotted from approximate real coordinates, so relative distance and
   direction are right even though the coastline is simplified. */
.area-map {
  width: 100%;
  max-width: 460px;
  height: auto;
  border-radius: var(--radius-lg);
  background: linear-gradient(160deg, #073152 0%, #04203a 100%);
  border: 1px solid var(--line-dark);
  display: block;
}
.area-map__ocean { fill: rgba(120, 190, 235, 0.10); }
.area-map__sea-label { fill: rgba(160, 200, 225, 0.5); font-family: "Inter", sans-serif; font-size: 14px; font-weight: 700; letter-spacing: 3px; }
.area-map__coast { fill: none; stroke: rgba(255, 255, 255, 0.28); stroke-width: 2; }
.area-map__reach { fill: url(#reachGlow); }
.area-map__dot { fill: var(--white); }
.area-map__label { fill: #c9d9e6; font-family: "Inter", sans-serif; font-size: 15px; font-weight: 600; }
.area-map__base-dot { fill: var(--orange); }
.area-map__base-ring { fill: none; stroke: var(--orange); stroke-width: 2; opacity: 0.55; }
.area-map__base-label { fill: var(--white); font-family: "Inter", sans-serif; font-size: 17px; font-weight: 700; }
.area-map__note { fill: #8fa6ba; font-family: "Inter", sans-serif; font-size: 13.5px; font-weight: 600; }

/* 15c — Sticky mobile call bar -------------------------------------------------------------------
   Mobile only. Above 640px the header CTA is always visible so this is hidden. */
.call-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  display: flex;
  gap: 0.6rem;
  padding: 0.6rem var(--space-3);
  padding-bottom: calc(0.6rem + env(safe-area-inset-bottom, 0px));
  background: rgba(2, 18, 31, 0.96);
  backdrop-filter: blur(10px);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  transform: translateY(115%);
  /* visibility flips with the slide so a hidden bar is also out of the tab
     order and invisible to screen readers */
  visibility: hidden;
  transition: transform var(--dur-slow) var(--ease), visibility 0s linear var(--dur-slow);
  will-change: transform;
}
.call-bar.is-visible {
  transform: translateY(0);
  visibility: visible;
  transition: transform var(--dur-slow) var(--ease), visibility 0s;
}
.call-bar .btn { flex: 1; min-height: 50px; font-size: 0.9rem; padding-inline: 0.75rem; }
/* Neither label may wrap: a two-line "Get a quote" made the bar look broken
   at 390px, which is the single most common screen this site will be read on. */
.call-bar .btn--ghost { flex: 0 1 auto; white-space: nowrap; }
.call-bar .btn--call { white-space: nowrap; }
/* The call button now carries the full number, so the secondary label shortens
   on the narrowest phones to keep both on one line. */
.call-bar__long { display: none; }
.call-bar__short { display: inline; }
@media (min-width: 430px) {
  .call-bar__long { display: inline; }
  .call-bar__short { display: none; }
}

/* keep the footer clear of the fixed bar */
body { padding-bottom: 76px; }
@media (min-width: 640px) {
  .call-bar { display: none; }
  body { padding-bottom: 0; }
}

/* 16 — Site footer (reusable, Powerhaus-style columns) --------------------------------------------
   Columns: brand + tagline | Services | Areas | Licences | Contact.
   Bottom bar: copyright, then ABN + contractor licence in small muted text. */
.site-footer { background: var(--bg-deep); color: var(--muted); padding-block: var(--space-4) var(--space-3); font-size: var(--fs-sm); }

.site-footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3);
  padding-bottom: var(--space-3);
  margin-bottom: var(--space-3);
  border-bottom: 1px solid var(--line-dark);
}
@media (min-width: 360px) {
  .site-footer__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
@media (min-width: 1000px) {
  .site-footer__grid { grid-template-columns: 1.4fr minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) 1.2fr; gap: var(--space-4); }
}
.site-footer__contact a,
.site-footer__contact span { overflow-wrap: anywhere; }

.site-footer__brand { grid-column: 1 / -1; }
@media (min-width: 1000px) { .site-footer__brand { grid-column: auto; } }
.site-footer__brand img { height: 42px; width: auto; margin-bottom: var(--space-2); }
.site-footer__brand p { max-width: 26em; }

.site-footer h3 { font-family: var(--font-display); color: var(--white); font-size: 0.95rem; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: var(--space-2); }
.site-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.2rem; }
/* Tap targets. 17px of text is a small thing to hit on a phone, and almost all
   of this traffic is phones. Padding lifts each row past the 24px minimum
   without stretching the footer out. */
.site-footer a { color: var(--muted); text-decoration: none; transition: color var(--dur) var(--ease);
  display: inline-block; padding-block: 0.3rem; }
.site-footer a:hover { color: var(--orange); }

.site-footer__contact li { display: flex; gap: 0.6rem; align-items: flex-start; }
.site-footer__contact svg { width: 16px; height: 16px; flex: none; color: var(--orange); margin-top: 3px; }
.site-footer__contact a { color: var(--white); font-weight: 700; }

.site-footer__licences li { display: grid; gap: 0.05rem; padding-bottom: 0.35rem; }
.site-footer__licences strong { color: #c9d9e6; }

.site-footer__legal { display: grid; gap: 0.3rem; }

/* Love Your Work Co. credit, sits alongside the copyright line */
.site-footer__credit { color: #6b8296; }
.site-footer__credit a { color: #9db3c5; font-weight: 600; text-decoration: none; border-bottom: 1px solid rgba(157, 179, 197, 0.35); }
.site-footer__credit a:hover { color: var(--white); border-bottom-color: var(--orange); }
.site-footer__heart { color: var(--orange); font-style: normal; }

.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;
}
.site-footer__legal-small { color: #6b8296; }
.site-footer__legal-row { display: flex; flex-wrap: wrap; gap: 0.4rem 1.5rem; }

/* Text us line under the hero buttons (24 Sep 2026). */
.text-alt { margin: var(--space-2, .75rem) 0 0; font-size: var(--fs-sm, .9rem); }
.text-alt a { font-weight: 600; color: inherit; text-decoration: underline; text-underline-offset: 3px; }
