/* ==========================================================================
   Terraguard Technologies — site design system
   Built 18 September 2026 from:
     - Terraguard-homepage-draft-for-approval.pdf (15–16 Sept), the band structure
     - the live CO2 calculator, the button and badge treatment
     - Skills/website-build-standards/references/DESIGN.md, the invariants
   AMENDMENTS awaiting sign-off are marked AMENDED.
   ========================================================================== */

:root {
  /* palette */
  --ink:      #080c23;
  --blue:     #1c4e80;
  --sky:      #38b6ff;
  --yellow:   #efd434;
  --white:    #ffffff;
  --mist:     #e6ebf2;  /* AMENDED from #f4f6f8. The old value was ~4% off white,
                           which read as one long light stretch rather than a ground. */
  --cloud:    #d2dae5;  /* AMENDED from #dde3ea so hairlines register on the new Mist. */
  --slate:    #666f80;
  --graphite: #39414f;

  /* type */
  --title: Antic, Optima, Palatino, Georgia, serif;
  --body:  Jost, "Century Gothic", "Trebuchet MS", system-ui, sans-serif;

  /* shape — both from the live calculator */
  --card-r: 16px;
  --btn-r:  999px;

  --wrap: 1200px;
  --shadow: 0 1px 2px rgba(8,12,35,.05), 0 14px 32px -18px rgba(8,12,35,.22);
}

*, *::before, *::after { box-sizing: border-box; }

/* 80px clears the desktop sticky header (measured ~69px) with a small margin,
   so a focused element (e.g. tabbing to a skip-link target or an in-page
   anchor) doesn't land underneath it. The mobile header is taller than this
   until Phase 3's menu button rebuild lands — revisit this value then. */
html { scroll-behavior: smooth; scroll-padding-top: 80px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } *{ transition:none!important; animation:none!important; } }

body {
  margin: 0;
  background: var(--white);
  color: var(--graphite);
  font-family: var(--body);
  /* AMENDED 1 October 2026: 300 to 400. Checked against the brand guidelines
     first — neither DESIGN.md nor visual-identity.md specifies a body weight,
     they only fix Antic 400 for display and Jost 600 for h3-and-below, so
     this doesn't conflict with anything settled. 300 read as too light for
     a full paragraph measure at 17px; 400 is still clearly lighter than the
     600 headings and strong text, so the hierarchy holds. */
  font-weight: 400;
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
}
img, svg { display: block; max-width: 100%; }
a, button, .btn, .t-dot, .faq summary { touch-action: manipulation; }

/* ---------- skip link ----------
   Added 1 October 2026. Off-screen until focused (first Tab press), which is
   the standard pattern — permanently visible would just be clutter for a
   mouse user. White/Ink rather than Signal Yellow so it reads as part of the
   focus system (matches the Sky focus ring below) rather than spending
   another "yellow touch". */
.skip-link { position: absolute; left: 1rem; top: -4rem; z-index: 100;
  background: var(--white); color: var(--ink); font-weight: 600; font-size: .9rem;
  padding: .7rem 1.2rem; border-radius: 8px; box-shadow: var(--shadow);
  transition: top .15s ease; }
.skip-link:focus { top: 1rem; outline: 2px solid var(--sky); outline-offset: 2px; }

/* ---------- grounds. Four, not two. AMENDED ---------- */
.g-white { background: var(--white); color: var(--graphite); }
.g-mist  { background: var(--mist);  color: var(--graphite); }
.g-ink   { background: var(--ink);   color: rgba(221,227,234,.88); }
.g-blue  { background: var(--blue);  color: rgba(255,255,255,.90); }

.sec { padding: clamp(2.8rem, 6vw, 4.8rem) 0; }
.sec--tight { padding: clamp(2rem, 4vw, 3rem) 0; }
.w { max-width: var(--wrap); margin: 0 auto; padding: 0 clamp(1.1rem, 3.5vw, 2.5rem); }
.narrow { max-width: 760px; }

/* ---------- type ---------- */
h1, h2, h3 { margin: 0 0 .7rem; text-wrap: balance; }
h1, h2 { font-family: var(--title); font-weight: 400; color: var(--ink); line-height: 1.1; }
h1 { font-size: clamp(2.1rem, 1.3rem + 3.2vw, 3.5rem); max-width: 20ch; }
/* AMENDED 23 September 2026, Natalie's comment: a lede should be the same width as
   the heading above it. h1 already had a 20ch cap; h2 had none, so headings ran the
   full 1200px while the lede stopped at 60ch. Capping h2 at 35ch and taking the lede
   to 65ch brings the two blocks to roughly the same width without pushing body text
   past the 65-character limit in the design system. */
h2 { font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.4rem); max-width: 35ch; }
h3 { font-family: var(--body); font-weight: 600; font-size: 1.06rem; line-height: 1.3; color: var(--ink); }
.g-ink h1, .g-ink h2, .g-ink h3, .g-blue h1, .g-blue h2, .g-blue h3 { color: var(--white); }

p { margin: 0 0 1rem; }
p:last-child { margin-bottom: 0; }
.lede { font-size: 1.12rem; max-width: 65ch; }
.prose { max-width: 66ch; }
strong { font-weight: 600; color: var(--ink); }
.g-ink strong, .g-blue strong { color: var(--white); }
small { font-size: .82rem; color: var(--slate); }
.g-ink small { color: rgba(221,227,234,.66); }

/* eyebrow. Blue on light, Sky on dark.
   AMENDED 24 September 2026: font-size was .68rem (10.88px against the site's
   16px root), under the 11px floor for functional text. Sky (--sky) on the Blue
   ground measured 3.8:1 against a 4.5:1 requirement (fine on Ink at 8.56:1, the
   Blue case was the failure). Bumped to .78rem and swapped in a lighter tint,
   used for this label only, not the shared --sky token, so icons, focus rings
   and the tagline are untouched. */
.eyebrow {
  font-size: .78rem; letter-spacing: .18em; text-transform: uppercase;
  font-weight: 600; color: var(--blue); margin: 0 0 .7rem;
}
.g-ink .eyebrow, .g-blue .eyebrow { color: #7dcdff; }

/* the tagline, Sky, as the calculator uses it */
.tagline { color: var(--sky); font-weight: 500; }

/* ---------- badge: outlined yellow pill, straight from the calculator ---------- */
.badge {
  display: inline-flex; align-items: center; gap: .45rem;
  font-size: .72rem; letter-spacing: .13em; text-transform: uppercase; font-weight: 600;
  color: var(--yellow); border: 1px solid rgba(239,212,52,.55);
  border-radius: var(--btn-r); padding: .34rem 1rem; margin: 0 0 1.2rem;
}
.badge::before { content: "◆"; font-size: .6rem; line-height: 1; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--body); font-size: .97rem; font-weight: 600;
  padding: .82rem 2rem; border-radius: var(--btn-r);
  border: 1px solid transparent; text-decoration: none; cursor: pointer;
  transition: background .16s, color .16s, border-color .16s, transform .16s ease, box-shadow .16s ease;
}
/* Added 24 September 2026: a small lift on every button, active state settles
   it back down rather than lifting further, so a click reads as a press. */
