/* ==========================================================================
   SITE CONSTRUCT WA — landing page
   --------------------------------------------------------------------------
   Colour contract (verified with WCAG matrix, do not improvise pairings):
     text  #f3efe6 on bg #121417 ......... 16.08:1  text-safe
     text  #f3efe6 on surface #1b1e24 .... 14.55:1  text-safe
     ochre #f43e04 on bg #121417 .........  4.87:1  text-safe
     ochre #f43e04 on surface #1b1e24 ....  4.40:1  UI-SAFE ONLY — not body text
     soft  #ff6a33 on surface #1b1e24 ....  5.85:1  text-safe  <-- use on cards
     ink   #121417 on ochre #f43e04 ......  4.87:1  text-safe  <-- button labels
   RULE: orange TEXT on a graphite surface must be --ochre-soft, never --ochre.

   Photography: Site Construct's own project archive (Benchmark, Atlas Pearls,
   Emergency Vet Wangara, Dental Circle, Spearwood Medical, VEOLIA, NBN, JDL).
   ========================================================================== */

@layer tokens, base, layout, motion, components, utils;

/* ========================================================================== */
@layer tokens {

  /* Typed custom properties — these are what make gradients/angles animatable */
  @property --dial      { syntax: "<percentage>"; inherits: true;  initial-value: 0%;   }
  @property --sweep     { syntax: "<percentage>"; inherits: false; initial-value: 0%;   }
  @property --glow      { syntax: "<percentage>"; inherits: false; initial-value: 0%;   }

  :root {
    /* Brand — exact values, sampled from the logo. Not derived, not "improved". */
    --ink:        #121417;
    --graphite:   #1b1e24;
    --graphite-2: #23272f;
    --bone:       #f3efe6;
    --bone-dim:   #c7c3ba;
    --muted:      #8b8f96;
    --ochre:      #f43e04;
    --ochre-soft: #ff6a33;

    /* Derived tints — color-mix keeps them locked to the brand hue */
    --line:        color-mix(in oklab, var(--bone) 12%, transparent);
    --line-strong: color-mix(in oklab, var(--bone) 26%, transparent);
    --ochre-wash:  color-mix(in oklab, var(--ochre) 14%, transparent);
    --ochre-edge:  color-mix(in oklab, var(--ochre) 42%, transparent);
    --surface-up:  color-mix(in oklab, var(--bone) 4%, var(--graphite));
    --scrim:       color-mix(in srgb, var(--ink) 82%, transparent);

    /* Sector accents — a hue per sector, held in oklch so lightness stays even */
    --sec-industrial: oklch(64% 0.14  58);
    --sec-retail:     oklch(64% 0.13  32);
    --sec-office:     oklch(66% 0.09 232);
    --sec-defence:    oklch(62% 0.07 150);
    --sec-medical:    oklch(68% 0.10 196);
    --sec-care:       oklch(66% 0.10 300);
    --sec-food:       oklch(70% 0.12  88);
    --sec-land:       oklch(63% 0.15  42);
    --sec-mixed:      oklch(66% 0.12 340);

    /* Type — industrial grotesque system. Archivo carries display AND body,
       with weight (700 vs 300) doing the contrast; Plex Mono holds the
       technical register. Replaces the earlier Fraunces serif. */
    --font-display:   "Archivo", "Helvetica Neue", Arial, sans-serif;
    --font-interface: "Archivo", system-ui, -apple-system, sans-serif;
    --font-technical: "IBM Plex Mono", ui-monospace, Consolas, monospace;
    --font-eyebrow:   "Archivo Expanded", "Archivo", var(--font-interface);

    /* Fluid type scale */
    --step--1: clamp(0.80rem, 0.77rem + 0.15vw, 0.88rem);
    --step-0:  clamp(1.00rem, 0.96rem + 0.20vw, 1.12rem);
    --step-1:  clamp(1.25rem, 1.15rem + 0.50vw, 1.55rem);
    --step-2:  clamp(1.60rem, 1.35rem + 1.20vw, 2.30rem);
    --step-3:  clamp(2.05rem, 1.55rem + 2.40vw, 3.40rem);
    --step-4:  clamp(2.60rem, 1.60rem + 4.60vw, 5.40rem);

    /* Spacing scale — pick from this, never improvise a padding */
    --space-1: 0.25rem;  --space-2: 0.5rem;   --space-3: 0.75rem;
    --space-4: 1rem;     --space-6: 1.5rem;   --space-8: 2rem;
    --space-12: 3rem;    --space-16: 4rem;    --space-24: 6rem;
    --space-32: 8rem;    --space-48: 12rem;

    --measure: 62ch;
    --max: 1280px;
    --radius: 2px;          /* commercial construction: square, not soft */

    /* Motion */
    --ease-out:    cubic-bezier(.22,.61,.36,1);
    --d-press: 120ms;
    --d-hover: 160ms;
    --d-panel: 240ms;

    color-scheme: dark;
  }
}

/* ========================================================================== */
@layer base {

  *, *::before, *::after { box-sizing: border-box; }

  html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    /* keep anchored sections clear of the fixed masthead */
    scroll-padding-top: 5.5rem;
  }
  @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

  body {
    margin: 0;
    background: var(--ink);
    color: var(--bone);
    font-family: var(--font-interface);
    font-size: var(--step-0);
    font-weight: 300;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overflow-x: hidden;
  }

  h1, h2, h3 {
    font-family: var(--font-display);
    font-weight: 700;
    line-height: 1.0;
    letter-spacing: -0.035em;
    margin: 0;
    text-wrap: balance;
  }
  h1 { font-size: var(--step-4); }
  h2 { font-size: var(--step-3); }
  h3 { font-size: var(--step-1); letter-spacing: -0.01em; }

  p { margin: 0; text-wrap: pretty; max-width: var(--measure); }

  a { color: inherit; text-decoration-color: var(--ochre-edge); text-underline-offset: 0.25em; }

  img, svg { display: block; max-width: 100%; }
  img { height: auto; }

  ul { margin: 0; padding: 0; list-style: none; }

  ::selection { background: var(--ochre); color: var(--ink); }

  :focus-visible {
    outline: 2px solid var(--ochre-soft);
    outline-offset: 3px;
    border-radius: var(--radius);
  }

  /* Screen-reader-only, still focusable */
  .sr {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }
  .skip {
    position: absolute; top: var(--space-2); left: var(--space-2);
    z-index: 100; padding: var(--space-3) var(--space-4);
    background: var(--ochre); color: var(--ink);
    font-family: var(--font-technical); font-size: var(--step--1);
    transform: translateY(-200%);
  }
  .skip:focus-visible { transform: none; }
}

/* ========================================================================== */
@layer layout {

  .shell {
    width: min(100% - 2.5rem, var(--max));
    margin-inline: auto;
  }

  /* Section rhythm is weighted by role — pivotal sections get more air */
  .section        { padding-block: var(--space-24); }
  .section--major { padding-block: var(--space-32); }
  .section--tight { padding-block: var(--space-16); }

  .rule {
    height: 1px; border: 0; margin: 0;
    background: var(--line);
  }

  .eyebrow {
    font-family: var(--font-eyebrow);
    font-weight: 700;
    font-size: var(--step--1);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ochre-soft);
    margin: 0 0 var(--space-4);
    display: flex; align-items: center; gap: var(--space-3);

    &::before {
      content: ""; inline-size: var(--space-8); block-size: 2px;
      background: var(--ochre); flex: none;
    }
  }

  .lede {
    font-size: var(--step-1);
    color: var(--bone-dim);
    font-weight: 300;
    margin-top: var(--space-6);
  }

  .section-head { margin-bottom: var(--space-16); }
}

