/* ============================================================
   TOKENS. Palette sampled from the Gutter Proof logo file,
   tinted toward the footage grade. Finalised after the video gate.
   ============================================================ */
:root{
  --canvas:#0A141C;
  --panel:#10202D;
  --navy-deep:#031B2E;
  --accent:#A7DA02;
  --accent-hover:#B9E203;
  --accent-muted:rgba(167,218,2,.22);
  --text-primary:#F4F6F3;
  --text-secondary:#93A6B4;
  --hairline:rgba(147,166,180,.18);
  --border-strong:rgba(147,166,180,.42);

  --display:"Bricolage Grotesque",Georgia,serif;
  --body:"Public Sans",system-ui,-apple-system,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,monospace;

  --ease:cubic-bezier(.16,1,.3,1);
  --ease-io:cubic-bezier(.65,0,.35,1);

  --tshadow:0 1px 2px rgba(5,5,10,.95),0 3px 12px rgba(5,5,10,.78),0 10px 44px rgba(5,5,10,.8);

  --pad:clamp(1.25rem,2vw + .5rem,4rem);
  --maxw:1380px;
}

*,*::before,*::after{box-sizing:border-box}
html,body{overflow-x:hidden;overflow-x:clip}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--canvas);color:var(--text-primary);
  font-family:var(--body);font-size:clamp(1rem,.96rem + .2vw,1.0625rem);line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
img,svg,video{display:block;max-width:100%}
h1,h2,h3,p{margin:0}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
ul,ol{margin:0;padding:0;list-style:none}

.skip{position:absolute;left:-9999px;top:0;z-index:999;background:var(--accent);color:#0A141C;padding:.75rem 1.25rem;font-weight:500}
.skip:focus{left:.5rem;top:.5rem}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

.wrap{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--pad)}

/* The fixed environment layer, so scrolling reads as one place */
.env{position:fixed;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(ellipse 120% 80% at 50% -10%,rgba(3,27,46,.55) 0%,transparent 60%),
    radial-gradient(ellipse 90% 60% at 80% 110%,rgba(16,32,45,.5) 0%,transparent 65%);
}
.env::after{content:"";position:absolute;inset:-20%;opacity:.05;
  background-image:repeating-linear-gradient(97deg,transparent 0 6px,rgba(244,246,243,.55) 6px 7px);
  animation:drift 90s linear infinite;
}
@keyframes drift{from{transform:translateY(-6%)}to{transform:translateY(6%)}}

/* ============================================================ NAV */
/* The bar is solid from the first pixel. It used to fade in on scroll, which
   left the logo floating on whatever frame the video happened to be showing. */
.nav{position:fixed;inset:0 0 auto 0;z-index:100;height:76px;display:flex;align-items:center;
  background:rgba(10,20,28,.82);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  border-bottom:1px solid var(--hairline);
  transition:background-color .4s var(--ease)}
.nav.solid{background:rgba(9,18,26,.94)}
.nav .wrap{display:flex;align-items:center;justify-content:space-between;gap:1rem}
.navlinks{margin-left:auto}
.brand img{height:56px;width:auto;filter:drop-shadow(0 2px 10px rgba(5,10,16,.5))}
.navlinks{display:flex;gap:2rem}
.navlinks a{font-size:.8125rem;letter-spacing:.03em;color:var(--text-primary);opacity:.82;transition:opacity .3s var(--ease)}
.navlinks a:hover{opacity:1}

/* THE MENU. Below 900px the row of links does not fit, so it becomes a panel
   that drops out of the bar. The bar keeps its height either way: the panel
   is positioned off it rather than laid out inside it. */
.navtoggle{display:none;position:relative;width:44px;height:44px;margin-right:-.4rem;
  flex:none;background:transparent;border:0;cursor:pointer;border-radius:6px}
.navtoggle span{position:absolute;left:11px;width:22px;height:2px;border-radius:2px;
  background:var(--text-primary);
  transition:transform .34s var(--ease),opacity .2s var(--ease),background-color .3s var(--ease)}
.navtoggle span:nth-child(1){top:15px}
.navtoggle span:nth-child(2){top:21px}
.navtoggle span:nth-child(3){top:27px}
.navtoggle:hover span{background:var(--accent)}
.navtoggle:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* three bars become a cross, on the bars themselves rather than a swap */
.nav.open .navtoggle span:nth-child(1){transform:translateY(6px) rotate(45deg)}
.nav.open .navtoggle span:nth-child(2){opacity:0;transform:scaleX(.4)}
.nav.open .navtoggle span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}

/* a scrim under the panel, so the page behind it reads as parked. It is a
   pseudo-element on the bar, which means a tap on it is a tap on .nav, and
   the close handler below tests the panel rather than the bar because of it. */
.nav::after{content:"";position:absolute;left:0;right:0;top:100%;height:100vh;z-index:1;
  background:rgba(4,10,16,.62);opacity:0;pointer-events:none;
  transition:opacity .32s var(--ease)}
.nav.open::after{opacity:1;pointer-events:auto}

.navmenu{position:absolute;left:0;right:0;top:100%;z-index:2;
  display:none;flex-direction:column;padding:.5rem var(--pad) 1.35rem;
  background:rgba(9,18,26,.97);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);
  border-bottom:1px solid var(--hairline);
  box-shadow:0 24px 44px rgba(2,8,14,.55);
  opacity:0;transform:translateY(-12px);pointer-events:none;
  transition:opacity .32s var(--ease),transform .32s var(--ease)}
.nav.open .navmenu{opacity:1;transform:none;pointer-events:auto}
.navmenu a:not(.btn){padding:.95rem .25rem;color:var(--text-primary);
  font-size:1.05rem;border-bottom:1px solid var(--hairline);
  opacity:0;transform:translateY(-8px);
  transition:opacity .3s var(--ease),transform .3s var(--ease),color .3s var(--ease)}
.navmenu a:not(.btn):last-of-type{border-bottom:0}
.navmenu a:not(.btn):hover,.navmenu a:not(.btn):focus-visible{color:var(--accent)}
/* the links follow the panel down one after another */
.nav.open .navmenu a:not(.btn){opacity:1;transform:none}
.nav.open .navmenu a:nth-child(1){transition-delay:.05s}
.nav.open .navmenu a:nth-child(2){transition-delay:.09s}
.nav.open .navmenu a:nth-child(3){transition-delay:.13s}
.nav.open .navmenu a:nth-child(4){transition-delay:.17s}
.nav.open .navmenu a:nth-child(5){transition-delay:.21s}
.navmenucta{margin-top:1.1rem;align-self:flex-start;
  opacity:0;transform:translateY(-8px);
  transition:opacity .3s var(--ease) .24s,transform .3s var(--ease) .24s,
             background-color .35s var(--ease)}
.nav.open .navmenucta{opacity:1;transform:none}

@media (max-width:900px){
  .navlinks{display:none}
  .navtoggle{display:block}
  .navmenu{display:flex}

  /* On a phone the bar starts out of the way and lets the footage run to the
     top of the screen. It builds itself the moment the page moves, and it is
     also solid whenever the menu is down, because a panel hanging off nothing
     reads as a rendering fault. */
  .nav{background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none;
    border-bottom-color:transparent;
    transition:background-color .35s var(--ease),border-color .35s var(--ease)}
  .nav.solid,.nav.open{background:rgba(9,18,26,.94);
    backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
    border-bottom-color:var(--hairline)}
  /* with no bar behind them the burger has to carry its own contrast, the
     way the logo already does */
  .navtoggle span{box-shadow:0 1px 5px rgba(4,10,16,.85)}
  .nav.solid .navtoggle span,.nav.open .navtoggle span{box-shadow:none}
}
@media (max-width:600px){.brand img{height:44px}}

/* ============================================================ HERO
   The footage plays itself, at its own speed, from the moment it is ready.
   Nothing here is driven by the scroll, so the hero is exactly one screen
   tall and the page underneath starts where the visitor expects it to. */
.hero{position:relative;z-index:1;height:100svh}
.stage{position:relative;height:100%;overflow:hidden;background:var(--navy-deep)}
.stage video,.poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.stage video{opacity:0;transition:opacity .9s var(--ease);will-change:opacity;transform:translateZ(0)}
.stage.video-ready video{opacity:1}
.poster{background-size:cover;background-position:center;transition:opacity .9s var(--ease)}
.stage.video-ready .poster{opacity:0}
.stage.video-failed video{display:none}

/* Layer 1 of the legibility system: the always-on base scrim */
/* The product footage is far brighter than the footage this replaced, so the
   base scrim carries a left-weighted layer as well: the copy sits on the left
   third, and this darkens that without flattening the rest of the frame. */
.scrim{position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(to right,rgba(6,10,16,.58) 0%,rgba(6,10,16,.14) 46%,rgba(6,10,16,0) 70%),
    radial-gradient(ellipse 120% 90% at 50% 45%,rgba(10,10,18,0) 32%,rgba(10,10,18,.66) 100%)}

.bands{position:absolute;inset:0;pointer-events:none}
.band{position:absolute;left:0;top:0;width:100%;height:100%;display:flex;align-items:center;
  opacity:0;padding-inline:var(--pad);text-shadow:var(--tshadow)}
.band .inner{position:relative;z-index:2;width:100%;max-width:var(--maxw);margin-inline:auto}
/* Containers get px or min(), never ch: a ch on a container resolves against
   the inherited body font, not the display face inside it, which collapses
   the headline to one word per line. */
.band .col{max-width:min(46rem,62vw)}
.band .btn{text-shadow:none}
/* Layer 2: the per-band scrim, riding the band's --k */
.band::before{content:"";position:absolute;inset:-4%;pointer-events:none;
  opacity:calc(.25 + .75*var(--k,1));
  background:radial-gradient(ellipse 74% 62% at 32% 50%,rgba(5,5,10,.68) 0%,rgba(5,5,10,.46) 46%,rgba(5,5,10,0) 76%)}
/* the snow shot is the brightest frame in the run; this is weighted to where
   the copy sits rather than laid over the whole picture */
.band.settle::before{background:radial-gradient(ellipse 84% 70% at 30% 55%,rgba(5,5,10,.84) 0%,rgba(5,5,10,.62) 44%,rgba(5,5,10,0) 80%)}

.hline{font-family:var(--display);font-weight:700;line-height:1.02;letter-spacing:-.02em;
  font-size:clamp(2rem,1.1rem + 3.6vw,4.5rem);margin:0;text-wrap:balance}
.hsub{margin-top:1.25rem;color:#E6EDF0;max-width:34ch;font-size:clamp(.95rem,.9rem + .25vw,1.125rem)}

.w,.c{display:inline-block}
.w{white-space:pre}
/* The hero entrance: word by word, then the subline, then the buttons, then
   the proof strip. It rides --k, which the load ramp drives to 1 over the
   first 900ms so the copy arrives without needing a scroll. */
.b3 .w{--kc:clamp(0,(var(--k,0) - var(--th,0))*2.6,1);opacity:var(--kc);
  transform:translateY(calc((1 - var(--kc))*18px))}
.b3 .hsub{--ks:clamp(0,(var(--k,0) - .58)*3.4,1);opacity:var(--ks);
  transform:translateY(calc((1 - var(--ks))*14px))}
.b3 .ctarow{--kb:clamp(0,(var(--k,0) - .74)*4,1);opacity:var(--kb);
  transform:translateY(calc((1 - var(--kb))*14px))}

.ctarow{margin-top:2rem;display:flex;gap:1rem;flex-wrap:wrap;align-items:center;pointer-events:auto}

/* The proof strip. Only claims that hold on day one, with no counts to
   outgrow or contradict later. It rides the settle band's own reveal. */
.proof{margin-top:1.75rem;display:flex;flex-wrap:wrap;gap:.55rem 1.5rem;
  /* --k tops out at 1, so this needed at least 1/.14 to finish: at *5 the
     strip settled at 70% and never actually arrived, unlike its siblings. */
  --kp:clamp(0,(var(--k,0) - .86)*7.4,1);opacity:var(--kp);
  transform:translateY(calc((1 - var(--kp))*10px))}
.proof li{display:flex;align-items:center;gap:.5rem;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.07em;text-transform:uppercase;
  color:#E8EEF1}
.proof li::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--accent);flex:none}
@media (max-width:720px){.proof{gap:.5rem 1rem}.proof li{font-size:.64rem}}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  font-family:var(--mono);font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;
  padding:1rem 1.6rem;border-radius:999px;border:1px solid transparent;
  transition:transform .35s var(--ease),background-color .35s var(--ease),border-color .35s var(--ease),color .35s var(--ease)}