.btn:hover { transform: translateY(-2px); box-shadow: 0 8px 18px -10px rgba(8,12,35,.35); }
.btn:active { transform: translateY(0); box-shadow: none; }
/* Yellow is the primary on Ink and Blue, exactly as the calculator does it. */
.g-ink .btn--primary, .g-blue .btn--primary, .site-head .btn--primary { background: var(--yellow); color: var(--ink); }
.g-ink .btn--primary:hover, .g-blue .btn--primary:hover, .site-head .btn--primary:hover { background: #f5e267; }
/* Yellow may never touch white or Mist, so light grounds take Blue. */
.btn--primary { background: var(--blue); color: var(--white); }
.btn--primary:hover { background: #17406b; }
.btn--ghost { background: transparent; color: var(--blue); border-color: var(--cloud); }
.btn--ghost:hover { border-color: var(--blue); }
.g-ink .btn--ghost, .g-blue .btn--ghost, .site-head .btn--ghost { color: var(--white); border-color: rgba(255,255,255,.4); }
.g-ink .btn--ghost:hover, .g-blue .btn--ghost:hover, .site-head .btn--ghost:hover { border-color: var(--white); }
.ctas { display: flex; flex-wrap: wrap; gap: .7rem; align-items: center; }
.btn:focus-visible, a:focus-visible { outline: 2px solid var(--sky); outline-offset: 3px; }

/* ---------- links ---------- */
a { color: var(--blue); text-decoration: none; }
.prose a, .link { border-bottom: 1px solid rgba(28,78,128,.35); }
.prose a:hover, .link:hover { border-bottom-color: var(--blue); }
.g-ink a, .g-blue a { color: var(--yellow); }          /* yellow links, on Ink only */
.g-ink .link, .g-blue .link { border-bottom-color: rgba(239,212,52,.45); }
.g-ink .link:hover, .g-blue .link:hover { border-bottom-color: var(--yellow); }

/* ---------- header ---------- */
.site-head { background: var(--ink); position: sticky; top: 0; z-index: 50; }
.head-in { max-width: var(--wrap); margin: 0 auto; padding: .8rem clamp(1.1rem,3.5vw,2.5rem);
  display: flex; align-items: center; gap: 1.4rem; flex-wrap: wrap; }
.site-head img { height: 38px; width: auto; }
.nav { display: flex; gap: 1.3rem; flex-wrap: wrap; margin-left: auto; font-size: .92rem; }
/* AMENDED 1 October 2026: padding-bottom alone (2px) left under 24px of
   tappable height on a phone. .45rem top and bottom gives each link roughly
   24px of its own height on top of the line box, independent of the
   border-bottom indicator below it. */
.nav a { display: inline-block; color: rgba(221,227,234,.9); border-bottom: 1px solid transparent;
  padding: .45rem 0 .25rem; }
.nav a:hover { color: var(--white); }
.nav a[aria-current="page"] { color: var(--yellow); border-bottom-color: var(--yellow); }
.head-cta { display: flex; gap: .55rem; align-items: center; flex-wrap: wrap; }
.head-cta .btn { padding: .6rem 1.25rem; font-size: .88rem; }

/* ---------- mobile menu (Phase 3, added 1 October 2026) ----------
   Below 900px the full nav and the "Your CO2 figure" ghost button move into
   this disclosure; the bar keeps only the logo, "Book a collection" and the
   menu button, which is what gets the header down to ~64px instead of
   wrapping to three rows. 900px matches the breakpoint already used
   elsewhere on the site (.hero-split, .cert-split), rather than introducing
   a new one. */
.mobile-menu { display: none; }
@media (max-width: 899px) {
  .nav { display: none; }
  .head-cta .btn--ghost { display: none; }
  .head-cta { margin-left: auto; }
  /* nowrap + a tighter gap: with only three items left in the bar (logo,
     "Book a collection", the menu button) everything fits on one line at
     320px and up — flex-wrap:wrap (kept for the desktop nav row) was
     dropping the menu button to its own second row. */
  .head-in { flex-wrap: nowrap; gap: .6rem; padding-top: .6rem; padding-bottom: .6rem; }
  .mobile-menu { display: block; flex: none; }
  .head-cta .btn--primary { padding: .6rem 1.1rem; }
  .mobile-menu summary.menu-btn { padding: 0 .8rem; }
}
/* .site-head is already position:sticky, which is enough to anchor the
   panel below — .head-in itself needs no position set. */
.mobile-menu summary.menu-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 44px; padding: 0 1rem; border-radius: var(--btn-r); cursor: pointer;
  list-style: none; color: var(--white); border: 1px solid rgba(255,255,255,.4);
  font-family: var(--body); font-size: .88rem; font-weight: 600;
  transition: border-color .16s ease;
}
.mobile-menu summary.menu-btn::-webkit-details-marker { display: none; }
.mobile-menu summary.menu-btn:hover { border-color: var(--white); }
.mobile-menu summary.menu-btn:focus-visible { outline: 2px solid var(--sky); outline-offset: 3px; }

/* hamburger <-> close, in pure CSS off the native [open] attribute, so the
   icon still reflects state correctly even on the rare chance the script
   above fails to load. */
.menu-icon { position: relative; width: 17px; height: 2px; background: currentColor; border-radius: 1px; }
.menu-icon::before, .menu-icon::after { content: ""; position: absolute; left: 0; width: 17px; height: 2px;
  background: currentColor; border-radius: 1px; transition: transform .15s ease, top .15s ease; }
.menu-icon::before { top: -5px; }
.menu-icon::after { top: 5px; }
.mobile-menu[open] .menu-icon { background: transparent; }
.mobile-menu[open] .menu-icon::before { top: 0; transform: rotate(45deg); }
.mobile-menu[open] .menu-icon::after { top: 0; transform: rotate(-45deg); }
@media (prefers-reduced-motion: reduce) {
  .menu-icon::before, .menu-icon::after { transition: none; }
}

.mobile-menu-panel { position: absolute; left: 0; right: 0; top: 100%;
  background: var(--ink); border-top: 1px solid rgba(255,255,255,.14);
  box-shadow: var(--shadow); padding: .5rem clamp(1.1rem,3.5vw,2.5rem) 1.4rem; }
.mobile-nav { display: flex; flex-direction: column; }
.mobile-nav a { display: block; color: rgba(221,227,234,.9); padding: .85rem 0;
  border-bottom: 1px solid rgba(255,255,255,.1); font-size: 1rem; }
.mobile-nav a:last-child { border-bottom: 0; }
.mobile-nav a[aria-current="page"] { color: var(--yellow); }
.mobile-menu-panel .mobile-co2 { display: flex; width: 100%; margin-top: 1.1rem; }

/* ---------- hero, with the credential rail overlapping it ---------- */
.hero { padding: clamp(3rem,7vw,5.2rem) 0 0; }
/* AMENDED 22 September 2026: was .hero .sub, so every inner-page hero fell back to
   17px body at the full 1200px measure, well past the 65-character cap. .sub is only
   ever used on Ink, so widening the selector fixes all of them and leaves the
   homepage rendering exactly as before. */
/* AMENDED 23 September 2026, Natalie's comment on the What we do draft: yellow rule
   removed and the measure widened to sit flush with the H1. 35rem is the H1's own
   rendered width at full size (20ch of Antic at 3.5rem), so the two blocks align.
   This was "yellow touch 1 of 5"; four remain. */
/* FIXED 28 September 2026: font-size was silently not applying. clamp()'s
   middle term is a calc()-like expression, and calc() requires whitespace
   around + and - (not optional, unlike the commas) — ".98rem+.45vw" is
   invalid CSS, so the whole declaration was dropped and this fell back to
   the inherited body size. Found while fixing the same mistake in the new
   quote-mark rules below. */
.g-ink .sub { font-size: clamp(1.06rem, .98rem + .45vw, 1.3rem); max-width: 35rem;
  color: rgba(221,227,234,.92); margin: 0 0 1.9rem; }

/* credential rail */
.rail { max-width: var(--wrap); margin: 0 auto; padding: 0 clamp(1.1rem,3.5vw,2.5rem);
  transform: translateY(clamp(1.6rem, 4vw, 2.6rem)); }
.rail-in { background: var(--white); border-radius: var(--card-r); box-shadow: var(--shadow);
  display: grid; gap: 1px; background: var(--cloud); overflow: hidden; }
@media (min-width: 700px)  { .rail-in { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1000px) { .rail-in { grid-template-columns: repeat(4,1fr); } }
.rail-in > div { background: var(--white); color: var(--graphite); padding: 1.25rem 1.35rem; }
/* AMENDED 24 September 2026: retagged h3->h2 to fix a skipped heading level
   (h1 was followed directly by h3 with no h2 in the outline).
   AMENDED AGAIN 1 October 2026: these four labels ("Secure", "Accredited",
   "Award-winning", "Money back") aren't real section headings, so even as h2
   they polluted the page outline. Retagged to <p class="rail-label">, a
   non-heading element with the same look — the outline now runs h1 -> h2
   (real section titles) -> h3 with nothing from this rail in it. */
.rail .rail-label { font-size: .7rem; letter-spacing: .15em; text-transform: uppercase; color: var(--blue); margin-bottom: .4rem; font-family: var(--body); font-weight: 600; max-width: none; }
.rail p { font-size: .9rem; margin: 0; color: var(--graphite); }
.rail .award .rail-label { color: var(--ink); }
.rail .award .rail-label::after { content: " ◆"; color: var(--yellow); }  /* yellow touch 2 */

/* spacing after an overlapping rail */
.after-rail { padding-top: clamp(4.4rem, 9vw, 6.4rem); }

/* ---------- cards & grids ---------- */
.grid { display: grid; gap: 1.2rem; }
.grid-2 { grid-template-columns: 1fr; }
.grid-3 { grid-template-columns: 1fr; }
.grid-4 { grid-template-columns: 1fr; }
@media (min-width: 640px) { .grid-2, .grid-4 { grid-template-columns: 1fr 1fr; } }
@media (min-width: 820px) { .grid-3 { grid-template-columns: repeat(3,1fr); } }
@media (min-width: 1000px){ .grid-4 { grid-template-columns: repeat(4,1fr); } }

.card { background: var(--white); border-radius: var(--card-r); box-shadow: var(--shadow);
  padding: 1.5rem 1.5rem; display: flex; flex-direction: column; gap: .5rem;
  transition: box-shadow .22s ease, transform .22s ease; }
.card p { font-size: .95rem; }
.card .more { margin-top: auto; padding-top: .9rem; font-size: .88rem; font-weight: 500; color: var(--blue); }
a.card { color: inherit; }
.card--img { padding: 0; overflow: hidden; }
.card--img .shot { aspect-ratio: 16/9; background: var(--ink) url("texture.jpg") center/cover;
  display: grid; place-items: center; position: relative; overflow: hidden; }
.card--img .shot svg { width: 30%; max-width: 120px; height: auto; color: var(--sky); opacity: .95; }
/* Added 24 September 2026: real photography replaced the SVG placeholder icon on
   the homepage and case-studies cards. The gradient keeps the yellow .cat label
   readable over a photo of varying tone, same technique as .photo--overlay. The
   img itself gets the hover motion now (a slow zoom), replacing the old
   a.card--img:hover .shot svg opacity rule, which has had no svg to target since. */
.card--img .shot img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform .5s ease; }
.card--img .shot::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(8,12,35,.8), rgba(8,12,35,0) 60%); }
/* AMENDED 1 October 2026: .62rem (~10px) was under the 12px floor for this
   kind of functional label. .75rem (12px) is the minimum that still reads as
   a small tag rather than body text. */
