/* ==========================================================================
   STL Electrical, main.css
   Single stylesheet. Token layer first, then base, layout, components.
   Component blocks are marked with the build spec IDs (C1 to C15).
   Every HTML file references this file with a ?v= content hash. After editing,
   run tools/version-assets.py so the stamp matches, or let the project hook do
   it. An unstamped edit is served from cache and looks like it did nothing.
   Prepared by Bring Digital Performance.
   ========================================================================== */

/* --------------------------------------------------------------------------
   TOKENS
   Defined once. Nothing below this block hardcodes a colour, size or timing.
   -------------------------------------------------------------------------- */

:root {

  /* Colour: grounds ------------------------------------------------------ */
  --c-ink:          #14171a;   /* near-black ground, not pure black */
  --c-ink-raised:   #1e2226;   /* raised surface on a dark section */
  --c-ink-line:     #32383e;   /* hairline on a dark section */

  --c-paper:        #f6f5f3;   /* off-white ground, not pure white */
  --c-paper-raised: #ffffff;   /* raised surface on a light section */
  --c-paper-sunken: #eceae6;   /* recessed surface on a light section */
  --c-paper-line:   #dcd9d4;   /* hairline on a light section */

  /* Colour: text --------------------------------------------------------- */
  --c-text:         #14171a;   /* 15.4:1 on --c-paper */
  --c-text-soft:    #52585f;   /* 6.3:1  on --c-paper */
  --c-text-invert:  #f6f5f3;   /* 15.4:1 on --c-ink */
  --c-text-invert-soft: #a9afb6; /* 7.3:1 on --c-ink */

  /* Colour: action ------------------------------------------------------- */
  /* Phone CTA. The logo blue, so the one control that matters most is in the
     brand colour rather than a signal colour.
     A blue fill on a light page is only 2.41:1 against the ground, which fails
     the 3:1 non-text threshold, so the button carries a darker blue border and
     the boundary does that work instead: 5.45:1 on paper, 4.95:1 on sunken,
     5.94:1 on a white form card, 3.03:1 on ink. Never remove that border. */
  --c-action:        #28abe2;  /* logo blue. Label on it: 6.87:1 */
  --c-action-hover:  #4fbce8;  /* label 8.30:1 */
  --c-action-border: #136b90;  /* the boundary, and the only thing making the
                                  button a shape on a light ground */
  --c-action-text:   #14171a;  /* 6.87:1 on the fill */
  --c-star:         #b37a00;   /* review stars on light grounds, 3.4:1 */
  --c-urgent:       #c42b1c;   /* emergency flag on light grounds, 5.9:1 */
  --c-urgent-light: #ff6a5a;   /* emergency flag on dark grounds, 5.4:1 */
  --c-focus:        #0a84ff;   /* focus ring, visible on both grounds */
  /* The logo blue. Every highlight, rule, accent and eyebrow uses it.
     It measures 2.41:1 on paper, which fails both the 4.5 text threshold and
     the 3.0 UI threshold, so light grounds get the darkened twin instead.
     Same hue, 5.45:1 on paper, 4.95:1 on sunken, 5.94:1 on white. Use
     --c-brand on dark sections and --c-brand-ink on light ones. */
  --c-brand:        #28abe2;   /* logo blue, 6.87:1 on ink */
  --c-brand-ink:    #136b90;   /* the same blue, darkened for light grounds */

  /* Colour: form state --------------------------------------------------- */
  --c-error:        #b3261e;   /* 6.4:1 on white */
  --c-error-bg:     #fdf2f1;
  --c-ok:           #1b6b3a;

  /* Type ----------------------------------------------------------------- */
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* Fluid scale, 320px to 1440px. Display sizes carry the design. */
  --t-display: clamp(2.25rem, 1.4rem + 4.25vw, 5.5rem);  /* 36 to 88 */
  --t-h1:      clamp(2.125rem, 1.4rem + 3.6vw, 4rem);     /* 34 to 64 */
  --t-h2:      clamp(1.625rem, 1.23rem + 1.97vw, 2.75rem);/* 26 to 44 */
  --t-h3:      clamp(1.25rem, 1.1rem + 0.75vw, 1.625rem); /* 20 to 26 */
  --t-h4:      clamp(1.0625rem, 1rem + 0.31vw, 1.25rem);  /* 17 to 20 */
  --t-lead:    clamp(1.125rem, 1.05rem + 0.36vw, 1.3125rem);
  --t-body:    1.0625rem;      /* 17px. Older homeowners read this site. */
  --t-small:   0.9375rem;
  --t-micro:   0.8125rem;

  --lh-display: 1.02;
  --lh-head:    1.08;
  --lh-body:    1.6;

  --tr-display: -0.03em;       /* tight tracking at display sizes */
  --tr-head:    -0.02em;
  --tr-body:     0;
  --tr-caps:     0.08em;

  --w-regular: 400;
  --w-medium:  500;
  --w-semi:    600;
  --w-bold:    700;

  /* Space: one scale, used for everything -------------------------------- */
  --s-3xs: 0.25rem;
  --s-2xs: 0.5rem;
  --s-xs:  0.75rem;
  --s-sm:  1rem;
  --s-md:  1.5rem;
  --s-lg:  2rem;
  --s-xl:  3rem;
  --s-2xl: 4rem;
  --s-3xl: 6rem;
  --s-4xl: 8rem;

  /* Section rhythm scales with the viewport so pacing holds on mobile */
  --s-section: clamp(3.5rem, 2rem + 7.5vw, 7rem);

  /* Layout --------------------------------------------------------------- */
  --measure:    68ch;          /* reading measure, never exceeded by body copy */
  --measure-tight: 46ch;       /* display headings break cleanly here */
  --w-content:  1200px;        /* standard content column */
  --w-wide:     1440px;        /* full-bleed sections */
  --gutter:     clamp(1.25rem, 0.9rem + 1.75vw, 2.5rem);
  --grid-gap:   clamp(1rem, 0.6rem + 2vw, 2rem);

  /* Component sizing ----------------------------------------------------- */
  --header-h:   64px;
  --callbar-h:  68px;          /* content padding matches this exactly */
  --tap:        44px;          /* minimum tap target */

  /* Radii ---------------------------------------------------------------- */
  --r-sm:   6px;
  --r-md:   10px;
  --r-lg:   16px;
  --r-pill: 999px;

  /* Motion. Decelerate hard at the end. ---------------------------------- */
  --e-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --e-inout:  cubic-bezier(0.65, 0, 0.35, 1);
  --d-fast:   120ms;
  --d-base:   240ms;
  --d-slow:   520ms;

  /* Depth. No drop shadows. Separation is space, line and contrast. ------ */
  --line-light: 1px solid var(--c-paper-line);
  --line-dark:  1px solid var(--c-ink-line);

  --z-header:  100;
  --z-callbar: 200;
  --z-skip:    300;
}