/* ==========================================================================
   MOTION — scroll-driven, running on the compositor, no JavaScript.
   Everything degrades to the finished state when unsupported or when the
   visitor asks for reduced motion. Nothing is hidden by default.
   ========================================================================== */
@layer motion {

  @keyframes reveal-in   { from { opacity: 0; transform: translateY(18px); } }
  @keyframes reveal-slide{ from { opacity: 0; transform: translateX(-24px); } }
  @keyframes wipe-in     { from { clip-path: inset(0 100% 0 0); } }
  /* grow-x / grow-y drive LINE DRAWS (the scroll-progress bar and the
     lifecycle spine), not element entrances. A rule drawing itself from
     zero length is the intended effect, and transform keeps it on the
     compositor. Deliberate override of the usual zero-scale rule. */
  @keyframes grow-x      { from { transform: scaleX(0); } }
  @keyframes grow-y      { from { transform: scaleY(0); } }
  @keyframes dial-round  { to   { --dial: 100%; } }
  @keyframes dial-ping   { 0% { transform: scale(.62); opacity: 0; }
                           35% { opacity: .85; }
                          100% { transform: scale(1.55); opacity: 0; } }
  @keyframes sweep-across{ to   { --sweep: 100%; } }
  @keyframes lift-glow   { to   { --glow: 100%; } }
  @keyframes hail-in     { to   { transform: none; } }

  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {

      /* --- reading-order reveals ------------------------------------- */
      .reveal {
        animation: reveal-in linear both;
        animation-timeline: view();
        animation-range: entry 14% cover 52%;
      }
      .reveal-x {
        animation: reveal-slide linear both;
        animation-timeline: view();
        animation-range: entry 14% cover 54%;
      }
      /* stagger children off a single timeline, no JS delays needed */
      .stagger > * {
        animation: reveal-in linear both;
        animation-timeline: view();
        animation-range: entry 10% cover 46%;
      }
      .stagger > :nth-child(2) { animation-range: entry 14% cover 50%; }
      .stagger > :nth-child(3) { animation-range: entry 18% cover 54%; }
      .stagger > :nth-child(4) { animation-range: entry 22% cover 58%; }
      .stagger > :nth-child(5) { animation-range: entry 26% cover 62%; }
      .stagger > :nth-child(6) { animation-range: entry 30% cover 66%; }

      /* --- rules that draw themselves -------------------------------- */
      .rule--draw {
        transform-origin: left;
        animation: grow-x linear both;
        animation-timeline: view();
        animation-range: entry 0% cover 24%;
      }

      /* --- masthead scroll progress ---------------------------------- */
      .progress {
        transform-origin: left;
        animation: grow-x linear both;
        animation-timeline: scroll(root block);
      }

      /* --- lifecycle spine draws as the pinned scene plays ------------ */
      .spine__fill {
        transform-origin: top;
        animation: grow-y linear both;
        animation-timeline: view(block);
        animation-range: contain 0% contain 100%;
      }

      /* --- stage dials fill on entry (animating a typed custom prop) -- */
      .stage__dial {
        animation: dial-round linear both;
        animation-timeline: view();
        animation-range: entry 20% cover 40%;
      }
      /* one ring pings outward as the dial completes — transform+opacity
         only, so it stays on the compositor */
      .stage__ping {
        animation: dial-ping linear both;
        animation-timeline: view();
        animation-range: entry 34% cover 52%;
      }

      /* --- image wipe reveals ---------------------------------------- */
      .wipe {
        animation: wipe-in linear both;
        animation-timeline: view();
        animation-range: entry 10% cover 40%;
      }

    }
  }

  /* Honest fallback: no scroll-timeline support, or reduced motion, means
     every element above is simply in its finished state — nothing is lost. */
}