.card--img .shot .cat { position: absolute; left: 1rem; bottom: .85rem; font-size: .75rem;
  letter-spacing: .15em; text-transform: uppercase; font-weight: 600; color: var(--yellow); z-index: 1; }
/* Added 28 September 2026, on Natalie's instruction: photos on the community
   cards. Two of the four supplied photos are tall portraits, and a plain
   centre crop into this 16:9 band cut off the faces — this biases the crop
   toward the top third instead, same idea as .photo--top/.photo--upper
   elsewhere on the site. */
.card--img .shot--top img { object-position: center 18%; }
.card--img .body { padding: 1.35rem 1.45rem 1.5rem; display: flex; flex-direction: column; gap: .5rem; flex: 1; }
.card--img .body h3 { margin: 0; }
a.card--img:hover .shot img { transform: scale(1.05); }
/* Widened 24 September 2026 to a lift, matching the hover treatment added
   across buttons, cards and marks site-wide, not just a deeper shadow. */
a.card:hover { box-shadow: 0 2px 4px rgba(8,12,35,.08), 0 20px 40px -20px rgba(8,12,35,.35);
  transform: translateY(-3px); }
.g-mist .card { box-shadow: 0 1px 2px rgba(8,12,35,.06), 0 14px 32px -18px rgba(8,12,35,.28); }

/* numbered stage */
.stage .n { width: 2.4rem; height: 2.4rem; border-radius: 50%; background: var(--blue); color: var(--white);
  font-family: var(--title); font-size: 1.15rem; display: grid; place-items: center; margin-bottom: .9rem; }
.stage .out { margin-top: auto; padding-top: .9rem; border-top: 1px solid var(--cloud);
  font-size: .82rem; font-weight: 600; color: var(--blue); letter-spacing: .02em; }

/* ---------- certifications: ruled list beside a Mist aside ---------- */
/* align-items:start added 28 September 2026, on Natalie's instruction: grid's
   default stretch was forcing the aside beside the cert list (the paperwork
   card on Home, the award card on What we do, the certificates/insurance card
   on Certifications) to match the list's height, which grew a lot once T11
   and ICO were added — leaving a lot of dead space at the foot of the shorter
   card. Each column now just sizes to its own content. */
.cert-split { display: grid; gap: 2rem; align-items: start; }
@media (min-width: 900px) { .cert-split { grid-template-columns: 1.6fr 1fr; gap: 3rem; } }
.cert-list { border-top: 1px solid var(--cloud); }
/* AMENDED 23 September 2026, Natalie's comment: a mark cell beside each credential.
   Only the three ISO standards have a logo. The two Environment Agency registrations
   are numbers rather than marks, and ADISA deliberately carries none, because the
   organisation is not certified and a logo there would say it was. */
/* SUPERSEDED 28 September 2026, on Natalie's later instruction: the Environment
   Agency mark now appears against every Environment Agency registration (Waste
   Carrier Licence, S2 Exemption, and the new T11 Exemption), not just the licence.
   The list itself is now a single shared block, CERT_LIST() in build.js, rather
   than three separately hand-kept copies — that's what had let the mark go
   missing from one row on one page in the first place. ADISA still carries no
   mark, unchanged. */
/* AMENDED 23 September 2026: the real certification marks arrived, so the cell is
   now a landscape tile sized to them rather than a square placeholder. */
.cert-row { display: grid; grid-template-columns: 7rem 11rem 1fr; gap: 1.2rem;
  padding: 1.2rem 0; border-bottom: 1px solid var(--cloud); align-items: start; }
@media (max-width: 640px) {
  .cert-row { grid-template-columns: 7rem 1fr; gap: .35rem .9rem; }
  .cert-row dd { grid-column: 1 / -1; }
}
.cert-mark { width: 7rem; height: 3.5rem; border-radius: 8px; background: var(--white);
  box-shadow: inset 0 0 0 1px var(--cloud); display: grid; place-items: center;
  padding: .35rem; overflow: hidden; transition: transform .18s ease; }
/* AMENDED 28 September 2026, on Natalie's instruction: the ICO mark was being
   clipped. Root cause was max-height:100% here — inside a grid with
   place-items:center the img's containing block has no definite height, so a
   percentage max-height resolves to none and only max-width was ever actually
   constraining it. A mark much taller relative to its width than the ISO/EA
   marks (ICO's original was) then overflowed .cert-mark's fixed 3.5rem height
   and got silently cropped by its overflow:hidden. Fixed sizes instead of
   percentages, matching .cert-mark's own 7rem/3.5rem box minus its .35rem
   padding on each side, so this can't happen again regardless of a mark's
   aspect ratio. */
.cert-mark img { max-width: 6.3rem; max-height: 2.8rem; width: auto; height: auto;
  object-fit: contain; }
.cert-mark--none { background: transparent; box-shadow: none; }
/* Added 24 September 2026: a small lift on hover, matching .partner-mark. */
.cert-mark:not(.cert-mark--none):hover { transform: translateY(-2px); }
.cert-row dt { font-weight: 600; color: var(--blue); font-size: 1rem; }
/* FIXED 1 October 2026: the T11 reference (EPWEEE/T11/EXP/QS3295UJ/2026) is
   one unbroken string with no spaces, longer than this column's 11rem width
   — the other references (CBDU609517 etc.) were all short enough that this
   never surfaced before. overflow-wrap lets it break rather than spilling
   into the description column next to it. */
.cert-row dt small { display: block; color: var(--slate); font-weight: 400;
  font-variant-numeric: tabular-nums; letter-spacing: .02em; overflow-wrap: break-word; }
.cert-row dd { margin: 0; font-size: .95rem; }

/* ---------- top-of-page certification rail (what-we-do.html), added 28
   September 2026, on Natalie's instruction to surface the marks high on the
   page rather than only lower down in the explained list. Each mark is a
   link down to #credentials, reusing .cert-mark as-is. The award sits in the
   same rail but is picked out in Signal Yellow rather than a white tile, so
   it reads as a different kind of thing from a logo — the same "yellow
   carries the award in the credential rail" rule DESIGN.md already sets for
   the homepage rail, and it only appears here because this rail sits on the
   Ink hero ground; yellow may never touch white or pale blue. */
.cert-rail-top { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.4rem;
  margin-top: 1.8rem; }
a.cert-mark { text-decoration: none; }
a.cert-mark:focus-visible { outline: 2px solid var(--sky); outline-offset: 3px; }
.cert-rail-award { display: inline-flex; align-items: center; gap: .55rem;
  border: 1px solid var(--yellow); border-radius: 999px; padding: .6rem 1.2rem;
  color: var(--yellow); font-size: .86rem; font-weight: 600; letter-spacing: .01em;
  text-decoration: none; transition: background .18s ease; }
.cert-rail-award:hover, .cert-rail-award:focus-visible { background: rgba(239,212,52,.12); }
.cert-rail-award .dot { font-size: .7rem; }
.aside { background: var(--mist); border-radius: var(--card-r); padding: 1.5rem 1.6rem; align-self: start; }
.g-mist .aside { background: var(--white); }

/* ---------- the paperwork panel: solid Ink, Signal Yellow rule ---------- */
.papers { background: var(--ink); border-radius: var(--card-r); padding: 1.8rem 1.9rem; color: rgba(221,227,234,.9); }
.papers h3 { color: var(--white); font-size: 1.15rem; }
.papers .rule { height: 3px; width: 56px; background: var(--yellow); border-radius: 2px; margin: .2rem 0 1.2rem; } /* yellow touch 3 */
.papers dl { margin: 0; }
.papers .row { display: grid; grid-template-columns: 1fr auto; gap: 1rem;
  padding: .72rem 0; border-bottom: 1px solid rgba(221,227,234,.16); align-items: baseline; }