@media (min-width: 900px) {
  :root { --header-h: 76px; --callbar-h: 0px; }
}

/* --------------------------------------------------------------------------
   BASE
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--s-sm));
}

body {
  margin: 0;
  /* Bottom padding clears the sticky call bar on every page. C2 depends on this. */
  padding-bottom: var(--callbar-h);
  background: var(--c-paper);
  color: var(--c-text);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  font-weight: var(--w-regular);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;          /* belt and braces against 320px overflow */
}

h1, h2, h3, h4 {
  margin: 0 0 var(--s-sm);
  font-weight: var(--w-semi);
  line-height: var(--lh-head);
  letter-spacing: var(--tr-head);
  text-wrap: balance;
}

h1 { font-size: var(--t-h1); line-height: var(--lh-display); letter-spacing: var(--tr-display); }
h2 { font-size: var(--t-h2); }
h3 { font-size: var(--t-h3); }
h4 { font-size: var(--t-h4); }

p, ul, ol, dl, figure, table { margin: 0 0 var(--s-md); }
p { max-width: var(--measure); text-wrap: pretty; }
p:last-child, ul:last-child, ol:last-child { margin-bottom: 0; }

a { color: inherit; text-underline-offset: 0.2em; text-decoration-thickness: 1px; }
a:hover { text-decoration-thickness: 2px; }

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

ul, ol { padding-left: 1.25em; }
li + li { margin-top: var(--s-2xs); }

strong, b { font-weight: var(--w-semi); }

hr { border: 0; border-top: var(--line-light); margin: var(--s-xl) 0; }

table { border-collapse: collapse; width: 100%; font-size: var(--t-small); }
th, td { text-align: left; padding: var(--s-xs) var(--s-sm) var(--s-xs) 0; border-bottom: var(--line-light); vertical-align: top; }
th { font-weight: var(--w-semi); }
.l-section--dark th, .l-section--dark td { border-bottom-color: var(--c-ink-line); }
code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.9em; }

/* Focus. Never removed. */
:focus-visible {
  outline: 3px solid var(--c-focus);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

::selection { background: var(--c-action); color: var(--c-action-text); }

/* --------------------------------------------------------------------------
   LAYOUT PRIMITIVES
   Same grid on every template, so all pages feel structurally identical.
   -------------------------------------------------------------------------- */

.l-wrap {
  width: 100%;
  max-width: calc(var(--w-content) + (var(--gutter) * 2));
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.l-wrap--wide { max-width: calc(var(--w-wide) + (var(--gutter) * 2)); }
.l-wrap--narrow { max-width: calc(760px + (var(--gutter) * 2)); }

.l-section { padding-block: var(--s-section); }
.l-section--tight { padding-block: calc(var(--s-section) * 0.55); }

/* Dark and light section rhythm. Alternate down the page. */
.l-section--dark {
  background: var(--c-ink);
  color: var(--c-text-invert);
}
.l-section--dark h1, .l-section--dark h2, .l-section--dark h3 { color: var(--c-text-invert); }
.l-section--sunken { background: var(--c-paper-sunken); }

.l-grid {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
}
.l-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }

.l-stack > * + * { margin-top: var(--s-md); }
.l-stack--tight > * + * { margin-top: var(--s-2xs); }

.l-measure { max-width: var(--measure); }
.l-measure-tight { max-width: var(--measure-tight); }

/* Section eyebrow. Small, quiet, sits above a display heading. */
.l-eyebrow {
  display: block;
  margin-bottom: var(--s-xs);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-brand-ink);
}
.l-section--dark .l-eyebrow { color: var(--c-brand); }

/* Tables scroll inside their own container rather than breaking the page. */
.l-scroller { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* --------------------------------------------------------------------------
   UTILITIES
   -------------------------------------------------------------------------- */

.u-visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.u-nowrap { white-space: nowrap; }

/* Spacing utilities. Used sparingly, where a block needs to step away from
   what precedes it without earning a component of its own. */
.u-mt-md  { margin-top: var(--s-md); }
.u-mt-xl  { margin-top: var(--s-xl); }
.u-mt-2xl { margin-top: var(--s-2xl); }

/* Skip link. First focusable element on every page. */
.u-skip {
  position: absolute;
  top: var(--s-2xs);
  left: var(--s-2xs);
  z-index: var(--z-skip);
  padding: var(--s-xs) var(--s-sm);
  background: var(--c-action);
  color: var(--c-action-text);
  font-weight: var(--w-semi);
  border: 1px solid var(--c-action-border);
  border-radius: var(--r-sm);
  transform: translateY(calc(-100% - var(--s-sm)));
  transition: transform var(--d-fast) var(--e-out);
}
.u-skip:focus { transform: translateY(0); }

.u-icon {
  width: 1.25em;
  height: 1.25em;
  flex: none;
  fill: currentColor;
}

/* --------------------------------------------------------------------------
   BUTTONS
   Pill geometry, high contrast, sparse. The phone CTA is quiet in styling
   but permanent in position, per the design translation rules.
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2xs);
  min-height: var(--tap);
  padding: var(--s-xs) var(--s-md);
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font: inherit;
  font-size: var(--t-small);
  font-weight: var(--w-semi);
  letter-spacing: 0;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--d-fast) var(--e-out),
              border-color var(--d-fast) var(--e-out),
              color var(--d-fast) var(--e-out);
}

/* Primary: the phone. One treatment sitewide so it is always recognisable. */
.btn--call {
  background: var(--c-action);
  border-color: var(--c-action-border);
  color: var(--c-action-text);
}
.btn--call:hover { background: var(--c-action-hover); border-color: var(--c-action-border); }

/* Secondary: quote. Outlined, adapts to the ground it sits on. */
.btn--quote {
  background: transparent;
  border-color: currentColor;
  color: inherit;
}
.btn--quote:hover { background: var(--c-text); color: var(--c-paper); border-color: var(--c-text); }
.l-section--dark .btn--quote:hover,
.c3 .btn--quote:hover { background: var(--c-paper); color: var(--c-ink); border-color: var(--c-paper); }

/* Solid dark, for form submits on light grounds. */
.btn--submit {
  background: var(--c-ink);
  border-color: var(--c-ink);
  color: var(--c-text-invert);
  font-size: var(--t-body);
  padding-inline: var(--s-lg);
}
.btn--submit:hover { background: var(--c-ink-raised); border-color: var(--c-ink-raised); }

.btn--lg { min-height: 56px; font-size: var(--t-lead); padding-inline: var(--s-lg); }
.btn--block { width: 100%; }

/* Quiet text link with a persistent underline, for in-copy navigation. */
.link {
  color: inherit;
  font-weight: var(--w-medium);
  text-decoration: underline;
  text-decoration-color: var(--c-brand-ink);
  text-decoration-thickness: 2px;
}
.link:hover { text-decoration-color: currentColor; }
/* The underline is the affordance, so it swaps to the lighter logo blue on
   dark grounds rather than staying at the light-ground value. */
.l-section--dark .link, .c3 .link { text-decoration-color: var(--c-brand); }

/* A link that stands alone rather than sitting inside a sentence needs the
   full tap target, since the text-block exemption does not apply. */
.link--standalone { display: inline-flex; align-items: center; min-height: var(--tap); }

/* ==========================================================================
   C1: Header with tap-to-call
   Phone visible without scrolling at every viewport. Thin, translucent,
   stays out of the way. Solid fallback where backdrop-filter is unsupported.
   ========================================================================== */

.c1 {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--c-paper);
  border-bottom: var(--line-light);
}

