/* Beyond The Green Energy Assessments — draft site styles.
   Motion is CSS-only: nothing from an animation library ships to the browser.
   transform/opacity only, so every move is GPU-composited and LCP stays intact.
   prefers-reduced-motion switches all of it off. */

:root {
  --ink: #070B0A;
  --ink-2: #0E1413;
  --ink-3: #141C1A;
  --line: #22302C;
  --paper: #F4F8F6;
  --muted: #90A29B;
  --body: #C3D0CA;
  --green: #4E9E45;      /* from the logo */
  --blue: #2B3F93;       /* from the logo */
  --accent: #6FD35F;
  --accent-ink: #061009;
  --max: 1180px;
  --step--1: clamp(0.85rem, 0.81rem + 0.2vw, 0.95rem);
  --step-0: clamp(1rem, 0.96rem + 0.25vw, 1.1rem);
  --step-1: clamp(1.28rem, 1.1rem + 0.8vw, 1.7rem);
  --step-2: clamp(1.8rem, 1.35rem + 2vw, 3rem);
  --step-3: clamp(2.6rem, 1.6rem + 4.4vw, 5.4rem);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--body);
  font-family: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  font-size: var(--step-0);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;              /* slide-ins start off-canvas. `clip`, not `hidden`:
                                    hidden computes overflow-y to auto and makes BODY the
                                    scrolling box, so window scroll events stop firing and
                                    every scroll-driven reveal on the site dies. */
}

h1, h2, h3 { color: var(--paper); line-height: 1.06; letter-spacing: -0.025em; margin: 0 0 0.5em; font-weight: 650; }
h1 { font-size: var(--step-3); letter-spacing: -0.04em; }
h2 { font-size: var(--step-2); letter-spacing: -0.032em; }
h3 { font-size: var(--step-1); }
p { margin: 0 0 1em; max-width: 60ch; }
a { color: var(--paper); text-decoration-color: var(--line); text-underline-offset: 3px; }
a:hover { text-decoration-color: var(--accent); }

.wrap { max-width: var(--max); margin-inline: auto; padding-inline: 24px; }
.eyebrow {
  font-size: var(--step--1); letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 1.1rem; font-weight: 500;
}
.eyebrow.dim { color: var(--muted); }
.lede { font-size: var(--step-1); color: var(--paper); line-height: 1.4; font-weight: 400; }
.muted { color: var(--muted); }
.note { font-size: 0.82rem; color: var(--muted); }

/* ---------- scroll progress ---------- */
#progress {
  position: fixed; inset: 0 0 auto 0; height: 3px; z-index: 60;
  background: linear-gradient(90deg, var(--blue), var(--green), var(--accent));
  transform-origin: 0 50%; transform: scaleX(0);
  animation: grow linear both; animation-timeline: scroll(root block);
}
@keyframes grow { to { transform: scaleX(1); } }

/* ---------- header ---------- */
header.site {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--ink) 82%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
header.site .wrap { display: flex; align-items: center; justify-content: space-between; height: 72px; gap: 24px; }
.brand { display: flex; align-items: center; gap: 11px; font-weight: 650; color: var(--paper); text-decoration: none; letter-spacing: -0.02em; font-size: 1.02rem; }
.brand img { width: 34px; height: 34px; object-fit: contain; }
.brand span small { display: block; font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); font-weight: 500; }
nav.site { display: flex; align-items: center; }
nav.site a { color: var(--body); text-decoration: none; font-size: var(--step--1); margin-left: 26px; position: relative; }
nav.site a:not(.btn)::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -6px; height: 1px;
  background: var(--accent); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 220ms cubic-bezier(.2,.7,.2,1);
}
nav.site a:not(.btn):hover::after { transform: scaleX(1); }
@media (max-width: 860px) { nav.site a:not(.btn) { display: none; } .brand span small { display: none; } }

.btn {
  display: inline-flex; align-items: center; gap: 9px;
  background: var(--accent); color: var(--accent-ink); font-weight: 650;
  padding: 13px 22px; border-radius: 10px; text-decoration: none; border: 0;
  font-size: var(--step--1); cursor: pointer; letter-spacing: -0.01em;
  transition: transform 160ms cubic-bezier(.2,.7,.2,1), box-shadow 160ms ease, filter 160ms ease;
}
.btn:hover { transform: translateY(-2px); filter: brightness(1.05); box-shadow: 0 10px 30px -12px var(--accent); }
.btn.ghost { background: transparent; color: var(--paper); border: 1px solid var(--line); }
.btn.ghost:hover { border-color: var(--accent); box-shadow: none; }
.btn.quiet { background: none; border: 0; padding: 0; color: var(--accent); box-shadow: none; }
.btn.quiet:hover { transform: none; text-decoration: underline; }
.btn[disabled] { opacity: 0.4; cursor: not-allowed; transform: none; }

/* ---------- hero with real photography ---------- */
.hero {
  position: relative; min-height: min(92vh, 860px); display: flex; align-items: flex-end;
  padding: 140px 0 72px; overflow: hidden; border-bottom: 1px solid var(--line);
}
.hero-media { position: absolute; inset: 0; z-index: 0; background: radial-gradient(120% 90% at 78% 8%, #16302a 0%, #0b1412 45%, var(--ink) 100%); }
.hero-media img { width: 100%; height: 100%; object-fit: cover; opacity: 0.55; }
.hero-media::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--ink) 72%, transparent) 0%, color-mix(in srgb, var(--ink) 30%, transparent) 40%, var(--ink) 96%),
    linear-gradient(90deg, var(--ink) 4%, color-mix(in srgb, var(--ink) 20%, transparent) 65%);
}
/* slow drift on the hero image — scroll-driven, no JS, no scroll-jacking */
@supports (animation-timeline: view()) {
  .hero-media img { animation: drift linear both; animation-timeline: scroll(root block); }
  @keyframes drift { from { transform: scale(1.06) translateY(0); } to { transform: scale(1.12) translateY(-3%); } }
}
.hero .wrap { position: relative; z-index: 1; }
.hero h1 { max-width: 17ch; }
.hero .lede { max-width: 54ch; margin-top: 1.4rem; }
.hero .actions { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 2.4rem; align-items: center; }
.hero .meta { margin-top: 2.8rem; display: flex; gap: 12px; flex-wrap: wrap; }
.hero .meta span {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 10px 16px; border: 1px solid var(--line); border-radius: 999px;
  background: color-mix(in srgb, var(--ink-2) 70%, transparent);
  backdrop-filter: blur(6px);
  color: var(--muted); font-size: var(--step--1); line-height: 1;
  transition: border-color 200ms ease, transform 200ms cubic-bezier(.2,.7,.2,1);
}
.hero .meta span::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); flex: none;
}
.hero .meta span:hover { border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); transform: translateY(-2px); }
.hero .meta b { color: var(--paper); font-weight: 650; }

/* ---------- sections ---------- */
section { padding: clamp(72px, 10vw, 150px) 0; border-bottom: 1px solid var(--line); position: relative; }
.grid { display: grid; gap: 28px; }
@media (min-width: 780px) { .grid.c2 { grid-template-columns: 1fr 1fr; } .grid.c3 { grid-template-columns: repeat(3, 1fr); } }

.card {
  border: 1px solid var(--line); border-radius: 14px; padding: 28px;
  background: linear-gradient(180deg, var(--ink-2), var(--ink));
  transition: border-color 240ms ease, transform 240ms cubic-bezier(.2,.7,.2,1);
}
.card:hover { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); transform: translateY(-4px); }
.card h3 { margin-bottom: 0.45rem; }
.card p { margin-bottom: 0; font-size: var(--step--1); }
.card .num { color: var(--accent); font-size: 0.8rem; letter-spacing: 0.14em; display: block; margin-bottom: 14px; }