.papers .row:last-child { border-bottom: 0; }
.papers dt { color: var(--sky); font-weight: 500; font-size: .96rem; }
.papers dd { margin: 0; font-size: .86rem; color: rgba(221,227,234,.78); white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Added 1 October 2026: .papers carries its own Ink background but isn't
   inside a .g-ink *section* (on Home it sits in a .g-white section), so the
   ambient ".g-ink a" rule that makes links yellow never applied here — this
   link was falling back to the default Blue, which measured 2.25:1 on Ink.
   Sky, already used for .papers dt on this same background, measures 8.56:1
   (confirmed in the .eyebrow note above) and keeps this inside the existing
   two-colour system on Ink rather than adding a third link colour. */
.papers .link { color: var(--sky); border-bottom-color: rgba(56,182,255,.45); }
.papers .link:hover { border-bottom-color: var(--sky); }

/* ---------- policy data tables (privacy-policy.html), added 30 September 2026.
   The TG-ISP-05E privacy notice carries three real data tables (contact
   details, the data-we-collect matrix, retention periods) that the old
   prose-only legal pages never needed. .prose caps at 66ch for readability,
   which is fine for paragraphs but cramped for a 3-column table, so each
   table sits in a .table-scroll wrapper (horizontal scroll on narrow
   viewports rather than letting it force the page wide) and keeps the same
   66ch column, just wrapping cell text across more lines than it would at
   full .w width. Left-column th (scope="row") gives the two-column
   contact/retention tables a shaded label without a second component. */
.prose table { width: 100%; min-width: 460px; border-collapse: collapse; margin: 0 0 1.3rem; font-size: .92rem; }
.prose caption { caption-side: top; text-align: left; font-weight: 600; color: var(--ink); margin-bottom: .5rem; }
.prose th, .prose td { text-align: left; vertical-align: top; padding: .6rem .8rem; border-bottom: 1px solid var(--cloud); }
.prose thead th { background: var(--mist); color: var(--ink); font-weight: 600; font-size: .78rem; letter-spacing: .04em; text-transform: uppercase; }
.prose tbody th { background: var(--mist); color: var(--ink); font-weight: 500; white-space: nowrap; }
.prose td { color: var(--graphite); }
.prose tr:last-child td, .prose tr:last-child th { border-bottom: 0; }
.table-scroll { overflow-x: auto; margin: 0 0 1.3rem; }
.table-scroll table { margin-bottom: 0; }

/* ---------- partners/memberships marquee (about.html), added 24 September 2026 ---------- */
.partners-track { overflow: hidden; -webkit-mask-image: linear-gradient(to right, transparent, black 6%, black 94%, transparent);
  mask-image: linear-gradient(to right, transparent, black 6%, black 94%, transparent); }
.partners-row { display: flex; gap: 2.2rem; width: max-content; align-items: center;
  animation: partners-scroll 34s linear infinite; }
.partners-track:hover .partners-row { animation-play-state: paused; }
/* Squared up 24 September 2026, on Natalie's instruction: was 150x92 (a wide
   rectangle) against near-square 344x335 source crops, and — the bigger
   cause — those crops carried wildly different amounts of built-in white
   margin (as little as 26% vertical fill for one logo, as much as 69% for
   another), so even identically-scaled images looked inconsistently sized.
   Both fixed: the six source images in assets/photos/ were re-cropped to
   their actual content with uniform ~14% padding on a square canvas, and
   this box is now square to match. */
.partner-mark { width: 120px; height: 120px; flex: none; border-radius: 12px; background: var(--white);
  box-shadow: inset 0 0 0 1px var(--cloud); display: grid; place-items: center; padding: .8rem;
  transition: transform .18s ease, box-shadow .18s ease; }
.partner-mark img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }
.partner-mark:hover { transform: translateY(-3px); box-shadow: inset 0 0 0 1px var(--cloud), 0 10px 20px -12px rgba(8,12,35,.3); }
@keyframes partners-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .partners-row { animation: none; flex-wrap: wrap; justify-content: center; }
}

/* ---------- award band ---------- */
.award-band { display: grid; gap: 2rem; align-items: center; }
@media (min-width: 860px) { .award-band { grid-template-columns: auto 1fr; gap: 3.2rem; } }
.award-mark { width: clamp(140px, 18vw, 200px); height: auto; flex: none; }
.award-mark img { width: 100%; height: auto; }

/* ---------- testimonials, with the speech bubble ---------- */
/* Widened 24 September 2026 on Natalie's instruction (was max-width:22ch, a
   single narrow column with a large empty gap either side on wider screens). */
/* AMENDED 28 September 2026, on Natalie's instruction: bigger type, and large
   speech marks in opposite corners. position:relative here plus the ::before/
   ::after pair below is the one change that reaches every page this quote
   appears on (Home, Certifications, Case studies), since they all share this
   one .quote-big rule rather than each keeping their own copy. Yellow, same
   accent the quote-rule above it already uses. */
/* SCALED BACK the same day, on Natalie's instruction: the first pass ran too
   big. Font size down, but max-width widened at the same time (was 54rem) so
   the now-smaller text still uses the section's width rather than sitting in
   a narrower, emptier column. */
.quote-big { font-family: var(--title); font-size: clamp(1.5rem, 1.2rem + 1.3vw, 2.35rem);
  line-height: 1.36; color: var(--white); max-width: 64rem; margin-inline: auto;
  position: relative; padding: 0 .4rem; }
.quote-big::before, .quote-big::after { font-family: var(--title); color: var(--yellow);
  line-height: 1; position: absolute; opacity: .9; pointer-events: none;
  font-size: clamp(2.2rem, 1.7rem + 2.4vw, 4.2rem); } /* yellow touch 5 */
.quote-big::before { content: "\201C"; top: -.6rem; left: -.6rem; }
.quote-big::after { content: "\201D"; bottom: -1.9rem; right: -.6rem; }
.quote-rule { height: 3px; width: 56px; background: var(--yellow); border-radius: 2px; margin: 0 auto 1.6rem; } /* yellow touch 4 */
.quote-by { font-size: .95rem; color: var(--yellow); font-weight: 500; letter-spacing: .04em; margin-top: 1.8rem; }
.testimonial-band { text-align: center; }
/* Added 24 September 2026: a hairline for when a section needs to read as
   distinct from the next one but both sit on the same Ink background, so a
   colour change isn't an option (case-studies.html: testimonials into the
   closing CLOSE() band, both g-ink). Deliberately subtle — a divider, not a
   block boundary. */
.divide-bottom { border-bottom: 1px solid rgba(221,227,234,.14); padding-bottom: 3.5rem; }

/* ---------- scroll reveal, added 24 September 2026 ---------- */
/* Opt-in: add .reveal to a section for a fade/rise on first scroll into view.
   The driving script lives once in shell() and is a no-op on any page with no
   .reveal elements, so it costs nothing on pages that don't use it.
   Fails safe on purpose: .reveal alone is fully visible. The hidden starting
   state only applies under .reveal-active, which the script adds to <html>
   itself, and only once it has confirmed IntersectionObserver exists and
   there are .reveal elements to drive. No JS, a script error, or a crawler
   that doesn't execute JS all just see the content, never a blank section. */
.reveal { opacity: 1; transform: none; }
.reveal-active .reveal { opacity: 0; transform: translateY(28px); transition: opacity .7s ease, transform .7s ease; }
.reveal-active .reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal-active .reveal { opacity: 1; transform: none; transition: none; }
}
.testimonial-band .eyebrow { margin-bottom: 1rem; }

/* ---------- testimonial carousel, added 24 September 2026 ---------- */
/* Fails safe like .reveal above: with no .t-active class, .t-slide has no
   display rule of its own, so every slide just renders stacked in normal
   flow and nothing here depends on JS to be readable. The driving script
   only adds .t-active, and only once it has found more than one .t-slide
   to rotate. */
.t-slide { margin: 0; }
.t-carousel.t-active .t-slide { display: none; }
.t-carousel.t-active .t-slide.is-active { display: block; animation: t-fade .5s ease; }
@keyframes t-fade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.t-dots { display: none; }
.t-carousel.t-active .t-dots { display: flex; justify-content: center; gap: .1rem; margin-top: 2.2rem; }
/* AMENDED 1 October 2026: the visible dot stays 9px (::after), but the
   clickable button is 44px — WCAG's "ideally 44x44" tap-target size. Centring
   the small dot inside the larger button keeps the look identical to before.
   (The pause/play button this comment used to sit beside was removed the
   same day, on Natalie's instruction — this sizing fix is unrelated and
   stays.) */
.t-dot { width: 44px; height: 44px; border-radius: 50%; border: 0; background: transparent;
  padding: 0; cursor: pointer; display: grid; place-items: center; }
.t-dot::after { content: ""; width: 9px; height: 9px; border-radius: 50%;
  background: rgba(221,227,234,.3); transition: transform .15s ease, background .15s ease; }
.t-dot.is-active::after { background: var(--yellow); }
.t-dot:hover::after { background: rgba(221,227,234,.55); transform: scale(1.25); }
.t-dot.is-active:hover::after { background: var(--yellow); }
.t-dot:focus-visible { outline: 2px solid var(--sky); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .t-carousel.t-active .t-slide.is-active { animation: none; }
}