.btn-primary{background:var(--accent);color:#0A141C}
.btn-primary:hover{background:var(--accent-hover);transform:translateY(-2px)}
.btn-ghost{border-color:var(--border-strong);color:var(--text-primary)}
.btn-ghost:hover{border-color:var(--text-primary);transform:translateY(-2px)}
@media (pointer:coarse){.btn{min-height:44px}}

/* PROUDLY CANADIAN. Top right of whichever hero the visitor was given,
   clear of the fixed nav above it. An outlined leaf and two words: the
   claim is small on purpose, because it is a fact and not a headline. */
.canbadge{position:absolute;z-index:4;right:var(--pad);top:calc(76px + clamp(.75rem,2.4vh,1.5rem));
  display:inline-flex;align-items:center;gap:.6rem;
  padding:.55rem .95rem .55rem .8rem;border-radius:999px;
  border:1px solid rgba(167,218,2,.38);background:rgba(7,15,22,.62);
  backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px);
  text-shadow:none;pointer-events:none;
  opacity:0;transform:translateY(-8px);
  animation:canin .9s var(--ease) .75s forwards}
@keyframes canin{to{opacity:1;transform:none}}
.canbadge .leaf{width:1.35rem;height:1.35rem;flex:none;color:var(--accent);
  fill:none;stroke:currentColor;stroke-width:1.5;stroke-linejoin:round;stroke-linecap:round}
.canbadge b{font-family:var(--mono);font-weight:500;font-size:.68rem;letter-spacing:.14em;
  text-transform:uppercase;color:#EDF3F5;line-height:1.15;white-space:nowrap}
.canbadge b span{display:block;font-size:.58rem;letter-spacing:.1em;
  color:#B9C7D1;margin-top:.18rem}
@media (max-width:900px){
  .canbadge{top:calc(76px + 1.15rem);padding:.45rem .8rem .45rem .65rem;gap:.5rem}
  .canbadge .leaf{width:1.1rem;height:1.1rem}
  .canbadge b{font-size:.6rem;letter-spacing:.12em}
  .canbadge b span{display:none}
}
@media (max-width:600px){.canbadge{top:calc(76px + 1rem)}}

/* the scroll cue, in the corner the loading ring used to hold */
.chev{position:absolute;right:var(--pad);bottom:calc(var(--pad) + .5rem);width:26px;height:26px;
  color:var(--text-secondary);z-index:3;animation:chev 2.4s var(--ease-io) infinite}
@keyframes chev{0%,100%{transform:translateY(0);opacity:.5}50%{transform:translateY(7px);opacity:1}}

/* The static hero, a designed layout rather than an apology. It carries the
   same footage on a phone, playing itself behind the copy, and falls back to
   the still underneath it whenever the video cannot or should not run. */
.static-hero{display:none;position:relative;z-index:1;min-height:100svh;overflow:hidden;
  background:var(--navy-deep) center/cover no-repeat;align-items:flex-end}
.static-hero video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .9s var(--ease)}
.static-hero.video-ready video{opacity:1}
.static-hero .veil{position:absolute;inset:0;z-index:1;
  background:linear-gradient(to top,rgba(6,12,18,.94) 8%,rgba(6,12,18,.42) 52%,rgba(6,12,18,.55) 100%)}
.static-hero .inner{position:relative;z-index:2;padding:var(--pad) var(--pad) clamp(3rem,9vh,5rem);width:100%;
  max-width:var(--maxw);margin-inline:auto}
/* the proof strip rides --k, which only the wide hero's band writes. There is
   no band here, so it would read the 0 fallback and stay invisible. */
.static-hero .proof{opacity:1;transform:none}

/* ============================================================ SECTIONS */
main{position:relative;z-index:1}
section{position:relative}
.sec{padding-block:clamp(3.5rem,7.5vh,5.5rem)}
/* the header is fixed, so an anchor jump must clear it or the section
   heading lands underneath the nav */
section[id],main[id]{scroll-margin-top:calc(76px + 1.5rem)}
.kicker{font-family:var(--mono);font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--text-secondary);display:inline-flex;align-items:center;gap:.6rem}
.kicker::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--accent);flex:none}
.h2{font-family:var(--display);font-weight:700;letter-spacing:-.02em;line-height:1.06;
  font-size:clamp(1.75rem,1.1rem + 2.4vw,3.25rem);margin-block:1.1rem 1.25rem;max-width:18ch;
  text-wrap:balance}
.lede{color:var(--text-secondary);max-width:56ch}

/* Two-tone headlines. The white carries the sentence, the lime carries the
   point of it. Which words go lime is set per headline with data-lime, so the
   split can rebuild the text without markup getting in its way. */
.w.lm,.lm{color:var(--accent)}
.h2 .lm{color:var(--accent)}

/* The icon sprite. One <symbol> each, drawn once, referenced everywhere. */
.ic{width:1.35rem;height:1.35rem;flex:none;color:var(--accent);
  stroke:currentColor;fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.ic--lg{width:1.9rem;height:1.9rem}
.ic--sm{width:1.05rem;height:1.05rem}

/* THE STICKY CALL TO ACTION. It follows, it is not in a corner of the header,
   and it stands down while the form it points at is already on screen. */
.stickycta{position:fixed;z-index:90;left:50%;bottom:clamp(1rem,3.5vh,2.25rem);
  background-image:linear-gradient(100deg,transparent 36%,rgba(255,255,255,.42) 50%,transparent 64%);
  background-size:300% 100%;background-repeat:no-repeat;background-position:190% 0;
  display:inline-flex;align-items:center;gap:.7rem;white-space:nowrap;
  font-family:var(--mono);font-size:.78rem;letter-spacing:.09em;text-transform:uppercase;
  color:#08131A;background:var(--accent);padding:1.05rem 1.75rem;border-radius:999px;
  box-shadow:0 12px 38px rgba(0,0,0,.5),0 0 0 1px rgba(167,218,2,.45),
             0 0 44px rgba(167,218,2,.22);
  opacity:0;pointer-events:none;transform:translate(-50%,150%);
  transition:transform .6s var(--ease),opacity .45s var(--ease),
             background-color .3s var(--ease),box-shadow .3s var(--ease)}
.stickycta.on{opacity:1;pointer-events:auto;transform:translate(-50%,0);
  animation:ctashine 4s var(--ease-io) infinite}
/* a light crossing the button and a nudge on the arrow. Both are cheap: the
   sweep is a background-position on a small box, the nudge a transform on a
   16px icon. Neither touches the button's own transform, which .on owns. */
@keyframes ctashine{0%{background-position:190% 0}58%,100%{background-position:-90% 0}}
.stickycta.on svg{animation:ctanudge 4s var(--ease-io) infinite}
@keyframes ctanudge{0%,70%,100%{transform:translateX(0)}
                    79%{transform:translateX(4px)}88%{transform:translateX(0)}}
.stickycta:hover{background:var(--accent-hover);
  box-shadow:0 14px 42px rgba(0,0,0,.55),0 0 0 1px rgba(167,218,2,.7),0 0 60px rgba(167,218,2,.34)}
.stickycta svg{width:16px;height:16px;flex:none}
/* the quiet pulse of the ring, so a still page still reads as live */
.stickycta::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--accent);opacity:0;animation:ctaring 3.4s var(--ease-io) infinite}
.stickycta.on::after{animation-play-state:running}
@keyframes ctaring{0%{transform:scale(1);opacity:.55}70%,100%{transform:scale(1.22);opacity:0}}
@media (max-width:600px){
  .stickycta{left:var(--pad);right:var(--pad);transform:translateY(150%);
    justify-content:center;padding:1rem;font-size:.72rem}
  /* on a phone this is the only call to action on screen, so everything
     comes round faster and the ring travels further */
  .stickycta.on{transform:translateY(0);animation-duration:3.2s}
  .stickycta.on svg{animation-duration:3.2s}
  .stickycta::after{animation:ctaring 2.6s var(--ease-io) infinite}
}
@media (prefers-reduced-motion:reduce){
  .stickycta::after{display:none}
  .stickycta.on,.stickycta.on svg{animation:none}
  .stickycta{background-image:none}
}

/* ============================================================
   THE SCROLL ENGINE. Every element that moves on scroll carries
   data-fx and reads one number, --e, which runs 0 to 1 as the
   element crosses the viewport. JS writes only that number, and
   only when it has actually changed; CSS decides what it means.
   Nothing below touches layout, so nothing below can cost a frame.
   ============================================================ */
/* scoped to .js on purpose: with no script, --e is never defined, every
   calc() below is invalid at computed-value time, and the page renders
   fully visible and unmoved. The motion is an enhancement, not a gate. */
.js [data-fx],.js [data-fx-stagger]{--e:0}
[data-fx="rise"]{opacity:var(--e);transform:translate3d(0,calc((1 - var(--e)) * 26px),0)}
[data-fx="left"]{opacity:var(--e);transform:translate3d(calc((1 - var(--e)) * -44px),0,0)}
[data-fx="right"]{opacity:var(--e);transform:translate3d(calc((1 - var(--e)) * 44px),0,0)}
[data-fx="grow"]{opacity:var(--e);transform:scale(calc(.955 + .045 * var(--e)))}
[data-fx="rule"]{transform:scaleX(var(--e));transform-origin:0 50%}
/* a slow counter-drift against the page, for imagery only */
[data-fx="par"]{transform:translate3d(0,calc((.5 - var(--e)) * 46px),0);will-change:transform}
[data-fx="parx"]{transform:translate3d(calc((.5 - var(--e)) * 40px),0,0);will-change:transform}
/* headlines arrive a word at a time, each word on its own threshold */
[data-fx="words"] .w{--kc:clamp(0,(var(--e) - var(--th,0)) * 3.4,1);
  opacity:var(--kc);transform:translate3d(0,calc((1 - var(--kc)) * .44em),0)}
/* a stagger for anything laid out as a row or a grid of siblings */
[data-fx-stagger] > *{--kc:clamp(0,(var(--e) - var(--th,0)) * 3.2,1);
  opacity:var(--kc);transform:translate3d(0,calc((1 - var(--kc)) * 22px),0)}


/* ============================================================
   THE LIVE BACKGROUND. Three soft lights drifting behind a flat
   section, plus a sheen that crosses it. They are radial gradients
   with long transparent tails, so there is no blur filter to
   raster: the only thing that moves is a transform.
   ============================================================ */
.haslive{position:relative;overflow:hidden}
.haslive > .wrap{position:relative;z-index:1}
/* the lights sit under a scrim, not next to the copy. Without it the lime
   pushes the background luminance up and the secondary text drops to 2.5:1. */