@supports (backdrop-filter: blur(20px)) or (-webkit-backdrop-filter: blur(20px)) {
  .c1 {
    background: color-mix(in srgb, var(--c-paper) 82%, transparent);
    -webkit-backdrop-filter: saturate(1.6) blur(20px);
    backdrop-filter: saturate(1.6) blur(20px);
  }
}

.c1__bar {
  display: flex;
  align-items: center;
  gap: var(--s-sm);
  min-height: var(--header-h);
}

/* Wordmark. The existing STL logo file, at intrinsic ratio 283 x 89.
   Dimensions are set in the markup so it reserves space and never shifts. */
.c1__brand {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  margin-right: auto;
  text-decoration: none;
}
.c1__logo { width: auto; height: 30px; }
@media (max-width: 479px) { .c1__logo { height: 26px; } }
@media (min-width: 900px) { .c1__logo { height: 34px; } }

.c1__nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2xs) var(--s-md);
  margin: 0;
  padding: 0;
  list-style: none;
}
.c1__nav li + li { margin-top: 0; }
.c1__nav a {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  font-size: var(--t-small);
  font-weight: var(--w-medium);
  text-decoration: none;
}
.c1__nav a:hover { text-decoration: underline; }
.c1__nav a[aria-current="page"] {
  text-decoration: underline;
  text-decoration-color: var(--c-action);
  text-decoration-thickness: 2px;
}

/* Toggle is hidden until JS unhides it, so the nav is usable with JS off. */
.c1__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  background: transparent;
  border: var(--line-light);
  border-radius: var(--r-sm);
  color: inherit;
  cursor: pointer;
}
.c1__toggle[hidden] { display: none; }

.c1__call { flex: none; }
.c1__call .u-icon { width: 1em; height: 1em; }

/* Below 480px the brand, the menu toggle and the phone must share one row.
   The phone number itself never gets truncated or swapped for an icon. */
@media (max-width: 479px) {
  .c1__bar { gap: var(--s-2xs); }
  .c1__call { padding-inline: var(--s-sm); }
}

/* At 320px the logo, the menu and the full phone number still share one row.
   The number is never abbreviated to make space. */
@media (max-width: 359px) {
  .c1__logo { height: 22px; }
  .c1__call { padding-inline: var(--s-xs); }
}

/* Small viewports, JS off: nav stacks under the bar and stays reachable. */
@media (max-width: 899px) {
  .c1__nav {
    width: 100%;
    border-top: var(--line-light);
    padding-block: var(--s-2xs);
  }
  .c1__bar { flex-wrap: wrap; padding-bottom: 0; }
  .c1__nav ul { flex-direction: column; gap: 0; }
  .c1__nav li { border-bottom: var(--line-light); }
  .c1__nav li:last-child { border-bottom: 0; }
  .c1__nav a { min-height: 48px; font-size: var(--t-body); }

  /* JS on: the nav collapses behind the toggle. */
  .c1--js .c1__nav[hidden] { display: none; }
  .c1--js .c1__nav {
    position: absolute;
    left: 0; right: 0;
    top: 100%;
    background: var(--c-paper);
    border-bottom: var(--line-light);
    padding: 0 var(--gutter) var(--s-sm);
    max-height: calc(100dvh - var(--header-h) - var(--callbar-h));
    overflow-y: auto;
  }
}

@media (min-width: 900px) {
  .c1__toggle { display: none; }         /* nav is always open at this width */
  .c1__nav[hidden] { display: block; }   /* never collapsed on desktop */
}

/* ==========================================================================
   C2: Sticky mobile call bar
   Fixed to the viewport bottom on every page. body padding-bottom equals
   --callbar-h so it can never cover a submit button.
   ========================================================================== */

.c2 {
  position: fixed;
  inset: auto 0 0 0;
  z-index: var(--z-callbar);
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: var(--s-2xs);
  align-items: stretch;
  height: var(--callbar-h);
  padding: var(--s-2xs) var(--s-2xs) calc(var(--s-2xs) + env(safe-area-inset-bottom));
  background: var(--c-ink);
  border-top: var(--line-dark);
  color: var(--c-text-invert);
}

.c2 .btn { min-height: var(--tap); font-size: var(--t-small); }
.c2 .btn--quote { border-color: var(--c-text-invert-soft); }
.c2 .btn--quote:hover { background: var(--c-paper); color: var(--c-ink); }

@media (min-width: 900px) {
  .c2 { display: none; }
}

/* T10 plain content suppresses the bar. Body padding follows suit. */
.t10 { --callbar-h: 0px; }
.t10 .c2 { display: none; }

/* ==========================================================================
   C4: Breadcrumbs
   Every page below the homepage. Marked up with BreadcrumbList in the head.
   ========================================================================== */

.c4 {
  padding-block: var(--s-sm);
  border-bottom: var(--line-light);
  font-size: var(--t-small);
  color: var(--c-text-soft);
}
.c4 ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3xs) var(--s-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}
.c4 li { display: flex; align-items: center; gap: var(--s-2xs); margin: 0; }
.c4 li + li::before {
  content: "";
  width: 5px; height: 5px;
  border-right: 1.5px solid currentColor;
  border-top: 1.5px solid currentColor;
  transform: rotate(45deg);
  opacity: 0.6;
}
.c4 a { color: inherit; text-decoration: none; }
.c4 a:hover { text-decoration: underline; }
.c4 [aria-current="page"] { color: var(--c-text); font-weight: var(--w-medium); }