.bubble-tail { height: 26px; }
.bubble-tail svg { height: 26px; width: 100%; }

.quotes { display: grid; gap: 1.1rem; }
@media (min-width: 760px) { .quotes { grid-template-columns: repeat(3,1fr); } }
.quotes blockquote { margin: 0; background: rgba(255,255,255,.07); border-radius: var(--card-r); padding: 1.3rem 1.4rem; }
/* AMENDED 28 September 2026, on Natalie's instruction: same bigger-type,
   corner-quote-marks treatment as .quote-big, applied to this other
   testimonial pattern (Impact's donation quotes) so both places testimonials
   appear match. Marks sit on the text column only, not the photo beside it. */
.quotes p { font-size: 1.06rem; color: rgba(221,227,234,.9); }
.quotes cite { font-style: normal; font-size: .8rem; color: var(--sky); display: block; margin-top: .8rem; }
.quotes--wide blockquote > div { position: relative; padding: .5rem .3rem 0; }
.quotes--wide blockquote > div::before, .quotes--wide blockquote > div::after {
  font-family: var(--title); color: var(--yellow); line-height: 1; position: absolute;
  opacity: .9; pointer-events: none; font-size: clamp(2.4rem, 2rem + 2vw, 3.6rem); } /* yellow touch 6 */
.quotes--wide blockquote > div::before { content: "\201C"; top: -.3rem; left: -.6rem; }
.quotes--wide blockquote > div::after { content: "\201D"; bottom: -1.5rem; right: -.6rem; }

/* ---------- FAQ ---------- */
.faq { border-top: 1px solid var(--cloud); margin-top: 1.8rem; }
.faq details { border-bottom: 1px solid var(--cloud); }
.faq summary { display: flex; justify-content: space-between; gap: 1.5rem; align-items: baseline;
  padding: 1.15rem 0; cursor: pointer; font-weight: 600; color: var(--ink); font-size: 1.04rem; list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--blue); font-size: 1.3rem; line-height: 1; font-weight: 400; }
.faq details[open] summary::after { content: "−"; }
.faq .a { padding: 0 0 1.2rem; font-size: .96rem; max-width: 72ch; }

/* ---------- book-a-collection form ----------
   Added 24 September 2026. Error red is #c8322a, the same functional-only
   value the CO2 calculator uses for .field-error and nothing else — reused
   here for the site's first form rather than inventing a second red. */
.field { margin-bottom: 1.1rem; }
.field label { display: block; font-size: .88rem; font-weight: 600; color: var(--ink); margin-bottom: .35rem; }
.field label small { font-weight: 400; color: var(--slate); }
.field input, .field select, .field textarea {
  width: 100%; font-family: var(--body); font-size: .96rem; color: var(--graphite);
  background: var(--white); border: 1px solid var(--cloud); border-radius: 10px;
  padding: .65rem .8rem; transition: border-color .16s;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(28,78,128,.14);
}
.field textarea { resize: vertical; }
.form-privacy { margin: 0 0 1.1rem; }
.field-error { color: #c8322a; font-size: .88rem; font-weight: 500; margin: 0 0 1.1rem; }
#formThanks h3 { margin-bottom: .5rem; }

/* ---------- rebate split ---------- */
.split { display: grid; gap: 2rem; }
@media (min-width: 880px) { .split { grid-template-columns: 1.25fr 1fr; gap: 3rem; align-items: start; } }
.panel { background: var(--white); border-radius: var(--card-r); box-shadow: var(--shadow); padding: 1.6rem 1.7rem; }
.panel ul { margin: .8rem 0 0; padding-left: 1.15rem; font-size: .95rem; }
.panel li { margin-bottom: .45rem; }

/* ---------- closing ---------- */
.close-h { display: inline; background-image: linear-gradient(var(--yellow), var(--yellow));
  background-size: 100% 3px; background-repeat: no-repeat; background-position: 0 100%;
  padding-bottom: 3px; }                                   /* yellow touch 5 */

/* ---------- footer ---------- */
.site-foot { background: var(--ink); color: rgba(221,227,234,.78); padding: clamp(2.4rem,5vw,3.6rem) 0 2rem; font-size: .9rem; }
.foot-grid { display: grid; gap: 2rem; }
@media (min-width: 820px) { .foot-grid { grid-template-columns: 1.4fr 1fr 1fr 1.2fr; gap: 2.5rem; } }
.site-foot h3 { font-size: .68rem; letter-spacing: .16em; text-transform: uppercase; color: var(--sky); font-weight: 600; margin: 0 0 .85rem; }
.site-foot h3.compliance { color: var(--yellow); }          /* yellow touch 5b, footer heading */
.site-foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .48rem; }
/* AMENDED 1 October 2026: no vertical padding at all meant under 24px of
   tappable height on a phone. inline-block so the padding actually extends
   the clickable box rather than just the paint area. */
.site-foot a { display: inline-block; color: rgba(221,227,234,.82); padding: .4rem 0; }
.site-foot a:hover { color: var(--white); }
/* FIXED 1 October 2026: missing width:auto (the header's identical rule,
   .site-head img above, already had it). Without it, once the logo gained
   width/height HTML attributes for Phase 2's layout-shift fix, the browser
   held width at the attribute's 218px while this rule's height:44px
   squashed it — stretched/warped at any size. width:auto plus an explicit
   aspect-ratio (belt and braces, doesn't depend on the HTML attributes
   being read a particular way) means it can only ever scale proportionally,
   regardless of viewport. */
.site-foot img { height: 44px; width: auto; aspect-ratio: 218 / 132; margin-bottom: .9rem; }
.foot-tag { font-family: var(--title); font-size: 1.1rem; color: var(--white); margin: 0; }
.legal { border-top: 1px solid rgba(221,227,234,.16); margin-top: 2.4rem; padding-top: 1.3rem;
  font-size: .76rem; color: rgba(221,227,234,.62); display: grid; gap: .3rem; }
.legal b { color: rgba(221,227,234,.85); font-weight: 500; }
.foot-wide { grid-column: 1 / -1; border-top: 1px solid rgba(221,227,234,.14); padding-top: 1.4rem; margin-top: .6rem; }
.foot-wide ul { display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; font-size: .83rem; }

/* ---------- preview chrome ---------- */
.preview-bar { background: var(--yellow); color: var(--ink); font-size: .82rem; font-weight: 500;
  text-align: center; padding: .5rem 1rem; }
.preview-bar a { color: var(--ink); border-bottom: 1px solid rgba(8,12,35,.4); }

/* ==========================================================================
   What we do — page components. Added 22 September 2026.
   Built inside the invariants: four grounds, Sky/Blue accent, yellow on dark
   only, 16px cards with shadow and no border, 999px pills, Antic for display
   numerals only.
   ========================================================================== */

/* ---------- jump rail: on-page navigation, under the hero on Ink ---------- */
.jumps { display: flex; flex-wrap: wrap; gap: .5rem .55rem;
  margin-top: 2.1rem; padding-top: 1.7rem; border-top: 1px solid rgba(221,227,234,.18); }
.jumps a { font-size: .84rem; font-weight: 500; color: rgba(221,227,234,.9);
  border: 1px solid rgba(221,227,234,.26); border-radius: var(--btn-r);
  padding: .4rem 1.05rem; transition: color .16s, border-color .16s; }
.jumps a:hover { color: var(--yellow); border-color: rgba(239,212,52,.6); }

/* ---------- figure pair: a number that carries an argument ---------- */
.figs { display: grid; gap: 1.3rem; margin-top: 2rem; }
@media (min-width: 620px) { .figs { grid-template-columns: 1fr 1fr; gap: 2rem; } }
.fig { border-top: 3px solid var(--blue); padding-top: .95rem; }
.fig b { display: block; font-family: var(--title); font-weight: 400; line-height: 1.04;
  font-size: clamp(1.9rem, 1.4rem + 1.7vw, 2.6rem); color: var(--ink);
  font-variant-numeric: tabular-nums; }
/* Narrowed to a direct-child combinator 24 September 2026: this is meant for
   the description span that's a direct child of .fig, but as a plain
   descendant selector it was also matching .roll-text/.roll-char nested
   inside .fig b (the £10,000+ figure's per-character spans, added the same
   day) — and at equal-or-lower specificity, .fig span's "class + tag"
   beat .roll-char's plain class for the display property, forcing every
   character to display:block and stack vertically instead of flowing
   inline. The direct-child form only ever matched the description span
   anyway, so this is a no-op for it and fixes the real bug. */
.fig > span { display: block; margin-top: .4rem; font-size: .92rem;
  color: var(--slate); max-width: 36ch; }

/* ---------- process diagram ---------- */
.flow { margin-top: 2.3rem; }
.flow-scroll { overflow-x: auto; overflow-y: hidden; }
.flow-scroll > svg { min-width: 860px; width: 100%; height: auto; }
.flow-note { margin-top: 1rem; font-size: .87rem; color: var(--slate); max-width: 70ch; }
.flow-hint { display: none; }
@media (max-width: 900px) { .flow-hint { display: inline; } }

