  :root{
    --ground:#0B0C0D;
    --hair:rgba(255,255,255,.11);
    --hair-strong:rgba(255,255,255,.2);
    --panel-light:#F5F6F7;--hair-dark:rgba(11,12,13,.16);
    --ink:#F2F3F4;
    --plate-ink:#C6CACE;
    --muted:#9BA0A6;
    --dim:#8A9096;            /* 6.07:1 on --ground */
    --gold:#E9B30E;
    --gold-lit:#F6C63A;
    --trace-line:#8A7B45;
    --pulse-core:#FFF9D8;
    --slide-shade:rgba(0,0,0,.9);
    --pad:clamp(20px,5vw,72px);
    --navh:85px;
    --ease:cubic-bezier(.16,1,.3,1);
    /* An even ramp for opacity. --ease is an expo-out: it reaches nine tenths of its travel in
       the first quarter of its duration, which is right for a statement landing and wrong for a
       fade, where it reads as a snap however long the duration is. */
    --ease-fade:cubic-bezier(.4,0,.35,1);
  }
  *{margin:0;padding:0;box-sizing:border-box}
  /* The opening film is position:fixed at inset:0 and sits under everything at z-index 0,
     which is what lets the panels slide over it. A rubber band overscroll breaks that
     arrangement: the scrolled content, footer included, pulls away from the viewport edge
     while a fixed element stays locked to it, so at the foot of the page the film is
     uncovered in the strip the footer just left and is caught still playing. Reported by
     the client, 22 September 2026. Refusing the bounce on the vertical axis is the whole
     fix, and it costs nothing: there is no pull to refresh to preserve on a website, and
     the horizontal rail in the lineage sets its own overscroll rule on its own axis. */
  html{-webkit-text-size-adjust:100%;overscroll-behavior-y:none}
  body{overscroll-behavior-y:none}
  body{
    background:var(--ground);color:var(--ink);
    font-family:Archivo,system-ui,sans-serif;font-weight:400;
    font-size:16px;line-height:1.6;-webkit-font-smoothing:antialiased;
  }
  ::selection{background:var(--gold);color:var(--ground)}
  a{color:inherit}
  img{display:block;max-width:100%}
  :focus-visible{outline:2px solid var(--gold);outline-offset:3px}
  .wrap{max-width:1560px;margin:0 auto;padding-inline:var(--pad)}

  /* ---------- SKIP LINK ----------
     WCAG 2.4.1, Bypass Blocks, a Level A criterion the agreement commits us to. Eleven pages
     each put the same nav in front of the content, and a keyboard or screen reader user had no
     way past it. Off screen until focused, then it lands over the nav in the gold so it is
     unmistakably the thing that has focus. */
  .skiplink{
    position:absolute;left:12px;top:-64px;z-index:200;
    background:var(--gold);color:var(--ground);
    font-size:13px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
    padding:12px 18px;text-decoration:none;
    transition:top .18s var(--ease)}
  .skiplink:focus{top:12px}
  .skiplink:focus-visible{outline:2px solid var(--ground);outline-offset:-6px}

  /* ---------- NAV ---------- */
  .nav{
    position:fixed;inset:0 0 auto;z-index:60;
    display:flex;align-items:center;justify-content:space-between;gap:24px;
    padding:16px var(--pad);border-bottom:1px solid transparent;
    transition:background .45s var(--ease),border-color .45s var(--ease),
               opacity .7s var(--ease),transform .7s var(--ease);
  }
  /* Withheld for the whole hero so nothing sits over the journey, then arrives with the
     statement. Inert while hidden so it cannot be tabbed to. */
  body.hero-live .nav{opacity:0;transform:translateY(-12px);pointer-events:none;visibility:hidden}
  /* translateY(0) rather than none, so the bar keeps a transform in both states. Dropping to
     no transform at all releases its compositing layer at the same moment it becomes visible,
     and iOS does not reliably repaint a position:fixed element across that. */
  body.hero-live.nav-in .nav{opacity:1;transform:translateY(0);pointer-events:auto;visibility:visible}
  .nav.stuck{background:rgba(11,12,13,.86);backdrop-filter:blur(14px);border-bottom-color:var(--hair)}
  .brand{display:flex;align-items:center;gap:13px;text-decoration:none;flex-shrink:0}
  /* Full badge, white ring included. The tighter crop existed only because the old asset
     was 402px and its ring type turned to mush; the 2010px source holds up. */
  .brand img{width:52px;height:52px;clip-path:circle(49%)}
  .brand b{font-weight:700;font-size:29px;letter-spacing:.005em;white-space:nowrap;
    text-shadow:0 1px 16px rgba(0,0,0,.55)}
  .navlinks{display:flex;align-items:center;gap:clamp(20px,2.2vw,34px)}
  .navlinks a{
    text-decoration:none;font-size:13px;font-weight:600;letter-spacing:.15em;
    text-transform:uppercase;color:var(--ink);
    padding:8px 0;position:relative;transition:color .25s var(--ease);
    text-shadow:0 1px 14px rgba(0,0,0,.55);
  }
  .navlinks a:hover{color:var(--gold-lit)}
  .navlinks a::after{
    content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:var(--gold);
    transform:scaleX(0);transform-origin:left;transition:transform .35s var(--ease);
  }
  .navlinks a:hover::after{transform:scaleX(1)}
  /* A hairline sets the action apart from navigation rather than letting it sit in the row. */
  .navsep{width:1px;height:22px;background:var(--hair);flex-shrink:0}
  /* Selector has to out-rank `.navlinks a`, which is (0,1,1); a bare .navcta loses to it
     and its padding is silently discarded. */
  .navlinks a.navcta{
    border:1px solid var(--hair-strong);color:var(--ink)!important;
    padding:15px 28px;font-size:13px;font-weight:600;letter-spacing:.15em;
    text-transform:uppercase;
    transition:border-color .3s var(--ease),color .3s var(--ease),background .3s var(--ease)!important;
  }
  .navlinks a.navcta:hover{border-color:var(--gold);background:var(--gold);color:var(--ground)!important}
  .navlinks a.navcta::after{display:none}

  /* ---------- THE LINE ----------
     Four beats scrubbed by scroll, drawn entirely in code so every edge stays crisp and
     nothing photographic ever enters the void: the mark, the bore you fall into, the
     black, and the run of traces carrying current. */
  /* padding-block:0 overrides the global section rhythm, which would otherwise push the
     pinned stage down by 10vw and leave a band above the film. */
  /* The hero is a fixed backdrop, not a scrolling section: the rest of the site rides up
     over it and it never moves. A spacer supplies the scroll distance the film needs. */
  /* Pure black behind the film, not --ground. The film's own black is #000, so a #0B0C0D
     stage gives the masked band edges something to fade against and the join shows. Nothing
     else sits on this surface except the opening type and the cue, and 3 values of lift makes
     no difference to either. */
  /* Held, so the panel below can ride up over it. This is the first of the two slides and it
     is not the thing the client objected to: that was the 340svh scrubbed journey, where you
     scrolled and the page did not advance. This costs no extra scroll at all. The spacer is
     exactly one screen, so the hero occupies one screen and is then covered. */
  .hero{position:fixed;inset:0;height:100svh;z-index:0;padding-block:0;background:#000}
  /* One screen plus the depth of the seam that rides up over it, so the light panel does not
     show along the foot of the hero before the reader has scrolled. --seam-h is published by
     drawEdge, which is the only thing that knows the profile height at this width. */
  .hero-spacer{height:calc(100svh + var(--seam-h,64px));pointer-events:none}
  /* The statement sits in the graded band at the foot and centres on the page. Everything
     above it is clear film. The foot clearance has to beat the 64px routed seam or the sub
     copy lands on the edge of the light panel below. */
  .hero-pin{
    position:relative;height:100svh;overflow:hidden;
    display:flex;flex-direction:column;justify-content:flex-end;
    padding-bottom:clamp(92px,13svh,148px);
  }
  /* The panel's top edge is routed, not straight: the same orthogonal-with-rounded-corners
     grammar as the traces, so the seam reads as part of the system. */
  .over{position:relative;z-index:2}
  /* No shadow on any seam. It was cast by the seam's own shape and landed on the panel below
     it, taking #F5F6F7 down to #CBCCCC at the edge and fading back over 70px. On a flat light
     surface that is a grey wash, not depth. The routed line articulates the seam on its own
     and the panels separate by value; nothing here needs a shadow to be read. */
  /* Height and offset are set by drawEdge, which sizes the profile against the viewport.
     These are the pre-script values so nothing jumps before it runs. */
  .edge{position:absolute;top:0;left:0;width:100%;height:64px;display:block;
    transform:translateY(-63px);overflow:visible}
  /* Restored 2026-09-06. This seam was pulled on the theory that its notch was the black
     band at the top of the client panel. It was not: that band came from two stray closing
     tags that put whole sections outside .over and let the fixed hero paint over them. With
     the nesting corrected the profile reads as the routed edge it is, the same one the
     certifications panel carries. */
  .edge-fill{fill:var(--panel-light)}
  .over-body{position:relative;background:var(--ground)}
  /* Unpinned on 25 September at the client's direction. This panel used to stick at the
     top of the viewport while the section after it rode up over the top, which was the
     second of the two slides the design system describes. Trusted partners and Built for
     complex work are both light panels sitting next to each other now, so the slide had
     one light ground passing over another and read as a glitch rather than a gesture.
     It scrolls like an ordinary section: you come down the page and the band is simply
     there. The height goes with the pin, because a full viewport of logo wall only made
     sense while it was holding the screen. */
  #clients{position:relative;z-index:1;
    display:flex;flex-direction:column;justify-content:center;
    padding-block:clamp(48px,6vh,104px) clamp(72px,9vh,120px)}
  #clients ~ *{position:relative;z-index:2;background:var(--ground)}
  #work{position:relative}
  .edge--work .edge-fill{fill:var(--ground)}

  .stage{position:absolute;inset:0;z-index:0;pointer-events:none}
  /* The film runs clear. The only grade is at the foot: it reaches .84 at 80% and holds
     that to the bottom edge.

     This has been wrong in both directions. It ran to .97 first, which made the foot a
     flat black bar against the top of the white panel below, so it was released to .28 at
     the very bottom to let the film reach the edge. That released too far: the client's
     screenshot on 2026-09-22 shows the band visibly lifting off the ground before the
     screen ends, which reads as an unfinished gradient rather than a deliberate one.
     Holding .84 to the edge keeps it continuous without going near black, so the film is
     still 16% present where it meets the panel. Above 36% the picture is untouched. A
     short head grade carries the nav off a bright ceiling. */
  .stage::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:1;
    background:
      linear-gradient(180deg,rgba(0,0,0,.62) 0,rgba(0,0,0,.34) 78px,rgba(0,0,0,0) 168px),
      linear-gradient(180deg,rgba(0,0,0,0) 36%,rgba(0,0,0,.50) 60%,rgba(0,0,0,.84) 80%,
        rgba(0,0,0,.84) 100%)}
  /* The player is 16:9 and the hero is whatever shape the window is, so it is sized to
     cover: width drives it on a wide window, height drives it on a tall one, and it is
     centred on both axes so the middle of the frame is what survives the crop. */
  .stage iframe{
    position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
    width:100vw;height:calc(100vw * 9 / 16);
    min-width:calc(100svh * 16 / 9);min-height:100svh;
    border:0;display:block;pointer-events:none;z-index:0;
  }
  .grid{position:absolute;inset:0;width:100%;height:100%;display:block;opacity:0}
  .trace{fill:none;stroke:var(--trace-line);stroke-width:1.2;vector-effect:non-scaling-stroke}
  .pulse{position:absolute;inset:0;width:100%;height:100%;display:block;opacity:0;
    pointer-events:none}

  /* ---------- OPENING TYPE ---------- */
  /* The statement is withheld for the whole journey and lands once the current arrives. */
  .opening-inner{
    max-width:1560px;margin:0 auto;width:100%;position:relative;z-index:2;
    padding:0 var(--pad);text-align:center;
    opacity:0;transition:opacity .7s var(--ease);
  }
  .hero-pin.copy-in .opening-inner{opacity:1}
  /* 7.3vw, down from 8.6. The statement has to sit between two runs of the trace grid, the one
     at viewBox 175 and the one at 419, and at 8.6vw it measured 254px against a 220px band.
     The grid is the composition and the type is placed into it, so the type gives way. */
  /* 106px, then 88, now 56. Sitting over the film rather than on bare ground, the statement
     falls under the Restrained Display Rule: the building is the largest thing on the plate,
     and the type is its caption. This is the display-plate step the project plates already use. */
  h1{font-weight:600;font-size:clamp(38px,calc(3.75vw + 22px),76px);line-height:1.0;letter-spacing:-.032em}
  .ln{display:block;overflow:hidden;padding-bottom:.04em;margin-bottom:-.04em}
  .ln i{display:block;font-style:normal;transform:translateY(112%);
    transition:transform 1.05s var(--ease)}
  .copy-in .ln i{transform:none}
  .copy-in .ln--a i{transition-delay:.10s}
  .copy-in .ln--b i{transition-delay:.22s}
  .opening-sub{
    margin-top:clamp(14px,1.4vw,20px);color:var(--plate-ink);
    font-size:clamp(16px,calc(0.55vw + 12px),19px);max-width:52ch;line-height:1.55;
    margin-left:auto;margin-right:auto;
    opacity:0;transform:translateY(16px);
    transition:opacity .9s var(--ease),transform .9s var(--ease);
  }
  .copy-in .opening-sub{opacity:1;transform:none;transition-delay:.44s}

  /* The one light panel in the page. Every logo is forced to a single black so a wall of
     clashing brand colours reads as one system, and the marks hold far more of their
     interior detail than a white knockout on the ground does. */
  #clients{background:var(--panel-light);color:var(--ground)}
  #clients h2{color:var(--ground)}
  /* Nine marks, not twelve. AECOM and Turner came off on 2026-09-24 because they are
     general contractors rather than owners and Greg did not want the two mixed, and
     Northrop Grumman came off because G2.0 has never worked there. Six across left a row
     of six and then a row of three against three empty cells, which reads as unfinished.
     Five across on 25 September at the client's direction, so the wall reads as two rows
     with a gap at the end of the second rather than a square of three. More marks are
     coming and a tenth fills it exactly. */
  .logos{
    display:grid;grid-template-columns:repeat(5,1fr);
    border-top:1px solid var(--hair-dark);border-left:1px solid var(--hair-dark);
    margin-top:clamp(38px,4.4vw,62px);
  }
  .logo{
    border-right:1px solid var(--hair-dark);border-bottom:1px solid var(--hair-dark);
    display:flex;align-items:center;justify-content:center;
    padding:26px 22px;min-height:152px;
  }
  .logos.inview{opacity:1;transform:none}

  /* The logo panel is the one pinned section in the page: it holds still underfoot while the
     rest of the site slides up over it, so the reader dwells here and its reveal can take
     longer than a section that scrolls past. Opacity rides the even curve and only the travel
     keeps the ease-out, which is what stops a long fade still reading as a snap. */
  #clients .lead.inview.on{transition:opacity 1.5s var(--ease-fade),transform 1.5s var(--ease)}
  #clients .logo img{transition:opacity 1.15s var(--ease-fade),transform 1.15s var(--ease)}
  /* 12 cells at 68ms is an 0.75s cascade, so the wall lands over roughly two seconds. */
  #clients .logos.on .logo img{transition-delay:calc(var(--i,0) * 68ms)}
  .logo img{width:var(--w,120px);max-width:100%;height:auto;
    filter:brightness(0);opacity:0;transform:translateY(10px);
    transition:opacity .5s var(--ease),transform .5s var(--ease)}
  .logos.on .logo img{opacity:1;transform:none;transition-delay:calc(var(--i,0) * 30ms)}
  .logo img.stack{width:auto;height:var(--h,60px)}
  @media (max-width:620px){
    /* Two across on a phone, not three. Three fits without overflowing but puts the marks
       at 78px in a 111px cell, and a wordmark that small is not doing its job. Ten marks
       is five even rows at two across, and two even rows at five. */
    .logos{grid-template-columns:repeat(2,1fr)}
    .logo{padding:22px 16px;min-height:118px}
    .logo img{width:calc(var(--w,120px) * .82)}
    .logo img.stack{height:calc(var(--h,60px) * .82)}
    }

  /* ---------- PLATES ---------- */
  .plate{position:relative;isolation:isolate}
  .plate figure{position:relative;overflow:hidden;background:#08090A;height:min(74vh,760px)}
  .plate img{width:100%;height:100%;object-fit:cover}
  /* The wrapper has to carry the box, or height:100% on the img resolves against auto. */
  .plate picture{display:block;width:100%;height:100%}
  /* The SoFi photo sits high in frame: the Oculus is about a third down the source, so a
     centred crop pushes it to the top of the plate. Anchoring the crop to the top of the
     image brings the ring onto the plate's own centre line. */
  .plate img.crop-top{object-position:center top}
  /* The Tom Bradley frame is mostly ceiling: the concourse, the counters and the signage all
     sit in the lower third, and a centred crop in a 1.89:1 plate throws them away. */
  .plate img.crop-low{object-position:center 72%}
  .plate figure::after{
    content:"";position:absolute;inset:0;pointer-events:none;z-index:1;
    background:linear-gradient(180deg,rgba(11,12,13,.72) 0%,rgba(11,12,13,.12) 30%,rgba(11,12,13,.28) 56%,rgba(11,12,13,.94) 100%);
  }
  .refmark{position:absolute;right:var(--pad);bottom:9px;z-index:3;font-size:10px;
    letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.58)}
  .plate-copy{position:absolute;left:var(--pad);right:var(--pad);bottom:clamp(28px,3.4vw,46px);
    z-index:2;max-width:34ch}
  .plate-copy h3{font-weight:600;font-size:clamp(21px,2.1vw,32px);letter-spacing:-.022em;line-height:1.14}
  .plate-copy p{margin-top:12px;color:var(--plate-ink);font-size:clamp(15.5px,1.15vw,18px);
    max-width:46ch;line-height:1.62}

  .strip{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--gold);
    background:var(--ground);position:relative;z-index:4}
  .strip div{padding:20px 22px 24px;border-left:1px solid var(--hair);min-width:0}
  .strip div:first-child{border-left:0;padding-left:var(--pad)}
  .strip div:last-child{padding-right:var(--pad)}
  .strip dt{font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;color:var(--dim);
    margin-bottom:8px;font-weight:500}
  .strip dd{font-size:clamp(15px,1.2vw,18px);font-weight:500;letter-spacing:-.01em}
  /* Three cells rather than four. The Edge Padding Rule still holds: the first and last cell
     take --pad on their outer side, which is already written against :first-child and
     :last-child and so needs no per-count version. */
  .strip--3{grid-template-columns:repeat(3,1fr)}
  /* A strip only had one row until the certifications page took six cells, and the
     first-child and last-child rules were standing in for "starts a row" and "ends a row".
     With two rows the fourth cell carried a left border against nothing and sat 50px
     inside the page gutter that the first cell respects. Counting by threes fixes both and
     changes nothing for the three-cell strips on the project plates, where 3n+1 and 3n
     still resolve to the first and last. */
  .strip--3 div:nth-child(3n+1){border-left:0;padding-left:var(--pad)}
  .strip--3 div:nth-child(3n){padding-right:var(--pad)}
  .strip--3 div:nth-child(n+4){border-top:1px solid var(--hair)}

  /* ---------- SECTIONS ---------- */
  section{padding-block:clamp(52px,5.6vw,88px)}
  /* A bare p.lead (the closing contact block on every page) only ever inherited the 16px body
     step, which left it smaller than the section leads above it. It joins the same ramp. */
  .lead{max-width:62ch}
  p.lead{color:var(--muted);font-size:clamp(16.5px,1.35vw,20px);line-height:1.64;max-width:56ch}
  div.lead,.work-head{text-align:center;max-width:none;margin-inline:auto}
  div.lead h2,.work-head h2{max-width:16ch;margin-inline:auto}
  /* One step up from body: against a 144px heading the body step reads as a caption. */
  /* text-wrap:pretty keeps a single word off the last line, which a centred lead makes
     glaring. It is a guard, not a substitute for copy that fits. */
  div.lead p{max-width:60ch;margin-inline:auto;font-size:clamp(17px,1.5vw,22px);
    margin-top:clamp(20px,1.9vw,30px);text-wrap:pretty}
  h2{font-weight:600;font-size:clamp(38px,10vw,144px);line-height:0.98;letter-spacing:-.038em;
    text-wrap:balance}
  .lead p{margin-top:24px;color:var(--muted);font-size:clamp(16.5px,1.35vw,20px);max-width:66ch}
  /* 26px left only 73px between the headline ink and the top of the plate, because a 144px
     headline at 0.98 line height already eats most of it in descender space. The equivalent
     gap on the projects page is 117px; this now matches. */
  .work-head{padding-bottom:clamp(40px,5vw,84px)}
  #work{position:relative;background:var(--ground)}
  .plate--work + .plate--work{margin-top:clamp(44px,5vw,76px)}

  .lineage{display:grid;grid-template-columns:repeat(3,1fr);margin-top:clamp(36px,4.2vw,60px)}
  .era{padding:30px 30px 34px;border-left:1px solid var(--hair)}
  .era:first-child{border-left:0;padding-left:0}
  .era .yr{font-size:12px;letter-spacing:.08em;color:var(--dim);font-weight:500;display:block;margin-bottom:16px}

  /* ---------- BUILT FOR COMPLEX WORK ----------
     A credibility band between the work and the scopes, asked for by the client's CFO.

     What this section needed was not a better arrangement of five labels. It was the
     badge, which is not a logo but a seal: it carries a licence number, a telephone and a
     domain around its rim. So the seal sits whole at the right and the five facts stand
     as Honor wrote them. A second line carrying the evidence behind each fact was tried
     and taken out on 2026-09-22: she asked for five labels and did not ask for that.

     The seal is a grid cell rather than an absolutely positioned decoration. It was
     cropped by the section edge first, and bringing it in whole at the client's direction
     meant it had to align to the wrap's right margin like everything else on the page,
     which a box positioned against the viewport cannot do. */

  /* The seam is lifted a seam's height into whatever sits above it, and what sits above
     this one is the specification strip under the Intuit plate. At the section's default
     foot the light notch bit 54px into that strip's type. #services carries the room for
     How we work's seam for the same reason; #work now carries it for this one. */
  #work{padding-bottom:clamp(200px,14vw,240px)}
  /* Both of these are desktop figures that a phone inherited whole. The head clears the
     hero's seam at 52px on a 1440px screen, where the seam is a shallow notch across a wide
     page; on a 390px screen the same 52px is a seventh of the viewport before the section
     says what it is. The foot carries the 64px seam plus room for the light panel to arrive,
     and 200px of that on a phone reads as the page having ended. */
  @media (max-width:760px){
    #work{padding-top:28px;padding-bottom:132px}
  }

  #credibility{position:relative;padding-block:clamp(104px,12vw,180px)}
  .band-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,auto);
    gap:clamp(40px,7vw,124px);align-items:center}
  .band-copy{max-width:min(100%,640px)}
  .band-seal img{width:clamp(300px,34vw,580px);height:auto;display:block}
  .band-head{font-weight:700;font-size:clamp(31px,3.7vw,54px);line-height:1.03;
    letter-spacing:-.028em;margin:0 0 clamp(30px,3.6vw,48px);max-width:14ch}
  .band{list-style:none;margin:0;padding:0}
  .band li{border-top:1px solid var(--hair-strong);padding:clamp(16px,1.9vw,26px) 0;
    font-weight:600;font-size:clamp(18px,1.9vw,27px);letter-spacing:-.018em}
  /* The section holds with its foot on the bottom of the window while What we do rides over
     it, so its heading, its content and its foot all have to fit one screen: 900px of window
     less 639px of band left 261px to divide between clearance under the fixed nav and white
     under the last row, and the split was 144 and 117. Of that 117 the arriving seam takes
     64, so the dark shape reached the last row 53px after it appeared.

     There is no way to buy the foot except from the other two, so this takes it from the
     band: 6px off each row and 8px off the heading, which is 68px and reads as the same
     rhythm at a glance. The foot is then set from the measured content in pin.js rather
     than from a clamp, because the amount available is the window less the band and only
     the window is known in advance. */
  @media (min-width:1081px){
    .band-head{margin-bottom:clamp(26px,2.8vw,40px)}
    .band li{padding:clamp(14px,1.45vw,20px) 0}
    /* pin.js publishes --cred-foot. The fallback is what the section had before, so the
       foot is never worse than it was if the script does not run. Two ids, to clear
       `#clients ~ section.panel-light:not(.pinned)`. */
    #clients ~ section#credibility{padding-bottom:var(--cred-foot,clamp(96px,15vh,196px))}
  }

  /* Below the two columns the seal leads, because a mark under a list it is meant to
     stamp reads as a footnote to it. */
  /* Stacks at 1080 rather than 900. At the seal's larger size the two columns stop
     coexisting well before 900: the copy is squeezed against a mark that is no longer
     small enough to sit beside it. */
  @media (max-width:1080px){
    .band-grid{grid-template-columns:1fr;gap:clamp(30px,5vw,44px);justify-items:start}
    .band-copy{max-width:100%;order:2}
    .band-seal{order:1}
    .band-seal img{width:clamp(200px,40vw,300px)}
    .band li{font-size:clamp(17px,4.2vw,22px)}
  }

  /* On a phone the stacked layout was the desktop one with the columns unstacked, and it
     showed. At 200px in a 335px column the seal stranded 135px of empty panel beside it
     and read as a logo dropped in a corner rather than a stamp pressed on the page.
     Taking it to about three quarters of the column makes the placement look chosen, and
     the foot comes back in to pay for the height that adds: the section measured 801px
     against an 812px viewport, so it filled the screen exactly and breathed nowhere.
     The padding rule has to out-rank `#clients ~ section.panel-light:not(.pinned)`. */
  @media (max-width:640px){
    #clients ~ section#credibility{
      padding-block:clamp(76px,9.5vw,104px) clamp(148px,19vw,190px)}
    .band-seal img{width:min(70vw,290px)}
    .band-grid{gap:clamp(24px,6vw,34px)}
    /* Centred on a phone at the client's direction. The grid sets justify-items:start for
       the copy, so the seal overrides it for itself rather than the row. */
    .band-seal{justify-self:center}
  }

  /* Between a phone and the two column layout the stack has the same fault the phone had,
     and worse: at 768 the seal caps at 300px against a 676px column and strands 376px of
     empty panel. There is enough width here to put the copy and the seal back beside each
     other, in the desktop order, which uses the room rather than leaving it. */
  @media (min-width:641px) and (max-width:1080px){
    .band-grid{grid-template-columns:minmax(0,1fr) minmax(0,auto);
      align-items:center;gap:clamp(30px,4.5vw,56px)}
    .band-copy{order:0;max-width:100%}
    .band-seal{order:0}
    .band-seal img{width:clamp(200px,30vw,300px)}
  }

  /* ---------- PORTRAITS ----------
     A held box at the head of an era or a leader, 4:5, hairline bordered on the plate well so
     it reads as a reserved place rather than a broken image. It carries its own label saying
     what belongs there, which is the only honest way to ship a gap: nothing here pretends to
     be a photograph. Swap the div for an <img> inside the same box when the file arrives, and
     the layout does not move. Every one of these must be filled or its block pulled before
     launch, per the rule that nothing unconfirmed appears as though it were confirmed. */
  .portrait{
    aspect-ratio:4/5;width:100%;max-width:188px;margin:0 0 22px;
    border:1px solid var(--hair);background:var(--plate-well);
    position:relative;
    display:flex;align-items:flex-end;padding:14px;overflow:hidden}
  /* The 14px padding is the label's inset, and a photograph should ignore it. It used to
     try, with a matching negative margin, but a negative margin moves a flex item without
     resizing it: the image stayed 160x207 and simply sat 14px left and high of where it
     had been, leaving the well showing down the right and along the bottom. Taking it out
     of flow instead fills the box whatever the padding is. */
  .portrait img{position:absolute;inset:0;width:100%;height:100%;
    object-fit:cover;display:block}
  .portrait span{
    font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;
    color:var(--dim);font-weight:500;line-height:1.5}

  /* ---------- OWNERSHIP TODAY ----------
     Deliberately not a fourth column on the lineage. That timeline is a family line of the
     trade, and reading current ownership into it would claim a succession nobody has stated.
     Honor described these as two separate things on the call: photographs of Leo and Tyson in
     the timeline, and "a little bio of me and Greg with our pictures" alongside it. */
  /* Two tracks of a fixed measure, centred in a full width grid rather than two half width
     columns. At 1fr each, the blocks sat at the left of their own halves and drifted away
     from the page centre, which read as lopsided under the three even bays of the lineage.
     The grid element stays full width so its top rule still spans the page. Each bay is a third of the wrap, the same width
     as an era above, and the divider between them is the same left hairline the eras carry. */
  .leaders{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
    gap:0;margin-top:clamp(28px,3.6vw,44px);
    border-top:1px solid var(--hair);padding-top:clamp(28px,3.4vw,40px)}
  .leader{padding:0 clamp(24px,3vw,52px)}
  .leader + .leader{border-left:1px solid var(--hair)}
  .leader h3{font-weight:600;font-size:clamp(20px,1.55vw,23px);letter-spacing:-.016em;margin:0 0 6px}
  .leader .role{display:block;font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;
    color:var(--dim);font-weight:500;margin-bottom:14px}
  .leader p{color:var(--muted);font-size:clamp(15.5px,1.15vw,17.5px);line-height:1.66;max-width:40ch;margin:0}
  /* ---------- OWNERSHIP INSIDE THE LINEAGE (homepage) ----------
     Identical to the About page block. It only needs the heading step the interior sections
     get from `.sector h2`, which the homepage's own h2 rule would otherwise blow up to 144px,
     and some air between it and the rail above. */
  .owners{margin-top:clamp(44px,6vh,86px)}
  .owners h2{font-size:clamp(27px,3.1vw,44px);line-height:1.06;letter-spacing:-.026em}

  @media (max-width:1080px){
    /* Four across stops holding a readable measure before the layout itself breaks, so the
       pair wraps to two rows and the divider moves with it. */
    /* Three people, so the two-up that used to sit here would leave one stranded on its
       own row. The three-up holds down to the phone instead, where it stacks. */
    .leaders{grid-template-columns:repeat(3,minmax(0,1fr));row-gap:clamp(30px,4vw,48px)}
  }
  @media (max-width:760px){
    .leaders{grid-template-columns:1fr;gap:36px;row-gap:36px}
    .leader{padding:0}
    .leader:nth-child(n+2){border-left:0;border-top:1px solid var(--hair);padding-top:36px}
    .leader:nth-child(odd){padding-left:0}
    .portrait{max-width:160px}
  }
  .era h3{font-weight:600;font-size:clamp(20px,1.55vw,23px);letter-spacing:-.016em;margin-bottom:10px}
  .era p{color:var(--muted);font-size:clamp(15.5px,1.15vw,17.5px);line-height:1.66;max-width:36ch}


  .creds{display:grid;grid-template-columns:repeat(6,1fr);
    margin-top:clamp(32px,3.6vw,52px);border-top:1px solid var(--hair)}
  .cred{padding:24px 19px 28px 19px;border-right:1px solid var(--hair)}
  .cred:nth-child(6n+1){padding-left:0}
  .cred:last-child{border-right:0}
  .cred dt{font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;color:var(--dim);
    margin-bottom:9px;font-weight:500}
  .cred dd{font-size:16px;font-weight:500;letter-spacing:-.01em}

  .certs{display:grid;grid-template-columns:repeat(3,1fr);border-top:1px solid var(--hair);
    margin-top:clamp(32px,3.6vw,52px)}
  /* subgrid so the paragraph, the meta divider and the unlocks note land on the same line
     across all three cards. Without it each card sizes independently and the internal rules
     stagger wherever the copy happens to break. The card carries one more row on the
     certifications page, where an unlocks note follows the meta. */
  .cert{padding:34px 34px 40px;border-left:1px solid var(--hair);
    display:grid;grid-template-rows:subgrid;grid-row:span 3;align-content:start}
  .cert:has(.unlocks){grid-row:span 4}
  .cert:first-child{border-left:0;padding-left:0}
  .cert h3{font-weight:600;font-size:clamp(19px,1.65vw,24px);letter-spacing:-.02em;margin-bottom:12px}
  .cert p{color:var(--muted);font-size:clamp(15.5px,1.15vw,17.5px);line-height:1.66;max-width:36ch}
  .cert-meta{margin-top:26px;border-top:1px solid var(--hair);padding-top:20px}
  .cert-meta > div{margin-bottom:14px}
  .cert-meta > div:last-child{margin-bottom:0}
  .cert-meta dt{font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;color:var(--dim);
    margin-bottom:5px;font-weight:500}
  .cert-meta dd{font-size:16.5px;font-weight:500;letter-spacing:-.01em}
  /* Data the client still has to confirm. Marked so it can never be read as verified. */
  .cert-meta dd.tbc{font-weight:400;color:var(--dim);font-style:italic;
    border-bottom:1px dotted var(--hair-strong);padding-bottom:3px;display:inline-block}


  #contact{border-top:1px solid var(--hair)}
  /* The contact heading sits in a column of the two-column contact grid, not on bare
     ground across the page, so it takes the display-plate step rather than the headline
     step. At 144px it broke to five lines in a 660px column and towered over the details
     beside it. */
  #contact h2{font-size:clamp(27px,3.1vw,44px);line-height:1.08;letter-spacing:-.026em;
    max-width:18ch}
  /* Left to itself this ran the full 1.2fr column and broke after "and", leaving a first
     line nearly twice the second. balance evens the two, and the ch cap keeps it from
     setting one very long line at widths where balance has nothing to work with. */
  #contact .lead{text-wrap:balance;max-width:52ch}
  .contact-grid{display:grid;grid-template-columns:1.2fr 1fr;gap:clamp(32px,6vw,90px);align-items:start}
  /* The closing block lost its right hand column when the footer took over the office details.
     One column left, so it stops pretending to be a two column grid and takes a measure. */
  .contact-grid--solo{grid-template-columns:minmax(0,62ch)}
  .callbtn{display:inline-block;margin-top:32px;padding:18px 34px;background:var(--gold);
    color:var(--ground);text-decoration:none;font-weight:600;font-size:clamp(17px,1.5vw,22px);
    transition:background .3s var(--ease),transform .3s var(--ease)}
  .callbtn:hover{background:var(--gold-lit);transform:translateY(-1px)}
  /* A way further in, not a call to action. It takes the nav CTA's language rather than the
     primary button's, because gold is spoken for: the Three Golds Rule gives it the strip
     hairline, the primary button and the focus ring, and a second gold button on the same
     page spends the one that closes it. */
  /* Only where the block it stands in for is hidden. */
  #certifications .morebtn{display:none}
  @media (max-width:760px){ #certifications .morebtn{display:inline-block} }
  .morebtn{display:inline-block;margin-top:clamp(34px,4vw,52px);padding:16px 30px;
    border:1px solid var(--hair-strong);color:var(--ink);text-decoration:none;
    font-size:11.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
    transition:border-color .3s var(--ease),background .3s var(--ease),color .3s var(--ease)}
  .morebtn:hover{border-color:var(--gold);background:var(--gold);color:var(--ground)}
  .contact-meta dt{font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;color:var(--dim);
    margin-bottom:8px;font-weight:500}
  .contact-meta dd{font-size:17px;margin-bottom:26px;color:#D9DCDF}
  /* Each label and value is wrapped as a pair so the list can go two up on a phone.
     Flat, a dl in a two-column grid puts the label beside its own value instead. */
  .contact-meta > div:last-child dd{margin-bottom:0}
  .contact-meta a{text-decoration:none;border-bottom:1px solid var(--hair-strong);
    transition:border-color .3s var(--ease)}
  .contact-meta a:hover{border-color:var(--gold)}
  footer{position:relative;z-index:2;background:var(--ground);
    border-top:1px solid var(--hair);padding-block:clamp(44px,5vw,72px) 44px}

  /* ---------- FOOTER ----------
     Four bays: the mark, the work, the company, and how to reach the office. Links are set
     at reading size rather than at the 12.5px of the legal row underneath, because a footer
     nobody can read is decoration. The legal row keeps its own smaller step and its rule. */
  .footgrid{display:grid;grid-template-columns:1.7fr 1fr 1fr 1.15fr;
    gap:clamp(28px,3.6vw,64px);
    padding-bottom:clamp(34px,4vw,52px);
    border-bottom:1px solid var(--hair);margin-bottom:clamp(24px,2.6vw,34px)}
  /* The chief badge alone, at a size where its interior detail actually reads. The wordmark
     came off: the footer sits under a page that has already said the name several times, and
     the mark is the firm's most distinctive asset. It carries the alt text now. */
  .foot-mark{display:inline-block;text-decoration:none;line-height:0}
  .foot-mark img{width:clamp(96px,9vw,132px);height:auto;display:block}
  .foot-brand p{color:var(--muted);font-size:15px;line-height:1.6;margin:18px 0 0;max-width:34ch}
  .foot-col h4{font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;
    color:var(--dim);font-weight:500;margin:0 0 15px}
  .foot-col a{display:block;color:var(--muted);text-decoration:none;font-size:15px;
    padding:5px 0;transition:color .25s var(--ease)}
  .foot-col a:hover{color:var(--ink)}
  .foot-col a:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
  .foot-col p{color:var(--muted);font-size:15px;line-height:1.6;margin:0 0 12px}
  .foot-social{display:flex;gap:20px;margin-top:14px}
  .foot-social a{display:inline-block;padding:0;border-bottom:1px solid var(--hair-strong)}

  @media (max-width:980px){
    .footgrid{grid-template-columns:1fr 1fr;gap:clamp(28px,4vw,44px) clamp(24px,4vw,48px)}
    .foot-brand{grid-column:1 / -1}
  }
  @media (max-width:560px){
    .footgrid{grid-template-columns:1fr;gap:32px}
    .foot-brand{grid-column:auto}
  }

  /* ---------- TRACE FIELD ----------
     The hero's field restated around the closing call to action, so the page opens inside
     it and closes inside it. Traces fill the whole section and run off every edge, current
     travels through them, and the copy sits on top. Same routed() grammar as the hero grid
     and the two seams.

     An earlier version was a 96px strip above the copy. It was rejected: a strip is a
     decorated divider, not an environment, and "like the hero" means the content sits
     inside the field rather than beneath a pattern. */
  #contact{position:relative;overflow:hidden}
  #contact > .wrap{position:relative;z-index:1}
  .circuit{position:absolute;inset:0;z-index:0;pointer-events:none}
  .circuit-grid,.circuit-pulse{position:absolute;inset:0;width:100%;height:100%;display:block}
  .circuit-trace{fill:none;stroke:var(--trace-line);stroke-width:1.1;
    vector-effect:non-scaling-stroke;opacity:.42}
  /* Pulses ride canvas, not SVG. Full-section paths with stacked drop-shadow filters would
     be a dozen full-size gaussian blurs a frame; the hero was rewritten off SVG for exactly
     this and the same maths applies here. */
  .circuit-pulse{opacity:.9}
  @media (prefers-reduced-motion:reduce){
    .circuit-pulse{display:none!important}
  }
  .foot{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;font-size:12.5px;color:var(--dim)}
  /* The three licence numbers are separate elements rather than one string, so a phone can
     space them across the row. On a wide footer they read as one run and the separator is
     drawn between them instead. */
  .foot-lic i{font-style:normal}
  /* Pipes rather than a middot, at Honor's request, and set at hairline weight so the
     separator reads as a rule between the numbers rather than as another character. */
  .foot-lic i + i::before{content:"\00a0\00a0|\00a0\00a0";color:var(--hair-strong)}
  @media (max-width:760px){
    /* Two rows. The company and where it is are one fact and belong on one line, at either
       end of it; the licence numbers take the whole of the next line and space themselves
       across it, which is the same full-width even division the specification strips use. */
    .foot{display:grid;grid-template-columns:1fr auto;gap:15px 20px}
    .foot > span:nth-child(1){grid-area:1/1}
    .foot > span:nth-child(3){grid-area:1/2;text-align:right}
    .foot-lic{grid-area:2/1/3/3;display:flex;justify-content:space-between;gap:10px}
    .foot-lic i + i::before{content:none}
  }

  /* ---------- SCROLL REVEAL ---------- */
  .plate--work{opacity:0;transform:translateY(72px)}
  .plate--work.on{opacity:1;transform:none;
    transition:opacity 1s var(--ease),transform 1.15s var(--ease)}
  .plate--work img{filter:brightness(.10) contrast(1.28) saturate(.3);transform:scale(1.16)}
  .plate--work.on img{filter:brightness(.62) contrast(1.04) saturate(.92);transform:scale(1);
    transition:filter 1.9s var(--ease) .18s,transform 2.2s var(--ease)}
  .plate--work .strip{border-top-color:transparent}
  .plate--work .strip::before{content:"";position:absolute;top:-1px;left:0;right:0;height:1px;
    background:var(--gold);transform:scaleX(0);transform-origin:left}
  .plate--work.on .strip::before{transform:scaleX(1);transition:transform 1.05s var(--ease) .5s}
  .plate--work .plate-copy,.plate--work .strip div{opacity:0;transform:translateY(18px)}
  .plate--work.on .plate-copy,.plate--work.on .strip div{opacity:1;transform:none;
    transition:opacity .85s var(--ease),transform .85s var(--ease)}
  .plate--work.on .plate-copy{transition-delay:.42s}
  .plate--work.on .strip div:nth-child(1){transition-delay:.62s}
  .plate--work.on .strip div:nth-child(2){transition-delay:.70s}
  .plate--work.on .strip div:nth-child(3){transition-delay:.78s}
  .plate--work.on .strip div:nth-child(4){transition-delay:.86s}
  /* At three cells the third is the last one, so it takes the closing delay. */
  .plate--work.on .strip--3 div:nth-child(3){transition-delay:.86s}
  .inview{opacity:0;transform:translateY(18px)}
  .inview.on{opacity:1;transform:none;transition:opacity .85s var(--ease),transform .85s var(--ease)}

  /* ---------- RESPONSIVE ---------- */
  /* Row starts have to shed their left padding at every column count, so the count is
     fixed per breakpoint rather than left to auto-fit. */
  @media (max-width:1400px){
    .creds{grid-template-columns:repeat(3,1fr)}
    .cred{border-top:1px solid var(--hair)}
    .cred:nth-child(-n+3){border-top:0}
    .cred:nth-child(6n+1){padding-left:19px}
    .cred:nth-child(3n+1){padding-left:0}
    .cred:nth-child(3n){border-right:0}
  }
  @media (max-width:900px){
    .creds{grid-template-columns:repeat(2,1fr)}
    .cred:nth-child(-n+3){border-top:1px solid var(--hair)}
    .cred:nth-child(-n+2){border-top:0}
    .cred:nth-child(3n+1),.cred:nth-child(6n+1){padding-left:19px}
    .cred:nth-child(2n+1){padding-left:0}
    .cred:nth-child(3n){border-right:1px solid var(--hair)}
    .cred:nth-child(2n){border-right:0}
  }

  @media (max-width:1000px){
    .contact-grid,.certs,.lineage{grid-template-columns:1fr}
    .era,.cert{border-left:0;border-top:1px solid var(--hair);padding:26px 0 30px}
    .era:first-child,.cert:first-child{border-top:0;padding-top:0}
  }
  @media (max-width:760px){
    .navlinks a:not(.navcta){display:none}
    .strip{grid-template-columns:repeat(2,1fr)}
    .strip div{border-left:1px solid var(--hair);border-top:1px solid var(--hair);padding:16px 16px 18px}
    .strip div:first-child,.strip div:nth-child(3){border-left:0;padding-left:var(--pad)}
    .strip div:nth-child(-n+2){border-top:0}
    /* Square on a phone, against a separate square file. A 3:2 photograph poured into a
       portrait box loses about half its width, and the subject goes with it: the Intuit Dome
       sign and the LAX letters both sit off centre and both fall outside a centred crop.
       The mobile files are cropped deliberately, one window chosen per photograph, so the
       box and the file are the same shape and object-fit has nothing left to cut. */
    .plate figure{height:auto;aspect-ratio:1}

    /* The homepage keeps all three certificates on a desktop, where there is room to read
       them beside each other. On a phone that block ran 1400px on its own, so it gives way to
       the button and the detail is read on the certifications page instead. */
    #certifications .certs{display:none}

    /* The office, the numbers and the links sit under the call on a phone, so they go two
       up rather than running down as four stacked records with the fold in the middle. */
    .contact-meta{display:grid;grid-template-columns:1fr 1fr;gap:24px 20px;
      margin-top:clamp(30px,6vw,44px)}
    .contact-meta dd{margin-bottom:0}

    /* Nothing pins on a phone. The panel is unpinned everywhere now, so this only carries
       the tighter foot. */
    #clients{padding-block:clamp(52px,6vh,80px) clamp(72px,9vh,112px)}

    /* One cell per row. Three across is unreadable at this width and two leaves an orphan. */
    .strip--3{grid-template-columns:1fr}
    .strip--3 div:nth-child(n){border-left:0;border-top:1px solid var(--hair);
      padding:14px var(--pad) 16px}
    .strip--3 div:first-child{border-top:0}
    /* Paired rather than stacked. Six one-line records read as a block of six at two up and
       as a screenful of scrolling at one, and the values are short enough to hold half the
       width. nth-child selectors from the wider breakpoints out-rank a bare .cred, so these
       have to match their specificity or a stray indent survives. */
    .creds{grid-template-columns:repeat(2,1fr)}
    .cred:nth-child(n){border-right:1px solid var(--hair);border-bottom:1px solid var(--hair);
      padding:18px 14px 20px}
    .cred:nth-child(2n+1){padding-left:0}
    .cred:nth-child(2n){border-right:0;padding-right:0}
    .cred:nth-child(n+5){border-bottom:0}

    /* The three records under each certificate go two up for the same reason. Nine stacked
       rows across three certificates was most of the section's height. */
    .cert{padding:22px 0 26px}
    .cert-meta{margin-top:18px;padding-top:16px;
      display:grid;grid-template-columns:1fr 1fr;gap:13px 16px}
    .cert-meta > div{margin-bottom:0}
  }
  @media (prefers-reduced-motion:reduce){
    .logo img{opacity:1!important;transform:none!important}
    *{transition:none!important;animation:none!important}
    .ln i,.opening-sub,.plate--work,.plate--work .plate-copy,.plate--work .strip div,.inview,
    .opening-inner{opacity:1!important;transform:none!important}
    .c-draw{stroke-dashoffset:0!important}
    .c-bolt{opacity:1!important}
    .grid{opacity:1!important}
    .pulse{display:none!important}
    body.hero-live .nav{opacity:1!important;transform:none!important;pointer-events:auto!important;visibility:visible!important}
    .plate--work img{filter:brightness(.62) contrast(1.04) saturate(.92)!important;transform:none!important}
    .plate--work .strip::before{transform:scaleX(1)!important}
  }

  /* ---------- LEAD GRID ----------
     A faint gold rule grid behind one section heading. Not a fourth gold: it is the hero's
     trace grid held still, the same measured field the opening runs current through, which
     is why it belongs behind "What we do" and nowhere else.

     It runs the full page width and fades only at top and bottom. Anchored to the section
     at top:0 rather than centred on the heading, so it can never reach the light logo panel
     above; the section cannot clip it, because overflow:hidden on an ancestor would kill the
     sticky pin inside it. Width comes from the section, not 100vw, which would overshoot by
     the scrollbar and force a horizontal scroll. */
  #services{position:relative}
  #services > .wrap{position:relative;z-index:1}
  .lead-grid{
    position:absolute;left:0;right:0;top:-100px;z-index:0;pointer-events:none;
    height:clamp(500px,48vw,700px);
    background:
      repeating-linear-gradient(90deg,rgba(233,179,14,.26) 0 1px,transparent 1px 92px),
      repeating-linear-gradient(0deg,rgba(233,179,14,.26) 0 1px,transparent 1px 92px);
    /* Two masks intersected: a top-and-bottom fade, and a half-strength knockout under the copy so the
       rules read at half weight behind the type rather than vanishing. The knockout is sized to the visible text, not to the
       heading's box, which is the full wrap width and would leave nothing showing. Note the
       radii: radial-gradient percentages resolve against the whole box, not half of it, so
       36% of a 1440px grid is a 518px radius. The
       lead-in stays fully transparent past the 34px the grid sits above the section, so
       nothing reaches the light panel up there. */
    -webkit-mask-image:
      linear-gradient(180deg,
        transparent 0%,transparent 17%,rgba(0,0,0,.44) 24%,#000 31%,
        #000 70%,rgba(0,0,0,.52) 84%,rgba(0,0,0,.18) 93%,transparent 100%),
      radial-gradient(ellipse 36% 36% at 50% 58%,
        rgba(0,0,0,.32) 0%,rgba(0,0,0,.32) 80%,rgba(0,0,0,.74) 92%,#000 100%);
    mask-image:
      linear-gradient(180deg,
        transparent 0%,transparent 17%,rgba(0,0,0,.44) 24%,#000 31%,
        #000 70%,rgba(0,0,0,.52) 84%,rgba(0,0,0,.18) 93%,transparent 100%),
      radial-gradient(ellipse 36% 36% at 50% 58%,
        rgba(0,0,0,.32) 0%,rgba(0,0,0,.32) 80%,rgba(0,0,0,.74) 92%,#000 100%);
    -webkit-mask-composite:source-in;
    mask-composite:intersect;
  }
  /* Shorter on a phone: it stays behind the heading and the lead and stops there. Run down
     under the first square instead and it survives only as slivers in the side margins beside
     an opaque film, which reads as a stray rule rather than a field. Tried on 2026-08-09 and
     taken back out. */
  @media (max-width:760px){
    .lead-grid{height:clamp(320px,72vw,470px);
      background:
        repeating-linear-gradient(90deg,rgba(233,179,14,.26) 0 1px,transparent 1px 58px),
        repeating-linear-gradient(0deg,rgba(233,179,14,.26) 0 1px,transparent 1px 58px)}
  }

  /* ---------- SERVICE SCROLL ----------
     A square of film and the scope copy are both pinned to the middle of the window, so
     they never drift out of line with each other. Only the content changes as you scroll:
     copy cross-fades on the left, film cross-fades on the right, on the same centre line.
     The rail behind them supplies the scroll distance and carries the handover marks. */
  /* ---------- WHAT WE DO ----------
     Four scopes, each paired with its own film, stacked and scrolled. The pinned rail that
     held one frame and handed four films through it came out on 2026-09-02 at the client's
     direction: it was the second scroll-driven device on the page and it asked a reader to
     stay put while the page did the moving. The markup still separates copy from media, so
     the three wrappers go to display:contents and the pairs are ordered into a two column
     grid. Film left, copy right, all the way down. */
  .svc-scroll{position:relative;height:auto;margin-top:clamp(56px,8vw,124px)}
  .svc-pin{
    position:static;height:auto;padding-top:0;
    display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    column-gap:clamp(36px,5vw,96px);row-gap:clamp(64px,9vw,136px);
    align-items:center;
  }
  /* The wrappers stop being boxes so their children become grid items in their own right. */
  .svc-copy,.svc-media,.svc-frame{display:contents}

  .svc-step{grid-area:auto;opacity:1;pointer-events:auto;
    display:flex;flex-direction:column;justify-content:center}
  .svc-step h3{font-weight:600;font-size:clamp(30px,3.7vw,54px);line-height:1.04;
    letter-spacing:-.028em}
  .svc-step p{margin-top:clamp(16px,1.7vw,26px);color:var(--muted);
    font-size:clamp(17px,1.5vw,23px);line-height:1.6;max-width:42ch}

  .svc-slide{position:relative;inset:auto;transform:none;transition:none;
    aspect-ratio:4/3;overflow:hidden;background:#08090A;border:1px solid var(--hair)}
  .svc-slide img,.svc-slide video{width:100%;height:100%;object-fit:cover;display:block}
  .svc-slide video{filter:brightness(.86) contrast(1.04) saturate(.92)}

  /* Alternating: film left on rows one and three, copy left on rows two and four. The order
     values interleave the two wrappers into a single run of grid items, so a row is just the
     next two in that run. */
  .svc-slide[data-svc="0"]{order:0} .svc-step[data-svc="0"]{order:1}
  .svc-step[data-svc="1"]{order:2}  .svc-slide[data-svc="1"]{order:3}
  .svc-slide[data-svc="2"]{order:4} .svc-step[data-svc="2"]{order:5}
  .svc-step[data-svc="3"]{order:6}  .svc-slide[data-svc="3"]{order:7}

  @media (max-width:760px){
    /* One column, film above its own copy. Everything else is inherited from the base now
       that the base is stacked too: display:contents, the ordering and the reset transforms
       all live up there rather than being restated here. */
    .svc-pin{grid-template-columns:1fr;row-gap:0}
    /* One column, so alternation has nowhere to go: every film sits above its own copy. */
    .svc-slide[data-svc="0"]{order:0} .svc-step[data-svc="0"]{order:1}
    .svc-slide[data-svc="1"]{order:2} .svc-step[data-svc="1"]{order:3}
    .svc-slide[data-svc="2"]{order:4} .svc-step[data-svc="2"]{order:5}
    .svc-slide[data-svc="3"]{order:6} .svc-step[data-svc="3"]{order:7}
    .svc-slide{aspect-ratio:1/1}
    /* No foot scrim. It exists to hold copy off a bright frame, and here the copy is under
       the square rather than over it, so all it does is take 38% of a 375px film down by
       half. Three of the four films are dark to begin with: the low voltage one measures 42
       mean luminance mid-shot against the blueprint's 88, and the grade was set against the
       blueprint. Chrome generates the pseudo-element even under display:contents, so it is
       suppressed rather than repositioned. */
    .svc-slide::after{content:none}
    .svc-slide video{filter:brightness(.95) contrast(1.04) saturate(.94)}
    .svc-step{padding:clamp(18px,4.4vw,26px) 0 clamp(40px,9vw,62px)}
    .svc-step:last-child{padding-bottom:0}
    .svc-step p{margin-top:13px}
  }

  /* ---------- SUB-PAGE HEAD ----------
     Interior pages get no film. The head is the same centred heading axis as a homepage
     section, sized down one step so it reads as a page title rather than a second hero. */
  .pagehead{padding-block:clamp(120px,14vh,190px) clamp(40px,5vw,68px)}
  /* The section rhythm assumes a section arriving after other content. Straight under a page
     header it stacks on top of the header's own bottom padding, which put 215px between the
     lead and the first project on the index. The header supplies that space already. */
  .pagehead + section{padding-top:clamp(16px,1.8vw,28px)}
  .pagehead + section > .wrap > .pfilter:first-child{margin-top:0}
  .pagehead h1{font-weight:600;font-size:clamp(38px,10vw,144px);line-height:0.98;
    letter-spacing:-.038em;text-wrap:balance;max-width:16ch;margin-inline:auto;text-align:center}
  /* pretty, like the homepage leads: it holds back the last line so a lead cannot end on a
     two word stub, which a centred measure makes glaring. */
  .pagehead p{margin:24px auto 0;color:var(--muted);font-size:clamp(16.5px,1.35vw,20px);
    max-width:62ch;text-align:center;text-wrap:pretty}
  .navlinks a.here{color:var(--ink)}
  .navlinks a.here::after{transform:scaleX(1)}

  /* ---------- VALUE TILES ----------
     Two rows of three. Ruled cells, not cards: the grid is drawn with hairlines and the
     cells sit on the page ground, so this stays inside a system that has no raised
     surfaces, no radius and no shadows. The adjective is the heading, never a label above
     one, which the No Eyebrow Rule forbids. */
  .vals{display:grid;grid-template-columns:repeat(3,1fr);
    border-top:1px solid var(--hair);margin-top:clamp(36px,4.2vw,60px)}
  .val{padding:34px 34px 40px;border-left:1px solid var(--hair)}
  .val:nth-child(3n+1){border-left:0;padding-left:0}
  .val:nth-child(n+4){border-top:1px solid var(--hair)}
  .val h3{font-weight:600;font-size:clamp(19px,1.65vw,24px);letter-spacing:-.02em;margin-bottom:12px}
  .val p{color:var(--muted);font-size:clamp(15.5px,1.15vw,17.5px);line-height:1.66;max-width:36ch}

  @media (max-width:900px){
    .vals{grid-template-columns:repeat(2,1fr)}
    .val:nth-child(3n+1){border-left:1px solid var(--hair);padding-left:34px}
    .val:nth-child(2n+1){border-left:0;padding-left:0}
    .val:nth-child(n+3){border-top:1px solid var(--hair)}
  }
  /* Two up on a phone rather than one. Each commitment is a word and a single sentence, so
     stacked they made six tall blocks and a section a screen and a half long for six short
     facts. Paired, the whole set is three rows and can be taken in at once, which is what a
     list of commitments is for. The type drops a step to hold a workable measure in half the
     width. Nothing is cut: the same six, the same sentences. */
  @media (max-width:620px){
    .vals{grid-template-columns:repeat(2,1fr)}
    .val:nth-child(n){border-left:1px solid var(--hair);padding:20px 0 22px 17px}
    .val:nth-child(2n+1){border-left:0;padding-left:0}
    .val:nth-child(n+3){border-top:1px solid var(--hair)}
    .val:nth-child(-n+2){border-top:0}
    .val h3{font-size:18.5px;margin-bottom:8px}
    .val p{font-size:15px;line-height:1.58}
  }

  /* ---------- RECORD ----------
     A prequalification reviewer is filling in a form. This is that form, already filled:
     label left, value right, one hairline per row, copy-pasteable. */
  .record{border-top:1px solid var(--hair);margin-top:clamp(32px,3.6vw,52px)}
  .record > div{display:grid;grid-template-columns:minmax(180px,1fr) 2fr;
    gap:clamp(20px,4vw,64px);padding:20px 0 22px;border-bottom:1px solid var(--hair);
    align-items:baseline}
  .record dt{font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;color:var(--dim);
    font-weight:500}
  .record dd{font-size:16px;font-weight:500;letter-spacing:-.01em}
  .record dd small{display:block;margin-top:6px;font-size:15px;font-weight:400;
    letter-spacing:0;color:var(--muted);max-width:62ch}
  .record dd.tbc{font-weight:400;color:var(--dim);font-style:italic;
    border-bottom:1px dotted var(--hair-strong);padding-bottom:3px;display:inline-block}

  /* A build state, not a design flourish: it tells the client exactly what we still need. */
  .pending-note{margin-top:clamp(40px,5vw,68px);padding:18px 22px;
    border:1px solid var(--hair);border-left:1px solid var(--gold);
    color:var(--muted);font-size:clamp(15.5px,1.15vw,17.5px);max-width:78ch}

  .unlocks{margin-top:18px;padding-top:16px;border-top:1px solid var(--hair);
    color:var(--plate-ink);font-size:clamp(15.5px,1.15vw,17.5px);line-height:1.66;max-width:40ch}
  .unlocks b{display:block;font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;
    color:var(--dim);font-weight:500;margin-bottom:7px}

  @media (max-width:760px){
    .record > div{grid-template-columns:1fr;gap:8px}
  }

  /* ---------- ENQUIRY FORM ----------
     Fields are hairlines, not boxes: the same structural device as everything else, so the
     form reads as part of the page rather than a widget dropped into it. Gold appears once,
     on focus, which is a role it already holds. */
  .form-grid{display:grid;grid-template-columns:1.35fr .65fr;gap:clamp(32px,6vw,96px);
    align-items:start}
  .field-row{display:grid;grid-template-columns:1fr 1fr;gap:clamp(20px,3vw,44px)}
  .field{margin-bottom:clamp(22px,2.4vw,32px)}
  .field label{display:block;font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;
    color:var(--dim);font-weight:500;margin-bottom:10px}
  .field input,.field select,.field textarea{
    width:100%;background:transparent;color:var(--ink);
    font-family:inherit;font-size:16px;line-height:1.5;
    border:0;border-bottom:1px solid var(--hair);border-radius:0;
    padding:6px 0 12px;appearance:none;
    transition:border-color .3s var(--ease)}
  .field textarea{resize:vertical;min-height:120px}
  /* A file input inherits the shared field rule, which strips its chrome and leaves a bare
     unstyled control. The button is given the same treatment as the nav call button so the
     one place on the site that asks for an upload still looks like the rest of it. */
  .field input[type="file"]{
    font-size:14.5px;color:var(--muted);padding:0 0 12px}
  .field input[type="file"]::file-selector-button{
    font-family:inherit;font-size:11.5px;font-weight:600;letter-spacing:.15em;
    text-transform:uppercase;color:var(--ink);background:transparent;
    border:1px solid var(--hair-strong);border-radius:0;
    padding:11px 18px;margin-right:16px;cursor:pointer;
    transition:border-color .3s var(--ease),background .3s var(--ease),color .3s var(--ease)}
  .field input[type="file"]::file-selector-button:hover{
    border-color:var(--gold);background:var(--gold);color:var(--ground)}
  .field-note{font-size:12.5px;color:var(--dim);margin:10px 0 0;line-height:1.5}
  /* The role list on Careers. Titles, not prose, so they read as a set at a glance. */
  /* A fixed count rather than auto-fit. With auto-fit the number of columns changed with
     the window, so there was no way to say which cell begins a row: :first-child fixed the
     very first one and every other row-start kept a left border with nothing beside it.
     Seven roles over four columns is four and three, which leaves one gap at the end and
     is the tidiest a prime number gets. Four also gives Assistant Project Manager enough
     width to sit on one line, which it did not have at six across. */
  .roles{list-style:none;padding:0;margin:22px 0 0;
    display:grid;grid-template-columns:repeat(4,1fr);
    border-top:1px solid var(--hair)}
  .roles li{border-bottom:1px solid var(--hair);border-left:1px solid var(--hair);
    padding:15px clamp(12px,1.5vw,20px);font-size:16.5px;font-weight:500;color:var(--ink)}
  .roles li:nth-child(4n+1){border-left:0}
  .roles li:nth-child(n+5){border-top:1px solid var(--hair)}
  /* Seven titles over four columns leaves the last row a cell short, so the bottom rule
     stopped three quarters of the way across and the last column divider ran out above it.
     The eighth cell is empty and closes the rectangle. It carries no text and is hidden
     from screen readers, so it draws the two lines and says nothing. It works at two
     columns as well, where eight is four even rows; at one column there is no rectangle
     to close and an empty row would read as a missing title, so it goes. */
  .roles-gap{min-height:0}
  @media (max-width:1000px){
    .roles{grid-template-columns:repeat(2,1fr)}
    .roles li:nth-child(n){border-left:1px solid var(--hair);border-top:0}
    .roles li:nth-child(2n+1){border-left:0}
  }
  @media (max-width:760px){
    .roles{grid-template-columns:1fr}
    .roles li:nth-child(n){border-left:0;padding-left:0;padding-right:0}
    .roles-gap{display:none}
  }
  .field input::placeholder,.field textarea::placeholder{color:var(--dim)}
  .field input:hover,.field select:hover,.field textarea:hover{border-bottom-color:var(--hair-strong)}
  .field input:focus,.field select:focus,.field textarea:focus{
    outline:none;border-bottom-color:var(--gold)}
  /* The select needs its own mark: appearance:none removes the platform arrow. */
  .field select{background-image:linear-gradient(45deg,transparent 50%,var(--dim) 50%),
    linear-gradient(135deg,var(--dim) 50%,transparent 50%);
    background-position:calc(100% - 9px) 15px,calc(100% - 4px) 15px;
    background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:26px}
  .field select option{background:var(--ground);color:var(--ink)}

  /* The form sat straight under the lead with nothing between them, so the first field
     label read as the last line of the paragraph. */
  .form{margin-top:clamp(40px,4.6vw,66px)}
  .form .callbtn{margin-top:8px;border:0;cursor:pointer;font-family:inherit}
  .form-status{margin-top:18px;font-size:14.5px;color:var(--dim);max-width:52ch;opacity:0;
    transition:opacity .3s var(--ease)}
  .form-status.on{opacity:1}

  .form-aside{border-left:1px solid var(--hair);padding-left:clamp(24px,3vw,48px)}
  .aside-note{margin-top:30px;color:var(--muted);font-size:clamp(15.5px,1.15vw,17.5px);line-height:1.66;max-width:36ch}

  @media (max-width:900px){
    .form-grid{grid-template-columns:1fr;gap:clamp(40px,7vw,64px)}
    .form-aside{border-left:0;border-top:1px solid var(--hair);padding-left:0;
      padding-top:clamp(28px,5vw,44px)}
  }
  @media (max-width:620px){
    .field-row{grid-template-columns:1fr;gap:0}
  }

  /* ===== projects page ===== */
  /* Eleven projects on one page. Running eleven full-bleed plates down it would read as a
     slideshow, so the page carries three treatments and picks by how much the project and
     its photograph can actually hold: a plate for the landmark jobs, a card for the ones
     with a usable image, a hairline row for the ones with none. */

  .sector-head{
    display:flex;align-items:baseline;justify-content:space-between;gap:clamp(20px,3vw,48px);
    border-top:1px solid var(--hair);padding-top:20px;margin-bottom:clamp(26px,3vw,42px);
  }
  /* Display-plate, the documented step for a heading that is not the subject of the page.
     Five sector titles at the 144px headline step would each announce themselves as that
     subject, and none of them is: the h1 is. This was briefly its own near-identical step
     at 42px, which is the drift the ramp exists to prevent. */
  .sector h2{font-size:clamp(27px,3.1vw,44px);line-height:1.06;letter-spacing:-.026em;max-width:none}
  .sector-head span{color:var(--dim);font-size:14px;letter-spacing:.01em;text-align:right;flex:0 1 auto}
  .sector .plate{margin-block:clamp(32px,3.6vw,52px)}

  /* SoFi is one client and five packages, not five projects. Splitting it into five plates
     would inflate the count; this states the packages without pretending they are separate
     jobs. Leading zeros because these are a set, not a ranking. */
  .scopes{
    display:grid;grid-template-columns:repeat(4,1fr);list-style:none;
    border-top:1px solid var(--hair);margin-top:clamp(30px,3.4vw,48px);counter-reset:scope;
  }
  .scopes li{padding:22px 22px 28px;border-left:1px solid var(--hair);counter-increment:scope}
  .scopes li:first-child{border-left:0;padding-left:0}
  .scopes li::before{
    content:counter(scope,decimal-leading-zero);display:block;
    font-size:10.5px;letter-spacing:.19em;color:var(--dim);margin-bottom:13px;font-weight:500;
  }
  .scopes h4{font-weight:600;font-size:clamp(18px,1.4vw,20px);letter-spacing:-.014em;margin-bottom:9px}
  .scopes p{color:var(--muted);font-size:clamp(15.5px,1.15vw,17.5px);line-height:1.66}

  .jobs{display:grid;gap:clamp(20px,2.4vw,34px);margin-top:clamp(30px,3.4vw,48px)}
  .jobs--two{grid-template-columns:repeat(2,1fr)}
  .jobs--three{grid-template-columns:repeat(3,1fr)}
  .job{margin:0;display:grid;grid-template-rows:auto 1fr}
  /* The source photographs are the client's own and vary widely in exposure. The same grade
     the plates carry pulls them onto one ground so a grid of them reads as one set. */
  .job img{
    width:100%;aspect-ratio:16/10;object-fit:cover;display:block;background:#08090A;
    filter:brightness(.86) contrast(1.03) saturate(.92);
  }
  /* Federal and military work is not photographed. The slot holds its place rather than
     collapsing, so the caption still lines up with the job beside it and the absence reads
     as a fact about the sector instead of a layout accident. */
  /* outline, not border: a border participates in layout and pushed this frame a few pixels
     off the photograph beside it, which threw the two captions out of line across the row. */
  .job--noimg::before{
    content:"";display:block;width:100%;aspect-ratio:16/10;
    outline:1px solid var(--hair);outline-offset:-1px;
    background:repeating-linear-gradient(135deg,transparent 0 12px,rgba(255,255,255,.02) 12px 24px);
  }
  .job figcaption{
    border-top:1px solid var(--hair);margin-top:17px;padding-top:17px;
    color:var(--muted);font-size:clamp(15.5px,1.15vw,17.5px);line-height:1.66;
  }
  .job figcaption b{
    display:block;color:var(--ink);font-weight:600;font-size:clamp(18px,1.4vw,20px);
    letter-spacing:-.012em;margin-bottom:8px;
  }
  .job figcaption small{
    display:block;margin-top:11px;font-size:10.5px;letter-spacing:.19em;
    text-transform:uppercase;color:var(--dim);
  }

  /* Thirty tenants at five across is exactly six rows, so the block closes square. */
  .roster{
    display:grid;grid-template-columns:repeat(5,1fr);list-style:none;
    border-top:1px solid var(--hair);margin-top:clamp(26px,2.8vw,40px);
  }
  .roster li{
    padding:13px 16px 14px;border-bottom:1px solid var(--hair);border-left:1px solid var(--hair);
    font-size:clamp(15.5px,1.15vw,17.5px);color:var(--muted);
  }
  .roster li:nth-child(5n+1){border-left:0;padding-left:0}

  @media (max-width:1000px){
    .jobs--three,.jobs--two{grid-template-columns:1fr}
    .scopes{grid-template-columns:repeat(2,1fr)}
    .scopes li:nth-child(odd){border-left:0;padding-left:0}
    .scopes li:nth-child(n+3){border-top:1px solid var(--hair)}
    .roster{grid-template-columns:repeat(3,1fr)}
    .roster li:nth-child(n){border-left:1px solid var(--hair);padding-left:16px}
    .roster li:nth-child(3n+1){border-left:0;padding-left:0}
  }
  @media (max-width:620px){
    .sector-head{display:block}
    .sector-head span{display:block;text-align:left;margin-top:9px}
    .scopes{grid-template-columns:1fr}
    .scopes li:nth-child(n){border-left:0;padding-left:0;border-top:1px solid var(--hair)}
    .scopes li:first-child{border-top:0}
    .roster{grid-template-columns:repeat(2,1fr)}
    .roster li:nth-child(n){border-left:1px solid var(--hair);padding-left:16px}
    .roster li:nth-child(2n+1){border-left:0;padding-left:0}
  }

  /* A photograph whose subject runs top to bottom cannot take a full-bleed plate: the plate
     is close to 2:1 and this frame is 4:3, so a cover crop loses the crew at the top and the
     shield on the turf at the bottom, which is the whole picture. Contained, beside its copy,
     it keeps its own shape. */
  .feature{
    display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);
    gap:clamp(28px,4vw,68px);align-items:center;margin-top:clamp(30px,3.4vw,48px);
  }
  .feature figure{margin:0;overflow:hidden;background:#08090A}
  .feature img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;
    filter:brightness(.88) contrast(1.03) saturate(.94)}
  /* Title, the same step a project name takes inside a plate. It sits beside the photograph
     here rather than over it, but it is the same kind of thing and takes the same step. */
  .feature-copy h3{font-weight:600;font-size:clamp(21px,2.1vw,32px);letter-spacing:-.022em;
    line-height:1.14}
  .feature-copy > p{margin-top:16px;color:var(--muted);font-size:clamp(15px,1.2vw,18px);
    line-height:1.6;max-width:44ch}
  .feature-meta{margin-top:clamp(24px,2.6vw,36px);border-top:1px solid var(--hair)}
  .feature-meta > div{padding:15px 0;border-bottom:1px solid var(--hair)}
  .feature-meta dt{font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;
    color:var(--dim);margin-bottom:7px;font-weight:500}
  .feature-meta dd{font-size:17px;color:var(--ink);max-width:40ch}

  @media (max-width:900px){
    .feature{grid-template-columns:1fr;gap:clamp(22px,4vw,34px)}
    .feature-copy > p{max-width:none}
  }

  /* One upcoming project does not justify a data table. A hairline note states it and moves on. */
  /* The rule spans its container and the measure is capped on the text inside it. Capping the
     element instead left a half-width hairline under a full-width layout, and in a page this
     dependent on hairlines a rule that stops early reads as arbitrary. */
  .sector-note{border-top:1px solid var(--hair);margin-top:clamp(30px,3.4vw,48px);padding-top:18px}
  .sector-note p{color:var(--muted);font-size:clamp(15.5px,1.15vw,17.5px);line-height:1.66;max-width:74ch}
  .sector-note b{color:var(--ink);font-weight:600}

  /* The note takes the third cell of the federal row rather than sitting under it. It is
     there to answer the empty frame beside it, so it belongs on the same line as the answer. */
  /* Reserves the height the photograph would have taken, so the note's rule lands on the same
     line as the two figcaption rules beside it. Without it the row carries two rule heights,
     which in a page held together by hairlines reads as a mistake. */
  .job--note{display:grid;grid-template-rows:auto 1fr}
  .job--note::before{content:"";display:block;width:100%;aspect-ratio:16/10}
  .job--note p{
    border-top:1px solid var(--hair);margin-top:17px;padding-top:17px;
    color:var(--muted);font-size:clamp(15.5px,1.15vw,17.5px);line-height:1.66;
  }
  .job--note b{display:block;color:var(--ink);font-weight:600;font-size:17px;
    letter-spacing:-.008em;margin-bottom:9px}

  /* Prose that introduces a sector, not a centred section headline block. It sits between a
     full-bleed plate and a left-aligned list, so centring it breaks both edges. */
  .sector-lead{
    max-width:60ch;color:var(--muted);line-height:1.64;
    font-size:clamp(16.5px,1.35vw,20px);margin-top:clamp(26px,3vw,42px);
  }

  /* ===== certifications page ===== */
  /* Scoped to the two record tables on certifications.html. Nothing in this block changes
     the homepage's copy of the component.

     The shared row is `minmax(180px,1fr) 2fr`. On a page whose labels are all short that
     resolves to a 413px label track against 211px of longest label ink at 1440, so every
     row opened with 260px of nothing before its value and nineteen rows of it read as a
     ribbon rather than as a document. The track is capped instead: wide enough for the
     longest label with slack, and no wider. */
  #firm .record > div,
  #requested .record > div{
    grid-template-columns:minmax(180px,312px) minmax(0,1fr);
    column-gap:clamp(24px,3vw,48px);
  }

  /* Above 1160 the explanation moves out from under the value and into a column of its
     own, so the value column can be read straight down without notes breaking it, and the
     row carries ink across the full measure instead of trailing off after a third of it.
     Anonymous grid items do the split: the bare value text is one item, the <small> the
     other. Below 1160 there is not enough room for three tracks and it stacks as before. */
  @media (min-width:1160px){
    #firm .record dd:has(small){
      display:grid;grid-template-columns:minmax(0,.82fr) minmax(0,1fr);
      column-gap:clamp(28px,2.8vw,44px);align-items:baseline;
    }
    #firm .record dd:has(small) small{margin-top:0;max-width:none}
  }

  /* Below 1000 the three certification cards stack, and a 34ch paragraph down the left of
     an 810px column left two thirds of every card empty. Stacked, the card turns on its
     side instead: the claim and what it earns on the left, the certificate data in a ruled
     column on the right. The rule that separated the two horizontally becomes the rule
     that separates them vertically, so it is the same device doing the same job.
     `:has(.unlocks)` is the existing discriminator for this page's longer card, so the
     homepage's shorter one is untouched. */
  @media (min-width:560px) and (max-width:1000px){
    .cert:has(.unlocks){
      grid-template-rows:none;grid-row:auto;
      grid-template-columns:minmax(0,1fr) minmax(0,.78fr);
      column-gap:clamp(26px,4vw,52px);align-items:start;
    }
    .cert:has(.unlocks) > h3,
    .cert:has(.unlocks) > p,
    .cert:has(.unlocks) > .unlocks{grid-column:1;max-width:46ch}
    .cert:has(.unlocks) > .cert-meta{
      grid-column:2;grid-row:1 / span 3;
      margin-top:0;padding-top:0;border-top:0;
      border-left:1px solid var(--hair);padding-left:clamp(22px,3vw,40px);
    }
  }
  /* One narrow column: the measures that hold a card together at width only strand text. */
  @media (max-width:559px){
    .cert:has(.unlocks) > p,
    .cert:has(.unlocks) > .unlocks{max-width:none}
  }

  /* Every pending note in the build opens "Build note." and the lead-in was reading at the
     same weight as the sentence after it. This also lifts the note on contact.html, which
     uses the same idiom; it is the only rule here that reaches another page. The second
     note is tied to the table it annotates rather than sitting a full section step away. */
  .pending-note b{color:var(--ink);font-weight:600}
  #requested .pending-note{margin-top:clamp(30px,3.4vw,48px)}

  /* Retires the one-off inline style on the contact lead, which DESIGN.md records as a
     deviation. The inline styles on the other pages still win, so nothing there moves. */
  #contact p.lead{margin-top:22px;color:var(--muted)}

  @media (max-width:760px){
    #firm .record > div,
    #requested .record > div{grid-template-columns:1fr;column-gap:0}
  }
  /* ===== about page ===== */

  /* ---------- CREW ----------
     The crew photograph is the client's own, 1280 by 960 off gec2.com. It is deliberately
     NOT a plate. A plate bleeds and carries a four-cell specification strip under it, and
     this image can supply neither: full bleed would upscale a 1280px file 2.5x at a 1440
     window and worse again on a retina panel, and there is no verified specification to
     write beneath a photograph of people whose names and roles are not published.

     So it takes the other form the system already owns for a bounded image, the .svc-frame
     treatment: a 1px hairline making it a defined panel, and a capped width. The cap is
     620px, which holds the file at just over 2x on a retina display, so the photograph is
     never asked to do more than it can.

     The cap belongs on the TRACK, not only on the figure. An fr split leaves the picture
     sitting in a track wider than itself once the window passes about 1500, and the dead
     space to its right reads as a broken gap rather than a considered one: measured 140px
     at 1920 against a 72px grid gap. min(620px, 50%) makes the track exactly as wide as
     the picture is allowed to be, so the visual gap always equals the grid gap. The 50%
     is what keeps the copy from being crushed on the way down to the breakpoint. */
  .crew{display:grid;grid-template-columns:minmax(0,min(620px,50%)) minmax(0,1fr);
    gap:clamp(28px,4vw,72px);margin-top:clamp(36px,4.2vw,60px);align-items:start}
  /* The track caps the figure in two columns; this caps it in the stacked single column,
     where the track is the full page width and the photograph would otherwise stretch. */
  .crew-shot{border:1px solid var(--hair);max-width:620px}
  /* The film grade, not the plate grade. No type sits on this image so it does not need
     to be pushed as far back, and the plate's brightness(.62) turns flat phone daylight
     to mud. Both values already exist in the system; this adds no new number. */
  .crew-shot img{width:100%;height:auto;filter:brightness(.82) contrast(1.04) saturate(.9)}
  .crew-shot figcaption{padding:14px 16px 16px;border-top:1px solid var(--hair);
    color:var(--dim);font-size:12.5px;line-height:1.6}
  .crew-note p{color:var(--muted);font-size:clamp(15px,1.2vw,18px);line-height:1.68;
    max-width:56ch}
  .crew-note p + p{margin-top:20px}

  /* Collapses at the same 1000px as the contact grid, the capability rows and the lineage,
     so the page has no breakpoint of its own. */
  @media (max-width:1000px){
    .crew{grid-template-columns:1fr;gap:clamp(28px,5vw,44px)}
    /* The stacked lineage zeroes the first era's top padding because the homepage strip
       has no rule above it. This one does, so the padding has to come back or the first
       era's date line sits on the hairline. */
    .lineage--page .era:first-child{padding-top:26px}
  }

  /* ---------- LINEAGE ON ITS OWN PAGE ----------
     Same component as the homepage strip. On a dedicated page the three eras have room
     the homepage does not, so the measure opens from 34ch to 40ch and the block gets the
     top hairline that .vals and .creds already carry when they head a section. Nothing
     else changes, and no historical detail was added to fill the extra room. */
  .lineage--page .era p{max-width:40ch}

  /* ===== projects index and project pages ===== */
  /* The index shows one feature image per project and nothing else. Detail lives on the
     project's own page, so a reviewer scanning for their building type meets nine images and
     nine one-line scopes rather than a seven thousand pixel scroll. */
  .pcards{
    display:grid;grid-template-columns:repeat(3,1fr);
    gap:clamp(26px,3vw,44px) clamp(20px,2.4vw,34px);margin-top:clamp(30px,3.4vw,48px);
  }
  /* Four rows so the Full project button pins to the bottom of the card. Cards in a row
     stretch to equal height by default, so the buttons land on one line across the row
     however long the scope copy runs. */
  .pcard{display:grid;grid-template-rows:auto auto 1fr auto;text-decoration:none;color:inherit}
  .pcard img{
    width:100%;aspect-ratio:16/10;object-fit:cover;display:block;background:#08090A;
    filter:brightness(.86) contrast(1.03) saturate(.92);
    transition:filter .5s var(--ease),transform .5s var(--ease);
  }
  /* Holds the row where a project has no photograph, so the titles below still line up. */
  .pcard--noimg::before{
    content:"";display:block;width:100%;aspect-ratio:16/10;
    outline:1px solid var(--hair);outline-offset:-1px;
    background:repeating-linear-gradient(135deg,transparent 0 12px,rgba(255,255,255,.02) 12px 24px);
  }
  .pcard > b{
    display:block;border-top:1px solid var(--hair);margin-top:17px;padding-top:17px;
    font-weight:600;font-size:18px;letter-spacing:-.014em;line-height:1.2;
  }
  .pcard-text{margin-top:9px}
  .pcard-text p{color:var(--muted);font-size:14.5px;line-height:1.68}
  .pcard-text small{
    display:block;margin-top:12px;font-size:10.5px;letter-spacing:.19em;
    text-transform:uppercase;color:var(--dim);line-height:1.5;
  }
  /* The affordance has to be unmissable, so it borrows the nav CTA's language rather than
     being a text link that a scanning reader slides past. */
  .fullproj{
    justify-self:start;align-self:end;margin-top:20px;
    border:1px solid var(--hair-strong);padding:12px 22px;
    font-size:11px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--ink);
    transition:background .3s var(--ease),border-color .3s var(--ease),color .3s var(--ease);
  }
  .pcard--link:hover .fullproj,.pcard--link:focus-visible .fullproj{
    background:var(--gold);border-color:var(--gold);color:var(--ground);
  }
  .pcard--link:hover img{filter:brightness(1) contrast(1.03) saturate(1)}

  /* Project pages. The crumb sits above the title so the page announces where it lives
     before it announces what it is. */
  /* The crumb joins the centred heading axis rather than breaking it. Every other page
     opener on the site is centred, and one left-aligned title on the project pages would
     read as a different template rather than a deeper level of the same one. */
  .pagehead--project{text-align:center}
  .crumb{
    display:inline-block;margin-bottom:clamp(18px,2vw,28px);
    font-size:16.5px;font-weight:500;letter-spacing:.19em;text-transform:uppercase;
    color:var(--dim);text-decoration:none;transition:color .25s var(--ease);
  }
  .crumb::before{content:"\2190\00a0\00a0"}
  .crumb:hover{color:var(--ink)}

  .scopes--two{grid-template-columns:repeat(2,1fr)}

  /* Two ways out of a project page, built the same way so they read as one control rather
     than as a button that happened to land next to a link. Both are a label over a title at
     the same step, mirrored, with the arrow pointing the way each one goes. A bordered button
     opposite a bare title was two different languages doing the same job. */
  .nextproj{
    border-top:1px solid var(--hair);padding-top:22px;
    display:flex;align-items:flex-start;justify-content:space-between;
    gap:clamp(20px,3vw,44px);flex-wrap:wrap;
  }
  .nextproj-side{display:flex;flex-direction:column}
  .nextproj-to{align-items:flex-end;text-align:right}
  .nextproj-side span{
    font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;color:var(--dim);font-weight:500;
  }
  /* The documented title step, not a step of its own. clamp(19px,1.9vw,28px) was four pixels
     off it and bought nothing, which is the same mistake DESIGN.md already records against
     the 34px version of this element. */
  .nextproj-side a{
    margin-top:7px;font-weight:600;font-size:clamp(21px,2.1vw,32px);letter-spacing:-.022em;
    text-decoration:none;transition:color .25s var(--ease);
  }
  .nextproj-side a:hover{color:var(--gold)}
  .nextproj-back a::before{content:"\2190\00a0\00a0"}
  .nextproj-to a::after{content:"\00a0\00a0\2192"}

  @media (max-width:620px){
    /* Stacked, both left aligned: a right aligned block under a left aligned button reads as
       two things that failed to line up rather than as two ends of a row. */
    .nextproj{align-items:flex-start;gap:26px}
    .nextproj-to{align-items:flex-start;text-align:left}
  }

  @media (max-width:1000px){
    .pcards{grid-template-columns:repeat(2,1fr)}
    .scopes--two{grid-template-columns:repeat(2,1fr)}
  }
  @media (max-width:620px){
    .pcards{grid-template-columns:1fr}
    /* This block sits after the one that collapses .scopes, and .scopes--two matches at the
       same specificity, so without naming it here the two-up stays two-up on a phone. */
    .scopes--two{grid-template-columns:1fr}
  }

  /* Filter by industry. A preconstruction lead arrives looking for their own building type,
     so this is navigation, not decoration. Counts are on the buttons because the number is
     the answer to "do you do this kind of work" as much as the cards are. */
  /* .pcard sets display:grid, and an author display rule outranks the user agent's
     [hidden]{display:none}, so without this the filter would set the attribute and hide
     nothing. Attribute plus attribute out-ranks the single class. */
  [data-sector][hidden]{display:none}
  .pfilter{margin-top:clamp(28px,3.2vw,44px)}
  .pfilter-label{
    display:block;font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;
    color:var(--dim);font-weight:500;margin-bottom:14px;
  }
  .pfilter-row{display:flex;flex-wrap:wrap;gap:10px}
  .pfilter-btn{
    font-family:inherit;cursor:pointer;background:none;
    border:1px solid var(--hair);color:var(--muted);
    padding:11px 17px;font-size:11.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
    transition:border-color .3s var(--ease),color .3s var(--ease),background .3s var(--ease);
  }
  .pfilter-btn:hover{border-color:var(--hair-strong);color:var(--ink)}
  .pfilter-btn.on{background:var(--ink);border-color:var(--ink);color:var(--ground)}

  /* The aerospace entries have no photograph and never will, so the mark stands in the frame
     the photograph would have occupied. Same hatched ground as the other absences, which is
     what keeps it reading as "nothing to show here" rather than as a logo wall. */
  /* The marks show in their own colours, so the frame becomes the light panel rather than the
     dark hatched ground the other absences use. Four of the five are dark blues and a red and
     would be close to invisible on near-black. This is the same surface the homepage logo wall
     and the certificate frames already use: light means a mark or a document, not a photograph. */
  .pcard-mark{
    width:100%;aspect-ratio:16/10;display:flex;align-items:center;justify-content:center;
    padding:0 clamp(24px,3vw,52px);
    background:var(--panel-light);
  }
  /* .pcard img also matches here and hands these three down: a 16:10 aspect-ratio, object-fit
     cover, and a dark background. The background is the one that bites, because
     brightness(0) invert(1) turns it white and the mark disappears inside a white box. All
     three have to be reset, not just the filter. */
  .pcard-mark img{
    width:var(--w,180px);max-width:100%;height:auto;
    aspect-ratio:auto;object-fit:contain;background:none;filter:none;
  }
  .pcard-mark img.stack{width:auto;height:var(--h,96px)}

  /* The same eight choices as one control on a phone, where the row wraps to four lines and
     pushes the first project off the screen. Hidden above the breakpoint, and built in JS, so
     without a script neither the row nor this appears and the whole grid is shown instead. */
  .pfilter-select{
    display:none;width:100%;font-family:inherit;cursor:pointer;
    background:transparent;color:var(--ink);
    border:1px solid var(--hair);border-radius:0;appearance:none;
    /* 16px because iOS zooms the page when it focuses a control set smaller than that, and a
       filter that zooms the layout on every use is worse than one that reads a step large. */
    font-size:16px;letter-spacing:-.01em;padding:15px 38px 15px 15px;
    background-image:linear-gradient(45deg,transparent 50%,var(--dim) 50%),
      linear-gradient(135deg,var(--dim) 50%,transparent 50%);
    background-position:calc(100% - 21px) 24px,calc(100% - 16px) 24px;
    background-size:5px 5px,5px 5px;background-repeat:no-repeat;
    transition:border-color .3s var(--ease);
  }
  .pfilter-select:hover{border-color:var(--hair-strong)}
  .pfilter-select:focus{outline:none;border-color:var(--gold)}
  .pfilter-select option{background:var(--ground);color:var(--ink)}
  @media (max-width:760px){
    .pfilter-row{display:none}
    .pfilter-select{display:block}
  }
  @media (max-width:620px){
    .pfilter-btn{padding:10px 13px;font-size:10.5px;letter-spacing:.08em}
  }

  /* Alternating half rows. Full bleed rather than inside the wrap, so the photograph really
     is half the window and the page reads as a sequence of packages rather than a column of
     cards. The copy half keeps --pad on its outer edge, so its text still lands on the same
     gutter as every other left edge in the site. */
  .altrow{
    display:grid;grid-template-columns:1fr 1fr;align-items:center;
  }
  /* One ratio for all four, or the row height follows whatever each source photograph
     happens to be and the sequence loses its beat: this set runs 1.33 to 2.17, which is a
     540px row next to a 332px one. 3:2 is the closest fit to the set, so it crops least. */
  .alt-media{margin:0;overflow:hidden;background:#08090A;aspect-ratio:3/2}
  .alt-media img{
    width:100%;height:100%;object-fit:cover;display:block;
    filter:brightness(.88) contrast(1.03) saturate(.94);
  }
  .alt-copy{
    display:flex;flex-direction:column;justify-content:center;
    padding-block:clamp(44px,6vw,88px);
  }
  /* Odd rows put copy left, even rows put it right, and the media takes the other half.
     order on the media is what flips it, so the copy stays first in the source and a screen
     reader always meets the package before its photograph. */
  .altrow:nth-child(odd) .alt-copy{padding-left:var(--pad);padding-right:clamp(28px,5vw,86px)}
  .altrow:nth-child(even) .alt-copy{padding-right:var(--pad);padding-left:clamp(28px,5vw,86px)}
  .altrow:nth-child(even) .alt-media{order:-1}
  .alt-copy h3{
    font-weight:600;font-size:clamp(27px,3.1vw,44px);line-height:1.06;letter-spacing:-.026em;
  }
  .alt-copy p{
    margin-top:clamp(16px,1.6vw,22px);color:var(--muted);line-height:1.64;
    font-size:clamp(16.5px,1.35vw,20px);max-width:44ch;
  }

  @media (max-width:900px){
    /* Stacked, alternating sides has no meaning in one column, so every row reads the same way
       down: see the stacked scope row block further down for the order the parts take. */
    .altrow{grid-template-columns:1fr}
    .alt-media img{min-height:clamp(240px,58vw,420px)}
    .altrow:nth-child(n) .alt-copy{
      padding:clamp(28px,6vw,44px) var(--pad) clamp(40px,8vw,64px);
    }
  }

  .pcard-text .tbc,
  .scopes .tbc{
    color:var(--dim);font-style:italic;
    border-bottom:1px dotted var(--hair-strong);padding-bottom:2px;
  }

  /* Work that is on site rather than finished. A reviewer reads current work as capacity,
     which is a different signal from a completed record, so it is marked rather than folded
     in silently. */
  .pcard-status{
    display:inline-block;margin-top:12px;padding:5px 10px;
    border:1px solid var(--hair-strong);color:var(--ink);
    font-size:10.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  }

  /* The service films are square, so the row media takes 1:1 rather than the 3:2 the
     photographic project rows use. */
  /* Honor, 24 September: "the picture seems a little big next to this little design build
     area" and the wording "is a little on the smaller side". A square film at half the row
     was 713px tall beside four list items. The film takes 4:3 and a slightly narrower
     column, and the list comes up a step, which closes the gap from both ends. */
  .alts--film .alt-media{aspect-ratio:4/3}
  /* The last film ran into the closing call to action. At 1440 there were 82px between the
     foot of it and Let's work, against 129px between the rows above, so the boundary between
     two sections read tighter than the rhythm inside one. Contact carries about 82px of its
     own head already, so what goes here is the difference. */
  .alts--film{padding-bottom:clamp(56px,9vw,96px)}
  .alts--film .alt-media video{
    width:100%;height:100%;object-fit:cover;display:block;background:#08090A;
    filter:brightness(.86) contrast(1.04) saturate(.9);
  }

  /* Client, 25 September: the scope rows should sit on the measure What we do uses on the
     home page rather than running to the window edges. What moves is the container, not the
     split: the row keeps Honor's 1.08/0.92 from 24 September, so the film does not grow back
     on its way in. The copy gives up the outer gutter it was carrying, because the wrap now
     provides it, and the film takes the hairline the home page's frames carry.

     Above the stack only. Below 900px the row is restructured into one column and every part
     takes --pad for itself against a full bleed film, so a wrap here would double the gutter
     and box a photograph that is meant to run edge to edge. */
  @media (min-width:901px){
    .alts--film{max-width:1560px;margin-inline:auto;padding-inline:var(--pad);
      margin-top:clamp(40px,5vw,72px);padding-bottom:clamp(88px,10vw,150px)}
    /* Honor, 24 September: "the picture seems a little big next to this little design build
       area". The film takes the narrower half.

       This has to be inside the breakpoint. Unscoped, `.alts--film .altrow` out-ranks the
       `.altrow{grid-template-columns:1fr}` that stacks every other row of this kind on a
       phone, and a media query adds no specificity to answer it with, so since 24 September
       this page alone has been holding two columns all the way down to 390px: a 179px film
       beside a list, where every other alternating row on the site stacks.

       The split is by column and the media swaps columns on even rows, so the narrow half
       was landing on the copy there and the films came out 556px on one row and 653px on
       the next. She asked for a smaller picture, not one that alternates size, so the ratio
       follows the parts rather than the positions. */
    .alts--film .altrow{grid-template-columns:1.08fr 0.92fr;
      padding-block:0;column-gap:clamp(36px,5vw,96px)}
    /* Client, 25 September: Commercial and Industrial has to start where the Design-Build
       film above it starts, and Low Voltage where the Testing and Maintenance film does.

       Swapping the tracks on even rows was the wrong way to keep the film narrow. It made
       the right hand column start at 700 on those rows against 797 on the others, so a
       scope's heading sat 97px left of the film it followed and the page had two right
       hand edges. The tracks are the same on every row now, which fixes the alignment but
       hands the media the wide half on even rows, so the media gives the difference back
       as width and sits against the outer gutter. Both things hold: one column start all
       the way down, and Honor's smaller film on all four rows. */
    .alts--film .altrow:nth-child(even) .alt-media{
      width:calc(100% * 0.92 / 1.08);justify-self:start}
    .alts--film .altrow + .altrow{margin-top:clamp(64px,9vw,136px)}
    .alts--film .altrow:nth-child(odd) .alt-copy,
    .alts--film .altrow:nth-child(even) .alt-copy{padding:0}
    .alts--film .alt-media{border:1px solid var(--hair)}
  }
  .svc-items{
    list-style:none;margin-top:clamp(22px,2.4vw,32px);
    border-top:1px solid var(--hair);max-width:46ch;
  }
  .svc-items li{
    padding:12px 0;border-bottom:1px solid var(--hair);
    font-size:clamp(17px,1.35vw,19.5px);color:var(--ink);
  }


  /* The certificates, shown as documents. A certificate is evidence, so it is displayed whole
     on a light panel rather than cropped into the dark grid: contain, not cover, because a
     cropped certificate is worth nothing to the reviewer reading the numbers off it. */
  .docs{
    display:grid;grid-template-columns:repeat(3,1fr);
    gap:clamp(24px,3vw,44px);margin-top:clamp(30px,3.4vw,48px);
  }
  .doc{margin:0;display:grid;grid-template-rows:auto 1fr}
  /* Square, because the set is mixed: two portrait letters and one landscape certificate.
     At 3:4 the landscape one floated in 228px of white. A square frame costs the portrait
     documents a little size and stops the odd one out reading as a mistake. */
  .doc-frame{
    background:var(--panel-light);aspect-ratio:1;
    display:flex;align-items:center;justify-content:center;
    padding:clamp(12px,1.4vw,20px);
  }
  .doc-frame img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain}
  .doc figcaption{border-top:1px solid var(--hair);margin-top:17px;padding-top:17px}
  .doc figcaption > b{
    display:block;font-weight:600;font-size:18px;letter-spacing:-.014em;margin-bottom:14px;
  }
  .doc-meta > div{display:flex;gap:14px;padding:7px 0;align-items:baseline}
  /* A line of prose under each certificate title, at Honor's request, so the card says what
     the certification is for rather than only what it is called. */
  .doc-note{color:var(--muted);font-size:clamp(14.5px,1.1vw,16px);line-height:1.58;
    margin:10px 0 16px;max-width:42ch}

  .doc-meta dt{
    flex:0 0 auto;min-width:88px;font-size:10.5px;letter-spacing:.19em;
    text-transform:uppercase;color:var(--dim);font-weight:500;
  }
  .doc-meta dd{font-size:clamp(15.5px,1.15vw,17.5px);color:var(--ink)}

  @media (max-width:900px){
    .docs{grid-template-columns:repeat(2,1fr)}
  }
  @media (max-width:620px){
    .docs{grid-template-columns:1fr}
    .doc-frame{aspect-ratio:4/5}
  }

  /* Client type and location under the lead, on the centred axis with it. This is what the
     specification strip carried before it came off the project pages: two facts a reviewer
     scans for, at a size that does not compete with the scope description above them. */
  .head-meta{
    display:flex;justify-content:center;flex-wrap:wrap;
    gap:clamp(30px,5vw,76px);margin-top:clamp(26px,3vw,42px);
  }
  /* Client, 22 September 2026: three times the size. At 10.5px against a 102px headline
     this pair was a footnote to a page whose whole job is to say what the work was and
     where. The tracking comes down as the size goes up, because .19em was set for a
     caption and opens into a gap at this scale. */
  .head-meta dt{
    font-size:clamp(12px,1.55vw,16px);letter-spacing:.09em;text-transform:uppercase;
    color:var(--dim);font-weight:600;margin-bottom:clamp(6px,.7vw,9px);
  }
  .head-meta dd{font-size:clamp(17px,2.25vw,23.5px);line-height:1.2;
    letter-spacing:-.015em;color:var(--ink)}

  /* A plate with nothing over it does not need the scrim that protects overlaid copy. The
     full-strength one darkens the top of the frame by 72% for text that is no longer there. */
  .plate--bare figure::after{
    background:linear-gradient(180deg,rgba(11,12,13,.42) 0%,rgba(11,12,13,0) 26%,
      rgba(11,12,13,0) 74%,rgba(11,12,13,.52) 100%);
  }

  /* An alternating row that is alone in its own block has no odd or even neighbour to
     alternate against, so the flip is explicit. Has to out-rank .altrow:nth-child(odd),
     which is (0,3,0), hence the doubled class. */
  .altrow.altrow--flip .alt-media{order:-1}
  .altrow.altrow--flip .alt-copy{padding-left:clamp(28px,5vw,86px);padding-right:var(--pad)}
  @media (max-width:900px){
    .altrow.altrow--flip .alt-copy{padding:clamp(28px,6vw,44px) var(--pad) clamp(40px,8vw,64px)}
  }

  /* ---------- A STACKED SCOPE ROW ----------
     Stacked, the two halves of the row become one column and the copy block reads as a single
     run of text with a picture parked above it. Split instead: the number and the name go on
     top of the film, and what the scope actually consists of, the paragraph and the list of
     services, comes after it. A reader meets the name, sees the work, then reads the detail.

     .alt-copy goes to display:contents so its four children become siblings of the figure and
     can be ordered against it. The padding it was carrying goes with it, so each child takes
     --pad for itself; the film stays full bleed, which is why it could never have been done by
     putting the copy in two blocks in the markup.

     These have to sit after the flip rules rather than in the stacking block above: the flip
     uses a doubled class to out-rank nth-child, and only source order breaks that tie. */
  @media (max-width:900px){
    .alt-copy{display:contents}
    /* .altrow is a <section>, so it was also taking the global section rhythm: 52px of its own
       above and below on top of the spacing the parts carry, which put 149px between one
       scope's last service and the next scope's number. The parts own the spacing here. */
    .altrow{padding-block:0}
    .alt-copy h3{order:1;padding:clamp(28px,5.6vw,44px) var(--pad) 0}
    /* Every selector that sets order on the media has to be answered, not just the bare one.
       .altrow:nth-child(even) .alt-media and the doubled flip class are both (0,3,0) and out-rank
       a plain descendant; before this they happened to agree on -1, so nothing showed. */
    .altrow .alt-media,
    .altrow:nth-child(odd) .alt-media,
    .altrow:nth-child(even) .alt-media,
    .altrow.altrow--flip .alt-media{order:2;margin-top:clamp(22px,4.6vw,34px)}
    .alt-copy p{order:3;padding-inline:var(--pad);
      margin-top:clamp(22px,4.6vw,34px);max-width:none}
    .svc-items{order:4;margin-inline:var(--pad);
      margin-bottom:clamp(28px,5.6vw,44px);max-width:none}
    /* A rule between scopes, full bleed like every other structural hairline here. Without one
       the run of them reads as one long column of text and film with no sign of where a scope
       ends; empty ground was trying to do that job and only made the page longer.
       The list gives up its own closing rule to it. Inset under the last service and full
       bleed 25px below it, the two read as one line drawn twice rather than as a list closing
       and a scope ending. */
    .svc-items li:last-child{border-bottom:0}
    .altrow + .altrow{border-top:1px solid var(--hair)}
  }

  /* A pair of images capped so neither is asked to do more than its file can. These two
     renderings are 640 and 596 pixels wide; at the ungoverned two-up they would sit in 631px
     cells and be upscaling before a retina panel doubles it. The cap puts them in ~453px
     cells, which holds at 1x and is honest at 2x. The right hand gutter it leaves is the
     price, and it is the same trade the crew figure on the About page makes. */
  .jobs--pair{grid-template-columns:repeat(2,1fr);max-width:940px}
  .jobs--pair img{aspect-ratio:16/9}

  /* ---------- LINEAGE TIMELINE ----------
     The rule above the three eras draws itself left to right, and each generation arrives as
     the line reaches it. It is a chronology, so it should be read in time rather than land
     all at once. The line is the existing hairline; only the gold travelling over it is new,
     which keeps this inside the trace and current language the rest of the site already uses.

     Timings are tied together on purpose: the line takes 1.9s across three equal columns, so
     it passes the second node at .63s and the third at 1.27s, and each era's copy is delayed
     to just behind those. Change the duration and the delays have to move with it. */
  .lineage{border-top:0;position:relative}
  /* Generates no box, so the three eras stay direct grid items of .lineage exactly as
     before. It exists only so a phone has something to scroll that is not the element
     the track is positioned against. */
  .lineage-rail{display:contents}
  /* The rule itself stays a hairline. What travels it is the motion-role gold, the same
     current that runs the hero traces and the contact field, and it is transient: it crosses
     once and leaves. A permanently gold rule would be a fourth accent use, and the Three
     Golds Rule says the answer to a fourth is a hairline or nothing. This is the hairline. */
  .lineage-track{
    position:absolute;top:0;left:0;right:0;height:1px;background:var(--hair);overflow:hidden;
  }
  .lineage-track::after{
    content:"";position:absolute;top:0;bottom:0;left:0;width:22%;
    background:linear-gradient(90deg,rgba(255,249,216,0),var(--pulse-core),rgba(255,249,216,0));
    opacity:0;transform:translateX(-100%);
  }
  .lineage.on .lineage-track::after{animation:lineageRun 1.9s var(--ease) .1s forwards}
  /* 454% is the track divided by the segment: far enough for the trailing edge to clear. */
  @keyframes lineageRun{
    0%{opacity:0;transform:translateX(-100%)}
    10%{opacity:1}
    86%{opacity:1}
    100%{opacity:0;transform:translateX(454%)}
  }

  /* A node where each generation starts. It fills to ink, not to gold: the current passing is
     the gold moment, and the node is what the current leaves behind. */
  .lineage .era{position:relative}
  .lineage .era::before{
    content:"";position:absolute;top:-3px;left:-3px;width:5px;height:5px;
    background:var(--ground);border:1px solid var(--hair-strong);border-radius:50%;
    transition:background .5s var(--ease),border-color .5s var(--ease);
  }
  .lineage .era:first-child::before{left:0}
  .lineage.on .era::before{background:var(--ink);border-color:var(--ink)}
  .lineage.on .era:nth-of-type(2)::before{transition-delay:.63s}
  .lineage.on .era:nth-of-type(3)::before{transition-delay:1.27s}

  .lineage .era > *{opacity:0;transform:translateY(12px)}
  .lineage.on .era > *{
    opacity:1;transform:none;
    transition:opacity .75s var(--ease),transform .75s var(--ease);
  }
  .lineage.on .era:nth-of-type(1) > *{transition-delay:.16s}
  .lineage.on .era:nth-of-type(2) > *{transition-delay:.79s}
  .lineage.on .era:nth-of-type(3) > *{transition-delay:1.43s}

  @media (max-width:1000px){
    /* One column: the line is no longer a timeline across the page, so it stops pretending
       to be one and the eras simply settle in order. */
    .lineage-track{display:none}
    .lineage--page{border-top:1px solid var(--hair)}
    .lineage .era::before{display:none}
  }
  /* ---------- LINEAGE ON A PHONE ----------
     Horizontal again, as a slider. Stacked it read as three unrelated blocks, and the single
     idea the component exists to carry, one line handed on twice, is the first thing that
     goes. One generation to a screen, advancing on its own, swipeable, and the rule above
     turned into the position it is at.

     The rail is what scrolls. The track has to stay put above it, and an absolutely
     positioned child of a scroller travels with the content, so the two cannot be the same
     element: .lineage keeps the track, .lineage-rail takes the overflow. */
  /* Nothing to drive above the breakpoint: the eras are a grid there, not a rail. */
  .lineage-nav{display:none}
  @media (max-width:760px){
    .lineage{display:block;position:relative;padding-top:26px;border-top:0}
    .lineage-rail{display:flex;overflow-x:auto;overscroll-behavior-x:contain;
      scroll-snap-type:x mandatory;scrollbar-width:none}
    .lineage-rail::-webkit-scrollbar{display:none}
    .lineage .era{flex:0 0 100%;scroll-snap-align:start;border:0;padding:0 0 2px}
    .lineage--page .era:first-child{padding-top:0}
    .lineage .era::before{display:none}
    /* The travelling gold was a desktop moment: it crossed a timeline that was actually on
       screen. Here the rule states position instead, one segment per generation, and it is
       ink rather than gold because it is a permanent state, not a current passing. */
    .lineage-track{display:block}
    .lineage .lineage-track::after,.lineage.on .lineage-track::after{
      animation:none;opacity:1;width:33.333%;background:var(--ink);
      transform:translateX(0);transition:transform .62s var(--ease)}
    .lineage[data-i="1"] .lineage-track::after{transform:translateX(100%)}
    .lineage[data-i="2"] .lineage-track::after{transform:translateX(200%)}
    /* The staggered reveal was timed to the line crossing. Nothing crosses now. */
    .lineage.on .era > *{transition-delay:0s}

    /* One generation to a screen means the screen. At the section rhythm the strip came to
       543px on an 844px phone and read as a caption between two full-height neighbours,
       which is the opposite of what a slider is for. The section takes the viewport and the
       three parts space themselves inside it: lead at the top, the generation in the middle
       of the space that is left, the controls at the foot. The copy comes up one documented
       step each with the room, from the strip sizes that only existed to fit three columns
       across a desktop. */
    /* Two ids, so it clears #clients ~ section.pinned rather than tying with it. */
    #clients ~ section#about{min-height:100svh;justify-content:flex-start}
    #about > .wrap{flex:1;display:flex;flex-direction:column;justify-content:center;
      gap:clamp(30px,7vh,64px)}
    #about .lineage{padding-top:30px}
    #about .era .yr{margin-bottom:20px}
    #about .era h3{font-size:clamp(21px,2.1vw,32px);line-height:1.14;letter-spacing:-.022em;
      margin-bottom:14px}
    #about .era p{font-size:clamp(15px,1.2vw,18px);line-height:1.6;max-width:38ch}
    #about .lineage-nav{margin-top:10px}

    /* A slider that advances on its own still has to say it can be taken by hand, and the
       rule above states position without offering to change it. These are the offer. */
    .lineage-nav{display:flex;gap:10px;justify-content:flex-end;margin-top:20px}
    .lineage-arrow{
      width:44px;height:44px;display:grid;place-items:center;cursor:pointer;
      background:none;border:1px solid var(--hair-strong);color:var(--ink);
      transition:border-color .3s var(--ease),color .3s var(--ease)}
    .lineage-arrow svg{width:19px;height:19px;display:block}
    .lineage-arrow.is-prev svg{transform:scaleX(-1)}
    .lineage-arrow:active{border-color:var(--ink)}
  }
  @media (prefers-reduced-motion:reduce){
    .lineage-track::after{display:none}
    .lineage .era > *{opacity:1;transform:none}
    .lineage .era::before{background:var(--ink);border-color:var(--ink)}
  }

  /* ---------- STACKED PANELS ----------
     The clients panel established the move: a light surface arriving over the dark with a
     routed seam, which the next section then slides up over. Why Choose Us and Certifications
     take the same treatment, Three Generations stays dark between them, and Contact closes it.
     Every seam is drawn by the same drawEdge pass, so the profile is identical on all of them.

     A light section redefines the token set rather than restating every colour. One override
     point, and everything downstream (hairlines, labels, muted prose) follows without any
     component knowing it is on a light ground. Selectors have to out-rank `#clients ~ *`,
     which carries an id and therefore beats any bare class. */
  #clients ~ section.panel-light{
    background:var(--panel-light);
    --ink:#0B0C0D;
    --muted:#545A60;      /* 6.5:1 on the panel */
    --dim:#63696F;        /* 5.1:1, the Floor Plus One Rule on a light ground */
    --hair:rgba(11,12,13,.16);
    --hair-strong:rgba(11,12,13,.30);
    color:var(--ink);
  }

  /* Pinned so the following section rides up over it. Certifications is 1273px and cannot
     pin, so it does not try: it scrolls, and Contact slides over it.

     A panel centred in the whole of 100svh is centred in a box a reader can only see the
     lower part of, because the nav is fixed over the top 85px of it. The optical middle
     lands half a nav high at every size, and once the panel is within a nav of filling the
     window it stops being an optical problem and starts hiding the heading: measured at
     1440x900 the first line of Why Choose Us sat 27px above the bottom edge of the bar with
     191px of empty panel under the last row of tiles. So the bar is reserved as padding, and
     the head and the foot are fr rows rather than fixed padding, which is what lets them
     take a share of the room that is actually left after the nav and the content instead of
     a share of a viewport that was never all available.

     Asymmetric on purpose, 6 to 15, the ratio the two padding steps stated. The content sits
     in the middle of the space below the bar and the heavier foot lifts the last row clear
     of the seam arriving over it. Without that the panel reads as already being covered
     while you are still reading it. */
  #clients ~ section.pinned{
    position:sticky;top:0;min-height:100svh;
    display:grid;grid-template-rows:6fr auto 15fr;
    padding-block:var(--navh) 0;
  }
  /* The lineage panel carries the rail and the two owners now, and that is more than a window
     holds: at 1280x900 the wrap alone measures 909px before any padding, so it cannot be made
     to fit at any padding. A sticky panel taller than the viewport is the bug, because the
     overflow sits below the fold of something stuck to the top and cannot be scrolled to. So
     this one section stops being pinned and scrolls like any other band. #why keeps its pin. */
  #clients ~ section#about.pinned{
    position:relative;min-height:0;
    display:block;
    padding-block:clamp(64px,9vh,120px) clamp(64px,9vh,120px);
  }
  #clients ~ section.pinned > .wrap{grid-row:2}
  /* Certifications is too tall to pin, but the same seam arrives over it, so it needs the
     same clearance at the foot. */
  #clients ~ section.panel-light:not(.pinned){
    padding-bottom:clamp(96px,15vh,196px);
  }

  /* Only a section that fits may pin, and neither of these fits at every desktop size. Below
     1000px the eras stack and Three Generations measures 951px of content on its own, which
     would want a 1143px window; below a 900px window the room left after the nav and the
     content cannot give the foot the 64px the seam occupies, so the next panel arrives on
     top of the last row. Either way the panel loses its bottom permanently, which is worse
     than not pinning, so they scroll and take the page rhythm instead.

     Same specificity as the rule above and a media query adds none, so this only wins by
     sitting after it. */
  @media (max-width:1000px),(max-height:899px){
    #clients ~ section.pinned{
      position:relative;min-height:0;
      padding-block:clamp(48px,6vh,88px) clamp(96px,15vh,196px);
    }
  }

  /* Nothing pins on a phone. A sticky panel at top:0 that is taller than the viewport can
     never show its own foot: it locks the moment its top reaches zero, and the opaque section
     behind it slides up over everything below the fold. Measured at 390x844 the three pinned
     panels ran 1001, 1379 and 1057 against an 844 viewport, so the last row of logos, the
     second row of commitments and the end of the lineage were all unreachable. The margin
     these hold at desktop, ~70px, is a phone's worth of overflow. They scroll instead.

     This has to sit here rather than in the mobile block above: the selector is the same
     specificity as the pinned rule, and a media query adds none, so only source order breaks
     the tie.

     The flex column comes back because the pinned rule is a grid now, and the phone layout of
     Three Generations is built on it: #about > .wrap takes flex:1 to hold the lead at the top,
     the generation in the middle and the controls at the foot of a full screen. */
  @media (max-width:760px){
    #clients ~ section.pinned{
      position:relative;min-height:0;display:flex;flex-direction:column;
      padding-block:clamp(52px,6vh,80px) clamp(72px,9vh,112px);
    }
    #clients ~ section.panel-light:not(.pinned){
      padding-bottom:clamp(72px,9vh,112px);
    }
  }

  /* ---------- HERO ON A PHONE ----------
     The player is 16:9 against a portrait viewport, so covering it crops hard to the middle
     of the frame. That is the right trade for a background: no letterbox seams against the
     ground, and the centre of the shot is what the film was framed around anyway. The cover
     sizing in .stage iframe already handles it, so there is nothing to override here. The
     band-and-feather treatment that lived here drove off the scrub and went with it. */

  /* ---------- TOUCH TARGETS ----------
     Several links sit at their text height on a phone, which is 18px for a 15.5px link and
     33px for the filter buttons. A finger needs more than that. Padding grows the hit area
     and a matching negative margin holds the visual rhythm where the extra height would
     otherwise push the layout apart. Everything below clears 44px. */
  @media (max-width:760px){
    .contact-meta dd a,
    .form-aside a,
    .foot a{display:inline-block;padding-block:13px;margin-block:-13px}
    .crumb{padding-block:13px;margin-block:-13px 0}
    .pfilter-btn{padding-block:14px}
    .nextproj-side a{display:inline-block;padding-block:6px}
    .navlinks a{padding-block:14px}
  }

  /* ---------- MOBILE NAV ----------
     Five links plus a 325px brand lockup do not fit a 390px viewport. Before this the four
     links were display:none and the Contact button rendered 126px off the right edge, so a
     phone had no navigation at all: the brand was the only thing you could tap.

     Below 760px the brand shrinks, the row collapses to a Menu button, and the links move to
     a full-screen panel at a size worth tapping. */
  .navtoggle{display:none}
  .navmenu[hidden]{display:none}

  /* The bar collapses to a Menu button below 1080px, not 760px. Careers made it six items,
     and the links went from 11.5px to 13px so they would hold over the clear hero film, so
     the row now needs about 1180px to sit beside a 29px wordmark without running off the
     edge. Everything about how the panel itself looks still belongs to the 760px block; this
     only decides when the row gives way. */
  @media (min-width:761px) and (max-width:1180px){
    .navlinks a:not(.navcta),.navsep{display:none}
    .navtoggle{
      display:inline-block;font-family:inherit;cursor:pointer;background:none;
      border:1px solid var(--hair-strong);color:var(--ink);
      padding:13px 20px;font-size:12px;font-weight:600;letter-spacing:.15em;
      text-transform:uppercase;
    }
    .navmenu{
      position:fixed;inset:0;z-index:55;background:var(--ground);
      display:flex;flex-direction:column;justify-content:flex-start;
      padding:calc(var(--navh) + 40px) var(--pad) var(--pad);
    }
    .navmenu-list{display:flex;flex-direction:column;gap:4px}
    .navmenu-list a{
      color:var(--ink);text-decoration:none;font-size:clamp(28px,4vw,40px);
      font-weight:600;letter-spacing:-.026em;padding:14px 0;
      border-bottom:1px solid var(--hair);
    }
  }

  @media (max-width:760px){
    /* The bar is shorter here than the 85px the desktop lockup needs, and --navh is what the
       menu panel and the hero pin measure themselves against, so it has to say so. */
    :root{--navh:73px}
    /* backdrop-filter on a position:fixed bar, composited over a position:fixed hero that
       holds a video and a canvas, is one of the reliable ways to get nothing at all out of
       iOS: the bar reserves its box and draws none of its contents, which is exactly how this
       read on a phone. The blur is a nicety and the ground behind it is near-black anyway, so
       a phone gets an opaque bar. Desktop keeps the blur; it has never had the fault. */
    .nav.stuck{background:var(--ground);backdrop-filter:none;-webkit-backdrop-filter:none}
    .brand img{width:38px;height:38px}
    .brand b{font-size:18px}
    .navlinks a,.navsep{display:none}
    .navtoggle{
      display:inline-block;font-family:inherit;cursor:pointer;background:none;
      border:1px solid var(--hair-strong);color:var(--ink);
      padding:13px 20px;font-size:11.5px;font-weight:600;letter-spacing:.16em;
      text-transform:uppercase;
    }
    .navmenu{
      /* Below the nav, not above it. At z-index 70 the panel covered its own Close button and
         the only way out was to pick a link. The nav is 60, so 55 puts the panel over the page
         and under the control that dismisses it. */
      position:fixed;inset:0;z-index:55;background:var(--ground);
      /* Top aligned, not centred. Centred, the list floats in the middle of the screen with
         no relationship to the bar that opened it and shifts position page to page as the
         current-page item changes; hung directly under the nav it reads as an extension of it. */
      display:flex;flex-direction:column;justify-content:flex-start;
      padding:var(--navh) var(--pad) var(--pad);
    }
    .navmenu-list{display:flex;flex-direction:column}
    .navmenu-list a{
      display:block;padding:18px 0;border-bottom:1px solid var(--hair);
      text-decoration:none;font-weight:600;letter-spacing:-.026em;
      font-size:clamp(27px,7.5vw,44px);line-height:1.1;
    }
    /* No rule above the first link. It has nothing above it to divide from, and a hairline
       under the bar reads as a second, lighter bar. */
    .navmenu-list a[aria-current="page"]{color:var(--dim)}
  }

  /* The statement used to be anchored to the trace grid's two runs on a phone. The grid went
     with the scrub, so it simply centres in the pin now, the same as it does on a desktop. */
  @media (max-width:760px){
    .hero-pin{padding-bottom:8svh}
  }

  /* ---------- ROOM AT THREE POINTS ON THE HOME PAGE ----------
     Client, 22 September 2026. Three places on the home page closed too early: the last
     scope film ran straight into the commitments, the leadership block sat tight under the
     lineage, and the ground gave out under Who runs it before the seam arrived. Each of
     these sections carries more than a default section pad was built for, so each gets its
     own. Written against the rules above rather than replacing them, so the phone values
     stay proportionate instead of inheriting a desktop number. */
  #services{padding-bottom:clamp(132px,13.5vw,216px)}
  .owners{margin-top:clamp(124px,13.5vh,188px)}
  #clients ~ section#about.pinned{padding-bottom:clamp(152px,18.5vh,236px)}

  /* ---------- THE FEATURED PLATES ARE LINKS ----------
     Client, 22 September 2026. The three plates on the home page named projects that have
     their own pages and gave the reader no way through to them. The anchor stays static so
     .plate-copy keeps resolving against the figure, and it takes the figure's height so the
     photograph is the target rather than the caption alone. The affordance is the same one
     the cards on the projects page carry, so the gesture reads as the one already learned. */
  .plate-link{display:block;height:100%;text-decoration:none;color:inherit}
  .plate-copy .fullproj{display:inline-block;margin-top:clamp(16px,1.7vw,24px)}
  .plate-link:hover .fullproj,
  .plate-link:focus-visible .fullproj{
    background:var(--gold);border-color:var(--gold);color:var(--ground);
  }
  .plate-link:focus-visible{outline:2px solid var(--gold);outline-offset:-4px}

  /* ---------- SECTIONS THAT HOLD WHILE THE NEXT RIDES OVER ----------
     Client, 25 September: Trusted partners should ride up over Featured projects the way
     the page rides over the film, What we do over the credibility band, and How we work
     over What we do.

     A section can only hold still if it fits the screen, and two of these do not: Featured
     projects runs about 3.3 screens and What we do about 3.2. Pinned at top:0 everything
     past the first screenful sits below the fold and can never be reached, which is the
     bug already recorded against the lineage panel further down this file.

     The fix is a negative top equal to the overhang, so the section scrolls normally and
     then holds once its foot reaches the fold. That offset is the section's own height,
     which CSS cannot read, so pin.js measures each one and publishes --pin-top. It also
     adds .js-pin to <html>, and nothing here applies without it: with the script absent or
     still parsing, every section scrolls the ordinary way and the page reads correctly.
     That is the end state the design system asks every animation to have.

     The selectors carry an id because `#clients ~ *` sets position:relative on everything
     after the logo wall and would otherwise win. */
  .js-pin #work.slide-under,
  .js-pin #clients ~ section.slide-under{
    position:sticky;top:var(--pin-top,0px);
  }
  .js-pin #work.slide-under{z-index:0;background:var(--ground)}

  /* The phone holds too, at the client's direction on 25 September. It was excluded when
     this went in, on the reasoning recorded against the lineage panel above: a panel taller
     than the window, stuck at the top, hides everything past the first screenful. That
     reasoning belongs to top:0 and does not survive the measured offset. A section here
     scrolls normally, so the whole of it is read on the way down, and only then does it
     hold its last screenful while the next one covers it. Featured projects is 2306px on a
     390px phone and What we do 2720px, and both behave.

     Still nothing on a short window. Under about 620px there is not enough left after the
     nav for a held section to read while it is being covered. */
  @media (max-height:620px){
    .js-pin #work.slide-under,
    .js-pin #clients ~ section.slide-under{position:relative;top:auto}
  }