/* ==========================================================================
   C13: Enquiry form
   Five fields maximum. Short variant (name, phone) for T7.
   Works with JS disabled. JS only improves error messaging.
   ========================================================================== */

.c13 {
  background: var(--c-paper-raised);
  border: var(--line-light);
  border-radius: var(--r-lg);
  padding: clamp(var(--s-md), 3vw, var(--s-lg));
}
.l-section--dark .c13 { border-color: transparent; }

/* The form is a light card, and on the hubs, the service pages and the
   emergency page it sits inside a dark section. .l-section--dark colours
   headings by descendant, so it reached through the card and painted the
   title #f6f5f3 on white: 1.09:1, effectively invisible. Every other element
   in the form carries an explicit colour, which is why only the title broke.
   Reset at the card rather than at .c13__title, so a heading added inside it
   later cannot reintroduce this. */
.l-section--dark .c13 h1,
.l-section--dark .c13 h2,
.l-section--dark .c13 h3,
.l-section--dark .c13 h4 { color: var(--c-text); }

.c13__title { font-size: var(--t-h3); margin-bottom: var(--s-3xs); }
.c13__intro { font-size: var(--t-small); color: var(--c-text-soft); margin-bottom: var(--s-md); }

.c13__fields { display: grid; gap: var(--s-md); }
@media (min-width: 620px) {
  .c13__fields--split { grid-template-columns: 1fr 1fr; }
  .c13__field--full { grid-column: 1 / -1; }
}

.c13__field { display: grid; gap: var(--s-3xs); }

.c13__label {
  font-size: var(--t-small);
  font-weight: var(--w-semi);
  color: var(--c-text);
}
.c13__optional { font-weight: var(--w-regular); color: var(--c-text-soft); }

.c13__hint { font-size: var(--t-micro); color: var(--c-text-soft); }

.c13__input,
.c13__select,
.c13__textarea {
  width: 100%;
  min-height: var(--tap);
  padding: var(--s-xs) var(--s-sm);
  background: var(--c-paper-raised);
  border: 1px solid #8d939a;      /* 3:1 against white, per AA for UI components */
  border-radius: var(--r-md);
  font: inherit;
  font-size: var(--t-body);
  color: var(--c-text);
  transition: border-color var(--d-fast) var(--e-out);
}
.c13__textarea { min-height: 7.5rem; resize: vertical; }
.c13__input:hover, .c13__select:hover, .c13__textarea:hover { border-color: var(--c-text); }
.c13__input:focus, .c13__select:focus, .c13__textarea:focus { border-color: var(--c-text); }

.c13__select {
  appearance: none;
  padding-right: var(--s-xl);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%2352585f' d='M1.4 0 6 4.6 10.6 0 12 1.4 6 7.4 0 1.4Z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--s-sm) center;
  background-size: 12px 8px;
}

/* Error state. Announced in text and by border, never by colour alone. */
.c13__field--error .c13__input,
.c13__field--error .c13__select,
.c13__field--error .c13__textarea {
  border-color: var(--c-error);
  border-width: 2px;
  background: var(--c-error-bg);
}
.c13__error {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3xs);
  font-size: var(--t-small);
  font-weight: var(--w-medium);
  color: var(--c-error);
}
.c13__error:empty { display: none; }
.c13__error .u-icon { width: 1em; height: 1em; margin-top: 0.28em; }

.c13__actions { margin-top: var(--s-md); display: grid; gap: var(--s-xs); }

/* Consent line sits beneath the submit button on every form. */
.c13__consent {
  font-size: var(--t-micro);
  color: var(--c-text-soft);
  max-width: var(--measure);
  margin: 0;
}
.c13__consent a { color: var(--c-text); }

/* Honeypot. Off-screen rather than display:none so bots still fill it. */
.c13__trap {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* Short variant for the emergency template. */
.c13--short .c13__fields { grid-template-columns: 1fr; }

/* ==========================================================================
   C3: Footer with NAP
   ABN, licence number, service links, suburb links, opening hours.
   NAP is text, and must match the Google Business Profile character for
   character. Do not reformat the phone or the address.
   ========================================================================== */

.c3 {
  background: var(--c-ink);
  color: var(--c-text-invert);
  padding-block: var(--s-section) var(--s-lg);
}

.c3__grid {
  display: grid;
  gap: var(--s-xl) var(--grid-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
}
.c3__col--wide { grid-column: span 1; }
@media (min-width: 900px) {
  .c3__grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; }
}

.c3__brand { margin: 0 0 var(--s-md); }
.c3__brand img { width: auto; height: 38px; }

.c3__heading {
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-brand);
  margin-bottom: var(--s-sm);
}

.c3 ul { margin: 0; padding: 0; list-style: none; }
.c3 li + li { margin-top: 0; }
.c3 li a,
.c3__nap a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-size: var(--t-small);
  color: var(--c-text-invert);
  text-decoration: none;
}
.c3 li a:hover, .c3__nap a:hover { text-decoration: underline; }

.c3__nap { font-size: var(--t-small); font-style: normal; color: var(--c-text-invert); }
.c3__nap p { margin-bottom: var(--s-2xs); max-width: 34ch; }
.c3__phone {
  font-size: var(--t-h3);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-head);
  text-decoration: none;
  display: inline-block;
  min-height: var(--tap);
}

.c3__hours { font-size: var(--t-small); }
.c3__hours div { display: grid; gap: 0 var(--s-sm); max-width: 24rem; padding-block: var(--s-3xs); }
@media (min-width: 1100px) { .c3__hours div { grid-template-columns: auto 1fr; } .c3__hours dd { text-align: right; } }
/* The hours block is reused outside the footer: the contact page renders it
   on a light section. The inverted colour was unconditional, which put it at
   2.03:1 there. Default to the light surface and invert only on a dark one. */
.c3__hours dt { color: var(--c-text-soft); }
.c3 .c3__hours dt,
.l-section--dark .c3__hours dt { color: var(--c-text-invert-soft); }
.c3__hours dd { margin: 0; }

.c3__legal {
  margin-top: var(--s-xl);
  padding-top: var(--s-md);
  border-top: var(--line-dark);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2xs) var(--s-md);
  align-items: center;
  justify-content: space-between;
  font-size: var(--t-micro);
  color: var(--c-text-invert-soft);
}
.c3__legal p { margin: 0; max-width: none; }
.c3__legal a { color: var(--c-text-invert); min-height: 0; }