/* ========================================================================== */
@layer components {

  /* --- masthead ---------------------------------------------------------- */
  .masthead {
    position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 50;
    background: color-mix(in srgb, var(--ink) 72%, transparent);
    border-block-end: 1px solid var(--line);
    backdrop-filter: blur(14px) saturate(1.4);
    -webkit-backdrop-filter: blur(14px) saturate(1.4);
  }
  .masthead__bar {
    display: flex; align-items: center; gap: var(--space-8);
    padding-block: var(--space-4);
  }
  .masthead__logo { flex: none; }
  .masthead__logo img { inline-size: clamp(140px, 15vw, 190px); }

  .navlinks {
    margin-inline-start: auto;
    display: flex; gap: var(--space-6); align-items: center;
    font-size: var(--step--1); letter-spacing: 0.02em;
  }
  .navlinks a {
    text-decoration: none; color: var(--bone-dim);
    transition: color var(--d-hover) var(--ease-out);
    &:hover { color: var(--bone); }
  }
  @media (max-width: 860px) { .navlinks { display: none; } }

  /* Compact nav — a native <details> disclosure, so it works with no JS
     and is keyboard-operable out of the box. */
  .navmenu { display: none; margin-inline-start: auto; }
  @media (max-width: 860px) { .navmenu { display: block; } }

  .navmenu summary {
    list-style: none; cursor: pointer;
    font-family: var(--font-technical); font-size: var(--step--1);
    letter-spacing: 0.08em; text-transform: uppercase; color: var(--bone);
    border: 1px solid var(--line-strong);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    transition: border-color var(--d-hover) var(--ease-out);
  }
  .navmenu summary::-webkit-details-marker { display: none; }
  .navmenu summary::after { content: " +"; color: var(--ochre-soft); }
  .navmenu[open] summary { border-color: var(--ochre-edge); }
  .navmenu[open] summary::after { content: " ×"; }

  .navmenu__panel {
    position: absolute; inset-inline: 0; inset-block-start: 100%;
    background: var(--ink);
    border-block-end: 1px solid var(--line);
    display: grid; gap: var(--space-1);
    padding: var(--space-4) 1.25rem var(--space-6);
  }
  .navmenu__panel a {
    text-decoration: none; color: var(--bone-dim);
    padding: var(--space-3) 0;
    border-block-end: 1px solid var(--line);
    font-size: var(--step-0);
  }
  .navmenu__panel a:hover { color: var(--bone); }

  .progress {
    block-size: 2px; inline-size: 100%;
    background: linear-gradient(90deg, var(--ochre), var(--ochre-soft));
  }

  /* --- buttons ----------------------------------------------------------- */
  .btn {
    display: inline-flex; align-items: center; gap: var(--space-3);
    padding: var(--space-4) var(--space-8);
    font-family: var(--font-technical);
    font-size: var(--step--1); letter-spacing: 0.06em; text-transform: uppercase;
    text-decoration: none; border-radius: var(--radius);
    border: 1px solid transparent; cursor: pointer;
    transition: background var(--d-hover) var(--ease-out),
                border-color var(--d-hover) var(--ease-out),
                color var(--d-hover) var(--ease-out);
  }
  /* ink on ochre = 4.87:1, a legal text pairing */
  .btn--primary {
    background: var(--ochre); color: var(--ink); font-weight: 500;
    &:hover { background: var(--ochre-soft); }
    &:active { transform: translateY(1px); transition-duration: var(--d-press); }
  }
  .btn--ghost {
    border-color: var(--line-strong); color: var(--bone);
    &:hover { border-color: var(--bone); background: color-mix(in oklab, var(--bone) 6%, transparent); }
  }

  /* --- hero -------------------------------------------------------------- */
  /* Full-bleed hero: photograph behind, headline over the top. A gradient
     scrim guarantees the type sits on near-solid ink (16:1) rather than
     depending on what happens to be in the frame behind it. */
  .hero {
    position: relative;
    min-block-size: 100svh;
    display: grid; align-items: end;
    overflow: clip;
    isolation: isolate;
  }
  .hero__media {
    position: absolute; inset: 0; z-index: -2;
    overflow: clip;
  }
  .hero__img {
    inline-size: 100%; block-size: 100%;
    object-fit: cover;
    /* holds the lit doorway and figures in frame as the box narrows */
    object-position: 58% 58%;
  }
  .hero__scrim {
    position: absolute; inset: 0; z-index: -1;
    background:
      linear-gradient(100deg,
        var(--ink) 0%,
        var(--scrim) 36%,
        color-mix(in srgb, var(--ink) 30%, transparent) 64%,
        color-mix(in srgb, var(--ink) 58%, transparent) 100%),
      linear-gradient(to top, var(--ink) 2%, transparent 46%);
  }
  .hero__inner { padding-block: var(--space-24) var(--space-16); }
  .hero__title {
    max-inline-size: 17ch;
    & em {
      font-style: normal;
      color: var(--ochre);          /* 4.87:1 on ink — legal */
      display: block;
    }
  }
  .hero__lede { margin-top: var(--space-6); max-inline-size: 46ch; }
  .hero__actions {
    margin-top: var(--space-12);
    display: flex; flex-wrap: wrap; gap: var(--space-4);
  }

  /* credentials band — lifted out of the hero so the hero always fits the
     viewport and the aerial is not cropped by an over-tall box */
  .statband { border-block-end: 1px solid var(--line); }
  .hero__stats {
    display: grid; gap: var(--space-8);
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  }
  .stat__n {
    font-family: var(--font-display);
    font-weight: 700; letter-spacing: -0.03em;
    font-size: var(--step-2); line-height: 1;
    color: var(--bone);
  }
  .stat__l {
    font-family: var(--font-technical);
    font-size: var(--step--1); color: var(--muted);
    letter-spacing: 0.04em; margin-top: var(--space-2);
  }

  /* --- the gap / problem beat -------------------------------------------- */
  .gap-diagram {
    margin-top: var(--space-12);
    display: grid; gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
    counter-reset: link;
  }
  .gap-node {
    border: 1px solid var(--line);
    border-block-start: 2px solid var(--line-strong);
    padding: var(--space-6) var(--space-4);
    background: var(--graphite);
    font-family: var(--font-technical);
    font-size: var(--step--1);
    color: var(--bone-dim);
    position: relative;
  }
  /* :has() — the node that owns the break styles itself and its neighbours */
  .gap-node:has(.gap-node__break) {
    border-block-start-color: var(--ochre);
    color: var(--ochre-soft);           /* 5.85:1 on graphite — legal */
    background: linear-gradient(var(--ochre-wash), transparent), var(--graphite);
  }
  /* marker drawn in CSS, not typed as a glyph — no font-coverage risk */
  .gap-node__break {
    display: flex; align-items: center; gap: var(--space-2);
    margin-top: var(--space-2);
    font-size: var(--step--1); color: var(--ochre-soft);

    &::before {
      content: ""; inline-size: 7px; block-size: 7px; flex: none;
      background: var(--ochre);
      transform: rotate(45deg);
    }
  }

  /* --- split band (photo + text) ----------------------------------------- */
  .split {
    display: grid; gap: var(--space-16);
    grid-template-columns: 1fr;
    align-items: center;
  }
  @media (min-width: 900px) {
    .split { grid-template-columns: 1.05fr 1fr; gap: var(--space-24); }
    .split--flip > :first-child { order: 2; }
  }
  /* full frame, no crop — the box takes the photograph's own aspect */
  .split__media {
    position: relative;
    border: 1px solid var(--line);
  }
  .split__media img {
    inline-size: 100%; block-size: auto;
  }

  /* --- lifecycle: the pinned scene --------------------------------------- */
  .lifecycle { position: relative; }
  .lifecycle__grid {
    display: grid; gap: var(--space-12);
    grid-template-columns: 1fr;
  }
  @media (min-width: 1000px) {
    .lifecycle__grid { grid-template-columns: 30ch 1fr; gap: var(--space-24); }
    .lifecycle__aside {
      position: sticky; inset-block-start: 8rem;
      align-self: start;
      block-size: fit-content;
    }
  }

  .stages {
    position: relative;
    counter-reset: stage;
    display: grid; gap: var(--space-4);
  }
  /* the spine the stages hang off */
  .spine {
    position: absolute; inset-block: 0; inset-inline-start: 27px;
    inline-size: 2px; background: var(--line);
  }
  .spine__fill {
    position: absolute; inset: 0;
    background: linear-gradient(var(--ochre), var(--ochre-soft));
  }

  .stage {
    counter-increment: stage;
    display: grid;
    grid-template-columns: 56px 1fr;
    gap: var(--space-6);
    align-items: start;
    padding-block: var(--space-6);
  }
  .stage__dial {
    inline-size: 56px; block-size: 56px; flex: none;
    border-radius: 50%;
    display: grid; place-items: center;
    position: relative;
    background:
      conic-gradient(var(--ochre) var(--dial), color-mix(in oklab, var(--bone) 10%, transparent) 0);
    transition: transform var(--d-panel) var(--ease-out);
  }
  /* expanding ring, sits outside the dial and never affects layout */
  .stage__ping {
    position: absolute; inset: -7px;
    border-radius: 50%;
    border: 1px solid var(--ochre);
    opacity: 0;
    pointer-events: none;
  }
  .stage__dial::before {
    content: ""; position: absolute; inset: 3px;
    border-radius: 50%; background: var(--ink);
  }
  .stage__dial::after {
    content: counter(stage, decimal-leading-zero);
    position: relative;
    font-family: var(--font-technical); font-size: var(--step--1);
    font-weight: 500;
    /* muted until the ring fills, then full accent — same driving value */
    color: color-mix(in oklab, var(--ochre-soft) var(--dial), var(--muted));
  }
  /* pointer response — gated to real pointers so touch never sticks */
  @media (hover: hover) and (pointer: fine) {
    .stage:hover .stage__dial { box-shadow: 0 0 0 5px var(--ochre-wash); }
    .stage:hover .stage__name { color: var(--ochre-soft); }
    @media (prefers-reduced-motion: no-preference) {
      .stage:hover .stage__dial { transform: scale(1.09); }
    }
  }
  .stage__name {
    transition: color var(--d-hover) var(--ease-out);
  }
  .stage__name {
    font-family: var(--font-display);
    font-size: var(--step-2);
    line-height: 1;
  }
  .stage__body { color: var(--bone-dim); margin-top: var(--space-3); }
  .stage__tag {
    font-family: var(--font-technical); font-size: var(--step--1);
    color: var(--muted); letter-spacing: 0.06em; text-transform: uppercase;
    margin-top: var(--space-3); display: block;
  }

  /* --- projects ---------------------------------------------------------- */
  .projects {
    display: grid; gap: var(--space-8);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 330px), 1fr));
  }
  .project {
    container-type: inline-size;
    container-name: project;
    position: relative;
    border: 1px solid var(--line);
    background: var(--graphite);
    overflow: clip;
    /* the card itself is the 3D stage — a tilt-panel, fittingly */
    perspective: 900px;
    transition: border-color var(--d-panel) var(--ease-out);
    &:hover { border-color: var(--ochre-edge); }
  }
  .project__media {
    aspect-ratio: 3 / 2; overflow: clip;
    background: var(--ink);
    transform-style: preserve-3d;
  }
  .project__media img {
    inline-size: 100%; block-size: 100%; object-fit: cover;
    transition: transform var(--d-panel) var(--ease-out),
                filter var(--d-panel) var(--ease-out);
    filter: saturate(0.9) contrast(1.02);
  }
  /* hover motion gated to real pointers, per the motion rules */
  @media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
    .project:hover .project__media img {
      transform: scale(1.04) rotateX(1.2deg);
      filter: saturate(1) contrast(1.05);
    }
  }
  .project__body { padding: var(--space-6); }
  .project__name {
    font-family: var(--font-display); font-size: var(--step-1);
    line-height: 1.1;
  }
  .project__meta {
    margin-top: var(--space-3);
    font-family: var(--font-technical); font-size: var(--step--1);
    color: var(--muted);
    display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4);
  }
  .project__sector {
    display: inline-flex; align-items: center; gap: var(--space-2);
    color: var(--bone-dim);
    &::before {
      content: ""; inline-size: 8px; block-size: 8px;
      background: var(--sector, var(--ochre));
      flex: none;
    }
  }
  .project__flag {
    font-family: var(--font-technical); font-size: var(--step--1);
    letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--ochre-soft);              /* 5.85:1 on graphite */
    border: 1px solid var(--ochre-edge);
    padding: 0 var(--space-2);
  }

  /* container query — the card responds to its own width, not the viewport */
  @container project (min-width: 420px) {
    .project__body { padding: var(--space-8); }
    .project__name { font-size: var(--step-2); }
  }

  /* --- capability: illustrated formats ----------------------------------- */
  /* Full frames, never cropped and never upscaled past their native width.
     subgrid aligns the captions even though the frames differ slightly. */
  .capstrip {
    display: grid; gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
    margin-block-end: var(--space-4);
  }
  @supports (grid-template-rows: subgrid) {
    .capstrip { grid-template-rows: repeat(2, auto); }
    .capshot { grid-row: span 2; grid-template-rows: subgrid; display: grid; }
  }
  .capshot {
    margin: 0;
    border: 1px solid var(--line);
    background: var(--graphite);
    align-content: start;
    transition: border-color var(--d-panel) var(--ease-out);
    &:hover { border-color: var(--ochre-edge); }
  }
  .capshot img { inline-size: 100%; block-size: auto; }
  .capshot figcaption {
    padding: var(--space-4) var(--space-6);
    /* same face and size as the capability descriptions (.cap__d), owner 19/09/2026 */
    font-family: var(--font-interface);
    font-size: var(--step--1); line-height: 1.55;
    color: var(--muted);
  }
  .capstrip__note {
    font-family: var(--font-interface); font-size: var(--step--1); line-height: 1.55;
    color: var(--muted);
    margin-block-end: var(--space-12);
  }

  /* The sectors used to be a loose grey sentence between the photographs and the capability
     grid and read as an orphan (owner, 20/09/2026). It is now the head of that grid: same
     1px rule, sharing its top edge, with the sectors as tags rather than a run-on list. */
  .sectors {
    border: 1px solid var(--line); border-block-end: 0;
    background: var(--graphite);
    padding: var(--space-6);
    display: grid; gap: var(--space-4);
  }
  .sectors__label {
    font-family: var(--font-eyebrow); font-weight: 700;
    font-size: var(--step--1); letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--ochre-soft);
    margin: 0; display: flex; align-items: center; gap: var(--space-3);
    &::before { content: ""; inline-size: var(--space-8); block-size: 2px; background: var(--ochre); flex: none; }
  }
  .sectors__list {
    display: flex; flex-wrap: wrap; gap: var(--space-2);
    font-family: var(--font-technical); font-size: var(--step--1); line-height: 1;
    & li {
      padding: var(--space-2) var(--space-3);
      border: 1px solid var(--line);
      color: var(--bone-dim);
      white-space: nowrap;
    }
  }

  /* --- capability grid (subgrid keeps rows aligned) ---------------------- */
  .capability {
    display: grid; gap: 1px;
    background: var(--line);
    border: 1px solid var(--line);
    /* Nine tiles, so the column count is pinned rather than auto-fit: three across fills every
       row exactly, and at two across the last tile takes the spare cell. An auto-fit grid left
       a hole in the last row at some widths (owner, 20/09/2026). */
    grid-template-columns: 1fr;
  }
  @media (min-width: 620px)  { .capability { grid-template-columns: repeat(2, 1fr); }
                               .cap:last-child { grid-column: span 2; } }
  @media (min-width: 1000px) { .capability { grid-template-columns: repeat(3, 1fr); }
                               .cap:last-child { grid-column: auto; } }
  .cap {
    background: var(--ink);
    padding: var(--space-8) var(--space-6);
    display: grid; gap: var(--space-3);
    align-content: start;
    position: relative;
    transition: background var(--d-panel) var(--ease-out);
    &:hover { background: var(--graphite); }
  }
  @supports (grid-template-rows: subgrid) {
    .capability { grid-template-rows: repeat(3, auto); }
    .cap { grid-row: span 3; grid-template-rows: subgrid; }
  }
  .cap__n {
    font-family: var(--font-technical); font-size: var(--step--1);
    color: var(--ochre-soft); letter-spacing: 0.08em;
  }
  .cap__t { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.025em; font-size: var(--step-1); }
  .cap__d { color: var(--muted); font-size: var(--step--1); line-height: 1.55; }

  /* --- partners statement (solution band) -------------------------------- */
  .partners {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--step-2);
    line-height: 1.1;
    letter-spacing: -0.03em;
    color: var(--bone);
    & em { font-style: normal; color: var(--ochre); }   /* 4.87:1 on ink */
  }

  /* --- land / investment ledger ------------------------------------------ */
  .ledger {
    display: grid; gap: 1px; background: var(--line);
    border-block: 1px solid var(--line);
  }
  .ledger__row {
    background: var(--ink);
    display: grid; gap: var(--space-4);
    grid-template-columns: 1fr;
    padding: var(--space-8) 0;
  }
  @media (min-width: 820px) {
    .ledger__row { grid-template-columns: 12ch 1fr 1fr; gap: var(--space-12); align-items: baseline; }
  }
  .ledger__k {
    font-family: var(--font-technical); font-size: var(--step--1);
    color: var(--ochre-soft); letter-spacing: 0.08em; text-transform: uppercase;
  }
  .ledger__t { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.025em; font-size: var(--step-1); }
  .ledger__d { color: var(--muted); font-size: var(--step--1); line-height: 1.6; }

  /* --- contact ----------------------------------------------------------- */
  .contact {
    border: 1px solid var(--line);
    background:
      radial-gradient(120% 140% at 8% 0%, var(--ochre-wash), transparent 58%),
      var(--graphite);
    padding: clamp(var(--space-12), 6vw, var(--space-32));
  }
  .contact__grid {
    display: grid; gap: var(--space-12);
    grid-template-columns: 1fr;
  }
  @media (min-width: 900px) { .contact__grid { grid-template-columns: 1.2fr 1fr; gap: var(--space-24); } }
  .contact__list { display: grid; gap: var(--space-6); }
  .contact__item {
    display: grid; gap: var(--space-1);
    padding-block-end: var(--space-6);
    border-block-end: 1px solid var(--line);
  }
  .contact__k {
    font-family: var(--font-technical); font-size: var(--step--1);
    color: var(--muted); letter-spacing: 0.08em; text-transform: uppercase;
  }
  .contact__v {
    font-size: var(--step-1); color: var(--bone);
    text-decoration: none;
    &:hover { color: var(--ochre-soft); }
  }
  /* an unconfirmed value is visibly marked, never quietly blank */
  .tbc {
    font-family: var(--font-technical); font-size: var(--step--1);
    color: var(--ochre-soft);
    border: 1px dashed var(--ochre-edge);
    padding: var(--space-1) var(--space-3);
    display: inline-block;
  }

  /* --- footer ------------------------------------------------------------ */
  .footer {
    border-block-start: 1px solid var(--line);
    padding-block: var(--space-12);
    color: var(--muted); font-size: var(--step--1);
  }
  .footer__bar {
    display: flex; flex-wrap: wrap; gap: var(--space-6);
    align-items: center; justify-content: space-between;
  }
  .footer__links { display: flex; flex-wrap: wrap; gap: var(--space-6); }
  .footer__links a { text-decoration: none; &:hover { color: var(--bone); } }

  /* ======================================================================
     PROJECT LIGHTBOX — a :target overlay. No JavaScript: the card links to
     an id, :target reveals it, and the close control links back to
     #projects. Each one holds a scroll-snap slideshow of real photography.
     ====================================================================== */

  /* stretched link: one real, labelled link makes the whole card clickable */
  .project__link {
    text-decoration: none; color: inherit;
    &::after { content: ""; position: absolute; inset: 0; z-index: 2; }
  }
  .project__more {
    margin-top: var(--space-4);
    font-family: var(--font-technical); font-size: var(--step--1);
    letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--ochre-soft);
    display: flex; align-items: center; gap: var(--space-2);

    &::after {
      content: ""; inline-size: 6px; block-size: 6px; flex: none;
      border-block-start: 1px solid currentColor;
      border-inline-end: 1px solid currentColor;
      transform: rotate(45deg);
      transition: transform var(--d-hover) var(--ease-out);
    }
  }
  @media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
    .project:hover .project__more::after { transform: rotate(45deg) translate(2px, -2px); }
  }

  .lightbox {
    position: fixed; inset: 0; z-index: 80;
    display: grid; grid-template-rows: 1fr;
    place-items: center;
    padding: var(--space-4);
    background: color-mix(in srgb, var(--ink) 88%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    /* visibility keeps the contents out of the tab order while closed */
    visibility: hidden; opacity: 0;
    transition: opacity var(--d-panel) var(--ease-out),
                visibility var(--d-panel) var(--ease-out);
  }
  .lightbox:target { visibility: visible; opacity: 1; }

  .lightbox__backdrop { position: absolute; inset: 0; cursor: zoom-out; }

  .lightbox__panel {
    position: relative;
    inline-size: min(100%, 1360px);
    max-block-size: 92svh;
    display: grid; grid-template-rows: auto 1fr;
    gap: var(--space-4);
    background: var(--graphite);
    border: 1px solid var(--line-strong);
    padding: var(--space-6);
    overflow: hidden;
  }
  .lightbox__head {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-6);
    padding-inline-end: var(--space-12);
  }
  .lightbox__title { font-size: var(--step-2); }
  .lightbox__meta {
    font-family: var(--font-technical); font-size: var(--step--1);
    color: var(--bone-dim); letter-spacing: 0.04em;
  }
  .lightbox__close {
    position: absolute; inset-block-start: var(--space-4); inset-inline-end: var(--space-4);
    z-index: 3;
    inline-size: 42px; block-size: 42px;
    display: grid; place-items: center;
    border: 1px solid var(--line-strong); border-radius: var(--radius);
    text-decoration: none; color: var(--bone);
    font-family: var(--font-technical); font-size: var(--step-1); line-height: 1;
    background: var(--ink);
    transition: border-color var(--d-hover) var(--ease-out),
                color var(--d-hover) var(--ease-out);
    &:hover { border-color: var(--ochre); color: var(--ochre-soft); }
  }

  /* the slideshow: CSS scroll-snap, swipe or drag, no script */
  .lightbox__rail {
    display: flex; gap: var(--space-4);
    overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: thin;
    scrollbar-color: var(--ochre) transparent;
    padding-block-end: var(--space-3);
  }
  @media (prefers-reduced-motion: reduce) { .lightbox__rail { scroll-behavior: auto; } }
  .lightbox__rail img {
    flex: 0 0 auto;
    max-block-size: min(66svh, 620px);
    max-inline-size: 100%;
    inline-size: auto; block-size: auto;
    object-fit: contain;
    scroll-snap-align: center;
    border: 1px solid var(--line);
  }
  .lightbox__hint {
    font-family: var(--font-technical); font-size: var(--step--1);
    color: var(--muted); letter-spacing: 0.06em; text-transform: uppercase;
  }

  /* ======================================================================
     HAIL — the scroll-triggered enquiry prompt. Slides in past the hero on
     browsers with scroll timelines; simply sits there on browsers without
     one (never hidden by a feature that might not exist).
     ====================================================================== */
  .hail-dismiss:checked ~ .hail { display: none; }

  .hail {
    position: fixed; z-index: 60;
    inset-block-end: var(--space-6);
    inset-inline-end: var(--space-6);
    inline-size: min(calc(100vw - 2 * var(--space-6)), 380px);
    display: flex; align-items: center; gap: var(--space-4);
    padding: var(--space-4) var(--space-6);
    background: var(--ochre);
    color: var(--ink);
    border-radius: var(--radius);
    box-shadow: 0 18px 50px color-mix(in srgb, #000 55%, transparent);
  }
  .hail__text { font-size: var(--step--1); font-weight: 500; line-height: 1.35; }
  .hail__cta {
    font-family: var(--font-technical); font-size: var(--step--1);
    font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--ink); white-space: nowrap;
    text-decoration-color: color-mix(in srgb, var(--ink) 45%, transparent);
  }
  .hail__close {
    margin-inline-start: auto; flex: none;
    inline-size: 26px; block-size: 26px;
    display: grid; place-items: center; cursor: pointer;
    border: 1px solid color-mix(in srgb, var(--ink) 35%, transparent);
    border-radius: var(--radius);
    font-family: var(--font-technical); font-size: var(--step--1); line-height: 1;
    color: var(--ink);
    transition: background var(--d-hover) var(--ease-out);
    &:hover { background: color-mix(in srgb, var(--ink) 14%, transparent); }
  }
  .hail__close:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

  @supports (animation-timeline: scroll()) {
    @media (prefers-reduced-motion: no-preference) {
      .hail {
        transform: translateY(160%);
        animation: hail-in linear both;
        animation-timeline: scroll(root block);
        animation-range: 92svh 128svh;
      }
    }
  }
}