/* ---------- long-form stages ---------- */
.steps { margin-top: 2.2rem; display: grid; gap: 1.9rem; }
.step { display: grid; gap: 1rem; padding-top: 1.9rem; border-top: 1px solid var(--cloud); }
.step:first-child { padding-top: 0; border-top: 0; }
@media (min-width: 900px) {
  .step { grid-template-columns: 4.4rem 1fr 19rem; gap: 2.2rem; align-items: start; }
}
.step-side { display: grid; gap: 1rem; align-content: start; }
.step-n { width: 3.1rem; height: 3.1rem; border-radius: 50%; background: var(--blue);
  color: var(--white); font-family: var(--title); font-size: 1.4rem;
  display: grid; place-items: center; }
.step h3 { font-size: 1.22rem; margin-bottom: .6rem; }
.step .prose { max-width: 62ch; }
/* AMENDED 23 September 2026: Ink, not white. A white card on a white ground was
   relying on a shadow alone and barely registered. Ink is the treatment the site
   already gives paperwork, so this matches the homepage panel. */
.step .out { background: var(--ink); border-radius: var(--card-r);
  box-shadow: var(--shadow); padding: 1.15rem 1.3rem 1.25rem; align-self: start; }
.step .out h4 { margin: 0 0 .55rem; font-size: .66rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--sky); font-weight: 600; }
.step .out p { margin: 0; font-size: .9rem; color: rgba(221,227,234,.92); }
.step .out em { display: block; margin-top: .5rem; font-style: normal;
  font-size: .8rem; color: rgba(221,227,234,.66); font-variant-numeric: tabular-nums; }

/* ---------- the four documents, and what each one proves ---------- */
.rule-y { height: 3px; width: 56px; background: var(--yellow);
  border-radius: 2px; margin: .2rem 0 1.4rem; }        /* yellow, dark grounds only */
.docs { margin: 2.1rem 0 0; border-top: 1px solid var(--cloud); }
.doc { display: grid; gap: .45rem 2rem; padding: 1.4rem 0; border-bottom: 1px solid var(--cloud); }
@media (min-width: 900px) { .doc { grid-template-columns: 16rem 1fr 11.5rem; align-items: baseline; } }
.doc dt { font-weight: 600; color: var(--blue); font-size: 1rem; }
.doc dd { margin: 0; font-size: .95rem; max-width: 56ch; }
.doc .when { font-size: .86rem; font-weight: 500; color: var(--slate);
  font-variant-numeric: tabular-nums; }
@media (min-width: 900px) { .doc .when { text-align: right; } }
.g-ink .docs, .g-ink .doc { border-color: rgba(221,227,234,.18); }
.g-ink .doc dt { color: var(--sky); }
.g-ink .doc .when { color: rgba(221,227,234,.7); }

/* ---------- scope: what we take, what we cannot ---------- */
.scope { display: grid; gap: 1.8rem; margin-top: 2rem; }
@media (min-width: 840px) { .scope { grid-template-columns: 1fr 1fr; gap: 2.6rem; } }
/* Added 24 September 2026: the two columns are grid items, so they already
   match height (grid's default align-items:stretch) — but each column's own
   content didn't line up, because "We collect"'s intro was one line shorter
   than "We can also help with"'s, so the checklists below started at
   different heights. First fix was min-height on both intros, forcing the
   short one up to match — worked, but left a visible dead gap under the
   one-line text (flagged the same day: too much empty space). Replaced with
   the actual fix: the short intro's copy was extended so it wraps to two
   lines naturally at the breakpoint this column renders at (tested: 49.2px
   against the long intro's natural 49.4px, near enough there's nothing left
   to force). No min-height needed now that the two are genuinely the same
   length — removing it here rather than leaving a rule with nothing to do.
   Flex column still lets margin-top:auto on .scope-cta push the "Contact us"
   button flush to the bottom of the row, filling the space "We can also
   help with"'s longer, paragraph-style items leave under the checklist. */
.scope > div { display: flex; flex-direction: column; }
.scope-cta { margin-top: auto; padding-top: 1.6rem; }
.scope ul { list-style: none; margin: .9rem 0 0; padding: 0; display: grid; gap: .6rem; }
.scope li { position: relative; padding-left: 1.8rem; font-size: .95rem; }
.scope li::before { position: absolute; left: 0; top: 0; font-weight: 600; }
.scope .yes li::before { content: "\2713"; color: var(--blue); }
.scope .no  li::before { content: "\2715"; color: var(--slate); }

/* ---------- town tags ---------- */
.tags { display: flex; flex-wrap: wrap; gap: .45rem .5rem; margin-top: 1.6rem; }
.tags span { font-size: .84rem; font-weight: 500; color: var(--graphite);
  background: var(--white); border-radius: var(--btn-r); padding: .38rem 1.05rem;
  box-shadow: 0 1px 2px rgba(8,12,35,.06); }

/* ---------- a white panel sitting on the Blue band ---------- */
.g-blue .panel { color: var(--graphite); }
.g-blue .panel h3, .g-blue .panel strong { color: var(--ink); }
.g-blue .panel a { color: var(--blue); }
.g-blue .panel .link { border-bottom-color: rgba(28,78,128,.35); }
.g-blue .panel .link:hover { border-bottom-color: var(--blue); }


/* ---------- photography slots ----------
   The library is thin (see photo-shot-list.md), so every slot below is a marked
   placeholder naming the shot it needs. They are not decorative: each one is a
   brief. Replace with the real frame before this page goes anywhere near live. */
.photo { margin: 0; }
.photo-box { aspect-ratio: 4 / 3; max-width: 100%; border-radius: var(--card-r);
  background: var(--ink) url("texture.jpg") center/cover;
  display: grid; place-items: center; align-content: center; gap: .7rem;
  padding: 1.2rem; text-align: center; overflow: hidden; }
.photo-box--wide { aspect-ratio: 16 / 7; }
.photo-box svg { width: 40px; height: 40px; color: var(--sky); }
.photo-tag { font-size: .62rem; letter-spacing: .17em; text-transform: uppercase;
  font-weight: 600; color: var(--yellow); }        /* yellow on Ink only */
.photo figcaption { margin-top: .7rem; font-size: .82rem; color: var(--slate); max-width: 46ch; }
.g-ink .photo figcaption, .g-blue .photo figcaption { color: rgba(221,227,234,.7); }

/* ---------- hero split: copy beside an image ----------
   Added 23 September 2026 on Natalie's comment asking for a photo or graphic in
   the hero. The jump rail stays full width beneath it. */
.hero-split { display: grid; gap: 2rem; align-items: center; }
@media (min-width: 900px) { .hero-split { grid-template-columns: 1.15fr .85fr; gap: 3.2rem; } }
/* a photo box on Ink needs an edge, or it disappears into the ground */
.g-ink .photo-box { box-shadow: inset 0 0 0 1px rgba(221,227,234,.18); }

/* a figure pair stacked into a narrow column beside the main measure */
.figs--stack { grid-template-columns: 1fr; margin-top: 0; }
@media (min-width: 620px) { .figs--stack { grid-template-columns: 1fr; gap: 1.4rem; } }

/* ---------- stat cards ----------
   Amended 23 September 2026 on Natalie's comment that the stats should stand out.
   Blue boxes on a White ground, which is the comparison-card pattern already in the
   brand design style. A Blue card is a component, not a ground, so this does not
   spend the one-Blue-band-per-page limit. */
.figs--3 { margin-top: 2.6rem; }
@media (min-width: 760px) { .figs--3 { grid-template-columns: repeat(3, 1fr); gap: 1.2rem; } }
.fig--blue { background: var(--blue); border-top: 0; border-radius: var(--card-r);
  padding: 1.5rem 1.6rem; }
.fig--blue b { color: var(--white); }
.fig--blue span { color: rgba(255,255,255,.82); max-width: none; }
/* a card still waiting on an approved figure */
.fig--todo { background: transparent; box-shadow: inset 0 0 0 1px var(--cloud); }
.fig--todo b { color: var(--slate); font-family: var(--body); font-weight: 600;
  font-size: 1rem; letter-spacing: .14em; text-transform: uppercase; }
.fig--todo span { color: var(--slate); }

/* ---------- a text plate over a photograph ----------
   The shot list sets the treatment: an Ink plate under the text, brand from the
   treatment rather than from signage in the frame. */
.photo--overlay .photo-box { align-content: space-between; justify-items: start;
  text-align: left; padding: 1.5rem; }
.photo-mark { display: flex; align-items: center; gap: .6rem; }
.photo-mark svg { width: 26px; height: 26px; }
.photo-plate { background: rgba(8,12,35,.9); border-radius: 12px; padding: 1.05rem 1.25rem;
  max-width: 46ch; }