/* alternating image + copy rows */
.split { display: grid; gap: clamp(28px, 5vw, 64px); align-items: center; }
@media (min-width: 860px) {
  .split { grid-template-columns: 1.05fr 1fr; }
  .split.flip .split-media { order: 2; }
}
.split + .split { margin-top: clamp(64px, 8vw, 120px); }
.split-media { position: relative; border-radius: 16px; overflow: hidden; border: 1px solid var(--line); aspect-ratio: 16/10; background: linear-gradient(140deg, #16302a, var(--ink-2) 60%); }
.split-media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 900ms cubic-bezier(.2,.7,.2,1); }
.split:hover .split-media img { transform: scale(1.04); }
.split-media figcaption {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 14px 18px; font-size: 0.8rem;
  color: var(--paper); background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--ink) 92%, transparent));
}
.split.muted-row .split-media { aspect-ratio: 16/7; }
.split.muted-row h3 { font-size: var(--step-1); }

/* technical table */
table.spec { width: 100%; border-collapse: collapse; font-size: var(--step--1); }
table.spec th, table.spec td { text-align: left; padding: 15px 16px; border-bottom: 1px solid var(--line); vertical-align: top; }
table.spec th { color: var(--muted); font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; font-size: 0.72rem; }
table.spec tbody tr { transition: background 200ms ease; }
table.spec tbody tr:hover { background: var(--ink-2); }

/* The NCC editions heading used to be sticky and rode down the page over the content
   below it. A heading that follows you is a distraction, not navigation. */
.sticky-head { padding: 0 0 12px; }

.counters { display: flex; gap: clamp(32px, 6vw, 72px); flex-wrap: wrap; }
.counter .n { font-size: var(--step-2); color: var(--paper); font-weight: 650; letter-spacing: -0.035em; display: block; }
.counter .n em { color: var(--accent); font-style: normal; }
.counter .l { color: var(--muted); font-size: var(--step--1); }

/* full-bleed quote band */
.band { position: relative; overflow: hidden; }
.band-media { position: absolute; inset: 0; }
.band-media img { width: 100%; height: 100%; object-fit: cover; opacity: 0.3; }
.band-media::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, var(--ink) 10%, color-mix(in srgb, var(--ink) 55%, transparent)); }
.band .wrap { position: relative; }

/* ---------- scroll motion ---------- */
.reveal, .slide-l, .slide-r, .rise {
  opacity: 0;
  transition: opacity 700ms ease, transform 820ms cubic-bezier(.16,.84,.28,1);
  will-change: transform, opacity;
}
.slide-l { transform: translateX(-70px); }
.slide-r { transform: translateX(70px); }
.rise    { transform: translateY(42px); }
.reveal  { transform: translateY(18px); }
.in { opacity: 1 !important; transform: none !important; }
.d1 { transition-delay: 90ms; } .d2 { transition-delay: 180ms; } .d3 { transition-delay: 270ms; } .d4 { transition-delay: 360ms; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal, .slide-l, .slide-r, .rise { opacity: 1; transform: none; transition: none; }
  #progress { animation: none; transform: scaleX(1); }
  .hero-media img { animation: none; }
  .btn, .card, .split-media img { transition: none; }
}

/* ---------- contact ---------- */
.contact-grid { display: grid; gap: 34px; align-items: start; }
@media (min-width: 880px) { .contact-grid { grid-template-columns: 1fr 1fr; } }
.contact-card { border: 1px solid var(--line); border-radius: 16px; padding: clamp(24px, 3vw, 38px); background: linear-gradient(180deg, var(--ink-2), var(--ink)); }
.contact-card .email { font-size: var(--step-1); color: var(--paper); text-decoration: none; display: inline-block; margin: 6px 0 18px; border-bottom: 1px solid var(--accent); }
details.drawings { margin-top: 26px; border-top: 1px solid var(--line); padding-top: 22px; }
details.drawings summary { cursor: pointer; color: var(--accent); font-size: var(--step--1); list-style: none; }
details.drawings summary::-webkit-details-marker { display: none; }
details.drawings summary::before { content: "+ "; }
details.drawings[open] summary::before { content: "– "; }

/* ---------- quote form ---------- */
.quote { margin-top: 22px; }
.steps { display: flex; gap: 8px; margin-bottom: 24px; }
.steps i { height: 3px; flex: 1; background: var(--line); border-radius: 2px; transition: background 240ms ease; }
.steps i.on { background: var(--accent); }
.step { display: none; }
.step.on { display: block; animation: stepin 420ms cubic-bezier(.16,.84,.28,1) both; }
@keyframes stepin { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: none; } }
.step h3 { margin-bottom: 1.1rem; scroll-margin-top: 100px; font-size: var(--step-1); }
fieldset { border: 0; padding: 0; margin: 0 0 18px; }
legend { color: var(--muted); font-size: var(--step--1); margin-bottom: 10px; padding: 0; }
.opts { display: grid; gap: 10px; }
@media (min-width: 640px) { .opts.two { grid-template-columns: 1fr 1fr; } }
.opt {
  display: flex; gap: 12px; align-items: flex-start; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: 10px; cursor: pointer;
  transition: border-color 160ms ease, background 160ms ease, transform 160ms ease;
}
.opt:hover { border-color: var(--muted); transform: translateX(3px); }
.opt input { margin-top: 4px; accent-color: var(--accent); }
.opt:has(input:checked) { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.opt span small { display: block; color: var(--muted); font-size: 0.86em; }
label.field { display: block; margin-bottom: 14px; font-size: var(--step--1); color: var(--muted); }
input[type=text], input[type=email], textarea, input[type=file] {
  width: 100%; margin-top: 6px; padding: 12px 14px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--ink); color: var(--paper);
  font: inherit; font-size: var(--step--1);
}
input:focus, textarea:focus, .opt:focus-within, summary:focus-visible, a:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.nav-row { display: flex; gap: 10px; justify-content: space-between; margin-top: 22px; }
.outcome { display: none; padding: 22px; border-radius: 12px; border: 1px solid var(--accent); margin-top: 18px; background: color-mix(in srgb, var(--accent) 6%, transparent); }
.outcome.on { display: block; animation: stepin 420ms cubic-bezier(.16,.84,.28,1) both; }

footer.site { padding: 56px 0 76px; color: var(--muted); font-size: var(--step--1); border-top: 1px solid var(--line); }
footer.site .wrap { display: flex; gap: 24px; justify-content: space-between; flex-wrap: wrap; }
footer.site img { width: 30px; height: 30px; margin-bottom: 10px; }

/* ---------- sub-bar: in-page sections of the current page live in the header,
     the report types live here, and the current one is marked ---------- */
.subbar { border-top: 1px solid var(--line); background: color-mix(in srgb, var(--ink-2) 88%, transparent); }
.subbar .wrap { display: flex; align-items: center; gap: 22px; height: 46px; overflow-x: auto; scrollbar-width: none; }
.subbar .wrap::-webkit-scrollbar { display: none; }
.subbar-label { color: var(--muted); font-size: 0.7rem; letter-spacing: 0.16em; text-transform: uppercase; flex: none; }
.subbar a { color: var(--body); text-decoration: none; font-size: 0.88rem; white-space: nowrap; padding: 4px 0; border-bottom: 2px solid transparent; transition: color 160ms ease, border-color 160ms ease; }
.subbar a:hover { color: var(--paper); border-color: var(--line); }
.subbar a.on { color: var(--accent); border-color: var(--accent); }