/* ========================================================================== */
@layer utils {
  .flow > * + * { margin-block-start: var(--space-6); }
  .defer { content-visibility: auto; contain-intrinsic-size: auto 700px; }
  .nowrap { white-space: nowrap; }
}

/* ==========================================================================
   Added 19/09/2026: WA cost benchmark marquee and directional slide-ins
   ========================================================================== */
@layer components {
  /* --- WA cost benchmarks (Koste rates, CSS-only marquee) ---------------- */
  .costs__head {
    display: flex; flex-wrap: wrap; justify-content: space-between;
    align-items: end; gap: var(--space-6);
    margin-block-end: var(--space-12);
  }
  .costs__source {
    font-family: var(--font-technical); font-size: var(--step--1);
    color: var(--muted); letter-spacing: 0.04em;
    & a { color: var(--bone); }
    & a:hover { color: var(--ochre-soft); }
  }
  .costs__lane {
    overflow: hidden;
    border-block: 1px solid var(--line);
    padding-block: var(--space-4);
    &:focus-visible { outline: 2px solid var(--ochre-soft); outline-offset: -2px; }
  }
  .costs__track {
    display: flex; inline-size: max-content;
    gap: var(--space-3); padding-inline-end: var(--space-3);
  }
  .cost-card {
    flex: none;
    inline-size: clamp(270px, 26vw, 360px);
    padding: var(--space-6);
    border: 1px solid var(--line);
    border-block-start: 3px solid var(--sector, var(--ochre));
    background:
      linear-gradient(150deg,
        color-mix(in oklab, var(--sector, var(--ochre)) 9%, transparent),
        transparent 58%),
      var(--graphite);
  }
  .cost-card__type {
    font-family: var(--font-technical); font-size: 0.68rem;
    letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted);
  }
  .cost-card__name {
    font-size: var(--step-1); line-height: 1.15; letter-spacing: -0.02em;
    min-block-size: 2.3em;
    margin-block: var(--space-3) var(--space-6);
  }
  .cost-card__vals {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2);
    margin: 0; padding-block-start: var(--space-3);
    border-block-start: 1px solid var(--line);
    & dt {
      font-family: var(--font-technical); font-size: 0.66rem;
      letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted);
    }
    & dd {
      margin: var(--space-1) 0 0;
      font-family: var(--font-display); font-weight: 700;
      font-size: var(--step-0); letter-spacing: -0.01em;
      font-variant-numeric: tabular-nums; color: var(--bone);
    }
    /* mid rate is the headline figure; soft orange is text-safe on graphite */
    & .is-mid dd { color: var(--ochre-soft); }
  }
  @media (max-width: 640px) { .cost-card { inline-size: 78vw; } }
}