.photo-plate p { margin: 0; font-size: .94rem; color: rgba(221,227,234,.88); }
.photo-plate strong { display: block; color: var(--white); font-weight: 600; margin-bottom: .3rem; }

/* ---------- the award, given its own weight ----------
   Amended 23 September 2026 on Natalie's comment. Ink card on the Mist ground so it
   carries rather than sits quietly beside the list, and the award only: the ISO
   certification note moved under the list where it belongs. */
/* AMENDED 23 September 2026, Natalie's comment: white, not Ink, because the award
   badge is dark artwork and disappeared against the Ink ground. The shadow keeps it
   reading as a feature on the Mist band, and the rule turns Blue because yellow may
   never touch white. */
.aside--award { padding: 1.7rem 1.8rem; box-shadow: var(--shadow); }
.g-mist .aside--award { background: var(--white); }
.rule-b { height: 3px; width: 56px; background: var(--blue);
  border-radius: 2px; margin: 0 0 1.1rem; }
.aside--award h3 { font-size: 1.18rem; }
.aside--award .photo-box { aspect-ratio: 16 / 10; }
.aside--award .photo { margin-top: .2rem; }
.aside--award .photo-box { box-shadow: inset 0 0 0 1px var(--cloud); }

/* additional services sit beside the equipment list, so they need their own marker */
.scope .also li::before { content: "+"; color: var(--blue); font-size: 1.05rem; line-height: 1.1; }
.scope .also li { margin-bottom: .2rem; }
.scope .also strong { display: block; }

/* ---------- the value scale on the cost band ----------
   Added 23 September 2026. It carries no numbers on purpose: the point is that a
   collection is costed individually, so a scale that showed figures would promise
   a precision we do not have and the org rule forbids committing to anyway. */
.scale { margin-top: 2.4rem; }
.scale-scroll { overflow-x: auto; overflow-y: hidden; }
.scale-scroll > svg { min-width: 720px; width: 100%; height: auto; }

/* ---------- real photography ----------
   Added 23 September 2026 when the approved shots arrived. These are placed and
   cropped, not retouched: the crop is controlled per image with object-position so
   nobody's head is cut off, and the grade is a light CSS pass toward the Ink and
   Blue register the shot list asks for. Anything needing the background actually
   cleaned up has to go through a photo editor. */
.photo--real .photo-box { padding: 0; display: block; background: var(--cloud);
  position: relative; box-shadow: none; }
.photo--real .photo-box img { width: 100%; height: 100%; object-fit: cover;
  object-position: center; filter: saturate(.94) contrast(1.03); }
.g-ink .photo--real .photo-box { box-shadow: inset 0 0 0 1px rgba(221,227,234,.18); }
/* per-image crop, so heads stay in frame */
.photo--top    .photo-box img { object-position: center top; }
.photo--upper  .photo-box img { object-position: center 30%; }

/* the text plate sits over the photograph, on a scrim so it stays readable */
.photo--overlay.photo--real .photo-box::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(8,12,35,.78) 0%, rgba(8,12,35,.25) 45%, rgba(8,12,35,0) 70%); }
.photo--overlay.photo--real .photo-plate { position: absolute; left: 1.5rem; right: 1.5rem;
  bottom: 1.5rem; background: none; padding: 0; max-width: 52ch; }
.photo--overlay.photo--real .photo-plate p { color: rgba(255,255,255,.92); }

/* ---------- the paperwork breakdown, over the photograph ----------
   Moved out of the diagram on 23 September 2026 at Natalie's request. Built as HTML
   cards rather than SVG so the row reflows on a phone instead of scrolling sideways,
   and so the photograph behind it can be swapped without redrawing anything. */
/* AMENDED 23 September 2026: the photograph behind this band is gone, replaced by a
   gradient through the Ink and Blue register. The picture was almost entirely hidden
   behind four cards and a scrim, so it was paying for weight it never delivered. */