/* ---------- stats band, high on the page, counts up on entry ---------- */
.stats { padding: clamp(36px, 5vw, 60px) 0; background: linear-gradient(180deg, var(--ink-2), var(--ink)); }
.stats .counters { display: grid; grid-template-columns: repeat(2, 1fr); gap: 28px; }
@media (min-width: 820px) { .stats .counters { grid-template-columns: repeat(4, 1fr); } }
.stats .counter { text-align: left; }
.stats .counter .n { font-size: clamp(2.4rem, 1.6rem + 3vw, 4rem); color: var(--paper); font-weight: 700; letter-spacing: -0.045em; display: block; font-variant-numeric: tabular-nums; line-height: 1; }
.stats .counter .n::after { content: attr(data-suffix); color: var(--accent); }
.stats .counter .l { color: var(--muted); font-size: var(--step--1); display: block; margin-top: 8px; }

/* ---------- scroll cue ---------- */
.scrollcue { position: absolute; left: 50%; bottom: 26px; width: 26px; height: 42px; border: 1px solid var(--line); border-radius: 14px; translate: -50% 0; z-index: 2; }
.scrollcue span { position: absolute; left: 50%; top: 9px; width: 3px; height: 8px; background: var(--accent); border-radius: 2px; translate: -50% 0; animation: cue 1.9s cubic-bezier(.4,0,.2,1) infinite; }
@keyframes cue { 0% { opacity: 0; transform: translateY(0); } 25% { opacity: 1; } 75% { opacity: 0; transform: translateY(15px); } 100% { opacity: 0; } }
@media (max-width: 760px) { .scrollcue { display: none; } }

/* ---------- marquee of building types ---------- */
.marquee-sec { padding: 0; border-bottom: 1px solid var(--line); }
.marquee { overflow: hidden; padding: 26px 0; mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); }
.marquee-track { display: flex; gap: 56px; width: max-content; animation: slide 38s linear infinite; }
.marquee-track span { color: var(--muted); font-size: clamp(1.4rem, 1rem + 1.6vw, 2.4rem); font-weight: 600; letter-spacing: -0.03em; white-space: nowrap; }
.marquee-track span:nth-child(3n) { color: color-mix(in srgb, var(--accent) 65%, var(--muted)); }
@keyframes slide { to { transform: translateX(-50%); } }
.marquee:hover .marquee-track { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) { .marquee-track { animation: none; } .scrollcue span { animation: none; } }

/* ---------- ambient green field ----------
   Dark, slow-moving pools of the brand green sitting behind everything. Fixed and
   pointer-transparent, so they never interfere with content or scrolling. */
body::before {
  content: "";
  position: fixed; inset: -20vh -10vw;
  z-index: -2; pointer-events: none;
  background:
    radial-gradient(40vw 40vw at 12% 6%,  color-mix(in srgb, var(--green) 55%, transparent) 0%, transparent 62%),
    radial-gradient(46vw 46vw at 88% 20%, color-mix(in srgb, var(--accent) 30%, transparent) 0%, transparent 60%),
    radial-gradient(54vw 54vw at 72% 76%, color-mix(in srgb, var(--green) 45%, transparent) 0%, transparent 64%),
    radial-gradient(42vw 42vw at 16% 90%, color-mix(in srgb, var(--blue) 40%, transparent) 0%, transparent 62%);
  filter: blur(30px) saturate(125%);
  opacity: 0.95;
  animation: drift-field 38s ease-in-out infinite alternate;
}

/* a second, tighter layer keeps the centre of the page from going flat */
body::after {
  content: "";
  position: fixed; inset: 0;
  z-index: -1; pointer-events: none;
  background: radial-gradient(80vw 65vh at 50% 45%,
    color-mix(in srgb, var(--ink) 8%, transparent) 0%,
    color-mix(in srgb, var(--ink) 38%, transparent) 60%,
    color-mix(in srgb, var(--ink) 60%, transparent) 100%);
}

@keyframes drift-field {
  from { transform: translate3d(-2%, -1%, 0) scale(1); }
  to   { transform: translate3d(3%, 2%, 0) scale(1.08); }
}

/* sections sit on the field rather than hiding it */
section { background: transparent; }
section.hero, .marquee-sec, .stats { background: transparent; }
header.site { background: color-mix(in srgb, var(--ink) 78%, transparent); }
.card { background: linear-gradient(180deg, color-mix(in srgb, var(--ink-2) 92%, transparent), color-mix(in srgb, var(--ink) 88%, transparent)); }
.contact-card { background: linear-gradient(180deg, color-mix(in srgb, var(--ink-2) 94%, transparent), color-mix(in srgb, var(--ink) 90%, transparent)); }

@media (prefers-reduced-motion: reduce) { body::before { animation: none; } }

/* ---------- NCC 2025 solar array: panels install themselves as the section arrives ---- */
.solar-sec { overflow: hidden; }
.roof { margin-top: clamp(28px, 4vw, 52px); position: relative; }
.roof svg { width: 100%; height: auto; display: block; max-height: 62vh; }
.roof-plane { opacity: 0; transform: translateY(24px); transition: opacity 700ms ease, transform 900ms cubic-bezier(.16,.84,.28,1); }
.pv {
  opacity: 0;
  transform: translateY(40px) scale(0.86);
  transform-origin: center;
  transform-box: fill-box;
  transition: opacity 520ms ease, transform 620ms cubic-bezier(.2,.9,.25,1);
  transition-delay: calc(var(--i) * 55ms + 220ms);
}
.sun-glow { opacity: 0; transition: opacity 1200ms ease 900ms; }
.roof.in .roof-plane { opacity: 1; transform: none; }
.roof.in .pv { opacity: 1; transform: none; }
.roof.in .sun-glow { opacity: 1; }
.roof-meta {
  display: flex; gap: 28px; flex-wrap: wrap; justify-content: center;
  color: var(--muted); font-size: var(--step--1); margin-top: 6px;
}
.roof-meta b { color: var(--paper); font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  .roof-plane, .pv, .sun-glow { opacity: 1 !important; transform: none !important; transition: none; }
}