@layer motion {
  @keyframes cost-scroll   { to { transform: translateX(-50%); } }
  /* explicit inset(0) end state: inset() does not interpolate to `none`, so
     without it the wipe snaps open halfway instead of drawing across */
  @keyframes slide-from-l  { from { opacity: 0; transform: translateX(-10vw); clip-path: inset(0 100% 0 0); }
                             to   { clip-path: inset(0); } }
  @keyframes slide-from-r  { from { opacity: 0; transform: translateX(10vw);  clip-path: inset(0 0 0 100%); }
                             to   { clip-path: inset(0); } }
  @keyframes image-settle  { from { transform: scale(1.18); } }

  /* the slide-ins start off-canvas; clip stops them adding a sideways scroll */
  main { overflow-x: clip; }

  @media (prefers-reduced-motion: no-preference) {
    /* marquee runs on time, not scroll; hovering or focusing it pauses it */
    .costs__track { animation: cost-scroll 110s linear infinite; }
    .costs__lane:hover .costs__track,
    .costs__lane:focus-within .costs__track { animation-play-state: paused; }
  }
  @media (prefers-reduced-motion: reduce) {
    .costs__lane { overflow-x: auto; }
    .costs__track [aria-hidden="true"] { display: none; }
  }

  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      /* image blocks slide and wipe in from their own side, and the
         photograph inside settles from a slight zoom as it lands */
      .slide-l, .slide-r {
        animation: slide-from-l linear both;
        animation-timeline: view();
        animation-range: entry 8% cover 56%;
      }
      .slide-r { animation-name: slide-from-r; }
      :is(.slide-l, .slide-r) img {
        animation: image-settle linear both;
        animation-timeline: view();
        animation-range: entry 0% cover 50%;
      }
    }
  }
}