.haslive::after{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:rgba(4,14,23,.56)}
.livebg{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
.livebg i{position:absolute;display:block;border-radius:50%;will-change:transform}
.livebg i:nth-child(1){width:64vw;aspect-ratio:1;left:-18%;top:-34%;
  background:radial-gradient(circle,rgba(167,218,2,.46) 0%,rgba(167,218,2,.18) 36%,transparent 70%);
  animation:lb1 38s var(--ease-io) infinite alternate}
.livebg i:nth-child(2){width:54vw;aspect-ratio:1;right:-16%;top:18%;
  background:radial-gradient(circle,rgba(58,150,208,.44) 0%,rgba(58,150,208,.16) 38%,transparent 72%);
  animation:lb2 46s var(--ease-io) infinite alternate}
.livebg i:nth-child(3){width:58vw;aspect-ratio:1;left:22%;bottom:-38%;
  background:radial-gradient(circle,rgba(167,218,2,.34) 0%,rgba(167,218,2,.13) 40%,transparent 74%);
  animation:lb3 54s var(--ease-io) infinite alternate}
@keyframes lb1{from{transform:translate3d(0,0,0) scale(1)}
                 to{transform:translate3d(16%,12%,0) scale(1.18)}}
@keyframes lb2{from{transform:translate3d(0,0,0) scale(1.1)}
                 to{transform:translate3d(-14%,-16%,0) scale(.92)}}
@keyframes lb3{from{transform:translate3d(0,0,0) scale(.95)}
                 to{transform:translate3d(-18%,-10%,0) scale(1.2)}}
.livebg::after{content:"";position:absolute;left:0;right:0;top:0;height:1px;
  background:linear-gradient(to right,transparent,rgba(167,218,2,.6),transparent)}

/* ============================================================
   S1, THE REAL COST. A drawn house holds still while the list of
   what water does to it scrolls past. Each item lights its own
   marker, and the markers run from the eave down to below grade,
   so scrolling is literally following the water down the building.
   ============================================================ */
/* no overflow:hidden here: an ancestor that clips makes itself the scroll
   container for position:sticky inside it, and the house then releases. The
   glow below is inset:0 so there is nothing to clip anyway. */
.costsec{position:relative}
.costsec::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse 70% 50% at 78% 30%,rgba(167,218,2,.05),transparent 70%)}
.costsec > .wrap{position:relative;z-index:1}

.hazgrid{margin-top:clamp(2.5rem,6vh,4rem);display:grid;
  grid-template-columns:.95fr 1.05fr;gap:clamp(1.5rem,4vw,4rem);align-items:stretch}
/* the sticky element has to live inside a box that spans the whole row, or it
   runs out of containing block and releases halfway down the list */
.hazstage{position:relative}
.hazsticky{position:sticky;top:calc(76px + clamp(1rem,4vh,2.5rem));
  padding-block:clamp(.5rem,2vh,1.5rem)}

/* On a wide screen the house sits beside the list and the following button
   is already on screen the whole way down, so there is nothing to add. */
.hazcta{display:none}
.house{width:100%;height:auto;max-height:74svh;overflow:visible}