/* ---------- glazing comparison ---------- */
.glazer { border: 1px solid var(--line); border-radius: 16px; padding: clamp(20px,3vw,32px); background: linear-gradient(180deg, color-mix(in srgb, var(--ink-2) 92%, transparent), transparent); margin-top: clamp(28px,4vw,48px); }
.pane-rows { display: grid; gap: 10px; }
.pane-row { display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; }
.pane-row span {
  aspect-ratio: 3 / 4; border-radius: 4px;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
  /* --heat is driven by the slider: 1 = blazing single glazing, 0 = controlled */
  background:
    linear-gradient(160deg,
      color-mix(in srgb, #ffb347 calc(var(--heat, 0.8) * 62%), transparent),
      color-mix(in srgb, #2f7fd6 calc((1 - var(--heat, 0.8)) * 45%), transparent));
  box-shadow: inset 0 0 calc(var(--heat, 0.8) * 26px) color-mix(in srgb, #ff7a2f calc(var(--heat,0.8)*55%), transparent);
  transition: background 260ms ease, box-shadow 260ms ease;
}
.glazer-control { display: flex; align-items: center; gap: 16px; margin: 26px 0 18px; color: var(--muted); font-size: var(--step--1); }
.glazer-control input { flex: 1; accent-color: var(--accent); }
.glazer-readout { display: flex; gap: clamp(24px,5vw,60px); flex-wrap: wrap; }
.glazer-readout b { display: block; font-size: var(--step-1); color: var(--paper); font-variant-numeric: tabular-nums; }
.glazer-readout b.pass { color: var(--accent); }
.glazer-readout b.fail { color: #ff8a6a; }
.glazer-readout small { color: var(--muted); font-size: 0.78rem; }

/* ---------- pathway picker ---------- */
.picker { display: grid; gap: 22px; margin-top: clamp(28px,4vw,44px); border: 1px solid var(--line); border-radius: 16px; padding: clamp(20px,3vw,32px); background: linear-gradient(180deg, color-mix(in srgb, var(--ink-2) 92%, transparent), transparent); }
@media (min-width: 900px) { .picker { grid-template-columns: 1fr 1fr auto; align-items: start; } }
.picker-label { display: block; color: var(--muted); font-size: 0.74rem; letter-spacing: 0.14em; text-transform: uppercase; margin-bottom: 10px; }
.picker-opts { display: flex; gap: 8px; flex-wrap: wrap; }
.picker-opts button {
  border: 1px solid var(--line); background: transparent; color: var(--body);
  padding: 10px 14px; border-radius: 999px; font: inherit; font-size: var(--step--1); cursor: pointer;
  transition: border-color 160ms ease, color 160ms ease, background 160ms ease;
}
.picker-opts button:hover { border-color: var(--muted); }
.picker-opts button.on { border-color: var(--accent); color: var(--paper); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.picker-out strong { display: block; font-size: var(--step-1); color: var(--paper); margin-bottom: 12px; }

/* ---------- picker: hold the layout still ----------
   Swapping the building/planning block and changing the answer text was resizing the
   columns, so the buttons jumped every time one was pressed. Fixed tracks, both
   conditional blocks in the same cell, and reserved height for the answer. */
@media (min-width: 900px) {
  .picker { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr) minmax(290px, 320px); }
  .picker > .picker-q:first-child { grid-column: 1; grid-row: 1; }
  .picker > [data-when] { grid-column: 2; grid-row: 1; }
  .picker-out { grid-column: 3; grid-row: 1; }
}
.picker-q { min-height: 158px; }
.picker > .picker-q:first-child { min-height: 0; }
.picker-opts { min-height: 42px; align-content: flex-start; }
.picker-opts button { white-space: nowrap; }
.picker-out strong { min-height: 2.5em; }

/* coverage note: where a service is state-limited, say so without shouting */
.coverage { color: var(--muted); font-size: var(--step--1); max-width: 62ch; }
.coverage b { color: var(--paper); font-weight: 650; }

/* ==========================================================================
   Second motion pass — added where the page was still arriving flat.
   Same rules as the first pass: transform/opacity/clip-path only, no library,
   nothing new shipped to the browser, all of it off under reduced-motion.
   ========================================================================== */

/* ---------- 1. the hero arrives, rather than just being there ----------
   Everything above the fold was static on load. Each line now rises in turn,
   which is the one place on the site where a load animation is read as craft
   rather than delay. Durations are short and the h1 starts almost immediately,
   so the LCP element is not held back. */
@keyframes hero-in { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } }
.hero .eyebrow,
.hero h1,
.hero .lede,
.hero .actions,
.hero .meta span,
.hero .scrollcue { animation: hero-in 760ms cubic-bezier(.16,.84,.28,1) both; }
.hero .eyebrow  { animation-delay: 40ms; }
.hero h1        { animation-delay: 90ms; }
.hero .lede     { animation-delay: 220ms; }
.hero .actions  { animation-delay: 330ms; }
.hero .meta span:nth-child(1) { animation-delay: 430ms; }
.hero .meta span:nth-child(2) { animation-delay: 500ms; }
.hero .meta span:nth-child(3) { animation-delay: 570ms; }
.hero .scrollcue { animation-delay: 900ms; animation-duration: 900ms; }

/* ---------- 2. the header tightens as you leave the hero ----------
   Height is deliberately NOT animated: the header is sticky and in flow, so
   animating its height would shift every section below it and cost CLS. The
   brand lockup scales and the bar darkens instead — the same read, no layout. */
@supports (animation-timeline: scroll(root block)) {
  header.site {
    animation: bar-settle linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 180px;
  }
  @keyframes bar-settle {
    to {
      background: color-mix(in srgb, var(--ink) 94%, transparent);
      box-shadow: 0 14px 34px -26px #000;
    }
  }
  .brand {
    animation: brand-settle linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 180px;
    transform-origin: 0 50%;
  }
  @keyframes brand-settle { to { transform: scale(0.92); } }
}

/* ---------- 3. images wipe open instead of sliding ----------
   A photograph that slides in from the side reads as a slide deck. The same frame
   wiping open while the image inside settles out of a slight zoom is what a
   considered site does, and it costs one extra property.

   The clip goes on the IMG, never on the figure. Chrome folds an element's own
   clip-path into its IntersectionObserver rect, so a figure clipped to zero width
   reads as not visible, never receives .in, and can never un-clip itself. The
   figure is the observed element, so it has to keep its full area. */
.split-media.slide-l, .split-media.slide-r, .split-media.reveal, .split-media.rise {
  transform: none;              /* the wipe replaces the slide, not joins it */
  opacity: 1;
}
.split-media.slide-l img, .split-media.slide-r img,
.split-media.reveal img, .split-media.rise img {
  clip-path: inset(0 100% 0 0);
  transform: scale(1.14);
  transition: clip-path 980ms cubic-bezier(.16,.84,.28,1),
              transform 1500ms cubic-bezier(.16,.84,.28,1);
}
.split-media.slide-r img { clip-path: inset(0 0 0 100%); }
.split-media.in img { clip-path: inset(0 0 0 0); transform: scale(1); }

/* ---------- 4. the section eyebrow draws its rule ----------
   A 26px accent rule that grows out of the left as the section lands. It gives
   every section on every page the same small opening gesture, which is what
   makes separate pages feel like one site. */
.eyebrow::before {
  content: ""; display: inline-block; width: 26px; height: 1px;
  background: currentColor; margin-right: 12px; vertical-align: middle;
  transform-origin: 0 50%;
}
.eyebrow.reveal::before, .eyebrow.rise::before,
.eyebrow.slide-l::before, .eyebrow.slide-r::before {
  transform: scaleX(0);
  transition: transform 720ms cubic-bezier(.16,.84,.28,1) 140ms;
}
.eyebrow.in::before { transform: scaleX(1); }

/* ---------- 5. the card label underlines itself on entry ----------
   SECTION J / RESIDENTIAL / 01 / 02 / 03 — the label was the one part of a card
   doing no work. The rule under it arrives after the card has settled. */
.card .num { position: relative; padding-bottom: 8px; }
.card .num::after {
  content: ""; position: absolute; left: 0; bottom: 0; width: 34px; height: 2px;
  background: var(--accent); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 640ms cubic-bezier(.16,.84,.28,1) 220ms, width 240ms ease;
}
.card.in .num::after { transform: scaleX(1); }
.card:hover .num::after { width: 54px; }

/* ---------- 6. technical tables fill row by row ----------
   The spec tables are the densest thing on the service pages. Dealing the rows
   out in sequence makes them read as a list being worked through. Capped at ten
   rows: past that the last row waits too long to be worth it. */
@keyframes row-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
table.spec.in tbody tr { animation: row-in 460ms cubic-bezier(.16,.84,.28,1) both; }
table.spec.in tbody tr:nth-child(1)  { animation-delay:  60ms; }
table.spec.in tbody tr:nth-child(2)  { animation-delay: 120ms; }
table.spec.in tbody tr:nth-child(3)  { animation-delay: 180ms; }
table.spec.in tbody tr:nth-child(4)  { animation-delay: 240ms; }
table.spec.in tbody tr:nth-child(5)  { animation-delay: 300ms; }
table.spec.in tbody tr:nth-child(6)  { animation-delay: 360ms; }
table.spec.in tbody tr:nth-child(7)  { animation-delay: 420ms; }
table.spec.in tbody tr:nth-child(8)  { animation-delay: 480ms; }
table.spec.in tbody tr:nth-child(9)  { animation-delay: 540ms; }
table.spec.in tbody tr:nth-child(n+10) { animation-delay: 600ms; }

/* ---------- 7. the quote band gets the hero's parallax ----------
   The full-bleed band already carries the same photograph as the hero; it may as
   well drift the same way as it passes. */
@supports (animation-timeline: view()) {
  .band-media img {
    animation: band-drift linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }
  @keyframes band-drift {
    from { transform: scale(1.1) translateY(-2%); }
    to   { transform: scale(1.1) translateY(3%); }
  }
}

/* ---------- everything above, switched off ---------- */
@media (prefers-reduced-motion: reduce) {
  .hero .eyebrow, .hero h1, .hero .lede, .hero .actions,
  .hero .meta span, .hero .scrollcue { animation: none; }
  header.site, .brand, .band-media img { animation: none; }
  .split-media img { clip-path: none !important; transform: none !important; transition: none; }
  .eyebrow::before { transform: scaleX(1) !important; transition: none; }
  .card .num::after { transform: scaleX(1); transition: none; }
  table.spec.in tbody tr { animation: none; }
}

/* ==========================================================================
   Contact block, second pass.
   It was two cards of unequal weight: a business card on the left whose loudest
   element was an underlined mailto, and on the right the actual conversion action
   dressed as a footnote. The hierarchy was upside down — the thing you want them
   to do looked the least important thing on the screen.
   ========================================================================== */

.contact-lede { max-width: 52ch; color: var(--body); }
.contact-grid { align-items: stretch; }          /* was start — the cards ended ragged */

/* --- left: the two ways to reach him, as rows rather than a stacked card --- */
.contact-card.reach { display: flex; flex-direction: column; justify-content: center; padding-block: clamp(14px, 2vw, 22px); }
.reach-row {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: 4px 16px; padding: 20px 4px; text-decoration: none;
  border-bottom: 1px solid var(--line);
  transition: padding-left 220ms cubic-bezier(.2,.7,.2,1), border-color 220ms ease;
}
.reach-row:first-child { border-top: 1px solid var(--line); }
.reach-row .l { grid-column: 1; color: var(--muted); font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase; }
.reach-row .v {
  grid-column: 1; color: var(--paper); font-weight: 600; letter-spacing: -0.02em;
  font-size: clamp(1rem, 0.88rem + 0.55vw, 1.3rem); overflow-wrap: anywhere;
}
.reach-row .go {
  grid-column: 2; grid-row: 1 / span 2; color: var(--accent); font-size: 1.1rem;
  opacity: 0; transform: translateX(-8px);
  transition: opacity 220ms ease, transform 220ms cubic-bezier(.2,.7,.2,1);
}
.reach-row:hover { padding-left: 12px; border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.reach-row:hover .go, .reach-row:focus-visible .go { opacity: 1; transform: none; }
.reach-row:hover .v { color: var(--accent); }
.abn { margin: 22px 0 0; font-size: 0.76rem; line-height: 1.5; max-width: none; }

/* --- right: the action card carries the accent and ends on a real button --- */
.contact-card.act {
  display: flex; flex-direction: column;
  background:
    radial-gradient(120% 90% at 100% 0%, color-mix(in srgb, var(--accent) 9%, transparent) 0%, transparent 60%),
    linear-gradient(180deg, color-mix(in srgb, var(--ink-2) 94%, transparent), color-mix(in srgb, var(--ink) 90%, transparent));
  border-color: color-mix(in srgb, var(--accent) 28%, var(--line));
}
.contact-card.act > p { color: var(--body); }
.contact-card.act details.drawings { margin-top: auto; border-top: 0; padding-top: 18px; }
/* summary carries `color: var(--accent)` from the text-link rule, which outranks
   .btn — the label was accent green on an accent green button, i.e. invisible. */
details.drawings summary.btn { display: inline-flex; width: auto; color: var(--accent-ink); }
details.drawings summary.btn::before { content: none; }       /* the +/– belonged to a text link */
details.drawings summary.btn::after { content: "\2192"; transition: transform 220ms cubic-bezier(.2,.7,.2,1); }
details.drawings[open] summary.btn { background: transparent; color: var(--muted); border: 1px solid var(--line); padding-inline: 18px; }
details.drawings[open] summary.btn::after { transform: rotate(90deg); }
details.drawings[open] summary.btn:hover { color: var(--paper); border-color: var(--accent); box-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  .reach-row, .reach-row .go, details.drawings summary.btn::after { transition: none; }
  .reach-row .go { opacity: 1; transform: none; }
}

/* With the quote form open the action card becomes very tall, and stretching the
   contact rows to match leaves a large empty panel beside it. Once it is open the
   left card stops matching height and sits at its natural size. */
@media (min-width: 880px) {
  .contact-grid:has(details.drawings[open]) .contact-card.reach { align-self: start; }
}

/* ==========================================================================
   Section J — the facade calculator, filling.
   The home page had a signature diagram and the service pages had none. This is
   the Section J one, and it animates the METHOD, not a verdict: no PASS, no star,
   no result. A promise of compliance is not ours to make on a marketing page.
   ========================================================================== */

.fc { display: grid; gap: clamp(20px, 3vw, 34px); margin-top: clamp(32px, 4vw, 52px); }
@media (min-width: 960px) { .fc { grid-template-columns: 1.55fr 1fr; align-items: center; } }

.fc-svg {
  width: 100%; height: auto; display: block;
  border: 1px solid var(--line); border-radius: 16px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--ink-2) 92%, transparent), var(--ink));
}
.fc-ground { stroke: var(--line); stroke-width: 2; }
.fc-outline { fill: none; stroke: var(--muted); stroke-width: 2; }
.fc-parapet { stroke: var(--line); }
.fc-door { fill: #0d1614; stroke: var(--line); stroke-width: 2; }
.glz { fill: color-mix(in srgb, var(--blue) 30%, #0d1614); stroke: var(--line); stroke-width: 1.5; }

/* the outline draws itself, then the glass is dealt out left to right */
@media (prefers-reduced-motion: no-preference) {
  .fc-outline { stroke-dasharray: 2400; stroke-dashoffset: 2400; }
  .fc.in .fc-outline { animation: fc-draw 1100ms cubic-bezier(.16,.84,.28,1) both; }
  @keyframes fc-draw { to { stroke-dashoffset: 0; } }

  .glz { opacity: 0; transform-box: fill-box; transform-origin: 50% 100%; transform: scaleY(0.18); }
  .fc.in .glz { animation: fc-glz 620ms cubic-bezier(.16,.84,.28,1) both;
                animation-delay: calc(760ms + var(--i) * 78ms); }
  @keyframes fc-glz {
    0%   { opacity: 0; transform: scaleY(0.18); fill: var(--accent); }
    55%  { opacity: 1; transform: scaleY(1.04); fill: var(--accent); }
    100% { opacity: 1; transform: scaleY(1);
           fill: color-mix(in srgb, var(--blue) 30%, #0d1614); }
  }

  /* a read head travelling with the pickup, so the sequence has a cause */
  .fc-scan { stroke: var(--accent); stroke-width: 2; opacity: 0; }
  .fc.in .fc-scan { animation: fc-scan 1850ms cubic-bezier(.33,0,.4,1) 700ms both; }
  @keyframes fc-scan {
    0%   { transform: translateX(60px);  opacity: 0; }
    12%  { opacity: 0.85; }
    88%  { opacity: 0.85; }
    100% { transform: translateX(860px); opacity: 0; }
  }
}

/* the tally beside it */
.fc-tally { border: 1px solid var(--line); border-radius: 16px; padding: clamp(20px, 2.4vw, 28px);
  background: linear-gradient(180deg, color-mix(in srgb, var(--ink-2) 94%, transparent), color-mix(in srgb, var(--ink) 90%, transparent)); }
.fc-cap { color: var(--accent); font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase; margin: 0 0 6px; }
.fc-row { display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
  padding: 15px 0; border-bottom: 1px solid var(--line); }
.fc-row:last-child { border-bottom: 0; padding-bottom: 0; }
.fc-l { color: var(--muted); font-size: var(--step--1); }
.fc-row .counter { color: var(--body); font-size: var(--step--1); white-space: nowrap; }
.fc-row .n { color: var(--paper); font-weight: 650; font-size: var(--step-1);
  letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.fc-row .n::after { content: none; }     /* the stats band's suffix rule must not reach in here */

@media (prefers-reduced-motion: reduce) { .fc-scan { display: none; } }

/* `.counter .n` is display:block for the stats band, which dropped the unit onto a
   line of its own in the facade tally. Here the number and its unit are one phrase. */
.fc-row .n { display: inline; }
.fc-slat { stroke: var(--line); stroke-width: 2; }   /* reads as a roller door, not a blank opening */

/* ==========================================================================
   Residential / Lighting / Stormwater diagrams.
   One mechanism for all three: `.pk` parts are dealt out in `--i` order, each
   flashing accent as it is picked up before settling. Same rule as Section J -
   the drawing shows the work being done, never a result.
   ========================================================================== */

.dgm .node, .dgm .room, .dgm .plate { stroke: var(--line); stroke-width: 2; }
.dgm-parts > .pk, .dgm-parts > * { fill: color-mix(in srgb, var(--blue) 26%, #0d1614); stroke: var(--line); stroke-width: 2; }
.dgm .pk-glass { fill: color-mix(in srgb, var(--accent) 22%, #0d1614); }
.dgm .plate { fill: none; stroke: var(--muted); }
.dgm .room { fill: color-mix(in srgb, var(--blue) 22%, #0d1614); }
.dgm .room-l { fill: var(--muted); font-size: 15px; letter-spacing: 0.1em;
  font-family: inherit; font-weight: 600; }
.dgm .node-l { fill: var(--muted); font-size: 15px; letter-spacing: 0.1em; text-anchor: middle;
  font-family: inherit; font-weight: 600; }
.dgm .node-soft { fill: color-mix(in srgb, var(--green) 30%, #0d1614); }
.dgm .flow { fill: none; stroke: var(--line); stroke-width: 3; }
.dgm text { fill: var(--muted); }               /* text must not take the part fill */

@media (prefers-reduced-motion: no-preference) {
  .pk { opacity: 0; }
  .fc.in .pk { animation: pk-in 640ms cubic-bezier(.16,.84,.28,1) both;
               animation-delay: calc(560ms + var(--i) * 230ms); }
  @keyframes pk-in {
    0%   { opacity: 0; }
    45%  { opacity: 1; }
    100% { opacity: 1; }
  }
  /* The accent flash rides on the shape itself, not the label. Where the shape IS
     the `.pk` element (the house section), both animations have to be named in one
     declaration - a second `animation:` rule at higher specificity replaces the
     shorthand outright and the part never fades in. */
  .fc.in .pk > rect, .fc.in .pk > polygon, .fc.in .pk > circle {
    animation: pk-flash 900ms ease-out both;
    animation-delay: calc(560ms + var(--i) * 230ms);
  }
  .fc.in rect.pk, .fc.in polygon.pk {
    animation: pk-in 640ms cubic-bezier(.16,.84,.28,1) both,
               pk-flash 900ms ease-out both;
    animation-delay: calc(560ms + var(--i) * 230ms), calc(560ms + var(--i) * 230ms);
  }
  @keyframes pk-flash {
    0%   { stroke: var(--accent); filter: brightness(1.9); }
    55%  { stroke: var(--accent); filter: brightness(1.35); }
    100% { stroke: var(--line);   filter: none; }
  }

  /* water moves through the train once the nodes are in */
  .dgm .flow { stroke-dasharray: 10 12; }
  .fc.in .dgm .flow { stroke: color-mix(in srgb, var(--accent) 60%, var(--line));
                      animation: flow-run 1.6s linear 1500ms infinite; }
  @keyframes flow-run { to { stroke-dashoffset: -44; } }
}
.dgm .node-wall { fill: color-mix(in srgb, var(--blue) 40%, #0d1614); }   /* walls read apart from the roof */
.dgm .node-glass { fill: color-mix(in srgb, var(--accent) 20%, #0d1614); }
/* labels sit on top of the parts, so muted grey was not carrying */
.dgm .node-l, .dgm .room-l { fill: color-mix(in srgb, var(--paper) 82%, transparent); font-size: 16px; }

/* the residential plan: furniture sits under the pickups and never animates */
.dgm .plate-fill { fill: color-mix(in srgb, var(--ink-2) 92%, transparent); stroke: none; }
.dgm .plan-fur .part { fill: none; stroke: var(--line); stroke-width: 1.5; }
.dgm .wall { fill: color-mix(in srgb, var(--blue) 46%, #0d1614); stroke: none; }
.dgm .glass { fill: var(--accent); stroke: none; }
.dgm .hatch { stroke: color-mix(in srgb, var(--green) 45%, transparent); stroke-width: 1.5; }
.dgm .lg { fill: color-mix(in srgb, var(--paper) 62%, transparent); font-size: 15px;
  letter-spacing: 0.14em; font-weight: 600; }
.dgm .ceiling { opacity: 0.55; }
.fc.in .dgm .ceiling { animation-name: pk-in-soft; }
@keyframes pk-in-soft { from { opacity: 0; } to { opacity: 0.55; } }

/* luminaires: the fitting, and the pool it throws */
.dgm .pool { fill: url(#lamp-pool); stroke: none; }
.dgm .lume { fill: var(--accent); stroke: none; }
@media (prefers-reduced-motion: no-preference) {
  .dgm .lamp { opacity: 0; }
  .fc.in .dgm .lamp {
    animation: lamp-on 620ms cubic-bezier(.16,.84,.28,1) both;
    animation-delay: calc(760ms + var(--i) * 230ms + var(--j) * 55ms);
  }
  /* a fitting strikes, overshoots, then settles - a lamp does not fade up linearly */
  @keyframes lamp-on {
    0%   { opacity: 0; }
    28%  { opacity: 1; }
    46%  { opacity: 0.55; }
    100% { opacity: 1; }
  }
}

/* ---------- stormwater: rain, gutter, tank, raingarden ---------- */
.dgm-train .roofband { fill: color-mix(in srgb, var(--blue) 44%, #0d1614); stroke: none; }
.dgm-train .gutter, .dgm-train .pipe { fill: color-mix(in srgb, var(--muted) 34%, #0d1614); stroke: none; }
.dgm-train .tank { fill: #0d1614; stroke: var(--muted); stroke-width: 2; }
.dgm-train .garden { fill: color-mix(in srgb, var(--green) 34%, #0d1614); stroke: none; }
.dgm-train .plant { fill: none; stroke: color-mix(in srgb, var(--accent) 70%, transparent); stroke-width: 2; }
.dgm-train .water { fill: color-mix(in srgb, var(--blue) 70%, var(--accent)); stroke: none;
  transform-box: fill-box; transform-origin: 50% 100%; }
.dgm-train .drop { stroke: color-mix(in srgb, var(--accent) 55%, transparent); stroke-width: 2;
  stroke-linecap: round; }

@media (prefers-reduced-motion: no-preference) {
  .dgm-train .water { transform: scaleY(0); }
  /* the tank fills only once the gutter has had time to deliver anything */
  .fc.in .dgm-train .water { animation: tank-fill 2600ms cubic-bezier(.4,0,.5,1) 1750ms both; }
  @keyframes tank-fill { to { transform: scaleY(1); } }

  .dgm-train .drop { opacity: 0; }
  .fc.in .dgm-train .drop {
    animation: rain 1100ms linear infinite;
    animation-delay: calc(700ms + var(--j) * 90ms);
  }
  /* drops fall the height of the roof run, then restart - the slope catches them */
  @keyframes rain {
    0%   { opacity: 0;   transform: translate(0, 0); }
    12%  { opacity: 0.9; }
    82%  { opacity: 0.9; }
    100% { opacity: 0;   transform: translate(0, 120px); }
  }
}
@media (prefers-reduced-motion: reduce) {
  .dgm-train .water { transform: scaleY(1); }
  .dgm-train .drop { opacity: 0.6; }
}

/* ---------- SDA: the scored categories ---------- */
.dgm-cats .cat { fill: color-mix(in srgb, var(--ink-2) 92%, transparent); stroke: var(--line); stroke-width: 2; }
.dgm-cats .cat-l { fill: color-mix(in srgb, var(--paper) 84%, transparent); font-size: 15px;
  letter-spacing: 0.1em; font-weight: 600; }
.dgm-cats .cat-bar { fill: var(--accent); transform-box: fill-box; transform-origin: 0 50%; }
@media (prefers-reduced-motion: no-preference) {
  .dgm-cats .cat-bar { transform: scaleX(0); }
  .fc.in .dgm-cats .cat-bar { animation: cat-fill 700ms cubic-bezier(.16,.84,.28,1) both;
                              animation-delay: calc(900ms + var(--i) * 230ms); }
  @keyframes cat-fill { to { transform: scaleX(1); } }
}

/* ---------- NCC 2025: the adoption timeline ---------- */
.dgm-time .axis { stroke: var(--line); stroke-width: 2; }
.dgm-time .tick { stroke: var(--line); stroke-width: 2; }
.dgm-time .stop { fill: var(--accent); stroke: none; }
.dgm-time .stop-d { fill: color-mix(in srgb, var(--paper) 90%, transparent); font-size: 21px;
  font-weight: 700; letter-spacing: -0.01em; text-anchor: middle; }
.dgm-time .stop-w { fill: var(--muted); font-size: 15px; letter-spacing: 0.08em; text-anchor: middle; }
.dgm-time .pk:last-child .stop { fill: var(--muted); }   /* the NT has not adopted it */

/* ---------- SDA: the site plan ---------- */
.dgm-cats .sp-site { fill: none; stroke: var(--line); stroke-width: 2; stroke-dasharray: 9 7; }
.dgm-cats .sp-house { fill: color-mix(in srgb, var(--ink-2) 94%, transparent); stroke: var(--muted); stroke-width: 2; }
.dgm-cats .sp-drive { fill: color-mix(in srgb, var(--ink-2) 80%, transparent); stroke: var(--line); stroke-width: 2; }
.dgm-cats .sp-pv { fill: color-mix(in srgb, var(--blue) 72%, var(--accent)); stroke: none; }
.dgm-cats .sp-tank { fill: color-mix(in srgb, var(--blue) 66%, var(--accent)); stroke: none; }
.dgm-cats .sp-garden { fill: color-mix(in srgb, var(--green) 52%, #0d1614); stroke: none; }
.dgm-cats .sp-tree { fill: color-mix(in srgb, var(--green) 44%, #0d1614); stroke: color-mix(in srgb, var(--accent) 50%, transparent); stroke-width: 1.5; }
.dgm-cats .sp-pave { stroke: color-mix(in srgb, var(--accent) 45%, transparent); stroke-width: 2; }
.dgm-cats .sp-bike, .dgm-cats .sp-bin { fill: color-mix(in srgb, var(--muted) 40%, #0d1614); stroke: none; }
.dgm-cats .sp-glaze { fill: var(--accent); stroke: none; }
.dgm-cats .sp-l { fill: color-mix(in srgb, var(--paper) 80%, transparent); font-size: 14px; letter-spacing: 0.09em; font-weight: 600; }
.dgm-cats .sp-f { fill: var(--muted); font-size: 12px; letter-spacing: 0.14em; }

/* ---------- NCC 2025: the elevation ---------- */
.dgm-time .n-box { fill: color-mix(in srgb, var(--ink-2) 92%, transparent); stroke: var(--muted); stroke-width: 2; }
.dgm-time .n-door { fill: #0d1614; stroke: var(--line); stroke-width: 2; }
.dgm-time .n-glz { fill: color-mix(in srgb, var(--blue) 30%, #0d1614); stroke: var(--line); stroke-width: 1.5; }
.dgm-time .n-roof { fill: color-mix(in srgb, var(--paper) 62%, var(--muted)); stroke: none; }
.dgm-time .n-pv { fill: color-mix(in srgb, var(--blue) 74%, var(--accent)); stroke: none; }
.dgm-time .n-mark { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-dasharray: 8 6; }
.dgm-time .n-l { fill: color-mix(in srgb, var(--paper) 84%, transparent); font-size: 14px;
  letter-spacing: 0.09em; font-weight: 600; }

@media (prefers-reduced-motion: no-preference) {
  /* the array installs panel by panel, the way the roof diagram on the home page does */
  .dgm-time .n-pv { opacity: 0; }
  .fc.in .dgm-time .n-pv { animation: pk-in 420ms ease-out both;
                           animation-delay: calc(1020ms + var(--k) * 70ms); }
}

/* The shell was unboxed for one pass and put straight back: Taner, 21 Sep, *"I'm
   starting to think that those boxes did look better"* - and he was right. The frame
   is what holds a drawing apart from the ambient green field behind it; without it the
   labels fell into the background. The sameness across pages was the real complaint,
   and that is answered by the drawings differing, not by stripping the frame.
   What survives from that pass: the drawings are capped in size rather than running
   the full column. */
.fc-svg { max-width: 100%; }
@media (min-width: 960px) { .fc { grid-template-columns: 1.5fr 1fr; } }

/* ==========================================================================
   Diagram labels were unreadable over the ambient green field - a dim grey on a
   dark, textured background. Every label now paints its own dark halo first, the
   way a drawing note does on a busy plan, and sits at full strength.
   ========================================================================== */
.dgm text, .dgm .node-l, .dgm .room-l, .dgm .lgd-l, .dgm .sp-l, .dgm .sp-f,
.dgm-time .n-l, .dgm-time .stop-d, .dgm-time .stop-w {
  paint-order: stroke fill;
  stroke: color-mix(in srgb, var(--ink) 92%, transparent);
  stroke-width: 5px;
  stroke-linejoin: round;
}
.dgm .node-l, .dgm .room-l, .dgm .sp-l, .dgm-time .n-l { fill: var(--paper); }
.dgm .sp-f { fill: color-mix(in srgb, var(--paper) 58%, transparent); }

/* the elevation reads as a building, not a rectangle: a return wall, a parapet
   shadow and a shadow on the ground give it the depth the flat box was missing */
.dgm-time .n-return { fill: color-mix(in srgb, var(--ink) 88%, transparent); stroke: var(--line); stroke-width: 2; }
.dgm-time .n-shadow { fill: color-mix(in srgb, var(--ink) 70%, transparent); }
.dgm-time .n-mark { stroke-dasharray: none; stroke-width: 2; opacity: 0.75; }

/* ==========================================================================
   SDA and NCC, third pass: animate the idea, not the specification.
   Taner, 21 Sep: *"it's meant to catch the eye ... like an animator behind it.
   It's not meant to be technical"*. No labels, no clause numbers in either.
   ========================================================================== */

/* --- SDA: six marks gathering around a building --- */
.dgm-cats .sd-bld polygon, .dgm-cats .sd-bld rect { fill: color-mix(in srgb, var(--ink-2) 96%, transparent);
  stroke: var(--muted); stroke-width: 2.5; }
.dgm-cats .sd-win { fill: color-mix(in srgb, var(--blue) 42%, #0d1614) !important; stroke: none !important; }
.dgm-cats .sd-dr { fill: color-mix(in srgb, var(--accent) 28%, #0d1614) !important; stroke: none !important; }
.dgm-cats .sd-ico { fill: var(--accent); stroke: var(--accent); stroke-width: 2.5; stroke-linecap: round; }
.dgm-cats .sd-ico [fill="none"] { fill: none; }

@media (prefers-reduced-motion: no-preference) {
  .dgm-cats .sd-ico { opacity: 0; }
  /* each mark drifts in from its own side and settles, rather than fading on the spot */
  .fc.in .dgm-cats .sd-ico {
    animation: ico-in 1100ms cubic-bezier(.16,.84,.28,1) both;
    animation-delay: calc(500ms + var(--i) * 190ms);
  }
  @keyframes ico-in {
    0%   { opacity: 0; translate: var(--fx) var(--fy); scale: 0.7; }
    60%  { opacity: 1; }
    100% { opacity: 1; translate: 0 0; scale: 1; }
  }
  .dgm-cats .sd-bld { opacity: 0; }
  .fc.in .dgm-cats .sd-bld { animation: pk-in 700ms ease-out both; }
}

/* --- NCC: three editions, the current one forward --- */
.dgm-time .bk-shelf { stroke: var(--line); stroke-width: 3; }
.dgm-time .bk-shadow { fill: color-mix(in srgb, var(--ink) 74%, transparent); }
.dgm-time .bk-spine { fill: color-mix(in srgb, var(--ink-2) 96%, transparent); stroke: var(--line); stroke-width: 2; }
.dgm-time .bk-band { fill: color-mix(in srgb, var(--muted) 30%, transparent); }
.dgm-time .bk-y { fill: var(--muted); font-size: 30px; font-weight: 700; letter-spacing: -0.02em;
  text-anchor: middle; }
.dgm-time .bk-now .bk-spine { fill: color-mix(in srgb, var(--green) 26%, var(--ink-2));
  stroke: var(--accent); }
.dgm-time .bk-now .bk-band { fill: var(--accent); }
.dgm-time .bk-now .bk-y { fill: var(--paper); }

@media (prefers-reduced-motion: no-preference) {
  .dgm-time .bk { opacity: 0; }
  .fc.in .dgm-time .bk { animation: bk-in 760ms cubic-bezier(.16,.84,.28,1) both;
                         animation-delay: calc(400ms + var(--i) * 260ms); }
  @keyframes bk-in { from { opacity: 0; translate: 0 -40px; } to { opacity: 1; translate: 0 0; } }
  /* the two earlier editions settle back; the current one comes forward and lifts */
  .fc.in .dgm-time .bk:not(.bk-now) { animation: bk-back 900ms cubic-bezier(.16,.84,.28,1) both;
                                      animation-delay: calc(1200ms + var(--i) * 140ms); }
  @keyframes bk-back { from { opacity: 1; scale: 1; }
                       to   { opacity: 0.52; scale: 0.9; } }
  .fc.in .dgm-time .bk-now { animation: bk-fwd 900ms cubic-bezier(.16,.84,.28,1) both;
                             animation-delay: 1400ms; }
  @keyframes bk-fwd { from { opacity: 1; scale: 1; translate: 0 0; }
                      to   { opacity: 1; scale: 1.14; translate: 0 -14px; } }
}
.dgm-time .bk, .dgm-cats .sd-ico { transform-box: fill-box; transform-origin: 50% 100%; }
/* stroke-only marks inside an icon (the bike frame, the bin lid) */
.dgm-cats .sd-ico .ln, .dgm-cats .sd-ico .ln * { fill: none; stroke: var(--accent); stroke-width: 2.5;
  stroke-linecap: round; stroke-linejoin: round; }
.dgm-cats .dgm-parts, .dgm-cats .sd-bld, .dgm-cats .sd-ico { transform-box: view-box; }
.dgm-cats .sd-scene { transform: scale(1.12); transform-origin: 450px 244px; }
/* the ceiling as a wash, and glazing that reads as an opening rather than a marker pen */
.dgm .ceil-wash { fill: color-mix(in srgb, var(--green) 16%, transparent); stroke: none; }
.dgm .glass { fill: color-mix(in srgb, var(--accent) 88%, transparent); }
/* the drawings sit centred in their frame instead of hard left with dead space beside */
.fc-svg { display: block; margin-inline: auto; }

/* ---------- audit follow-ups ---------- */

/* The read head was a 2px hairline and nobody saw it. It is now a band of light
   raking across the facade, which is what the sweep was always meant to look like. */
.fc-scan { fill: url(#rake); stroke: none; }
@media (prefers-reduced-motion: no-preference) {
  .fc.in .fc-scan { animation: fc-rake 2100ms cubic-bezier(.33,0,.4,1) 640ms both; }
  @keyframes fc-rake {
    0%   { transform: translateX(120px);  opacity: 0; }
    10%  { opacity: 1; }
    86%  { opacity: 1; }
    100% { transform: translateX(1020px); opacity: 0; }
  }
}

/* Each figure lights as the part of the drawing it counts arrives, so the numbers
   belong to the drawing instead of counting to themselves beside it. */
@media (prefers-reduced-motion: no-preference) {
  .fc.in .fc-row .n { animation: fig-lite 900ms ease-out both;
                      animation-delay: calc(1100ms + var(--i) * 240ms); }
  @keyframes fig-lite {
    0%   { color: var(--accent); text-shadow: 0 0 22px color-mix(in srgb, var(--accent) 60%, transparent); }
    100% { color: var(--paper);  text-shadow: none; }
  }
}

/* ==========================================================================
   Phone. The layout collapses correctly at every breakpoint (grids to one
   column, the sub-bar scrolls, type is clamped), but the diagrams do not:
   an SVG scales as one unit, so a 900-unit viewBox in a 382px column renders
   its 16px labels at about 7 real pixels. The drawings are the thing worth
   looking at, so their type is scaled back up in viewBox units instead.
   ========================================================================== */
@media (max-width: 760px) {
  .dgm text, .fc-svg text { font-size: 30px; }
  .dgm .sp-f { font-size: 24px; }
  .dgm-time .bk-y { font-size: 46px; }
  .dgm .room-l, .dgm .node-l { font-size: 30px; letter-spacing: 0.06em; }
  .dgm text { stroke-width: 8px; }          /* the halo has to scale with the type */

  /* a tally of four figures side by side becomes a stack of unreadable columns */
  .fc-tally { padding: 20px; }
  .fc-row { padding: 12px 0; }
  .fc-row .n { font-size: var(--step-0); }
}
/* Scaling the SVG type for phones pushed the room names up into the wall above them:
   their baseline was positioned for 15px type, not 30. SVG has no CSS way to move a
   baseline, so the labels are nudged down by the difference. */
@media (max-width: 760px) {
  .dgm .room-l { transform: translateY(16px); }
  .dgm .sp-f   { transform: translateY(6px); }
}
/* Five labels across the treatment train do not fit at the phone type size - RAINGARDEN
   and OUTFALL collided into one word. This diagram gets a smaller step than the others. */
@media (max-width: 760px) {
  .dgm-train .node-l { font-size: 25px; letter-spacing: 0.03em; }
}
/* The narrowest space on the fitout plate is 150 units wide and AMENITIES is a long
   word: at the phone type size the label ran past its own room. */
@media (max-width: 760px) { .dgm-plate .room-l { font-size: 25px; letter-spacing: 0.04em; } }

/* `nav.site a` (0,1,1) outranks `.btn` (0,1,0), so the header button was taking the
   nav's body-grey text colour and sitting grey-on-green. Same trap as the drawings
   summary button. The header button gets its ink back, explicitly. */
nav.site a.btn { color: var(--accent-ink); }
nav.site a.btn:hover { color: var(--accent-ink); }

/* "ENERGY ASSESSMENTS" was hidden under 860px, so on a phone the brand read as a bare
   "Beyond Green" with no idea what the business does. It stays, one step smaller. */
@media (max-width: 860px) {
  .brand span small { display: block; font-size: 0.58rem; letter-spacing: 0.12em; }
  .brand { font-size: 0.95rem; }
}