/* ==========================================================================
   Added 19/09/2026: Site Camera hero film (hero-film.js, see BRIEF.md).
   Without JS or WebGL none of the .is-live rules apply and the hero is the
   original photograph + headline at 100svh.
   ========================================================================== */
@layer components {
  .film { display: block; }
  .film__stage {
    position: relative;
    min-block-size: 100svh;
    display: grid; align-items: end;
    overflow: clip; isolation: isolate;
  }
  .film__stage > .film__beat { grid-area: 1 / 1; }
  .film__beat--later { display: none; }
  .film__beat--later h2 { font-size: var(--step-4); max-inline-size: 16ch; }
  .film__beat--later .lede { max-inline-size: 44ch; }
  .film__beat--later { padding-block: var(--space-24) var(--space-16); }

  .film__canvas {
    position: absolute; inset: 0;
    inline-size: 100%; block-size: 100%;
    opacity: 0; transition: opacity 0.6s var(--ease-out);
  }
  .film.is-ready .film__canvas { opacity: 1; }

  .film.is-live { block-size: 680svh; }   /* 46-week programme, plus the dwell the owner asked for 20/09 */
  .film.is-live .film__stage { position: sticky; inset-block-start: 0; block-size: 100svh; }
  .film.is-live .film__beat { opacity: 0; will-change: opacity, transform; }
  .film.is-live .film__beat--later { display: block; }

  /* programme readout + skip link, bottom right over the scene */
  .film__readout, .film__skip { display: none; }
  .film.is-live .film__readout {
    display: grid; grid-template-columns: auto auto; gap: var(--space-2) var(--space-6);
    position: absolute; z-index: 2;
    inset-block-end: var(--space-8); inset-inline-end: max(1.25rem, 4vw);
    font-family: var(--font-technical); font-size: var(--step--1);
    letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--bone); text-shadow: 0 1px 14px color-mix(in srgb, #000 70%, transparent);
  }
  .film__readout [data-film-week] { color: var(--ochre-soft); text-align: end; }
  .film__bar {
    grid-column: 1 / -1; inline-size: min(220px, 40vw); block-size: 2px;
    background: color-mix(in oklab, var(--bone) 25%, transparent);
    & i { display: block; block-size: 100%; background: var(--ochre); transform-origin: left; transform: scaleX(0); }
  }
  .film.is-live .film__skip {
    display: block; position: absolute; z-index: 2;
    inset-block-start: calc(var(--space-24) + var(--space-2)); inset-inline-end: max(1.25rem, 4vw);
    font-family: var(--font-technical); font-size: var(--step--1);
    letter-spacing: 0.08em; text-transform: uppercase;
    /* Now the photograph is no longer washed down, this link can land on bright sky, where a
       text shadow alone measured 2.5:1. It carries its own backing instead (owner, 20/09/2026). */
    color: var(--bone);
    padding: var(--space-2) var(--space-3);
    background: color-mix(in srgb, var(--ink) 74%, transparent);
    border: 1px solid var(--line);
    backdrop-filter: blur(3px);
    &:hover { color: var(--ochre-soft); border-color: var(--line-strong); }
  }

  @media (max-width: 700px) {
    .film.is-live { block-size: 570svh; }
    .film.is-live .film__readout { inset-block-end: auto; inset-block-start: calc(var(--space-24) - var(--space-2)); inset-inline: 1.25rem auto; }
    .film.is-live .film__skip { inset-block-start: calc(var(--space-24) - var(--space-2)); }
  }

  /* the hail prompt waits until the film has handed over to the page */
  :root:has(.film.is-live) { --film-h: 680svh; }
  @media (max-width: 700px) { :root:has(.film.is-live) { --film-h: 570svh; } }
  @supports (animation-timeline: scroll()) {
    @media (prefers-reduced-motion: no-preference) {
      :root:has(.film.is-live) .hail {
        animation-range: calc(var(--film-h) - 90svh) calc(var(--film-h) - 54svh);
      }
    }
  }
}

/* ==========================================================================
   Added 20/09/2026: enquiry form with document upload (#enquiry, enquiry-form.js)
   ========================================================================== */