/* ==========================================================================
   C5: Hero
   Configurable across T1, T2, T3, T5 and T7. One idea per viewport: the
   claim, the proof, the two ways to act. No image behind the type, so the
   largest contentful paint is text and lands immediately.
   ========================================================================== */

.c5 {
  padding-block: clamp(2.5rem, 1.5rem + 5vw, 5.5rem) clamp(2.5rem, 1.5rem + 4vw, 4.5rem);
}

/* Hero with a full bleed background image.
   Set the image per section, not globally:

     <section class="c5 c5--bg l-section--dark"
              style="--hero-image: url('/assets/img/hero-residential.jpg')">

   Each page therefore carries its own photograph. Setting --hero-image on
   :root or body instead would share one image across every hero.
   With none set the slot renders a hatch so placement stays reviewable.

   A scrim sits between image and type and never drops below 88% opacity.
   Measured, not estimated: at 88% over a pure white photograph the hero lands
   at h1 11.7:1, lead 5.8:1, chips 11.7:1, stars 7.1:1, emergency flag 4.5:1.
   The flag is the binding constraint and has almost no headroom, so lightening
   this breaks AA. Change the flag colour first and re-measure. */
.c5--bg {
  position: relative;
  isolation: isolate;
  background-color: var(--c-ink);
  color: var(--c-text-invert);
}
.c5--bg::before,
.c5--bg::after { content: ""; position: absolute; inset: 0; z-index: -1; }
/* Mobile first: no hero photograph at all below 900px. Written this way round
   rather than as an override so the browser never downloads the image on a
   phone, which is where the sub-2.5s LCP target actually has to be met. The
   scrim runs at full density over the flat ink ground. */
.c5--bg::before { background-image: none; }
.c5--bg::after {
  background: linear-gradient(100deg,
    color-mix(in srgb, var(--c-ink) 95%, transparent) 0%,
    color-mix(in srgb, var(--c-ink) 91%, transparent) 55%,
    color-mix(in srgb, var(--c-ink) 88%, transparent) 100%);
}

/* Desktop: the photograph appears, and the scrim opens up across it. 900px is
   the same breakpoint the nav and the sticky call bar switch at. */
@media (min-width: 900px) {
  .c5--bg::before {
    background-image: var(--hero-image,
      repeating-linear-gradient(-45deg, transparent 0 14px,
        color-mix(in srgb, var(--c-text-invert) 7%, transparent) 14px 15px));
    background-size: cover;
    background-position: center;
  }
  .c5--bg::after {
    background: linear-gradient(100deg,
      color-mix(in srgb, var(--c-ink) 92%, transparent) 0%,
      color-mix(in srgb, var(--c-ink) 56%, transparent) 55%,
      color-mix(in srgb, var(--c-ink) 40%, transparent) 100%);
  }
}

/* Label for the empty slot. Remove it when a real photograph is set. */
.c5__bgnote {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2xs);
  margin: var(--s-xl) 0 0;
  padding: var(--s-3xs) var(--s-xs);
  border: 1px dashed var(--c-ink-line);
  border-radius: var(--r-sm);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-text-invert-soft);
}

/* Emergency flag. Sits above the H1 so 24 hour cover is read first. */
.c5__flag {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2xs);
  margin-bottom: var(--s-md);
  padding: var(--s-3xs) var(--s-xs) var(--s-3xs) var(--s-2xs);
  border: 1px solid currentColor;
  border-radius: var(--r-pill);
  font-size: var(--t-small);
  font-weight: var(--w-semi);
  color: var(--c-urgent);
}
.l-section--dark .c5__flag { color: var(--c-urgent-light); }
.c5__flag .u-icon { width: 1.1em; height: 1.1em; }

.c5__title {
  font-size: var(--t-display);
  max-width: 18ch;
  margin-bottom: var(--s-md);
}

.c5__lead {
  font-size: var(--t-lead);
  color: var(--c-text-soft);
  max-width: 46ch;
  margin-bottom: var(--s-lg);
}
.l-section--dark .c5__lead { color: var(--c-text-invert-soft); }

.c5__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-xs);
  margin-bottom: var(--s-lg);
}
@media (max-width: 479px) {
  .c5__actions .btn { flex: 1 1 100%; }
}

/* ==========================================================================
   C6: Trust chips
   Three, inline, directly under the CTA. Numerals, not adjectives.
   Review figures come from the same cached Places response as C8.
   ========================================================================== */

.c6 {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2xs) var(--s-md);
  margin: 0;
  padding: 0;
  list-style: none;
}
.c6 li { display: flex; align-items: center; gap: var(--s-2xs); margin: 0; }
.c6__chip {
  display: flex;
  align-items: center;
  gap: var(--s-2xs);
  font-size: var(--t-small);
  font-weight: var(--w-medium);
}
.c6__chip .u-icon { width: 1.15em; height: 1.15em; color: var(--c-brand-ink); }
.l-section--dark .c6__chip .u-icon { color: var(--c-brand); }
.c6__chip b { font-weight: var(--w-semi); }

/* Star row. Darkened on light grounds to clear 3:1 as a graphic, and the
   rating is written out in text beside it either way. */
.c6__stars, .c8__stars { display: inline-flex; gap: 2px; color: var(--c-star); }
.l-section--dark .c6__stars, .l-section--dark .c8__stars { color: var(--c-action); }
.c6__stars .u-icon, .c8__stars .u-icon { width: 1em; height: 1em; color: inherit; }

/* ==========================================================================
   C7: Services grid
   Card labels use the service name as people search it.
   ========================================================================== */

.c7 { display: grid; gap: var(--grid-gap); grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); }

.c7__card {
  display: flex;
  flex-direction: column;
  gap: var(--s-2xs);
  padding: var(--s-md);
  background: var(--c-paper-raised);
  border: var(--line-light);
  border-radius: var(--r-lg);
  transition: border-color var(--d-base) var(--e-out), transform var(--d-base) var(--e-out);
}
.c7__card:hover { border-color: var(--c-brand-ink); transform: translateY(-2px); }
.c7__card h3 { font-size: var(--t-h4); margin: 0; }
.c7__card h3 a { text-decoration: none; }
/* The whole card is the target, the heading link carries the accessible name. */
.c7__card h3 a::after { content: ""; position: absolute; inset: 0; }
.c7__card { position: relative; }
.c7__card p { font-size: var(--t-small); color: var(--c-text-soft); margin: 0; }
.c7__card h3 a:focus-visible { outline: none; }
.c7__card:has(a:focus-visible) { outline: 3px solid var(--c-focus); outline-offset: 2px; }