.paper-over { position: relative; overflow: hidden; border-radius: var(--card-r);
  margin-top: 2.4rem;
  background: linear-gradient(135deg, #080c23 0%, #12335a 52%, #1c4e80 100%); }
/* AMENDED 23 September 2026, Natalie's comment: solid yellow cards, and the scrim
   lightened so the racking behind actually reads. Text on the cards is Ink, which
   measures 13.00 against Signal Yellow. This is the same pairing the primary button
   uses, so a yellow fill with Ink on it is inside the system; yellow as TEXT still
   never touches white or Mist. */
/* a soft Sky bloom off the top right, so the gradient has somewhere to go */
.paper-over::after { content: ""; position: absolute; inset: 0;
  background: radial-gradient(120% 90% at 88% 4%, rgba(56,182,255,.24), rgba(56,182,255,0) 62%); }
.paper-over-in { position: relative; z-index: 1; padding: clamp(1.6rem, 4vw, 2.6rem); }
.paper-over-in .eyebrow { color: var(--white); margin-bottom: 1.2rem;
 }
.paper-cards { display: grid; gap: .9rem; }
@media (min-width: 560px) { .paper-cards { grid-template-columns: 1fr 1fr; } }
@media (min-width: 980px) { .paper-cards { grid-template-columns: repeat(4, 1fr); } }
/* AMENDED 23 September 2026: white, not yellow. Each card is now the opposite of the
   ground it sits on, white here against the gradient, Ink in the stages against the
   white section, which makes one rule out of two treatments. */
.paper-card { background: var(--white); border-radius: var(--card-r);
  padding: 1.1rem 1.2rem 1.2rem;
  box-shadow: 0 2px 4px rgba(8,12,35,.18), 0 16px 34px -18px rgba(8,12,35,.5); }
.pc-rule { display: block; width: 26px; height: 3px; border-radius: 2px;
  background: var(--blue); margin-bottom: .9rem; }
.paper-card h3 { color: var(--ink); font-size: .98rem; margin: 0 0 .5rem; }
.paper-card em { font-style: normal; font-size: .82rem; color: var(--slate);
  font-variant-numeric: tabular-nums; }

/* two columns optically centred on each other rather than both hung from the top.
   Added 23 September 2026: the stat cards are taller than the copy beside them, so
   top-aligning left the text sitting high against a long column. */
@media (min-width: 880px) { .split--center { align-items: center; } }

/* ---------- the stages read as a sequence ----------
   Added 23 September 2026 on Natalie's comment. A dotted rail runs down the number
   column so one stage visibly flows into the next, the way the leaflet does it, and
   each stage carries the icon drawn from that leaflet's artwork. The rail is hidden
   below 900px, where the layout stacks and a vertical line would point at nothing. */
.step-rail { align-self: stretch; position: relative; }
.step-rail::after { content: ""; position: absolute; left: 1.55rem; top: 3.7rem; bottom: -3.8rem;
  border-left: 2px dotted var(--cloud); }
.step:last-child .step-rail::after { display: none; }
@media (max-width: 899px) { .step-rail::after { display: none; } }

.step-head { display: flex; align-items: center; gap: .65rem; margin-bottom: .7rem; }
.step-head svg { width: 28px; height: 28px; flex: none; color: var(--blue); }
.step-head h3 { margin: 0; }

/* ---------- case study teasers on Ink ----------
   Added 23 September 2026, replacing the quote blocks on this page. Same three-up
   shape as the quotes they replace, so the band keeps its rhythm. */
.studies { display: grid; gap: 1.1rem; margin-top: 2rem; }
@media (min-width: 760px) { .studies { grid-template-columns: repeat(3, 1fr); } }
/* AMENDED 23 September 2026: the real case study photographs replace the icons. */
.study { display: flex; flex-direction: column; overflow: hidden;
  background: rgba(255,255,255,.07); border-radius: var(--card-r);
  color: rgba(221,227,234,.9); transition: background .16s; }
a.study:hover { background: rgba(255,255,255,.13); }
.study-shot { display: block; aspect-ratio: 16 / 9; background: var(--ink); overflow: hidden; }
.study-shot img { width: 100%; height: 100%; object-fit: cover;
  filter: saturate(.94) contrast(1.03); transition: transform .3s; }
a.study:hover .study-shot img { transform: scale(1.03); }
@media (prefers-reduced-motion: reduce) { a.study:hover .study-shot img { transform: none; } }
.study-body { display: flex; flex-direction: column; gap: .55rem; flex: 1;
  padding: 1.3rem 1.4rem 1.4rem; }
.study .cat { font-size: .75rem; letter-spacing: .15em; text-transform: uppercase;
  font-weight: 600; color: var(--sky); }
.study h3 { color: var(--white); font-size: 1.06rem; margin: 0; }
.study p { font-size: .94rem; margin: 0; }
.study .more { margin-top: auto; padding-top: 1rem; font-size: .88rem;
  font-weight: 500; color: var(--yellow); }   /* yellow on Ink only */

/* the award badge sits at the top of the card, to the right of the heading it belongs to */
.award-head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1.2rem; margin-bottom: .9rem; }
.award-head > div { min-width: 0; }
.award-head h3 { margin: 0; }
.award-badge { width: 108px; height: auto; flex: none; }
@media (max-width: 420px) { .award-head { flex-direction: column-reverse; align-items: flex-start; } }

/* ---------- stage graphics ----------
   Replaced the photographs in the stage column on 23 September 2026. Drawn flat from
   the leaflet's subjects, on a Mist tile so they sit as artwork rather than as a card. */
/* AMENDED 23 September 2026: the supplied artwork carries its own white background,
   so the Mist tile came off rather than framing each graphic in a visible box. The
   section ground is white, so they now sit directly on it. */
.stage-art { display: grid; place-items: center; }
/* AMENDED 23 September 2026. Each graphic is now trimmed to its own content, scaled
   so the longest side matches, and centred on an identical square canvas, so all four
   carry the same visual weight and line up down the column whatever shape they are. */
.stage-art img { height: 140px; width: auto; max-width: 100%; }
.stage-art svg { width: 100%; height: auto; max-width: 160px; }

/* ---------- the document cards open ----------
   Merged 23 September 2026: chain of custody and what you receive were the same four
   documents told twice, so the explanation moved inside the cards as a disclosure. */
/* AMENDED 23 September 2026: the four cards were coming out different heights. Two
   causes. align-items was set to start when they became expandable, so each card sized
   itself; and two of the four names wrap to a second line while the others do not.
   Stretch makes every card in the row match, and reserving two lines for the name
   means the closed state is identical whatever the name is. */
.paper-cards { align-items: stretch; }
.paper-card { display: flex; flex-direction: column; }
.paper-card h3 { min-height: 2.6em; }
details.paper-card summary { list-style: none; cursor: pointer; display: block;
  position: relative; padding-right: 1.7rem; }
details.paper-card summary::-webkit-details-marker { display: none; }
details.paper-card summary::after { content: "+"; position: absolute; right: 0; top: -.15rem;
  color: var(--blue); font-size: 1.3rem; line-height: 1; font-weight: 400; }
details.paper-card[open] summary::after { content: "\2212"; }
details.paper-card summary:focus-visible { outline: 2px solid var(--sky); outline-offset: 4px; }
.paper-card > p { margin: .95rem 0 0; font-size: .88rem; line-height: 1.55; color: var(--graphite); }

/* ---------- a photograph that is not cropped, in a shape that is not a rectangle ----------
   Added 23 September 2026. The fixed 4:3 box was trimming the frame to fit. This lets
   the picture keep its own proportions and take the space it needs, and softens two
   opposite corners so it reads as composed rather than dropped in. */
.photo--free .photo-box { aspect-ratio: auto; }
.photo--free .photo-box img { width: 100%; height: auto; object-fit: contain; }
.photo--shaped .photo-box { border-radius: 18px 88px 18px 88px; }
@media (max-width: 620px) { .photo--shaped .photo-box { border-radius: 16px 56px 16px 56px; } }
/* Added 28 September 2026, on Natalie's instruction: no framing at all on the
   Home hero photo — not even the standard card radius .photo-box carries by
   default, and not the inset ring .photo--real adds on an Ink ground. Plain
   rectangular photo. The .g-ink-prefixed selector matches (rather than loses
   to) .g-ink .photo--real .photo-box's specificity, which was otherwise still
   winning and leaving the ring in place. */
.photo--plain .photo-box, .g-ink .photo--plain .photo-box { border-radius: 0; box-shadow: none; }

/* ---------- graphic and its document, in one outlined box ----------
   Added 23 September 2026. The graphic and the "you receive" card were two objects
   saying one thing. Border, not shadow: the design system declares elevation once,
   so an outlined card does not also get a shadow. */
.stage-box { border: 2px solid var(--blue); border-radius: var(--card-r);
  background: var(--white); overflow: hidden; }
.stage-box .stage-art { padding: 1.3rem 1.1rem .9rem; }
/* AMENDED 23 September 2026: the lower half fills with Blue. The outline only needs a
   light fill where it runs alongside the graphic; below the divider the fill and the
   outline are the same colour, which reads as a deliberate footer. Yellow measures
   5.77 against Terraguard Blue, so the label is legal as well as loud. */
.stage-box .out { background: var(--blue); box-shadow: none; border-radius: 0;
  padding: 1.05rem 1.25rem 1.2rem; }
.stage-box .out h4 { color: var(--yellow); }
.stage-box .out p { color: var(--white); }

/* Added from the Impact page artifact, 23 September 2026, folding it into the site build */
.card-icon { width: 2.6rem; height: 2.6rem; border-radius: 50%; background: var(--blue);
  display: grid; place-items: center; margin-bottom: .2rem; }
.card-icon svg { width: 1.3rem; height: 1.3rem; color: var(--white); }
.quotes .photo-box { aspect-ratio: 4 / 3; margin-bottom: 1.2rem; }

/* ---------- wide donation testimonials (impact.html), added 24 September 2026 ---------- */
/* The shared .quotes grid is repeat(3,1fr); with only two donation quotes that
   left them squeezed into two of three columns, off-centre, with the photo
   stacked full-width above the text making each card tall. This variant
   centres the pair, widens each to half the container, and moves the photo
   beside the text instead of above it. */
.quotes--wide { grid-template-columns: 1fr; gap: 1.4rem; max-width: 920px; margin: 0 auto; }
.quotes--wide blockquote { display: grid; grid-template-columns: 200px 1fr; gap: 1.6rem; align-items: center; text-align: left; }
.quotes--wide .photo { margin: 0; }
.quotes--wide .photo-box { aspect-ratio: 1 / 1; margin-bottom: 0; }
@media (max-width: 700px) {
  .quotes--wide blockquote { grid-template-columns: 1fr; }
  .quotes--wide .photo-box { aspect-ratio: 4 / 3; max-width: 260px; margin: 0 auto; }
}
.quotes cite span { display: block; color: rgba(221,227,234,.66); font-weight: 400; margin-top: .15rem; }
.split--center { align-items: center; }
.g-mist .panel { background: var(--white); }
video { display: block; max-width: 100%; }
.diagram-scroll { overflow-x: auto; overflow-y: hidden; }
.diagram-scroll > svg { min-width: 640px; width: 100%; height: auto; display: block; margin: 0 auto; }
.big-stat b { display: block; font-family: var(--title); font-weight: 400; line-height: 1;
  font-size: clamp(3.2rem, 1.5rem + 8vw, 6.4rem); color: var(--ink);
  font-variant-numeric: tabular-nums; }
.stage-box .out em { color: rgba(255,255,255,.76); }

/* ---------- CO2 teaser mockup card, added 1 October 2026 ----------
   Decorative only (aria-hidden in the markup). Echoes the real calculator's
   own look (Ink panel, Sky/Yellow accents, a category grid) without
   reproducing it pixel for pixel or stating a specific result. */
.co2-mock { background: var(--white); border-radius: var(--card-r); box-shadow: var(--shadow);
  padding: 1.3rem; max-width: 320px; width: 100%; margin-inline: auto; }
.co2-mock-head { font-size: .72rem; letter-spacing: .12em; text-transform: uppercase;
  font-weight: 600; color: var(--slate); margin: 0 0 .9rem; }
.co2-mock-stat { background: var(--ink); border-radius: calc(var(--card-r) - 6px);
  padding: 1rem 1.1rem; margin-bottom: 1rem; }
.co2-mock-eyebrow { display: block; font-size: .66rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--sky); font-weight: 600; margin-bottom: .35rem; }
.co2-mock-value { font-family: var(--title); font-size: 1.9rem; color: var(--yellow); font-weight: 400; }
.co2-mock-value small { font-family: var(--body); font-size: .82rem; font-weight: 500;
  color: rgba(221,227,234,.75); margin-left: .35rem; }
.co2-mock-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; margin-bottom: 1rem; }
.co2-mock-grid span { display: block; background: var(--blue); color: var(--white); border-radius: 10px;
  padding: .65rem .3rem; text-align: center; font-size: .68rem; font-weight: 600; letter-spacing: .01em; }
.co2-mock-btn { display: block; text-align: center; background: var(--yellow); color: var(--ink);
  border-radius: var(--btn-r); padding: .65rem; font-size: .82rem; font-weight: 600; }

/* ---------- roll-in text reveal, added 24 September 2026 ---------- */
/* Fails safe like .reveal/.t-carousel: .roll-char alone is plain, visible
   text. The animation only exists under .roll-active, added by the script
   in build.js's shell() once the element scrolls into view, and
   prefers-reduced-motion's blanket animation:none!important (top of this
   file) switches it off the same way it does everything else. */
.roll-text { display: inline-block; perspective: 480px; }
.roll-char { display: inline-block; transform-style: preserve-3d; }
.roll-active .roll-char {
  animation: roll-in .55s cubic-bezier(.2,.8,.2,1) both;
  animation-delay: var(--d, 0s);
}
@keyframes roll-in {
  from { transform: rotateX(85deg); opacity: 0; }
  to { transform: rotateX(0deg); opacity: 1; }
}