@layer components {
  .enquiry {
    margin-block-start: var(--space-16);
    padding-block-start: var(--space-12);
    border-block-start: 1px solid var(--line);
  }
  .enquiry__title { font-size: var(--step-2); margin-block-end: var(--space-8); }
  .enquiry__grid {
    display: grid; gap: var(--space-6);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  }
  .field { display: grid; gap: var(--space-2); }
  .field--wide { grid-column: 1 / -1; }
  .field > span, .field > span:first-child {
    font-family: var(--font-technical); font-size: var(--step--1);
    letter-spacing: 0.06em; text-transform: uppercase; color: var(--bone-dim);
    & b { color: var(--ochre-soft); font-weight: 500; }
  }
  .field input, .field select, .field textarea {
    font: inherit; font-size: var(--step-0); color: var(--bone);
    background: var(--graphite); border: 1px solid var(--line-strong);
    border-radius: var(--radius); padding: var(--space-3) var(--space-4);
    inline-size: 100%;
    &:focus-visible { outline: 2px solid var(--ochre-soft); outline-offset: 1px; border-color: transparent; }
  }
  .field textarea { resize: vertical; min-block-size: 8rem; }
  .field select option { background: var(--graphite); }

  .drop {
    position: relative; display: grid; gap: var(--space-2); place-items: center; text-align: center;
    padding: var(--space-8) var(--space-6);
    border: 1px dashed var(--line-strong); border-radius: var(--radius);
    background: var(--graphite); cursor: pointer;
    transition: border-color var(--d-hover) var(--ease-out), background var(--d-hover) var(--ease-out);
    &:hover, &.is-over { border-color: var(--ochre-soft); background: var(--surface-up); }
    &:focus-within { outline: 2px solid var(--ochre-soft); outline-offset: 1px; }
    & input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
  }
  .drop__cta { color: var(--bone); font-weight: 500; }
  .drop__hint { color: var(--muted); font-size: var(--step--1); line-height: 1.55; max-inline-size: 60ch; }
  .drop__list {
    list-style: none; margin: var(--space-3) 0 0; padding: 0; display: grid; gap: var(--space-1);
    font-size: var(--step--1); color: var(--bone-dim);
    & li::before { content: ""; display: inline-block; inline-size: 8px; block-size: 8px; margin-inline-end: var(--space-2); background: var(--ochre); }
    & li.is-bad { color: var(--ochre-soft); }
  }
  .enquiry__hp { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); }
  .consent {
    display: flex; gap: var(--space-3); align-items: start;
    margin-block: var(--space-8) var(--space-6);
    font-size: var(--step--1); line-height: 1.55; color: var(--muted); max-inline-size: 80ch;
    & input { inline-size: 18px; block-size: 18px; margin-block-start: 2px; accent-color: var(--ochre); flex: none; }
    & a { color: var(--bone); }
  }
  .enquiry__actions { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center; margin-block-start: var(--space-6); }
  .enquiry__actions .btn[disabled] { opacity: 0.6; cursor: progress; }
  .enquiry__status { font-size: var(--step--1); color: var(--bone-dim); &.is-bad { color: var(--ochre-soft); } }
  .enquiry__progress {
    margin-block-start: var(--space-4); block-size: 3px; background: var(--line);
    & i { display: block; block-size: 100%; background: var(--ochre); transform-origin: left; transform: scaleX(0); }
  }
  .enquiry__done h3 { font-size: var(--step-2); }
  .enquiry__done p { margin-block-start: var(--space-4); color: var(--bone-dim); }
}

/* ==========================================================================
   Added 20/09/2026: earthworks photograph behind the problem section
   ========================================================================== */
@layer components {
  /* Same treatment as the old hero: full-bleed, one screen tall, cover crop,
     hero scrim for the type. The photo's top edge is the section's top edge. */
  .landbg {
    position: relative; isolation: isolate; overflow: clip;
    min-block-size: 100svh;
    /* Centred content inside a full-screen box left slack at the foot, and the section's own
       bottom padding then met the next section's top padding: three dark bands in a row with
       nothing in them (owner, 20/09/2026). The content now sits toward the top of the frame
       and the junction carries one section's worth of air, not two and a half. */
    display: grid; align-content: start;
    padding-block: var(--space-24) var(--space-12);
  }
  .landbg + .section { padding-block-start: var(--space-16); }
}

/* ==========================================================================
   Added 20/09/2026: the hero film renders over the aerial photograph
   ========================================================================== */
@layer components {
  /* The photo stays behind the transparent 3D render. It used to darken toward dusk as you
     scrolled; the owner asked for that removed (20/09/2026), so the light on the land holds
     from the first screen to the last. */
  .film .hero__img { object-position: 60% 55%; }

  /* Lighter again (owner, 20/09/2026). Rather than wash the whole frame down, the ink is
     pooled where the words actually sit - bottom left - and the rest of the land is left open.
     The headline still clears AA against the pool; checked on the rendered page, not assumed. */
  .film .hero__scrim {
    background:
      /* the text column, all of it: the eyebrow sits high and the buttons low, so the ink runs
         the full height of the left side rather than pooling at the foot */
      linear-gradient(to right,
        color-mix(in srgb, var(--ink) 88%, transparent) 0%,
        color-mix(in srgb, var(--ink) 74%, transparent) 24%,
        color-mix(in srgb, var(--ink) 22%, transparent) 48%,
        transparent 64%),
      /* just enough at the foot for the stage and week readout on the right */
      linear-gradient(to top, color-mix(in srgb, var(--ink) 48%, transparent) 0%, transparent 26%);
  }
  .film .film__canvas { z-index: 1; }
}

/* ==========================================================================
   Added 20/09/2026: the five-party chain opens on hover, focus or tap
   ========================================================================== */