/* ==========================================================================
   C8: Reviews component
   Live Google Places data, cached server-side, 4 and 5 star only.
   No AggregateRating markup. Self-serving review markup gets devalued.
   ========================================================================== */

.c8__aggregate {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-2xs) var(--s-sm);
  margin-bottom: var(--s-lg);
}
.c8__score {
  font-size: var(--t-h2);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-head);
  line-height: 1;
}
.c8__count { font-size: var(--t-lead); color: var(--c-text-invert-soft); }

.c8__list {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}
.c8__list li { margin: 0; }

.c8__card {
  height: 100%;
  padding: var(--s-md);
  background: var(--c-ink-raised);
  border-radius: var(--r-lg);
}
.c8__card blockquote { margin: 0 0 var(--s-md); font-size: var(--t-small); }
.c8__card blockquote p { max-width: none; }
.c8__card figcaption { font-size: var(--t-micro); color: var(--c-text-invert-soft); }
.c8__card cite { font-style: normal; font-weight: var(--w-semi); color: var(--c-text-invert); }

.c8__out { margin-top: var(--s-lg); }

/* ==========================================================================
   C9: How it works
   Four steps. Removes the main objection for anyone burned by a tradie.
   ========================================================================== */

.c9 {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
}
.c9 li { margin: 0; padding-top: var(--s-sm); border-top: 2px solid var(--c-brand-ink); counter-increment: step; }
.l-section--dark .c9 li { border-top-color: var(--c-brand); }
.c9 li::before {
  content: counter(step);
  display: block;
  margin-bottom: var(--s-2xs);
  font-size: var(--t-small);
  font-weight: var(--w-semi);
  font-variant-numeric: tabular-nums;
  color: var(--c-text-soft);
}
.l-section--dark .c9 li::before { color: var(--c-text-invert-soft); }
.c9 h3 { font-size: var(--t-h4); margin-bottom: var(--s-3xs); }
.c9 p { font-size: var(--t-small); color: var(--c-text-soft); margin: 0; }
.l-section--dark .c9 p { color: var(--c-text-invert-soft); }

/* ==========================================================================
   C10: Credentials row
   Licence, insurance, standards. Nothing claimed that cannot be evidenced.
   ========================================================================== */

.c10 {
  display: grid;
  gap: var(--s-md) var(--grid-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}
.c10 li { display: flex; gap: var(--s-xs); margin: 0; }
.c10 .u-icon { width: 1.5rem; height: 1.5rem; margin-top: 0.1em; color: var(--c-brand-ink); }
.l-section--dark .c10 .u-icon { color: var(--c-brand); }
.c10 b { display: block; font-weight: var(--w-semi); }
.c10 span { font-size: var(--t-small); color: var(--c-text-soft); }
.l-section--dark .c10 span { color: var(--c-text-invert-soft); }

/* ==========================================================================
   C11: FAQ accordion
   details and summary as the base, so it opens with JavaScript disabled.
   ========================================================================== */

.c11 { border-top: var(--line-light); max-width: 52rem; }
.l-section--dark .c11 { border-top-color: var(--c-ink-line); }

.c11__item { border-bottom: var(--line-light); }
.l-section--dark .c11__item { border-bottom-color: var(--c-ink-line); }

.c11__q {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-md);
  min-height: var(--tap);
  padding-block: var(--s-sm);
  font-size: var(--t-h4);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-head);
  cursor: pointer;
  list-style: none;
}
.c11__q::-webkit-details-marker { display: none; }
.c11__q::after {
  content: "";
  flex: none;
  width: 12px; height: 12px;
  margin-top: 0.45em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transform-origin: 60% 60%;
  transition: transform var(--d-base) var(--e-out);
}
.c11__item[open] .c11__q::after { transform: rotate(-135deg); }
.c11__q:hover { color: var(--c-text-soft); }
.l-section--dark .c11__q:hover { color: var(--c-text-invert-soft); }

.c11__a { padding-bottom: var(--s-md); }
.c11__a p { font-size: var(--t-body); color: var(--c-text-soft); }
.l-section--dark .c11__a p { color: var(--c-text-invert-soft); }

/* Two column split. Shared by the CTA band and by any section that runs a
   pair of columns, so the column rhythm is identical across templates.
   ========================================================================== */

/* ==========================================================================
   C12: CTA band
   Phone plus form. Repeats at the page midpoint and end on T3.
   ========================================================================== */

.c12__grid, .l-split {
  display: grid;
  gap: var(--s-xl) var(--grid-gap);
  align-items: start;
}
@media (min-width: 860px) {
  .c12__grid, .l-split { grid-template-columns: 1fr 1fr; gap: var(--s-2xl); }
}
.c12__phone {
  display: inline-block;
  font-size: clamp(2rem, 1.3rem + 3.5vw, 3.25rem);
  font-weight: var(--w-bold);
  letter-spacing: var(--tr-display);
  line-height: 1.05;
  text-decoration: none;
  margin-block: var(--s-2xs) var(--s-sm);
}
.c12__phone:hover { text-decoration: underline; text-decoration-thickness: 3px; }

/* --------------------------------------------------------------------------
   ABOUT BLOCK
   Typographic while the client's own job photography is outstanding. The
   figure markup is ready in the template, commented, for the developer.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   IMAGE PLACEHOLDER
   Stands in for photography so placement can be reviewed without the pictures
   arguing for attention. Drawn entirely in CSS, no asset. Each one states the
   subject it is reserving, the crop and the intended alt text, so the slot is
   self documenting. Replace the whole .ph element with an <img> when the real
   photography is signed off.
   -------------------------------------------------------------------------- */

.ph {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-3xs);
  aspect-ratio: 3 / 2;
  padding: var(--s-sm);
  border: 1px dashed var(--c-paper-line);
  border-radius: var(--r-lg);
  background-color: var(--c-paper-sunken);
  background-image: repeating-linear-gradient(
    -45deg,
    transparent 0 10px,
    color-mix(in srgb, var(--c-text) 4%, transparent) 10px 11px);
  text-align: center;
  color: var(--c-text-soft);
}

.ph__tag {
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
}
.ph__subject {
  font-size: var(--t-small);
  font-weight: var(--w-semi);
  color: var(--c-text);
  max-width: 28ch;
}
.ph__meta {
  font-size: var(--t-micro);
  max-width: 34ch;
  line-height: 1.35;
}