.soil{fill:#08131B}
.grade{stroke:rgba(147,166,180,.35);stroke-width:2}
.cellar{fill:rgba(10,25,36,.85);stroke:rgba(147,166,180,.22);stroke-width:1.5;stroke-dasharray:7 7}
.drive{fill:#16242F;stroke:rgba(147,166,180,.22);stroke-width:1.5}
/* the second slab sits proud of the first: that offset is the heave */
.drive--up{fill:#1B2C39;stroke:rgba(147,166,180,.3)}
.roof{fill:url(#roofg);stroke:rgba(147,166,180,.3);stroke-width:2}
.wall{fill:url(#wallg);stroke:rgba(147,166,180,.28);stroke-width:2}
.found{fill:#101F2B;stroke:rgba(147,166,180,.24);stroke-width:1.5}
.fascia{fill:#243A4B}
.gutter{fill:#2E4757;stroke:rgba(167,218,2,.32);stroke-width:1.5}
.spout{stroke:#2E4757;stroke-width:9;fill:none;stroke-linecap:round}
.win rect{fill:rgba(167,218,2,.07);stroke:rgba(147,166,180,.32);stroke-width:1.5}
.win path{stroke:rgba(147,166,180,.3);stroke-width:1.4;fill:none}
.door{fill:#0E1D28;stroke:rgba(147,166,180,.3);stroke-width:1.5}
.siding path{stroke:rgba(147,166,180,.12);stroke-width:1.2;fill:none}

/* the markers. Dim until their entry in the list is the one being read. */
.pin2{transform-box:fill-box;transform-origin:center}
.p2halo{fill:rgba(167,218,2,.14);opacity:0;transform-box:fill-box;transform-origin:center;
  transform:scale(.5);transition:opacity .5s var(--ease),transform .5s var(--ease)}
/* stroke-width is not a compositor property, and these pins change state
   while the page is being scrolled, which is the worst moment to ask for a
   repaint. It still steps 2.4 to 3 on activation; it just is not eased there,
   and at 0.6px under an opacity that triples at the same time, nothing shows. */
.p2ring{fill:#0A141C;stroke:var(--accent);stroke-width:2.4;opacity:.34;
  transition:opacity .5s var(--ease)}
.p2n{fill:var(--accent);font-family:var(--mono);font-size:13px;text-anchor:middle;
  opacity:.4;transition:opacity .5s var(--ease)}
.pin2.on .p2halo{opacity:1;transform:scale(1)}
.pin2.on .p2ring{opacity:1;stroke-width:3}
.pin2.on .p2n{opacity:1}
.pin2.past .p2ring,.pin2.past .p2n{opacity:.72}

/* the list */
.hazlist{list-style:none;padding:0;margin:0;display:grid;gap:clamp(.75rem,2vh,1.25rem)}
.haz{display:grid;grid-template-columns:clamp(96px,13vw,148px) 1fr;gap:clamp(1rem,2vw,1.5rem);
  align-items:center;padding:clamp(.85rem,1.6vw,1.15rem);border-radius:6px;
  border:1px solid var(--hairline);background:rgba(16,32,45,.5);
  opacity:.42;transform:translate3d(0,0,0);
  transition:opacity .55s var(--ease),background-color .55s var(--ease),
             border-color .55s var(--ease),transform .55s var(--ease)}
.haz.on{opacity:1;background:rgba(19,38,53,.92);border-color:rgba(167,218,2,.34);
  transform:translate3d(6px,0,0)}
.haz figure{margin:0;border-radius:4px;overflow:hidden;aspect-ratio:1;
  border:1px solid var(--hairline);background:var(--panel)}
.haz img{width:100%;height:100%;object-fit:cover;display:block;
  filter:saturate(.7) contrast(1.03);transition:filter .6s var(--ease),transform .8s var(--ease)}
.haz.on img{filter:saturate(1) contrast(1.05);transform:scale(1.04)}
.hazn{font-family:var(--mono);font-size:.66rem;letter-spacing:.18em;color:var(--accent);opacity:.55;
  transition:opacity .5s var(--ease)}
.haz.on .hazn{opacity:1}
.haz h3{font-family:var(--display);font-weight:700;letter-spacing:-.02em;margin-top:.35rem;
  font-size:clamp(1.05rem,.95rem + .55vw,1.35rem);line-height:1.15}
.haz p{margin-top:.45rem;color:var(--text-secondary);font-size:.92rem;line-height:1.5}

@media (max-width:960px){
  /* On a phone the house leaves the flow and pins to the bottom of the screen,
     and the seven photographs scroll up over the top of it. The list carries
     enough bottom padding that the last card still clears the house. */
  .hazgrid{display:block}
  .hazlist{padding-bottom:2rem}
  .hazstage{position:fixed;left:0;right:0;bottom:0;z-index:40;pointer-events:none;
    padding:.6rem var(--pad) calc(.7rem + env(safe-area-inset-bottom,0px));
    background:linear-gradient(to top,var(--canvas) 44%,rgba(10,20,28,.88) 72%,rgba(10,20,28,0) 97%);
    opacity:0;transform:translateY(104%);
    transition:opacity .5s var(--ease),transform .5s var(--ease)}
  .hazstage.pinned{opacity:1;transform:none}
  .hazsticky{position:static;padding:0;background:none}
  .house{max-height:34svh;margin-inline:auto;display:block}
  /* the way out, under the house, inside the pinned strip. The strip itself
     is pointer-events:none so the list underneath stays scrollable; the
     button is the one thing in it that takes a tap. */
  .hazcta{display:flex;pointer-events:auto;width:100%;max-width:22rem;
    margin:.7rem auto 0;padding-block:.85rem}
  .p2n{font-size:19px}
  .p2ring{stroke-width:3.4}
}
@media (max-width:520px){
  .haz{grid-template-columns:clamp(78px,22vw,110px) 1fr;padding:.75rem}
  .haz p{font-size:.86rem}
}

.costnums{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--hairline);
  border:1px solid var(--hairline);border-radius:6px;overflow:hidden;
  margin-top:clamp(2.5rem,6vh,4rem)}
.costnum{background:rgba(16,32,45,.72);padding:clamp(1.1rem,2.2vw,1.6rem)}
/* Each numeral counts up to itself when the strip arrives, so the box it
   sits in has to be the width of the finished number from the start, or the
   line reflows on every tick. Tabular figures make every digit the same
   width, and the box is reserved in ch, so only the glyphs change. */
/* .costnum span is the label under the number and it is display:block, so
   this has to out-specify it or every digit run becomes its own line. The
   width it holds while counting is measured in px from the finished number,
   not guessed in ch: a ch is the advance of a proportional zero and the
   tabular figures used here are not the same width. */
.costnum b .cnum{display:inline-block;margin:0;text-align:left;
  font:inherit;letter-spacing:inherit;color:inherit;text-transform:none;
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.costnum b{display:block;font-family:var(--display);font-weight:700;letter-spacing:-.02em;
  font-size:clamp(1.35rem,1rem + 1.6vw,2.15rem);line-height:1.05}
.costnum span{display:block;margin-top:.5rem;font-family:var(--mono);font-size:.64rem;
  letter-spacing:.12em;text-transform:uppercase;color:var(--text-secondary);line-height:1.5}
@media (max-width:860px){.costnums{grid-template-columns:1fr;margin-top:clamp(1.5rem,4vh,2.5rem)}}

/* ============================================================
   S2, THE WALL. Eight guards that were all sold as the last one
   the owner would ever need. Each photograph drifts at its own
   speed as the section passes, so the wall reads as a place you
   are moving through rather than a grid of thumbnails.
   ============================================================ */
.h2--wide{max-width:26ch}
.wall{margin-top:3.25rem;display:grid;grid-template-columns:repeat(4,1fr);
  gap:clamp(.75rem,1.4vw,1.25rem);align-items:start}
.wi{position:relative;margin:0;border-radius:5px;overflow:hidden;
  border:1px solid var(--hairline);background:var(--panel);
  transition:border-color .45s var(--ease),transform .45s var(--ease)}
.wi img{width:100%;height:auto;aspect-ratio:4/3;object-fit:cover;display:block;
  filter:saturate(.82) contrast(1.04);transition:filter .5s var(--ease),transform .7s var(--ease)}
.wi:hover{border-color:rgba(167,218,2,.5);transform:translateY(-4px)}
.wi:hover img{filter:saturate(1) contrast(1.04);transform:scale(1.035)}
/* every one of them carries the same mark, which is the whole point */
.wibadge{position:absolute;top:.6rem;right:.6rem;width:1.85rem;height:1.85rem;display:grid;
  place-items:center;border-radius:50%;background:rgba(8,16,22,.72);
  border:1px solid rgba(226,114,91,.55);backdrop-filter:blur(6px)}
.wibadge .ic{width:.95rem;height:.95rem;color:#E2725B;stroke-width:2.1}
/* the wall's own parallax: each tile has its own --sp so nothing moves in lockstep */
.wall [data-fx="par"]{transform:translate3d(0,calc((.5 - var(--e,.5)) * var(--sp,1) * 42px),0)}
@media (max-width:1000px){.wall{grid-template-columns:repeat(3,1fr)}}
@media (max-width:700px){
  .wall{grid-template-columns:repeat(2,1fr)}
  .wall [data-fx="par"]{transform:translate3d(0,calc((.5 - var(--e,.5)) * var(--sp,1) * 18px),0)}
}

.verdict{margin-top:clamp(3rem,7vh,5rem);font-family:var(--display);font-weight:700;
  letter-spacing:-.03em;line-height:1.02;font-size:clamp(1.85rem,1rem + 4.2vw,4rem);
  max-width:20ch}

/* the resolution, set apart so it reads as the answer to the wall */
.resolve{margin-top:clamp(2rem,5vh,3rem);padding:clamp(1.5rem,3vw,2.25rem);border-radius:6px;
  background:var(--panel);border:1px solid var(--hairline);border-left:3px solid var(--accent);
  max-width:64rem;position:relative;overflow:hidden}
.resolve::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse 40% 90% at 0% 50%,rgba(167,218,2,.09),transparent 70%)}
.resolve p{color:var(--text-secondary);margin-top:1rem;max-width:64ch;position:relative}
/* the answer to the whole section, so it lands a word at a time rather than
   arriving as one more paragraph */
.resolve-lead{font-family:var(--display);font-weight:700;letter-spacing:-.02em;line-height:1.1;
  font-size:clamp(1.35rem,1.05rem + 1.3vw,2.1rem);color:var(--text-primary) !important;
  text-wrap:balance}
.resolve-lead .w{--kw:clamp(0,(var(--e,1) - var(--th,0) * .8) * 2.8,1);
  opacity:var(--kw);transform:translateY(calc((1 - var(--kw)) * 12px))}
.resolve .resolve-kicker{color:var(--text-secondary);font-weight:400;
  opacity:clamp(0,(var(--e,1) - .45) * 2.6,1)}

/* ============================================================
   S2b, THE COMPARISON. Two columns that arrive from opposite
   sides, an icon on every line, and a lime rule that fills down
   the side of the column that matters.
   ============================================================ */
/* ============================================================
   S2a, WHO WE ARE. Three complaints and one answer. Each one
   arrives from the side it is aligned to, an outlined numeral
   grows in with it, and behind the whole run a maple leaf draws
   itself with its own stroke. Everything rides --e, the same one
   number every other moving thing on this page reads.
   ============================================================ */
.whosec{position:relative;overflow:hidden}
.whosec::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse 62% 58% at 14% 18%,rgba(167,218,2,.055),transparent 68%)}
.whosec > .wrap{position:relative;z-index:2}
.whoh2{max-width:19ch}
.whosec .lede{max-width:52ch}

.whorun{position:relative;margin-top:clamp(2rem,6vh,3.5rem)}
.whoclaims{position:relative;z-index:2}

/* the leaf. It is drawn, not filled: the stroke runs round the outline as
   the run arrives, so the section has one thing in it that is being made
   rather than being shown. */
.wholeaf{position:absolute;z-index:1;pointer-events:none;
  right:-3vw;bottom:-4%;width:min(30rem,32vw);height:auto;
  fill:none;stroke:var(--accent);stroke-width:.11;stroke-linejoin:round;stroke-linecap:round;
  opacity:calc(.07 + .21 * var(--e,1))}
.wholeaf path{stroke-dasharray:1;stroke-dashoffset:calc(1 - var(--e,1))}

/* a complaint. --from is which side it comes in from, and it is the only
   thing that changes between the left ones and the right one. */
.whoclaim{--from:-1;position:relative;display:grid;grid-template-columns:auto 1fr;
  gap:clamp(1rem,2.6vw,2.2rem);align-items:start;
  max-width:min(40rem,72%);padding-block:clamp(1.4rem,3.6vh,2.4rem);
  opacity:calc(.06 + .94 * var(--e,1));
  transform:translate3d(calc((1 - var(--e,1)) * var(--from) * 110px),0,0);
  will-change:transform,opacity}
.whoclaim[data-side="r"]{--from:1;margin-left:auto;text-align:right;
  grid-template-columns:1fr auto}
.whoclaim[data-side="r"] .whon{order:2}
.whoclaim[data-side="r"] .whotext{order:1}

/* the numeral is an outline, like the leaf and like the badge in the hero */
.whon{font-family:var(--display);font-weight:700;line-height:.78;letter-spacing:-.045em;
  font-size:clamp(2.75rem,1.6rem + 4.6vw,5.5rem);
  color:transparent;-webkit-text-stroke:1.6px rgba(167,218,2,.45);
  opacity:calc(.15 + .85 * var(--e,1));
  transform:scale(calc(.82 + .18 * var(--e,1)));transform-origin:50% 40%}

.whotag{display:block;position:relative;padding-bottom:.65rem;margin-bottom:.75rem;
  font-family:var(--mono);font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;
  color:#E2725B}
/* the rule under the label draws itself across as the line arrives */
.whotag::after{content:"";position:absolute;left:0;bottom:0;height:1px;
  width:calc(var(--e,1) * 100%);max-width:4.5rem;background:currentColor;opacity:.6}
.whoclaim[data-side="r"] .whotag::after{left:auto;right:0}
.whoclaim p{margin:0;color:var(--text-secondary);
  font-size:clamp(.98rem,.94rem + .25vw,1.1rem);line-height:1.55}

/* the answer */
.whoturn{position:relative;margin-top:clamp(1.75rem,4.5vh,3rem);
  padding-top:clamp(1.75rem,4.5vh,2.75rem);max-width:min(42rem,64%);
  border-top:1px solid rgba(167,218,2,.3);
  opacity:calc(.1 + .9 * var(--e,1));
  transform:translate3d(0,calc((1 - var(--e,1)) * 30px),0)}
.whoturn::before{content:"";position:absolute;left:0;top:-1px;height:2px;
  width:calc(var(--e,1) * 6rem);background:var(--accent);
  box-shadow:0 0 14px rgba(167,218,2,.55)}
.whoturn .whotag--us{color:var(--accent)}
.whobig{font-family:var(--display);font-weight:700;letter-spacing:-.025em;line-height:1.05;
  font-size:clamp(1.5rem,1.1rem + 1.9vw,2.5rem);margin:0 0 1rem;text-wrap:balance}
/* the line assembles word by word off the block's own arrival */
.whobig .w{--kw:clamp(0,(var(--e,1) - var(--th,0)) * 3.2,1);
  opacity:var(--kw);transform:translateY(calc((1 - var(--kw)) * 14px))}
.whoturn > p{color:var(--text-primary);max-width:52ch;
  font-size:clamp(.98rem,.94rem + .25vw,1.1rem);line-height:1.6}

.whoflag{margin-top:1.75rem;display:inline-flex;align-items:center;gap:.7rem;
  padding:.85rem 1.15rem;border-radius:999px;
  border:1px solid rgba(167,218,2,.3);background:rgba(167,218,2,.06)}
.whoflag span{font-family:var(--mono);font-size:.7rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--text-primary);line-height:1.4}

@media (max-width:860px){
  /* the sides still alternate, because that is the point of the run, but the
     travel comes down so nothing has to cross the whole screen to arrive */
  .whoclaim{max-width:none;grid-template-columns:auto 1fr;
    transform:translate3d(calc((1 - var(--e,1)) * var(--from) * 46px),0,0)}
  .whoclaim[data-side="r"]{text-align:left;grid-template-columns:auto 1fr}
  .whoclaim[data-side="r"] .whon{order:0}
  .whoclaim[data-side="r"] .whotext{order:0}
  .whoclaim[data-side="r"] .whotag::after{left:0;right:auto}
  .whoturn{max-width:none}
  .wholeaf{right:-14vw;bottom:-2%;width:min(22rem,60vw);
    opacity:calc(.05 + .13 * var(--e,1))}
}

.vssec{background:linear-gradient(to bottom,var(--canvas) 0%,#071722 50%,var(--canvas) 100%)}

/* ============================================================
   S2b, THE DIFFERENCE. One beat per row, and the row is the
   argument: the usual way is written, a line is drawn through it
   as it is read, and ours arrives from the other side. Three
   numbers off the one --e drive all of it, so the whole thing is
   still just opacity and transform.
   ============================================================ */
/* the fold. Shut on arrival, and the button says what is inside it rather
   than saying "more". */
.vsdrop{margin-top:clamp(2rem,5vh,3rem);
  border-top:1px solid var(--hairline);border-bottom:1px solid var(--hairline)}
.vsdrop summary{list-style:none;cursor:pointer;padding-block:1.35rem;
  display:flex;align-items:center;justify-content:space-between;gap:1.5rem;
  font-family:var(--mono);font-size:.8rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--text-primary);transition:color .3s var(--ease)}
.vsdrop summary::-webkit-details-marker{display:none}
.vsdrop summary:hover{color:var(--accent)}
.vsdrop summary:focus-visible{outline:2px solid var(--accent);outline-offset:4px}
/* the chevron is drawn, not typed, so it turns cleanly on both sides */
.vsdrop summary i{flex:none;width:.62rem;height:.62rem;border-right:1.6px solid var(--accent);
  border-bottom:1.6px solid var(--accent);transform:translateY(-25%) rotate(45deg);
  transition:transform .35s var(--ease)}
.vsdrop[open] summary i{transform:translateY(15%) rotate(-135deg)}
@media (pointer:coarse){.vsdrop summary{padding-block:1.15rem;min-height:44px}}

.difs{list-style:none;margin:0;padding:0 0 clamp(.5rem,2vh,1.25rem)}
.difrow{
  --in:clamp(0,var(--e,1) * 1.9,1);              /* the row arriving */
  --cut:clamp(0,(var(--e,1) - .38) * 2.6,1);     /* the line through it */
  --swap:clamp(0,(var(--e,1) - .56) * 2.6,1);    /* what replaces it */
  display:grid;grid-template-columns:minmax(9rem,14rem) 1fr;
  gap:.5rem clamp(1.25rem,3vw,2.5rem);align-items:start;
  padding-block:clamp(1.35rem,3.4vh,2.1rem);
  border-top:1px solid var(--hairline)}

.difk{grid-column:1;grid-row:1 / span 2;
  display:flex;align-items:center;gap:.6rem;padding-top:.2rem;
  font-family:var(--mono);font-size:.68rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--text-secondary);
  opacity:calc(.2 + .8 * var(--in))}
.difk .ic{width:1.1rem;height:1.1rem;
  transform:scale(calc(.55 + .45 * var(--in)))}

.difrow p{margin:0;display:flex;align-items:flex-start;gap:.6rem;
  font-size:clamp(1rem,.95rem + .3vw,1.18rem);line-height:1.45}

/* the way it usually goes. It arrives from the left, then dims as the line
   finishes crossing it, because it is no longer the answer. */
.difthem{grid-column:2;grid-row:1;color:var(--text-secondary);
  opacity:calc((.08 + .92 * var(--in)) * (1 - .52 * var(--swap)));
  transform:translate3d(calc((1 - var(--in)) * -48px),0,0)}
/* The drawn bar only works while the sentence is one line: an absolutely
   positioned rule inside a wrapped inline box strikes the block, not the
   lines. Wide screens keep the draw; anywhere the sentence can wrap, the
   real line-through does the job and its colour is what wipes in. */
.difthem s{position:relative;text-decoration:none}
.difthem s::after{content:"";position:absolute;left:0;top:56%;height:2px;border-radius:2px;
  width:calc(var(--cut) * 100%);background:#E2725B;
  box-shadow:0 0 10px rgba(226,114,91,.45)}
@media (max-width:1100px){
  .difthem s::after{display:none}
  .difthem s{text-decoration:line-through;text-decoration-thickness:2px;
    text-decoration-color:rgba(226,114,91,calc(var(--cut)))}
}

/* and ours, from the other side, once the line has been drawn */
.difus{grid-column:2;grid-row:2;margin-top:.55rem;color:var(--text-primary);font-weight:500;
  opacity:var(--swap);
  transform:translate3d(calc((1 - var(--swap)) * 48px),0,0)}
.difus .ic{width:1.15rem;height:1.15rem;margin-top:.25rem;
  transform:scale(calc(.5 + .5 * var(--swap)))}

@media (max-width:760px){
  .difrow{grid-template-columns:1fr;gap:.65rem}
  .difk,.difthem,.difus{grid-column:1;grid-row:auto}
  .difthem{transform:translate3d(calc((1 - var(--in)) * -26px),0,0)}
  .difus{transform:translate3d(calc((1 - var(--swap)) * 26px),0,0)}
}

/* ============================================================
   S3, THE PROCESS. Six photographs of the same gutter, one camera
   position, one light. They crossfade on scroll so the run visibly
   changes under the copy. Five captions, and each one lands in a
   different part of the screen, so reading the process means
   travelling across the frame with it.
   Everything here is transform and opacity.
   ============================================================ */
.procseq{position:relative;background:#04121D}
.procseq.pinned{height:700vh}
.procstage{position:sticky;top:0;height:100svh;overflow:hidden;display:none}
.procseq.pinned .procstage{display:block}

/* The camera rig. Wider and taller than the stage so a lateral drift and a
   zoom arc never expose an edge. All six frames share it, so they pan and
   scale as one and the crossfade never slips. */
.proccam{position:absolute;left:-6%;top:-4.5%;width:112%;height:109%;
  will-change:transform;transform:translateZ(0);backface-visibility:hidden}
.proccam picture{display:contents}
.pshot{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;will-change:opacity;transform:translateZ(0)}
/* frame one is the state of the gutter before anyone touches it, and it is
   the floor the other five stack on: it never fades. */
#pshot-1{opacity:1}

/* The legibility system. Captions land in four different corners, so the
   scrim is weighted to all four rather than to the bottom. These are
   full-bleed layers on purpose: a scrim sized to the caption box shows its
   own rectangle over a photograph, which is worse than the problem it fixes.
   The middle of the frame, where the gutter is, stays open. */
.procveil{position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(ellipse 42% 52% at 4% 94%,rgba(2,10,17,.94) 0%,rgba(2,10,17,.80) 48%,rgba(2,10,17,0) 100%),
    /* the top left is the one hard corner: it is the blown-out sunset sky, and
       step two lands on it. It carries more weight than the other three. */
    radial-gradient(ellipse 54% 62% at 3% 2%, rgba(2,10,17,.96) 0%,rgba(2,10,17,.90) 54%,rgba(2,10,17,0) 100%),
    radial-gradient(ellipse 42% 52% at 96% 4%,rgba(2,10,17,.93) 0%,rgba(2,10,17,.78) 48%,rgba(2,10,17,0) 100%),
    radial-gradient(ellipse 42% 52% at 96% 94%,rgba(2,10,17,.93) 0%,rgba(2,10,17,.78) 48%,rgba(2,10,17,0) 100%),
    linear-gradient(to top,rgba(3,16,26,.52) 0%,rgba(3,16,26,.04) 48%,rgba(3,16,26,.12) 80%,rgba(3,16,26,.30) 100%)}

.prochud{position:absolute;inset:0;pointer-events:none;color:var(--text-primary)}
/* the standing section label. The full-bleed layout has the title card for
   this job, so it only appears in the compact one. */
.prockick{display:none}

/* The title card. It holds the first frame, the blocked gutter, for a beat
   before the first step is named. */
.procintro{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  text-align:center;padding-inline:var(--pad);text-shadow:var(--tshadow);
  opacity:var(--io,1);transform:scale(calc(1 - .04*(1 - var(--io,1))))}
.procintro h2{font-family:var(--display);font-weight:700;letter-spacing:-.025em;line-height:1.02;
  font-size:clamp(2rem,1.2rem + 3.4vw,4rem);margin-top:1rem}
.procintro p{margin-top:1rem;color:#DCE4E8;max-width:38ch;margin-inline:auto}

/* The rail. Five bars down the left edge that fill as their step runs, so
   the visitor always knows how far through the job they are. */
.procrail{position:absolute;left:var(--pad);top:50%;transform:translateY(-50%);
  display:flex;flex-direction:column;gap:1.1rem;opacity:var(--ro,0);
  }
.procrail li{display:flex;align-items:center;gap:.7rem;
  font-family:var(--mono);font-size:.62rem;letter-spacing:.14em;
  color:rgba(147,166,180,.45);transition:color .55s var(--ease)}
.procrail .bar{position:relative;width:3px;height:26px;border-radius:2px;flex:none;
  background:rgba(244,246,243,.16);overflow:hidden}
.procrail .bar::after{content:"";position:absolute;left:0;right:0;top:0;
  height:calc(var(--f,0) * 100%);background:var(--accent)}
.procrail li.done{color:rgba(196,209,217,.62)}
.procrail li.on{color:var(--accent)}

/* The captions. A two by two field plus a full-width band for the finale;
   the padding-left clears the rail at every position. */
.proccaps{position:absolute;inset:0;
  padding:calc(76px + clamp(1.25rem,4vh,2.75rem)) var(--pad) clamp(2rem,7vh,4rem) calc(var(--pad) + 4rem);
  display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;gap:1rem}
.proccap{--ex:0;max-width:min(29rem,40vw);
  opacity:var(--o,0);will-change:opacity,transform;text-shadow:var(--tshadow);
  transform:translate3d(calc(var(--ex) * var(--y,0) * 2.4px),calc(var(--y,0) * 1px),0)}
.proccap[data-pos="tl"]{grid-area:1/1;justify-self:start;align-self:start;--ex:-1}
.proccap[data-pos="tr"]{grid-area:1/2;justify-self:end;align-self:start;text-align:right;--ex:1}
.proccap[data-pos="bl"]{grid-area:2/1;justify-self:start;align-self:end;--ex:-1}
.proccap[data-pos="br"]{grid-area:2/2;justify-self:end;align-self:end;text-align:right;--ex:1}
.proccap[data-pos="bw"]{grid-area:2/1/3/3;justify-self:start;align-self:end;
  max-width:min(46rem,62vw);--ex:0}
.proccap .pnum{display:block;font-family:var(--mono);font-size:.68rem;letter-spacing:.2em;
  color:var(--accent);margin-bottom:.7rem}
.proccap h3{font-family:var(--display);font-weight:700;letter-spacing:-.025em;line-height:1.02;
  font-size:clamp(1.9rem,1.25rem + 2.6vw,3.5rem)}
.proccap p{margin-top:.7rem;color:#E2E9EC;max-width:38ch}
/* The step assembles line by line off its own entrance progress, --c, the way
   every other block on the page arrives. Swapping the whole caption in one
   move is what made the sequence feel chopped against the rest of the site. */
.proccap > *{--k:clamp(0,(var(--c,1) - var(--d,0)) * 2.6,1);
  opacity:var(--k);
  transform:translate3d(calc((1 - var(--k)) * var(--ex,0) * -14px),
                        calc((1 - var(--k)) * 15px),0)}
.proccap .pnum {--d:0}
.proccap h3    {--d:.11}
.proccap p     {--d:.24}
.proccap .pmeta{--d:.38}
.proccap[data-pos="tr"] p,.proccap[data-pos="br"] p{margin-left:auto}
.proccap .pmeta{display:inline-block;margin-top:1rem;font-family:var(--mono);
  font-size:.66rem;letter-spacing:.12em;text-transform:uppercase;color:var(--accent);
  border-top:1px solid var(--accent-muted);padding-top:.6rem}
.proccap .ctarow{margin-top:1.5rem;pointer-events:auto}

@media (max-width:1180px){
  .proccap{max-width:min(24rem,46vw)}
  .proccap p{font-size:.95rem}
}

/* ============================================================
   THE COMPACT LAYOUT. A phone cannot take a 16:9 photograph full
   bleed in portrait without cropping it down to a vertical sliver,
   and it has no room for copy in four corners. So the sequence
   keeps everything that matters, the six frames crossfading and
   the copy changing under them on scroll, and gives the photograph
   its own window with the copy underneath it.
   ============================================================ */
@media (max-width:900px),(orientation:portrait) and (max-width:1024px){
  /* --pf is where the photograph starts, --ph is how tall it is. Everything
     under it is placed off those two, so making room above the frame is one
     edit instead of five. */
  .procseq{--pf:calc(76px + 2.9rem);--ph:clamp(190px,40svh,360px)}
  .procseq.pinned{height:820vh}
  .procstage{background:var(--navy-deep)}

  /* the name of the section, above its photograph and holding all the way
     through, because the title card below scrolls away with the first step */
  .prockick{display:inline-flex;position:absolute;left:var(--pad);right:var(--pad);
    top:calc(76px + .95rem);z-index:2}

  /* the window. The rig no longer pans, so it needs no overhang; the zoom
     rides on the frames themselves, inside this box. */
  .proccam{left:0;top:var(--pf);width:100%;
    height:var(--ph);overflow:hidden;
    transform:none !important;border-block:1px solid rgba(147,166,180,.14)}
  .pshot{object-position:58% 50%;
    transform:scale(var(--pz,1)) translateZ(0);transform-origin:58% 50%}

  /* the copy is on the canvas below the photograph, so the frame keeps its
     own light and needs no scrim over it at all */
  .procveil{top:var(--pf);height:var(--ph);
    background:linear-gradient(to top,rgba(3,16,26,.30) 0%,rgba(3,16,26,0) 42%)}

  .procintro{align-items:flex-start;justify-content:flex-start;text-align:left;
    padding:calc(var(--pf) + var(--ph) + 4.6svh) var(--pad) clamp(4.25rem,9svh,5.5rem)}
  .procintro .kicker{display:none}          /* .prockick is already saying it */
  .procintro h2{font-size:clamp(1.75rem,1.2rem + 3.2vw,2.5rem);margin-top:0}
  .procintro p{margin-inline:0;margin-top:.85rem;font-size:.95rem}

  /* the rail lies down and runs across, above the copy */
  .procrail{left:var(--pad);right:var(--pad);
    top:calc(var(--pf) + var(--ph) + 2svh);transform:none;
    flex-direction:row;gap:.5rem}
  .procrail li{flex:1;flex-direction:column;align-items:flex-start;gap:.4rem;font-size:.58rem}
  .procrail .bar{width:100%;height:3px}
  .procrail .bar::after{top:0;bottom:0;height:auto;right:auto;
    width:calc(var(--f,0) * 100%)}

  .proccaps{padding:0;display:block}
  .proccap,.proccap[data-pos]{position:absolute;
    inset:auto var(--pad) clamp(4.25rem,9svh,5.5rem);
    top:calc(var(--pf) + var(--ph) + 4.6svh);
    display:flex;flex-direction:column;justify-content:center;
    max-width:none;text-align:left;justify-self:auto;align-self:auto;
    text-shadow:none}
  /* the copy still arrives from alternating sides, so it reads as movement
     rather than a caption being swapped out */
  .proccap[data-pos="tl"],.proccap[data-pos="br"]{--ex:1}
  .proccap[data-pos="bl"],.proccap[data-pos="tr"],.proccap[data-pos="bw"]{--ex:-1}
  .proccap h3{font-size:clamp(1.6rem,1.1rem + 3.2vw,2.4rem)}
  .proccap p{font-size:.925rem;line-height:1.5;max-width:none;margin-top:.55rem;margin-left:0}
  .proccap .pnum{margin-bottom:.45rem}
  .proccap .pmeta{margin-top:.8rem;padding-top:.5rem;font-size:.6rem}
  .proccap .ctarow{margin-top:1rem}
  .proccap .btn{padding:.85rem 1.3rem;font-size:.72rem}
}
/* short screens give the photograph less and the copy more */
@media (max-width:900px) and (max-height:700px),
       (orientation:portrait) and (max-width:1024px) and (max-height:700px){
  .procseq{--ph:clamp(150px,29svh,260px)}
  .proccap p{font-size:.875rem}
  .proccap h3{font-size:1.5rem}
}

/* The plain version. Only reduced motion sees this now: phones get the
   sequence too, in the compact layout above. */
.procfallback{padding-block:clamp(3.5rem,7.5vh,5.5rem)}
.procseq.pinned .procfallback{display:none}

/* On /process/ the written steps are the page, not a fallback, so the words
   always stay. Their photographs are the same six frames the sequence has
   just scrubbed through, and showing them again immediately underneath reads
   as the page repeating itself. Where the sequence ran, the stills stand
   down; where it never ran (reduced motion), they are the only pictures
   there are and they remain. */
body.procseq-on #steps .procbefore,
body.procseq-on #steps .procsteps figure{display:none}
.procsteps{margin-top:2.5rem;list-style:none;padding:0;display:grid;gap:clamp(2rem,5vh,3.25rem)}
.procsteps li{display:grid;grid-template-columns:1fr;gap:1rem}
.procsteps figure{margin:0;border-radius:4px;overflow:hidden;border:1px solid var(--hairline)}
.procsteps img{width:100%;height:auto;aspect-ratio:16/9;object-fit:cover;background:var(--panel)}
.procsteps .pnum{font-family:var(--mono);font-size:.7rem;letter-spacing:.2em;color:var(--accent)}
.procsteps h3{font-family:var(--display);font-weight:700;letter-spacing:-.02em;
  font-size:clamp(1.4rem,1.1rem + 1.2vw,1.9rem);margin-top:.4rem}
.procsteps p{margin-top:.5rem;color:var(--text-secondary);max-width:54ch}
.procbefore{margin-top:2.25rem;border-radius:4px;overflow:hidden;border:1px solid var(--hairline)}
.procbefore img{width:100%;height:auto;aspect-ratio:16/9;object-fit:cover}
.procbefore figcaption{padding:.85rem 1rem;font-family:var(--mono);font-size:.68rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--text-secondary);background:var(--panel)}
/* On a wide screen this list is the /process page's main content rather than
   a fallback, so each step sits beside its photograph instead of under one a
   screen tall. The sides alternate, so the eye zigzags down the job in order.
   Phones keep the single column above. */
@media (min-width:900px){
  .procsteps{gap:clamp(2.75rem,7vh,4.5rem)}
  .procsteps li{grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    gap:clamp(1.75rem,4vw,3.5rem);align-items:center}
  .procsteps li:nth-child(even) figure{order:2}
  .procbefore{max-width:52rem}
}

/* ============================================================
   S3b, WHAT YOU GET IN WRITING. The terms, stated plainly, in the
   place where a visitor starts asking what happens afterwards.
   ============================================================ */
.promise{background:var(--panel);border-block:1px solid var(--hairline)}
.promise .lede{max-width:54ch}

/* ============================================================
   S3b, IN WRITING. A document filling itself in. The term is set,
   a leader runs across to meet it, and the value writes itself in
   word by word. One row, three parts, all off the same --e.
   ============================================================ */
.doc{margin:clamp(2.25rem,6vh,3.5rem) 0 0;padding:0;
  border-top:1px solid var(--hairline)}
.docrow{
  --in:clamp(0,var(--e,1) * 2,1);                 /* the row arriving */
  --rule:clamp(0,(var(--e,1) - .18) * 2.4,1);     /* the leader running across */
  display:grid;grid-template-columns:minmax(9rem,14rem) minmax(1.5rem,.55fr) minmax(17rem,34rem);
  align-items:baseline;gap:0 clamp(.75rem,2vw,1.5rem);
  padding-block:clamp(1.15rem,3vh,1.75rem);
  border-bottom:1px solid var(--hairline)}

.docrow dt{display:flex;align-items:center;gap:.65rem;
  font-family:var(--mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--text-secondary);
  opacity:calc(.15 + .85 * var(--in));
  transform:translate3d(calc((1 - var(--in)) * -32px),0,0)}
.docrow dt .ic{width:1.2rem;height:1.2rem;
  transform:scale(calc(.5 + .5 * var(--in)))}

/* the leader. It is a dotted run that grows from the term out to the value,
   which is the whole trick: the two halves are visibly joined up. */
.leader{position:relative;height:1px;align-self:center;overflow:hidden}
.leader::before{content:"";position:absolute;inset:0;
  background:repeating-linear-gradient(to right,var(--border-strong) 0 2px,transparent 2px 7px);
  transform:scaleX(var(--rule));transform-origin:left}

.docrow dd{margin:0;
  opacity:calc(.1 + .9 * var(--in));
  transform:translate3d(calc((1 - var(--in)) * 32px),0,0)}
.docrow dd b{display:block;font-family:var(--display);font-weight:700;letter-spacing:-.02em;
  font-size:clamp(1.15rem,1rem + .8vw,1.5rem);line-height:1.12;text-wrap:balance}
/* the value assembles a word at a time, off the row's own arrival */
.docrow dd b .w{--kw:clamp(0,(var(--e,1) - .3 - var(--th,0) * .7) * 3.4,1);
  opacity:var(--kw);transform:translateY(calc((1 - var(--kw)) * 10px))}
.docrow dd .fine{display:block;margin-top:.45rem;color:var(--text-secondary);
  font-size:.9rem;line-height:1.5;
  opacity:clamp(0,(var(--e,1) - .5) * 2.6,1)}

/* the first row is the one that matters most, so it is the one in lime */
.docrow:first-child dd b{color:var(--accent)}
.docrow:first-child dt .ic{color:var(--accent)}

/* and it is signed */
.sign{display:flex;align-items:center;gap:clamp(1rem,3vw,2rem);flex-wrap:wrap;
  margin-top:clamp(1.75rem,4.5vh,2.75rem)}
.signmark{width:clamp(9rem,16vw,13rem);height:auto;flex:none;
  fill:none;stroke:var(--accent);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;
  opacity:calc(.25 + .75 * var(--e,1))}
.signmark path{stroke-dasharray:1;stroke-dashoffset:calc(1 - var(--e,1))}
.sign p{margin:0;font-family:var(--mono);font-size:.72rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--text-primary);line-height:1.5;max-width:34ch;
  opacity:clamp(0,(var(--e,1) - .45) * 2.4,1)}

@media (max-width:820px){
  .docrow{grid-template-columns:1fr;gap:.5rem}
  .leader{display:none}
  .docrow dd{transform:translate3d(calc((1 - var(--in)) * 20px),0,0)}
  .docrow dt{transform:translate3d(calc((1 - var(--in)) * -20px),0,0)}
}

/* S4, the real material */
.material{display:grid;grid-template-columns:.85fr 1.15fr;gap:clamp(2rem,5vw,4.5rem);align-items:center}
/* ============================================================
   S4, THE PRODUCT. The panel arrives on the scroll and the four
   points beside it each light a marker on the part they describe,
   so the copy stays short and the panel does the explaining.
   ============================================================ */
.matsec{position:relative;overflow:hidden}
.matsec::before{content:"";position:absolute;right:-12%;top:14%;width:56%;aspect-ratio:1;
  pointer-events:none;border-radius:50%;
  background:radial-gradient(circle,rgba(167,218,2,.08) 0%,transparent 68%)}
.matsec > .wrap{position:relative;z-index:1}

.prodstage{display:grid;grid-template-columns:.92fr 1.08fr;
  gap:clamp(1.5rem,4vw,4rem);align-items:center}
.matcopy .h2{max-width:none;font-size:clamp(1.5rem,1.05rem + 1.5vw,2.35rem);
  margin-block:.9rem 1rem}
.matcopy .lede{max-width:46ch;font-size:.95rem}

.prodshot{position:relative}
/* the panel enters with a slight turn, as though it is being set down */
[data-fx="prod"] .prodimg{opacity:var(--e);
  transform:translate3d(calc((1 - var(--e)) * 38px),calc((1 - var(--e)) * 22px),0)
            rotate(calc((1 - var(--e)) * -3.4deg))
            scale(calc(.92 + .08 * var(--e)));
  transform-origin:60% 60%;will-change:transform}
.prodimg{width:100%;height:auto;display:block;
  filter:drop-shadow(0 1.4rem 2.4rem rgba(0,0,0,.55))}
.prodglow{position:absolute;left:50%;top:50%;width:82%;aspect-ratio:1.4;
  transform:translate(-50%,-50%) scale(calc(.6 + .4 * var(--e,1)));
  opacity:calc(var(--e,1) * .9);pointer-events:none;
  background:radial-gradient(ellipse,rgba(167,218,2,.20) 0%,rgba(167,218,2,.06) 42%,transparent 72%)}

/* the weave at the scale a leaf meets it, set over the corner of the panel
   so the two readings of the same product sit in one picture */
.meshmacro{position:absolute;left:0;bottom:2%;z-index:2;margin:0;
  width:clamp(6.5rem,17%,10rem);text-align:center;
  opacity:calc(.1 + .9 * var(--e,1));
  transform:translate3d(calc((1 - var(--e,1)) * -22px),0,0) scale(calc(.88 + .12 * var(--e,1)))}
.meshmacro img{width:100%;height:auto;display:block;border-radius:50%;
  box-shadow:0 0 0 2px rgba(167,218,2,.55),0 1rem 2rem rgba(0,0,0,.55)}
.meshmacro figcaption{margin-top:.65rem;font-family:var(--mono);font-size:.58rem;
  letter-spacing:.12em;text-transform:uppercase;color:var(--text-secondary)}
@media (max-width:960px){.meshmacro{width:clamp(5.5rem,24%,8rem);bottom:-2%}}

/* ============================================================
   THE TWO LISTS. One switch, five circles a side: what the mesh
   stops on the way in, and what stopping it saves the house from.
   The tabs sit on the top rule, so the box reads as one object
   with two states rather than two stacked blocks.
   ============================================================ */
.guard{position:relative;margin-top:clamp(3rem,8vh,4.5rem);
  border:1px solid var(--border-strong);border-radius:16px;
  padding:clamp(2.5rem,6vh,3.25rem) clamp(.85rem,3vw,2.25rem) clamp(1.75rem,4vh,2.5rem);
  opacity:calc(.25 + .75 * var(--e,1))}
.guardtabs{position:absolute;top:0;left:50%;transform:translate(-50%,-50%);
  display:flex;gap:clamp(.4rem,1.5vw,1rem);white-space:nowrap}
.gtab{display:inline-flex;align-items:center;gap:.55rem;cursor:pointer;
  padding:.7rem clamp(.9rem,2vw,1.4rem);border-radius:999px;
  border:1px solid var(--border-strong);background:var(--canvas);
  font-family:var(--mono);font-size:clamp(.62rem,.55rem + .25vw,.78rem);
  letter-spacing:.1em;text-transform:uppercase;color:var(--text-secondary);
  transition:color .3s var(--ease),border-color .3s var(--ease),background-color .3s var(--ease)}
.gtab svg{width:1.05em;height:1.05em;flex:none;fill:none;stroke:currentColor;
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;
  transition:transform .35s var(--ease)}
.gtab:hover{color:var(--text-primary);border-color:var(--text-secondary)}
.gtab:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.gtab.on{background:var(--accent);border-color:var(--accent);color:#0A141C}
.gtab.on svg{transform:translateX(2px)}

.gpanel{display:none}
.gpanel.on{display:block}
.gitems{display:grid;grid-template-columns:repeat(5,1fr);
  gap:clamp(.4rem,1.6vw,1.5rem);list-style:none;margin:0;padding:0}
.gitems li{display:flex;flex-direction:column;align-items:center;text-align:center;
  gap:clamp(.6rem,1.6vh,1rem);
  /* each circle arrives a beat after the one before it, on the switch and on
     the scroll alike, so the row assembles instead of appearing */
  animation:gpop .5s var(--ease) both;animation-delay:calc(var(--i) * .07s)}
@keyframes gpop{from{opacity:0;transform:translateY(14px) scale(.9)}to{opacity:1;transform:none}}
.gcirc{display:grid;place-items:center;width:100%;max-width:clamp(3.4rem,9vw,5.5rem);
  aspect-ratio:1;border-radius:50%;
  border:2px solid rgba(167,218,2,.38);background:rgba(167,218,2,.045);
  transition:border-color .35s var(--ease),background-color .35s var(--ease)}
.gitems li:hover .gcirc{border-color:var(--accent);background:rgba(167,218,2,.11)}
.gcirc .ic{width:52%;height:52%;color:var(--accent);stroke-width:1.5}
.gitems b{font-family:var(--mono);font-weight:500;
  font-size:clamp(.55rem,.5rem + .22vw,.7rem);letter-spacing:.07em;
  text-transform:uppercase;color:var(--text-primary);line-height:1.35}
@media (prefers-reduced-motion:reduce){.gitems li{animation:none}}

.prodfeat{display:grid;gap:1.05rem;margin:1.9rem 0 0;padding:0;list-style:none}
.pfeat{display:flex;align-items:flex-start;gap:.9rem}
.pfeat .ic{width:1.5rem;height:1.5rem;margin-top:.1rem}
.pfeat b{display:block;font-family:var(--display);font-weight:700;letter-spacing:-.01em;
  font-size:clamp(1rem,.95rem + .35vw,1.15rem);line-height:1.1;margin-bottom:.3rem}
.pfeat span{display:block;color:var(--text-secondary);font-size:.9rem;line-height:1.4}

@media (max-width:960px){
  /* On a phone the section opens on its own name, then the panel, then the
     rest of the copy. The panel used to lead, which meant arriving at a
     photograph with no idea yet what it was a photograph of. */
  .prodstage{grid-template-columns:1fr;gap:1.4rem}
  .matcopy{display:contents}
  .mathead{order:1}
  .prodshot{order:2}
  .matbody{order:3}
  .matcopy .h2{margin-bottom:0}
}

/* ============================================================
   S7, THE SERVICE AREA. The pins are placed from real latitude
   and longitude through an equirectangular projection, so the
   shape of the region and the position of every municipality are
   the actual ones. The lake is there to orient, not to decorate.
   ============================================================ */
.areasec{position:relative;overflow:hidden}
.areagrid{margin-top:2.75rem;display:grid;grid-template-columns:1.5fr .95fr;
  gap:clamp(1.5rem,4vw,3.5rem);align-items:center}
.mapwrap{position:relative}
.gtamap{width:100%;height:auto;overflow:visible}
.water{fill:url(#waterg)}
.land{fill:url(#landg);stroke:rgba(167,218,2,.34);stroke-width:2}
.shore{fill:none;stroke:rgba(167,218,2,.20);stroke-width:1.5;stroke-dasharray:5 7}
.waterlabel{fill:rgba(147,166,180,.42);font-family:var(--mono);font-size:19px;letter-spacing:4px}

/* the pins drop in on their own thresholds as the map arrives */
.pin{cursor:pointer;
  --kc:clamp(0,(var(--e,1) - var(--th,0)) * 3.4,1);
  opacity:var(--kc);
  transform-box:fill-box;transform-origin:50% 100%}
.pinbody{fill:var(--accent);stroke:#08131A;stroke-width:1.6;
  transition:fill .3s var(--ease)}
.pindot{fill:#08131A}
.pinshadow{fill:rgba(0,0,0,.42)}
.pinlabel{fill:var(--text-secondary);font-family:var(--mono);font-size:15px;
  letter-spacing:1px;text-anchor:middle;
  transition:fill .3s var(--ease),font-size .3s var(--ease)}
.pin > *{transition:transform .45s var(--ease)}
.pin:hover .pinbody,.pin:focus-visible .pinbody,.pin.hi .pinbody{fill:#FFFFFF}
.pin:hover .pinlabel,.pin:focus-visible .pinlabel,.pin.hi .pinlabel{fill:var(--accent)}
.pin:hover .pinbody,.pin:focus-visible .pinbody,.pin.hi .pinbody,
.pin:hover .pindot,.pin:focus-visible .pindot,.pin.hi .pindot{transform:translateY(-6px) scale(1.14)}
.pin:focus{outline:none}
.pin:focus-visible .pinshadow{stroke:var(--accent);stroke-width:2}

.citylist{display:grid;grid-template-columns:1fr 1fr;gap:.15rem .4rem;align-self:center}
.cityb{display:flex;align-items:center;gap:.65rem;width:100%;text-align:left;
  padding:.62rem .7rem;border-radius:5px;color:var(--text-secondary);font-size:.95rem;
  border:1px solid transparent;
  transition:color .3s var(--ease),background-color .3s var(--ease),
             border-color .3s var(--ease),transform .3s var(--ease)}
.cityb .ic{width:1rem;height:1rem;opacity:.45;transition:opacity .3s var(--ease)}
.cityb:hover,.cityb.hi,.cityb:focus-visible{color:var(--text-primary);
  background:rgba(167,218,2,.08);border-color:rgba(167,218,2,.32);transform:translateX(4px)}
.cityb:hover .ic,.cityb.hi .ic,.cityb:focus-visible .ic{opacity:1}
@media (max-width:900px){
  .areagrid{grid-template-columns:1fr}
  .citylist{margin-top:1.5rem}
  /* A map of a place you live in is worth nothing without the names on it.
     At this width the full 1360 unit viewBox renders about a quarter scale,
     which is why the names used to come off; the fix is to crop the frame to
     the land (done in script, a viewBox is not settable from CSS), which
     buys a third more scale, then set every name under its own pin with a
     dark halo behind it. Three of the fourteen sit above their pin instead,
     because the pin below them is closer than a line of type is tall. */
  .pinlabel{display:block;font-size:33px;letter-spacing:.5px;
    paint-order:stroke;stroke:#0A141C;stroke-width:7px;stroke-linejoin:round;
    transform:translate(var(--mx,0px),var(--my,20px))}
  .pinlabel--up{--my:-20px}
  .pinart{transform:scale(1.5);transform-origin:0 0}
  .waterlabel{font-size:36px;text-anchor:end;transform:translate(170px,0)}
  .land{stroke-width:4}
  .shore{stroke-width:3;stroke-dasharray:10 14}
}
@media (max-width:340px){.citylist{grid-template-columns:1fr}}

/* S8, FAQ */
.faq{margin-top:2.5rem;border-top:1px solid var(--hairline)}
.faq details{border-bottom:1px solid var(--hairline)}
.faq summary{list-style:none;cursor:pointer;padding-block:1.35rem;display:flex;align-items:baseline;
  justify-content:space-between;gap:1.5rem;font-family:var(--display);font-weight:600;
  font-size:clamp(1rem,.95rem + .4vw,1.25rem)}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";font-family:var(--mono);color:var(--accent);flex:none;transition:transform .3s var(--ease)}
.faq details[open] summary::after{transform:rotate(45deg)}
.faq p{padding-bottom:1.5rem;color:var(--text-secondary);max-width:62ch}

/* S10, the form */
.formsec{background:var(--navy-deep)}

/* ---------- the drone over the inspection form ----------
   The section is already .haslive, so it is the positioned ancestor and it
   already clips. The transform is written by site.js frame by frame; this
   only says where the corner is and how big the thing is. It sits above the
   copy rather than under it, because a drone half behind a paragraph reads
   as a mistake, and it never takes a pointer event. */
.dronefly{position:absolute;top:0;right:clamp(.5rem,2.5vw,2.5rem);z-index:2;
  width:clamp(88px,12vw,164px);pointer-events:none;
  opacity:0;transition:opacity .55s var(--ease);will-change:transform}
.dronefly.on{opacity:1}
.dronefly img{display:block;width:100%;height:auto;
  filter:drop-shadow(0 14px 22px rgba(0,0,0,.5))}
/* no hover, no bob and no lag when motion is turned down: it is simply parked
   in the corner, which is what the JS writes in that case */
@media (prefers-reduced-motion: reduce){.dronefly{transition:none}}
.formgrid{display:grid;grid-template-columns:.9fr 1.1fr;gap:clamp(2rem,5vw,4.5rem);align-items:start}
.form{background:var(--panel);border:1px solid var(--hairline);border-radius:6px;padding:clamp(1.5rem,3vw,2.25rem);display:grid;gap:1.25rem}
.field{display:flex;flex-direction:column;gap:.4rem}
.field label{font-family:var(--mono);font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;color:var(--text-secondary)}
.field input{background:transparent;border:0;border-bottom:1px solid var(--border-strong);
  padding:.7rem 0;color:var(--text-primary);font-size:1rem;transition:border-color .3s var(--ease)}
.field input:focus-visible{border-color:var(--accent);outline:none}
.field input[aria-invalid="true"]{border-color:#E2725B}
.err{font-size:.78rem;color:#E2725B}
fieldset{border:0;padding:0;margin:0;display:flex;flex-direction:column;gap:.7rem}
fieldset legend{font-family:var(--mono);font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;color:var(--text-secondary);padding:0}
.radios{display:flex;gap:1.5rem;flex-wrap:wrap}
.radios label{display:flex;align-items:center;gap:.45rem;font-size:.95rem}
.radios input{accent-color:var(--accent)}
.submit{margin-top:.25rem;background:var(--accent);color:#0A141C;font-family:var(--mono);
  font-size:.8rem;letter-spacing:.08em;text-transform:uppercase;padding:1.05rem;border-radius:999px;
  transition:background-color .3s var(--ease),transform .3s var(--ease)}
.submit:hover{background:var(--accent-hover);transform:translateY(-2px)}
/* Sits under the button, where somebody deciding whether to type their
   address into a form can actually see it. Quiet, but not hidden. */
.formnote{margin-top:.9rem;font-size:.78rem;line-height:1.5;color:var(--text-secondary)}
.formnote a{border-bottom:1px solid var(--hairline);transition:border-color .3s var(--ease)}
.formnote a:hover{border-bottom-color:var(--accent)}
.success{text-align:center;padding:clamp(2rem,6vh,3.5rem) 1rem;display:grid;gap:.75rem}
.success .big{font-family:var(--display);font-weight:600;font-size:1.4rem;color:var(--accent)}
@media (max-width:900px){.formgrid{grid-template-columns:1fr}}

footer{border-top:1px solid var(--hairline);padding-block:3.5rem 2.5rem;position:relative;z-index:1}
.fgrid{display:grid;grid-template-columns:1.5fr 1fr 1fr;gap:2rem}
.fgrid img{height:56px;width:auto;align-self:start}
.fgrid h4{font-family:var(--mono);font-size:.7rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--text-secondary);margin:0 0 .75rem;font-weight:500}
.fgrid a,.fgrid p{color:var(--text-primary);font-size:.95rem}
.fgrid a{opacity:.85;transition:opacity .25s var(--ease),color .25s var(--ease)}
.fgrid a:hover{opacity:1;color:var(--accent)}
.fbot{margin-top:2.5rem;padding-top:1.5rem;border-top:1px solid var(--hairline);
  display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  font-size:.8rem;color:var(--text-secondary)}
@media (max-width:760px){.fgrid{grid-template-columns:1fr 1fr}}

/* ============================================================
   THE FIVE STATIC-HERO GATES.
   These five queries must stay character-for-character identical
   to the GATES array in JS, or one side loads what the other hides.
   ============================================================ */
@media (max-width:720px),
       (orientation:portrait) and (max-width:1024px),
       (orientation:portrait) and (pointer:coarse),
       (orientation:landscape) and (pointer:coarse) and (max-height:560px),
       (prefers-reduced-motion:reduce){
  .hero{display:none}
  .static-hero{display:flex}
}

/* Short screens keep the scrub but lose overlays that have no room */
@media (max-height:560px){.chev{display:none}}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;
    transition-duration:.001ms !important;transition-delay:0ms !important}
  [data-fx]{--e:1 !important}
  [data-fx="par"],[data-fx="parx"]{transform:none}
  .env::after{animation:none}
}
body.paused *,body.paused *::before,body.paused *::after{animation-play-state:paused !important}

/* ============================================================
   MULTI-PAGE COMPONENTS
   Everything below was added when the one-page site became a
   site. Nothing here introduces a new colour, face or radius:
   it is the same tokens, applied to the parts a multi-page
   structure needs and a single page did not.
   ============================================================ */

/* ---------- NAV: the call to action, and where you are ---------- */
.navcta{margin-left:1.75rem;flex:none;padding:.72rem 1.15rem;font-size:.7rem}
.navlinks a[aria-current="page"],.navmenu a[aria-current="page"]{opacity:1;color:var(--accent)}
/* five destinations and a button do not fit forever. The button is the first
   thing to go, because the following one is already on screen by then. */
@media (max-width:1240px){.navlinks{gap:1.4rem}.navlinks a{font-size:.78rem}}
@media (max-width:1080px){.navcta{display:none}}
@media (max-width:900px){.navcta{display:none}}

/* ---------- PAGE HEAD. Every page that is not the homepage opens
     on one of these: where you are, what the page is, and the way
     out. It is the hero's job done without the footage. ---------- */
.pagehead{position:relative;z-index:1;overflow:hidden;
  padding-block:calc(76px + clamp(2.75rem,8vh,5rem)) clamp(2.25rem,6vh,3.5rem)}
.pagehead::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse 66% 78% at 12% 0%,rgba(167,218,2,.075),transparent 66%)}
.pagehead > .wrap{position:relative;z-index:1}
.pagehead h1{font-family:var(--display);font-weight:700;letter-spacing:-.025em;line-height:1.03;
  font-size:clamp(2rem,1.2rem + 3vw,3.9rem);margin-block:1.1rem 1.25rem;
  max-width:20ch;text-wrap:balance}
.pagehead h1 .lm{color:var(--accent)}
.pagehead .lede{max-width:58ch;font-size:clamp(1rem,.96rem + .3vw,1.15rem)}
.pagehead .ctarow{margin-top:clamp(1.5rem,4vh,2.25rem)}
.pagehead .proof{opacity:1;transform:none;margin-top:1.75rem}

/* the trail back up. Small, mono, and the current page is not a link. */
.crumb{display:flex;flex-wrap:wrap;align-items:center;gap:.35rem .55rem;margin:0 0 1.35rem;
  font-family:var(--mono);font-size:.66rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--text-secondary)}
.crumb li{display:flex;align-items:center;gap:.55rem}
.crumb li + li::before{content:"/";opacity:.45}
.crumb a{transition:color .25s var(--ease)}
.crumb a:hover{color:var(--accent)}
.crumb [aria-current="page"]{color:var(--text-primary)}

/* ---------- the way on. A link that reads as the next step rather
     than as a word in a paragraph. ---------- */
.linkmore{display:inline-flex;align-items:center;gap:.6rem;margin-top:clamp(1.25rem,3vh,1.85rem);
  font-family:var(--mono);font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--accent);padding-bottom:.4rem;border-bottom:1px solid var(--accent-muted);
  transition:border-color .3s var(--ease),color .3s var(--ease)}
.linkmore::after{content:"";width:.42rem;height:.42rem;flex:none;
  border-right:1.6px solid currentColor;border-top:1.6px solid currentColor;
  transform:rotate(45deg);transition:transform .3s var(--ease)}
.linkmore:hover{border-bottom-color:var(--accent)}
.linkmore:hover::after{transform:translateX(3px) rotate(45deg)}
.linkrow{display:flex;flex-wrap:wrap;gap:.5rem 2.25rem;align-items:center}

/* ---------- THE FIVE STEPS, ABBREVIATED. The homepage and every
     location page carry the shape of the job without the detail:
     five names, one line each, and a way through to the long
     version. ---------- */
.stepstrip{margin-top:clamp(2rem,5vh,3rem);display:grid;
  grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));
  gap:1px;background:var(--hairline);border:1px solid var(--hairline);
  border-radius:6px;overflow:hidden}
.stepstrip li{background:rgba(16,32,45,.72);padding:clamp(1.1rem,2.2vw,1.5rem);
  display:flex;flex-direction:column;gap:.5rem;
  transition:background-color .4s var(--ease)}
.stepstrip li:hover{background:rgba(19,38,53,.94)}
.stepstrip .n{font-family:var(--mono);font-size:.64rem;letter-spacing:.18em;color:var(--accent)}
.stepstrip h3{font-family:var(--display);font-weight:700;letter-spacing:-.02em;line-height:1.1;
  font-size:clamp(1.05rem,.98rem + .4vw,1.3rem)}
.stepstrip p{color:var(--text-secondary);font-size:.88rem;line-height:1.5}
/* the fifth is the one the product goes on, so it is the one in lime */
.stepstrip li:last-child .n{color:var(--accent)}
.stepstrip li:last-child{background:rgba(167,218,2,.055)}

/* ---------- THE CORE POSITIONING. The one sentence the whole
     business is built on, given the largest type on the homepage
     and nothing else in the band to compete with it. ---------- */
.posit{position:relative;overflow:hidden;background:var(--panel);
  border-block:1px solid var(--hairline)}
.posit::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse 52% 80% at 6% 50%,rgba(167,218,2,.09),transparent 68%)}
.posit > .wrap{position:relative;z-index:1}
.positgrid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(1.75rem,5vw,4.5rem);
  align-items:start}
.positline{font-family:var(--display);font-weight:700;letter-spacing:-.03em;line-height:1.0;
  font-size:clamp(2.1rem,1.1rem + 4.2vw,4.25rem);max-width:15ch;text-wrap:balance;
  margin-top:1.1rem}
.positline .w{--kw:clamp(0,(var(--e,1) - var(--th,0)) * 3.2,1);
  opacity:var(--kw);transform:translateY(calc((1 - var(--kw)) * 16px))}
.positbody{padding-top:clamp(0rem,2.5vh,1.5rem)}
.positbody p{color:var(--text-secondary);max-width:52ch}
.positbody p + p{margin-top:1rem}
.positbody strong{color:var(--text-primary);font-weight:500}
@media (max-width:900px){.positgrid{grid-template-columns:1fr}}

/* ---------- A CARD GRID. Used for benefits, for what is on a
     location page, and for anywhere a short list needs to be
     read rather than scanned as prose. ---------- */
.tiles{margin-top:clamp(2rem,5vh,3rem);display:grid;
  grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));
  gap:clamp(.75rem,1.6vw,1.25rem)}
.tile{padding:clamp(1.2rem,2.4vw,1.7rem);border-radius:6px;
  border:1px solid var(--hairline);background:var(--panel);
  display:flex;flex-direction:column;gap:.6rem;
  transition:border-color .4s var(--ease),transform .4s var(--ease)}
.tile:hover{border-color:rgba(167,218,2,.34);transform:translateY(-3px)}
.tile .ic{width:1.6rem;height:1.6rem}
.tile b{font-family:var(--display);font-weight:700;letter-spacing:-.015em;line-height:1.15;
  font-size:clamp(1.02rem,.96rem + .35vw,1.2rem)}
.tile p{color:var(--text-secondary);font-size:.92rem;line-height:1.5}
/* a tile that is a link says so on hover, like everything else that is */
a.tile:hover b{color:var(--accent)}

/* ---------- TWO LISTS SIDE BY SIDE. What is covered and what is
     not, on the warranty page, and anywhere else the answer has
     two halves. ---------- */
.splitlist{margin-top:clamp(2rem,5vh,3rem);display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(1.25rem,3vw,2.5rem);align-items:start}
@media (max-width:860px){.splitlist{grid-template-columns:1fr}}
.splitlist > div{padding:clamp(1.25rem,2.6vw,1.85rem);border-radius:6px;
  border:1px solid var(--hairline);background:var(--panel)}
.splitlist > div.yes{border-left:3px solid var(--accent)}
.splitlist > div.no{border-left:3px solid #E2725B}
.splitlist h3{font-family:var(--display);font-weight:700;letter-spacing:-.02em;
  font-size:clamp(1.15rem,1rem + .6vw,1.45rem);line-height:1.12}
.plist{display:grid;gap:.9rem;margin-top:1.15rem}
.plist li{display:flex;gap:.75rem;align-items:flex-start;
  color:var(--text-secondary);font-size:.94rem;line-height:1.5}
.plist .ic{width:1.15rem;height:1.15rem;margin-top:.18rem;flex:none}
.plist--no .ic{color:#E2725B}
.plist b{display:block;color:var(--text-primary);font-weight:500;margin-bottom:.15rem}

/* ---------- A CALLOUT. One point that has to be read rather than
     skimmed past, set off the way the resolve block is. ---------- */
.note{margin-top:clamp(1.75rem,4.5vh,2.5rem);padding:clamp(1.25rem,2.6vw,1.85rem);
  border-radius:6px;background:var(--panel);border:1px solid var(--hairline);
  border-left:3px solid var(--accent);max-width:64rem}
.note h3{font-family:var(--display);font-weight:700;letter-spacing:-.02em;line-height:1.12;
  font-size:clamp(1.1rem,1rem + .5vw,1.35rem)}
.note p{margin-top:.7rem;color:var(--text-secondary);max-width:64ch}
.note p + p{margin-top:.7rem}

/* ---------- SERVICE AREA LINKS. The homepage and every location
     page carry the list; only the service areas page carries the
     map with it. ---------- */
.arealinks{margin-top:clamp(1.75rem,4.5vh,2.5rem);display:grid;
  grid-template-columns:repeat(auto-fill,minmax(11.5rem,1fr));gap:.4rem}
.arealink{display:flex;align-items:center;gap:.65rem;padding:.78rem .8rem;border-radius:5px;
  border:1px solid var(--hairline);background:rgba(16,32,45,.5);
  color:var(--text-secondary);font-size:.94rem;
  transition:color .3s var(--ease),background-color .3s var(--ease),
             border-color .3s var(--ease),transform .3s var(--ease)}
.arealink .ic{width:1rem;height:1rem;opacity:.45;transition:opacity .3s var(--ease)}
.arealink:hover,.arealink:focus-visible{color:var(--text-primary);
  background:rgba(167,218,2,.08);border-color:rgba(167,218,2,.32);transform:translateX(4px)}
.arealink:hover .ic,.arealink:focus-visible .ic{opacity:1}

/* the map's own list became links to the pages behind the pins */
.citylist a.cityb{text-decoration:none}
/* and so did the pins. The anchor sits inside the placed group, so the
   projection maths above is untouched by it. */
.pin a{cursor:pointer}
.pin a:focus{outline:none}

/* ---------- FAQ, GROUPED. One page of questions needs headings
     between them or it reads as a wall of plus signs. ---------- */
.faqcat + .faqcat{margin-top:clamp(2.5rem,6vh,3.75rem)}
.faqcat h2{font-family:var(--display);font-weight:700;letter-spacing:-.02em;line-height:1.1;
  font-size:clamp(1.2rem,1.05rem + .8vw,1.6rem)}
.faqcat .faq{margin-top:1.1rem}
.faq details[open] summary{color:var(--accent)}
.faq summary{transition:color .3s var(--ease)}
.faq summary:hover{color:var(--accent)}
@media (pointer:coarse){.faq summary{min-height:44px}}

/* ---------- LOCATION PAGES. The shared template, with the parts
     that differ between one municipality and the next. ---------- */
.locmeta{margin-top:clamp(1.5rem,4vh,2.25rem);display:flex;flex-wrap:wrap;gap:.5rem .75rem}
.locmeta span{display:inline-flex;align-items:center;gap:.5rem;
  padding:.5rem .85rem;border-radius:999px;
  border:1px solid var(--hairline);background:rgba(16,32,45,.55);
  font-family:var(--mono);font-size:.64rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--text-secondary)}
.locmeta span .ic{width:.95rem;height:.95rem}
.locsplit{display:grid;grid-template-columns:1.1fr .9fr;gap:clamp(1.75rem,4.5vw,4rem);
  align-items:center}
@media (max-width:900px){.locsplit{grid-template-columns:1fr}}
.locsplit figure{margin:0;border-radius:6px;overflow:hidden;border:1px solid var(--hairline)}
.locsplit img{width:100%;height:auto;aspect-ratio:4/3;object-fit:cover;display:block}
.locsplit figcaption{padding:.8rem 1rem;font-family:var(--mono);font-size:.64rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--text-secondary);background:var(--panel)}
.prose p{color:var(--text-secondary);max-width:62ch}
.prose p + p{margin-top:1rem}

/* ---------- FOOTER, now that there is a site to link to ---------- */
.fgrid{grid-template-columns:1.5fr 1fr 1.6fr}
.fbrand p{margin-top:1.1rem;color:var(--text-secondary);font-size:.92rem;max-width:32ch}
.fbrand .btn{margin-top:1.35rem}
.fgrid ul{display:grid;gap:.6rem}
/* the mark sits on the text baseline row rather than above it, so the row
   reads as one link and not as an icon with a caption */
.fgrid .flink{display:inline-flex;align-items:center;gap:.5rem}
.fgrid .fareas ul{grid-template-columns:1fr 1fr;gap:.6rem 1rem}
.fgrid li{line-height:1.35}
@media (max-width:1080px){.fgrid{grid-template-columns:1fr 1fr}}
@media (max-width:560px){
  .fgrid{grid-template-columns:1fr;gap:2.25rem}
  .fgrid .fareas ul{grid-template-columns:1fr 1fr}
}