@layer components {
  .gap-node { cursor: default; transition: border-color var(--d-hover) var(--ease-out), background var(--d-hover) var(--ease-out); }
  .gap-node::after {                       /* "there is more here" marker, drawn in CSS */
    content: "+"; position: absolute; inset-block-start: var(--space-3); inset-inline-end: var(--space-3);
    color: var(--muted); font-size: var(--step--1); line-height: 1;
    transition: transform var(--d-hover) var(--ease-out), color var(--d-hover) var(--ease-out);
  }
  .gap-node:hover, .gap-node:focus-within { z-index: 5; border-color: var(--line-strong); background-color: var(--surface-up); }
  .gap-node:hover::after, .gap-node:focus-within::after { transform: rotate(45deg); color: var(--ochre-soft); }
  .gap-node:focus-visible { outline: 2px solid var(--ochre-soft); outline-offset: 2px; }

  .gap-node__more {
    position: absolute; inset-block-start: calc(100% + var(--space-2)); inset-inline-start: -1px;
    inline-size: max(100%, 280px);
    padding: var(--space-4);
    background: var(--ink); border: 1px solid var(--line-strong); border-block-start: 2px solid var(--ochre);
    box-shadow: 0 18px 40px color-mix(in srgb, #000 55%, transparent);
    font-family: var(--font-interface); font-size: var(--step--1); line-height: 1.55;
    color: var(--bone-dim); text-transform: none; letter-spacing: 0;
    opacity: 0; visibility: hidden; transform: translateY(-6px);
    transition: opacity var(--d-panel) var(--ease-out), transform var(--d-panel) var(--ease-out), visibility var(--d-panel);
  }
  .gap-node:last-child .gap-node__more { inset-inline: auto -1px; }   /* keep the last one on screen */
  .gap-node:hover .gap-node__more, .gap-node:focus-within .gap-node__more, .gap-node:focus .gap-node__more {
    opacity: 1; visibility: visible; transform: none;
  }
  @media (prefers-reduced-motion: reduce) { .gap-node__more { transition: none; } }

  /* phones: the boxes wrap, so the text opens inside the box instead of floating off-screen */
  @media (max-width: 700px) {
    .gap-node__more {
      position: static; inline-size: auto; margin-block-start: 0; max-block-size: 0; padding: 0 0;
      border: 0; box-shadow: none; background: none; overflow: hidden; transform: none;
      transition: max-block-size var(--d-panel) var(--ease-out), padding var(--d-panel), opacity var(--d-panel);
    }
    .gap-node:hover .gap-node__more, .gap-node:focus-within .gap-node__more, .gap-node:focus .gap-node__more {
      max-block-size: 16rem; padding-block-start: var(--space-3);
    }
    .gap-node:last-child .gap-node__more { inset-inline: auto; }
  }
}

/* ==========================================================================
   Added 20/09/2026, reworked the same day to the owner's four-panel layout:
   tools down the left, enquiry form top right, our details and the office map
   beneath it. One 1px rule between panels, the same language as the capability
   grid. The two tall panels are capped and scroll inside themselves on a wide
   screen so the block reads as one page; on a phone everything stacks and
   scrolls with the page, because a scroll box inside a scrolling page is a
   trap on touch.
   ========================================================================== */
@layer components {
  .closing {
    display: grid; gap: 1px;
    background: var(--line);
    border: 1px solid var(--line);
  }
  .closing__right, .closing__lower { display: grid; gap: 1px; background: var(--line); }
  .closing__panel {
    background: var(--ink);
    padding: var(--space-8);
    min-inline-size: 0;              /* lets a panel shrink instead of forcing the grid wide */
  }
  .closing__h {
    font-family: var(--font-display); font-weight: 700;
    font-size: var(--step-1); letter-spacing: -0.025em;
    margin: 0 0 var(--space-3);
  }
  .closing__sub {
    font-size: var(--step--1); line-height: 1.55; color: var(--muted);
    margin-block-end: var(--space-8);
  }
  .closing__address {
    font-style: normal; line-height: 1.5;
    color: var(--bone);
    margin-block-end: var(--space-8);
  }
  .closing__actions { display: flex; flex-wrap: wrap; gap: var(--space-4); margin-block-start: var(--space-8); }

  /* the panels already carry their own heading, so the parts inside drop theirs */
  .closing__tools .tools { border: 0; background: transparent; }
  .closing__form .enquiry { margin-block-start: 0; padding-block-start: 0; border-block-start: 0; }
  /* The details panel is the shortest of the four, so it earns its height back: the phone and
     the email keep a full row, the two registrations share one, and the address sits tight. */
  .closing__details .contact__list { margin-block-start: 0; gap: var(--space-4) var(--space-6); grid-template-columns: 1fr 1fr; }
  .closing__details .contact__item:nth-child(-n+2) { grid-column: 1 / -1; }
  .closing__details .contact__v { overflow-wrap: anywhere; }
  .closing__details .closing__address { margin-block-end: var(--space-6); }
  .closing__details, .closing__map { padding: var(--space-6); }
  /* the full-page treatment (big values, a rule under each) does not fit a quarter panel */
  .closing__details .contact__item { padding-block-end: var(--space-2); border-block-end: 0; }
  .closing__details .contact__v { font-size: var(--step-0); }
  .closing__details .closing__h { margin-block-end: var(--space-2); }
  .closing__details .closing__address { margin-block-end: var(--space-4); }
  .closing__details .contact__list { gap: var(--space-3) var(--space-6); }

  /* --- the map ---------------------------------------------------------- */
  .closing__mapframe {
    position: relative;
    aspect-ratio: 4 / 3;
    border: 1px solid var(--line);
    background: var(--graphite);
    & iframe { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; border: 0; }
  }
  .closing__maplink {
    margin-block-start: var(--space-4);
    font-family: var(--font-technical); font-size: var(--step--1); line-height: 1.5;
    color: var(--muted);
    & a { color: var(--bone); }
    & a:hover { color: var(--ochre-soft); }
  }

  /* The tools and the form were built to run the full page width, so their own breakpoints
     watch the viewport. In a half-width panel that reads cramped, so inside the panel they
     answer to the PANEL's width instead and stack their result under their inputs. */
  .closing__tools { container-type: inline-size; }
  .closing__tools .tool { grid-template-columns: 1fr; padding: 0; gap: var(--space-8); }
  .closing__tools .tool__form { grid-template-columns: 1fr; }
  @container (min-width: 440px) {
    .closing__tools .tool__form { grid-template-columns: 1fr 1fr; }
  }

  @media (min-width: 1020px) {
    .closing {
      grid-template-columns: 1fr 1fr; align-items: stretch;
      /* one screen: the four panels share it rather than the page growing to fit them.
         The row is minmax(0,1fr) too - an auto row would size to its content and the
         panels would overflow the height instead of scrolling inside it. */
      block-size: clamp(640px, 88svh, 1000px);
      grid-template-rows: minmax(0, 1fr);
    }
    /* Proportions, not auto: an auto lower row sizes to its own content and starves the
       form of the height it needs. Two thirds form, one third details and map. */
    .closing__right { grid-template-rows: minmax(0, 1.45fr) minmax(0, 1fr); min-block-size: 0; }
    .closing__lower { grid-template-columns: 1fr 1fr; min-block-size: 0; }
    /* confined to their own area */
    .closing__tools, .closing__form { min-block-size: 0; overflow-y: auto; overscroll-behavior: contain; }
    .closing__details { min-block-size: 0; overflow-y: auto; }
    /* the map fills whatever is left of its panel rather than holding a fixed 4:3 */
    .closing__map { display: flex; flex-direction: column; min-block-size: 0; }
    .closing__map .closing__mapframe { aspect-ratio: auto; flex: 1 1 auto; min-block-size: 150px; }
    .closing__tools::-webkit-scrollbar, .closing__form::-webkit-scrollbar { inline-size: 10px; }
    .closing__tools::-webkit-scrollbar-thumb, .closing__form::-webkit-scrollbar-thumb {
      background: var(--line-strong); border: 3px solid var(--ink);
    }
    .closing__tools, .closing__form { scrollbar-width: thin; scrollbar-color: var(--line-strong) var(--ink); }
  }
}

/* ==========================================================================
   Added 20/09/2026: free tools (build cost, concrete volume, working days)
   ========================================================================== */
@layer components {
  .tools { border: 1px solid var(--line); background: var(--graphite); }
  .tools__tabs { display: flex; flex-wrap: wrap; border-block-end: 1px solid var(--line); }
  .tools__tab {
    appearance: none; background: none; border: 0; cursor: pointer;
    padding: var(--space-4) var(--space-8);
    font-family: var(--font-technical); font-size: var(--step--1);
    letter-spacing: 0.06em; text-transform: uppercase; color: var(--bone-dim);
    border-block-end: 2px solid transparent; margin-block-end: -1px;
    transition: color var(--d-hover) var(--ease-out), border-color var(--d-hover) var(--ease-out);
    &:hover { color: var(--bone); }
  }
  .tools__tab[aria-selected="true"] { color: var(--bone); border-block-end-color: var(--ochre); }
  .tool { display: grid; gap: var(--space-8); padding: clamp(var(--space-6), 3vw, var(--space-12)); }
  .tool[hidden] { display: none; }   /* display:grid would otherwise beat the hidden attribute */
  @media (min-width: 860px) { .tool { grid-template-columns: 1.15fr 1fr; gap: var(--space-12); align-items: start; } }
  .tool__form { display: grid; gap: var(--space-6); align-content: start; }
  @media (min-width: 560px) { .tool__form { grid-template-columns: 1fr 1fr; } .tool__form > .btn, .tool__hint { grid-column: 1 / -1; } }
  .tool__form .btn { justify-self: start; }
  .tool__hint { color: var(--muted); font-size: var(--step--1); line-height: 1.55; }

  .tool__result {
    display: grid; gap: var(--space-4); align-content: start;
    padding: var(--space-8); background: var(--ink); border: 1px solid var(--line);
  }
  .tool__out {
    display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-4);
    padding-block-end: var(--space-3); border-block-end: 1px solid var(--line);
    & span { font-family: var(--font-technical); font-size: var(--step--1); letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
    & b { font-family: var(--font-display); font-weight: 700; font-size: var(--step-1); letter-spacing: -0.02em; color: var(--bone); font-variant-numeric: tabular-nums; }
  }
  .tool__out.is-lead b { font-size: var(--step-2); color: var(--ochre-soft); }   /* 5.85:1 on ink */
  .tool__out:last-of-type { border-block-end: 0; padding-block-end: 0; }
  .tool__note { color: var(--muted); font-size: var(--step--1); line-height: 1.55; }
}

/* ==========================================================================
   Added 20/09/2026: the enquiry prompt steps aside at the tools and contact
   ========================================================================== */
@layer components {
  .hail { transition: opacity var(--d-panel) var(--ease-out), transform var(--d-panel) var(--ease-out); }
  .hail.is-away { opacity: 0; transform: translateY(140%); pointer-events: none; }
  @media (prefers-reduced-motion: reduce) { .hail.is-away { transform: none; visibility: hidden; } }
}