.l-section--dark .ph {
  border-color: var(--c-ink-line);
  background-color: var(--c-ink-raised);
  background-image: repeating-linear-gradient(
    -45deg,
    transparent 0 10px,
    color-mix(in srgb, var(--c-text-invert) 6%, transparent) 10px 11px);
  color: var(--c-text-invert-soft);
}
.l-section--dark .ph__subject { color: var(--c-text-invert); }

/* C15: Job photo strip.
   Real STL Electrical job photography, treated editorially. Every image is
   forced to the same 3:2 crop and the same neutral grade regardless of the
   source file, so a portrait phone shot and a landscape one sit together
   without looking like an album. Generous surrounding space, no shadow. */
.jobstrip {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  margin-top: var(--s-xl);
}

/* Every job photograph renders 3:2 whatever the source file is, centred both
   ways and cropped to fill. Portrait and landscape originals therefore sit
   together as a set. Overflow is hidden so nothing can escape the rounded box. */
.figure--job { margin: 0; overflow: hidden; }
.figure--job img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: center center;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--c-paper-sunken);
  filter: saturate(0.92) contrast(1.02);
}
.figure--job figcaption { margin-top: var(--s-2xs); font-size: var(--t-micro); color: var(--c-text-soft); }
.l-section--dark .figure--job figcaption { color: var(--c-text-invert-soft); }

/* --------------------------------------------------------------------------
   SECTION LEAD
   One lead paragraph per section, directly under the heading.
   -------------------------------------------------------------------------- */

.l-lead {
  font-size: var(--t-lead);
  color: var(--c-text-soft);
  max-width: var(--measure);
  margin-bottom: var(--s-xl);
}
.l-section--dark .l-lead { color: var(--c-text-invert-soft); }

/* --------------------------------------------------------------------------
   LISTS
   Used by the "when you need this" and "what's included" blocks on T3.
   -------------------------------------------------------------------------- */

.list--ticks { list-style: none; padding: 0; margin: 0; }
.list--ticks li {
  display: flex;
  gap: var(--s-xs);
  margin: 0;
  padding-block: var(--s-xs);
  border-bottom: var(--line-light);
}
.l-section--dark .list--ticks li { border-bottom-color: var(--c-ink-line); }
.list--ticks .u-icon {
  width: 1.25rem; height: 1.25rem;
  margin-top: 0.18em;
  flex: none;
  color: var(--c-brand-ink);
}
.l-section--dark .list--ticks .u-icon { color: var(--c-brand); }

@media (min-width: 760px) {
  .list--cols { columns: 2; column-gap: var(--s-2xl); }
  .list--cols li { break-inside: avoid; }
}

/* --------------------------------------------------------------------------
   PANEL
   A bordered aside for the timeframe and compliance blocks on T3. Border and
   space only, no shadow, no fill on light grounds.
   -------------------------------------------------------------------------- */

.panel {
  padding: clamp(var(--s-md), 3vw, var(--s-lg));
  border: var(--line-light);
  border-radius: var(--r-lg);
}
.l-section--dark .panel { border-color: var(--c-ink-line); }
.panel h3 { font-size: var(--t-h4); }
.panel dl { margin: 0; }
.panel dt {
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-brand-ink);
}
.l-section--dark .panel dt { color: var(--c-brand); }
.panel dd { margin: var(--s-3xs) 0 var(--s-md); }
.panel dd:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   RELATED LINKS
   Internal linking is built into the template, not added by hand later.
   -------------------------------------------------------------------------- */

.related { display: grid; gap: var(--s-xl) var(--grid-gap); }
@media (min-width: 760px) { .related { grid-template-columns: 1fr 1fr; } }
.related h3 { font-size: var(--t-h4); }
.related ul { list-style: none; margin: 0; padding: 0; }
.related li { margin: 0; border-bottom: var(--line-light); }
.related a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-sm);
  min-height: var(--tap);
  padding-block: var(--s-2xs);
  font-size: var(--t-small);
  font-weight: var(--w-medium);
  text-decoration: none;
}
.related a:hover { text-decoration: underline; }
.related a::after {
  content: "";
  flex: none;
  width: 7px; height: 7px;
  border-right: 2px solid currentColor;
  border-top: 2px solid currentColor;
  transform: rotate(45deg);
  opacity: 0.5;
}

/* T3 pushes the FAQ away from the heading by the same step as every other
   template, so the vertical rhythm does not change between page types. */
.c11 { margin-top: var(--s-xl); }

/* ==========================================================================
   C14: Map embed
   Lazy loaded, with an accessible name on the iframe. The address is always
   available as text elsewhere on the page, so the map is never the only
   source of the location.
   ========================================================================== */

.c14 {
  border: var(--line-light);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--c-paper-sunken);
}
.c14 iframe {
  display: block;
  width: 100%;
  height: clamp(260px, 45vw, 420px);
  border: 0;
}
.c14__note {
  padding: var(--s-xs) var(--s-sm);
  border-top: var(--line-light);
  font-size: var(--t-micro);
  color: var(--c-text-soft);
  margin: 0;
}

/* --------------------------------------------------------------------------
   BULLETS
   A condensed list with a bold lead-in per point. Deliberately a plain list
   rather than a grid: the content is a bold element followed by a bare text
   node, and a grid or flex parent would wrap that text in an anonymous item
   and break the layout. See the t7__steps note for what that looks like.
   -------------------------------------------------------------------------- */

.bullets { margin: 0; padding-left: 1.1em; }
.bullets li { margin: 0; padding-block: var(--s-3xs); max-width: 60ch; }
.bullets li + li { margin-top: var(--s-2xs); }
.bullets li::marker { color: var(--c-brand-ink); }
.bullets b { font-weight: var(--w-semi); }
.l-section--dark .bullets li::marker { color: var(--c-brand); }

/* --------------------------------------------------------------------------
   NOTES
   Short titled blocks. Used where a page needs substantive content but a
   single column of prose would read as a wall. Same rule and rhythm as C9
   without the step numbers, so the two sit together on a page.
   -------------------------------------------------------------------------- */

.notes { display: grid; gap: var(--s-lg) var(--grid-gap); margin: 0; padding: 0; list-style: none; }
@media (min-width: 760px) {
  .notes { grid-template-columns: 1fr 1fr; gap: var(--s-xl) var(--s-2xl); }
  .notes--stack { grid-template-columns: 1fr; gap: var(--s-xl); }
}
.notes > li { margin: 0; padding-top: var(--s-sm); border-top: 2px solid var(--c-brand-ink); }
.l-section--dark .notes > li { border-top-color: var(--c-brand); }
.notes h3 { font-size: var(--t-h4); margin-bottom: var(--s-2xs); }
.notes p { font-size: var(--t-small); color: var(--c-text-soft); max-width: 46ch; }
.l-section--dark .notes p { color: var(--c-text-invert-soft); }

/* --------------------------------------------------------------------------
   PROSE
   Long-form body copy on T2, T5, T9 and T10. One measure, generous leading,
   headings that keep their rhythm inside running text.
   -------------------------------------------------------------------------- */

.prose { max-width: var(--measure); }
.prose > * + * { margin-top: var(--s-md); }
.prose h2 { margin-top: var(--s-xl); margin-bottom: var(--s-2xs); }
.prose h3 { margin-top: var(--s-lg); margin-bottom: var(--s-2xs); font-size: var(--t-h4); }
.prose ul, .prose ol { padding-left: 1.25em; }
.prose li + li { margin-top: var(--s-2xs); }
.prose :first-child { margin-top: 0; }

/* ==========================================================================
   T4: Service areas index
   A text link to every location page, grouped, so crawl depth stays shallow.
   ========================================================================== */

/* Every group carries its own top margin rather than relying on an adjacent
   sibling rule. The theme puts editor content between the lead and the
   first group, and .prose has no bottom margin, so the heading landed
   hard against the last paragraph. Adjacent margins collapse, so groups
   still sit --s-xl apart from each other. */
.t4__group { margin-top: var(--s-xl); }
.t4__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0 var(--grid-gap);
  grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
}
.t4__list li { margin: 0; border-bottom: var(--line-light); }
/* Suburbs render as plain text until their page is written, so the coverage
   list stays complete without linking anywhere that 404s. Swap the span for an
   anchor as each location page goes live. */
.t4__list a,
.t4__list span {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  font-size: var(--t-small);
  font-weight: var(--w-medium);
  text-decoration: none;
}
.t4__list span { color: var(--c-text-soft); font-weight: var(--w-regular); }
.l-section--dark .t4__list span { color: var(--c-text-invert-soft); }
.t4__list a:hover { text-decoration: underline; }

/* ==========================================================================
   T7: Emergency
   A separate conversion system. The phone runs at the largest type size
   anywhere on the site and sits at the very top of the page.
   ========================================================================== */

.t7__hero { padding-block: var(--s-xl) var(--s-2xl); }

.t7__phone {
  display: block;
  font-size: clamp(2.75rem, 1.2rem + 7.5vw, 6rem);
  font-weight: var(--w-bold);
  letter-spacing: -0.04em;
  line-height: 1;
  text-decoration: none;
  margin-block: var(--s-sm) var(--s-md);
  word-break: keep-all;
}
.t7__phone:hover { text-decoration: underline; text-decoration-thickness: 4px; }

.t7__now {
  border-left: 3px solid var(--c-urgent);
  padding-left: var(--s-md);
}
.l-section--dark .t7__now { border-left-color: var(--c-urgent-light); }

.t7__steps { counter-reset: step; list-style: none; padding: 0; margin: 0; }
.t7__steps li {
  display: grid;
  grid-template-columns: 2rem 1fr;
  gap: var(--s-3xs) var(--s-xs);
  margin: 0;
  padding-block: var(--s-sm);
  border-bottom: var(--line-light);
  counter-increment: step;
}
.l-section--dark .t7__steps li { border-bottom-color: var(--c-ink-line); }
.t7__steps li::before {
  content: counter(step);
  /* The counter, the label and the description are three children in a two
     column grid, so each one is placed explicitly. Left to auto placement the
     description drops into the narrow counter column and the step blows out. */
  grid-column: 1;
  grid-row: 1;
  font-weight: var(--w-bold);
  font-variant-numeric: tabular-nums;
  color: var(--c-urgent);
}
.t7__steps b    { grid-column: 2; grid-row: 1; }
.t7__steps span { grid-column: 2; grid-row: 2; }
.l-section--dark .t7__steps li::before { color: var(--c-urgent-light); }
.t7__steps b { display: block; }
.t7__steps span { color: var(--c-text-soft); font-size: var(--t-small); }
.l-section--dark .t7__steps span { color: var(--c-text-invert-soft); }

/* ==========================================================================
   T8: Contact
   Phone, email and address as selectable text, never as an image.
   ========================================================================== */

.t8__nap { font-style: normal; }
.t8__nap dt {
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-brand-ink);
}
.t8__nap dd { margin: var(--s-3xs) 0 var(--s-md); font-size: var(--t-body); }
.t8__nap dd a { font-weight: var(--w-medium); }

/* ==========================================================================
   T10: Plain content
   No CTAs, no reviews, no sticky call bar competing with the text.
   The call bar token is zeroed on the page class, so body padding follows.
   ========================================================================== */

.t10__updated {
  font-size: var(--t-small);
  color: var(--c-text-soft);
  margin-bottom: var(--s-xl);
}

/* ==========================================================================
   T11 and T12: Thank you, and 404
   ========================================================================== */

.t11 { min-height: 60vh; display: grid; align-items: center; }
.t11__tick {
  width: 3rem; height: 3rem;
  color: var(--c-ok);
  margin-bottom: var(--s-md);
}

.t12__search { display: flex; gap: var(--s-2xs); max-width: 26rem; margin-top: var(--s-md); }
@media (max-width: 379px) {
  .t12__search { flex-wrap: wrap; }
  .t12__search .btn { width: 100%; }
}
.t12__search input {
  flex: 1 1 8rem;
  min-width: 0;            /* flex items default to min-width:auto and overflow */
  min-height: var(--tap);
  padding: var(--s-xs) var(--s-sm);
  background: var(--c-paper-raised);
  border: 1px solid #8d939a;
  border-radius: var(--r-md);
  font: inherit;
  color: var(--c-text);
}

/* ==========================================================================
   MOTION
   Restrained scroll-triggered fades only, gated behind prefers-reduced-motion.
   Elements are visible by default so nothing depends on JS to appear.
   ========================================================================== */

/* The hidden start state is scoped to .js, which is set by a one line inline
   script in the head. With JavaScript disabled the class never lands and the
   content renders normally, so nothing depends on script to appear. */
@media (prefers-reduced-motion: no-preference) {
  .js .js-reveal {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity var(--d-slow) var(--e-out), transform var(--d-slow) var(--e-out);
  }
  .js .js-reveal.is-in { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Print: drop the chrome, keep the contact details. */
@media print {
  .c1, .c2, .c13__actions { display: none; }
  body { padding-bottom: 0; background: #fff; }
  .c3 { background: #fff; color: #000; }
}
