/* ============================================================
   Archivo — one family, self-hosted.

   A single variable file covers 100-900, so every weight on the site
   costs one 36KB request instead of one per weight. Self-hosted rather
   than pulled from Google, which keeps the page's zero-third-party
   property intact and means it can't be slowed down by someone else's
   CDN having a bad day.

   swap, not block: the fallback shows instantly and Archivo replaces it
   when it lands. Nobody stares at invisible text.
   ============================================================ */
@font-face{
  font-family:"Archivo";
  src:url("/assets/fonts/archivo-var.woff2") format("woff2");
  font-weight:100 900;
  font-style:normal;
  font-display:swap;
}

/* ============================================================
   OnCallAI Pro — v5

   White. Editorial. Built the way Apple builds a product page:
   one idea per screen, typography doing the heavy lifting.

   The opening carries no image on purpose. A claim this short
   is stronger in silence, and holding the photography back until
   the industries section means it lands as evidence rather than
   decoration.

   The palette is two whites and three greys. Orange appears a
   handful of times on the whole page and never decorates — it
   only ever marks the thing you are meant to do next.
   ============================================================ */

:root{
  --paper:#FFFFFF;         /* the page */
  --band:#F5F5F7;          /* alternating chapters — Apple's exact grey */
  --ink:#1D1D1F;           /* near-black. Pure #000 on white is harsh */
  --ink-2:#6E6E73;         /* supporting copy */
  --ink-3:#86868B;         /* captions, legal */
  --rule:rgba(0,0,0,.10);
  --rule-soft:rgba(0,0,0,.06);
  --accent:#E8500F;        /* brand orange, darkened to hold AA on white */
  --accent-lift:#FF5A1F;

  --ease:cubic-bezier(.16,1,.3,1);
  --shell:1120px;
  --gutter:clamp(1.5rem,5vw,3.5rem);
  /* Applied to both the top and bottom of every section, so this value lands
     twice between neighbours: 14vh read as ~252px of empty page between one
     section and the next on a laptop. 10vh keeps the rhythm airy at ~180px. */
  --chapter:clamp(4.5rem,10vh,8rem);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--paper);color:var(--ink);
  /* One typeface doing all the work, weights carrying what a second font
     would otherwise carry. The system stack stays as the fallback, so the
     page is readable before the font arrives and if it never does. */
  font-family:"Archivo",-apple-system,BlinkMacSystemFont,"Inter","Helvetica Neue",Arial,sans-serif;
  font-size:17px;line-height:1.55;letter-spacing:-.01em;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}
h1,h2,h3{margin:0;font-weight:600;letter-spacing:-.035em;line-height:1.05;text-wrap:balance}
p{margin:0;text-wrap:pretty}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
button{font:inherit;color:inherit}

.shell{width:100%;max-width:var(--shell);margin-inline:auto;padding-inline:var(--gutter)}
.wide{width:100%;max-width:1440px;margin-inline:auto;padding-inline:var(--gutter)}
section{position:relative}
.chapter{padding-block:var(--chapter)}
/* The footer brings its own generous padding, so a full --chapter under the
   last section stacked ~126px of empty page on top of it. */
main > section:last-child{padding-bottom:clamp(3rem,7vh,4.5rem)}
.band{background:var(--band)}

.skip{position:absolute;left:50%;top:0;transform:translate(-50%,-140%);z-index:200;background:var(--ink);
  color:#fff;padding:.85rem 1.5rem;border-radius:0 0 12px 12px;font-size:.9rem;font-weight:500;transition:transform .24s}
.skip:focus{transform:translate(-50%,0)}
:where(a,button,summary,[tabindex]):focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:6px}

/* ============ type scale ============
   Four sizes with big jumps between them. Apple's whole trick is that the
   headline is enormous and everything else gets out of its way. */
.display{font-size:clamp(2.9rem,8vw,6.25rem);letter-spacing:-.045em;line-height:1.0}
.h2{font-size:clamp(2rem,4.6vw,3.5rem);letter-spacing:-.036em;line-height:1.06}
.h3{font-size:clamp(1.25rem,2vw,1.6rem);letter-spacing:-.024em;line-height:1.2}
.lede{font-size:clamp(1.125rem,1.7vw,1.4rem);line-height:1.5;color:var(--ink-2);letter-spacing:-.014em}
.body{font-size:1.0625rem;line-height:1.6;color:var(--ink-2)}
.cap{font-size:.8125rem;line-height:1.5;color:var(--ink-3);letter-spacing:0}
.kicker{font-size:.75rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--accent)}
.measure{max-width:34ch}
.measure-wide{max-width:52ch}
.center{text-align:center;margin-inline:auto}

/* ============ nav ============ */
.nav{position:fixed;inset-inline:0;top:0;z-index:100;height:52px;
  background:rgba(255,255,255,.72);backdrop-filter:saturate(180%) blur(20px);
  -webkit-backdrop-filter:saturate(180%) blur(20px);
  border-bottom:1px solid transparent;transition:border-color .4s var(--ease)}
.nav.is-stuck{border-bottom-color:var(--rule-soft)}
/* position:relative so the centred group can be measured against the BAR
   rather than against whatever space is left over beside the logo — a group
   centred in the remainder is not centred on the page, and on a wide monitor
   that miss is what made the old bar look lopsided. */
.nav__in{position:relative;height:100%;display:flex;align-items:center;justify-content:space-between;gap:1rem}
.nav__logo{display:flex;align-items:center;font-weight:600;font-size:.9375rem;letter-spacing:-.02em}
/* the two-tone the brand already uses — ONCALL solid, AI lighter */
.nav__word em{font-style:normal;color:var(--ink-3);font-weight:500}
.nav__links{display:flex;align-items:center;gap:1.75rem;font-size:.8125rem;color:var(--ink-2)}
/* the sections, pinned to the true centre of the bar */
.nav__set{position:absolute;left:50%;transform:translateX(-50%);
  display:flex;align-items:center;gap:1.75rem;white-space:nowrap}
/* the two ways to reach a human, cornered right opposite the logo */
.nav__side{display:flex;align-items:center;gap:1.75rem}
.nav__links a{transition:color .3s var(--ease)}
.nav__links a:hover{color:var(--ink)}
.nav__tel{font-size:.8125rem;font-weight:500;color:var(--ink);font-variant-numeric:tabular-nums}
.nav__cta{font-size:.8125rem;font-weight:500;color:var(--accent)}
/* ---------- the phone menu ----------
   The section links used to be display:none below 900px, which left a phone
   with no route to How it works, Industries, Websites, Pricing or Questions —
   the bar had a logo and a Book a call and nothing else. They live behind this
   button now. Same markup, same list, so it can't drift from the desktop nav. */
.nav__burger{display:none;width:38px;height:38px;margin-right:-9px;padding:0;
  border:0;background:none;cursor:pointer;-webkit-user-select:none;user-select:none;
  -webkit-tap-highlight-color:transparent;
  flex-direction:column;align-items:center;justify-content:center;gap:5px}
.nav__burger span{display:block;width:19px;height:1.5px;border-radius:2px;
  background:var(--ink);
  transition:transform .38s var(--ease),opacity .28s var(--ease)}
.nav--dark .nav__burger span{background:#fff}
/* the two bars fold into a cross rather than sliding away — it reads as the
   same object changing state, which is what tells you it's the same control */
.nav.is-open .nav__burger span:first-child{transform:translateY(3.25px) rotate(45deg)}
.nav.is-open .nav__burger span:last-child{transform:translateY(-3.25px) rotate(-45deg)}

@media (max-width:900px){
  .nav__burger{display:flex}
  /* the panel hangs off the fixed bar, so it stays put while the page moves */
  .nav__links{position:absolute;top:100%;left:0;right:0;
    flex-direction:column;align-items:stretch;gap:0;
    padding:.5rem var(--gutter) 1.25rem;
    background:rgba(255,255,255,.97);backdrop-filter:saturate(180%) blur(20px);
    -webkit-backdrop-filter:saturate(180%) blur(20px);
    border-bottom:1px solid var(--rule-soft);
    opacity:0;visibility:hidden;transform:translateY(-6px);
    transition:opacity .3s var(--ease),transform .38s var(--ease),visibility .3s}
  .nav.is-open .nav__links{opacity:1;visibility:visible;transform:none}
  /* the desktop centring has to come off completely here, or the sections sit
     absolutely positioned on top of the panel instead of inside it */
  .nav__set,.nav__side{position:static;transform:none;
    display:flex;flex-direction:column;align-items:stretch;gap:0;white-space:normal}
  .nav__links a{padding:.95rem 0;font-size:1.0625rem;border-bottom:1px solid var(--rule-soft)}
  .nav__side a:last-child{border-bottom:0}
  .nav__tel{font-size:1.0625rem}
  /* Over the black hero the panel is black too. A white sheet dropping over
     the opening reads as a flash of the wrong page. */
  .nav--dark .nav__links{background:rgba(0,0,0,.96);border-bottom-color:rgba(255,255,255,.12)}
  .nav--dark .nav__links a{color:rgba(255,255,255,.82);border-bottom-color:rgba(255,255,255,.1)}
  .nav--dark .nav__tel{color:#fff}
  /* the dark-panel rule above is specific enough to grey out the one link that
     must never be grey — orange only ever marks the thing to do next */
  .nav__links .nav__cta{color:var(--accent);font-weight:600}
  .nav--dark .nav__links .nav__cta{color:var(--accent-lift)}
  /* open, the bar itself has to be solid or the logo sits on the hero */
  .nav.is-open{background:rgba(255,255,255,.97)}
  .nav--dark.is-open{background:rgba(0,0,0,.96)}
}

/* ============ buttons ============
   Thin, architectural. The pill is Apple's; the restraint is the point. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  height:50px;padding:0 1.75rem;border-radius:999px;border:1px solid transparent;
  font-size:1rem;font-weight:500;letter-spacing:-.01em;cursor:pointer;white-space:nowrap;
  transition:transform .45s var(--ease),background-color .35s var(--ease),
             border-color .35s var(--ease),box-shadow .45s var(--ease),color .35s var(--ease)}
.btn--solid{background:var(--accent);color:#fff}
.btn--solid:hover{background:var(--accent-lift);transform:translateY(-2px);box-shadow:0 14px 32px -14px rgba(232,80,15,.75)}
/* background is set explicitly because these are not all links: "Chat with her
   instead" is a real <button>, which takes the UA's grey button background
   unless told otherwise, and rendered as a grey pill next to identical-looking
   transparent anchors. */
.btn--line{border-color:var(--rule);color:var(--ink);background:transparent}
.btn--line:hover{border-color:var(--accent);color:var(--accent);transform:translateY(-2px)}
.btn-row{display:flex;flex-wrap:wrap;gap:.75rem}
.btn-row--center{justify-content:center}

/* ============ reveal ============
   Slow, weighted, no bounce. The blur on entry is what makes it read as
   depth rather than as a slide-in. */
.r{opacity:0;transform:translateY(28px);filter:blur(6px);
  transition:opacity 1.1s var(--ease),transform 1.1s var(--ease),filter 1.1s var(--ease);
  transition-delay:var(--d,0ms)}
.is-in .r{opacity:1;transform:none;filter:none}
html:not(.js) .r{opacity:1;transform:none;filter:none}

/* ============ opening ============
   No image. The claim is four words; anything next to it is a distraction. */
.open{min-height:clamp(560px,84svh,900px);display:flex;align-items:center;
  padding-top:calc(52px + clamp(3rem,8vh,6rem));padding-bottom:clamp(3rem,8vh,6rem);text-align:center}
.open .lede{margin:1.75rem auto 0}
.open .btn-row{margin-top:2.5rem}

/* the quiet line under the buttons — texture without another paragraph */
.facts{display:flex;flex-wrap:wrap;justify-content:center;gap:.5rem 1.5rem;
  margin-top:clamp(3rem,7vh,4.5rem);padding-top:1.75rem;border-top:1px solid var(--rule-soft);
  max-width:44rem;margin-inline:auto}
.facts span{font-size:.8125rem;color:var(--ink-3);letter-spacing:0}

/* ============ the stat band ============ */
.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(2rem,5vw,4.5rem);margin-top:clamp(3rem,7vh,4.5rem)}
.stat b{display:block;font-size:clamp(2.5rem,5vw,4rem);font-weight:600;letter-spacing:-.045em;line-height:1;margin-bottom:.6rem}
.stat span{display:block;font-size:.9375rem;color:var(--ink-2);max-width:22ch}
@media (max-width:720px){ .stats{grid-template-columns:1fr;gap:2.5rem} }

/* Capability facts, deliberately small. These used to be a full .stats row —
   three numbers at 4rem — sitting directly above the money figures, and two
   banks of huge numbers in one section fought each other for the same job.
   Hairline tops rather than big type: the money is what should shout here. */
.quickfacts{list-style:none;margin:clamp(3rem,7vh,4.5rem) 0 0;padding:0;
  display:grid;grid-template-columns:repeat(3,1fr);
  gap:1rem clamp(1.5rem,3vw,2.5rem)}
.quickfacts li{font-size:.9375rem;line-height:1.5;color:var(--ink-2);
  padding-top:.9rem;border-top:1px solid var(--rule)}
.quickfacts b{display:block;color:var(--ink);font-weight:600;margin-bottom:.2rem}
@media (max-width:720px){ .quickfacts{grid-template-columns:1fr;gap:.85rem} }

/* Follows the lede directly now that the quickfacts have moved down the page,
   so it needs ordinary section spacing rather than the big gap it carried when
   it sat under a bank of stats. */
/* A white panel inside the grey band. The section was a wall of black type on
   one flat background; lifting the money onto paper separates it structurally
   rather than by adding colour, which this design system spends very
   sparingly. */
.ledger{margin-top:clamp(2.5rem,6vh,3.5rem);background:var(--paper,#fff);
  padding:clamp(1.75rem,4vw,3rem);border:1px solid var(--rule-soft)}
.ledger .stats{margin-top:2.25rem}
/* The one splash of accent. It is the punchline of the block and the only
   number on the page that is money leaving rather than money arriving. The
   site's rule is that accent marks the next action and never decorates — this
   is a deliberate exception, not a licence to colour other figures. */
.stat--loss{color:var(--accent)}
/* Reserve the width the final number needs, so the count-up does not reflow
   the three columns while it runs. */
.stat b[data-count]{display:block;min-width:5ch}
/* On a phone the shell already insets 24px; the panel's own padding stacked on
   top of that left the copy about 271px wide on a 375px screen, which is a
   narrow column for body text. Less padding inside the panel on small screens —
   the border and the white are doing the separating, not the space. */
@media (max-width:560px){
  .ledger{padding:1.5rem 1.25rem}
}

/* ============ asymmetric editorial ============
   Statement left, detail right. A different shape from the 3-up steps
   below it, so the page never repeats a layout twice running. */
.split{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(2.5rem,7vw,6rem);align-items:start}
.split__aside{display:grid;gap:2rem;padding-top:.6rem}
@media (max-width:860px){ .split{grid-template-columns:1fr;gap:2.5rem} }

/* ============ steps ============ */
.steps{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(2rem,4vw,3.5rem);margin-top:clamp(3rem,6vh,4.5rem)}
.step{padding-top:1.5rem;border-top:1px solid var(--rule)}
.step__n{font-size:.75rem;font-weight:600;letter-spacing:.14em;color:var(--ink-3);display:block;margin-bottom:1rem}
.step h3{margin-bottom:.6rem}
@media (max-width:820px){ .steps{grid-template-columns:1fr;gap:2rem} }

/* ============ the build week, as a distance ============
   Three columns of prose made "about a week" a claim in a headline with
   nothing under it. One continuous rule with three stops on it makes the
   week a shape you can see before you read a word — and it stops this
   section reading as the same 3-up grid as everything below it. */
.track{list-style:none;margin:clamp(3rem,6vh,4.5rem) 0 0;padding:0;position:relative;
  display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(2rem,4vw,3.5rem)}
.track::before{content:"";position:absolute;left:0;right:0;top:5px;height:1px;background:var(--rule)}
.track__stop{position:relative;padding-top:2.5rem}
/* the dot is a ring punched out of the section behind it, so its fill has to
   match that section — grey on a band, white on paper */
.track__stop::before{content:"";position:absolute;left:0;top:0;width:11px;height:11px;
  border-radius:50%;background:var(--band);border:1px solid var(--ink-3)}
.track--paper .track__stop::before{background:var(--paper)}
/* the last stop is the one that matters, so it's the only one filled */
.track__stop:last-child::before{background:var(--accent);border-color:var(--accent)}
.track__when{display:block;font-size:.75rem;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3);margin-bottom:.75rem}
.track__stop:last-child .track__when{color:var(--accent)}
.track__stop h3{margin-bottom:.6rem}
@media (max-width:820px){
  /* stacked, the spine turns and runs down the left instead of across */
  .track{grid-template-columns:1fr;gap:2.25rem}
  .track::before{left:5px;right:auto;top:6px;bottom:6px;width:1px;height:auto}
  .track__stop{padding-top:0;padding-left:2.25rem}
  .track__stop::before{top:5px}
}

/* ============ the dashboard panel ============
   A desktop app shown at desktop proportions and scaled down, never reflowed.
   The frame renders at a fixed --dashW and the whole thing is transform-scaled
   to whatever width the panel actually is, so the composition survives from a
   1920 monitor to a 390px phone.

   The scale factor is set in JS because CSS can't read the container's width
   into a transform. Layout still has to reserve the right box, which is what
   the aspect-ratio and the --dashS fallback are for — if the script never
   runs, you get an unscaled frame clipped to a sensible height rather than a
   collapsed section. */
.dash{--dashW:1400px;--dashH:960px;--dashS:1;
  margin-top:clamp(2.5rem,6vh,4rem);
  border-radius:16px;overflow:hidden;
  border:1px solid rgba(255,255,255,.1);
  box-shadow:0 40px 90px -50px rgba(0,0,0,.9);
  /* the box the scaled frame will occupy */
  height:calc(var(--dashH) * var(--dashS))}
/* The dashboard is 1834px tall at this width and the panel shows 1180 of it,
   so the last table rows get cut. Faded out rather than guillotined: a hard
   edge across a half-drawn row reads as a rendering bug, a fade reads as "this
   keeps going", which is the truth. Masked rather than covered with a
   gradient, so the card's border stays crisp around the fading interior. */
.dash__frame{width:var(--dashW);height:var(--dashH);
  transform:scale(var(--dashS));transform-origin:0 0;
  -webkit-mask-image:linear-gradient(to bottom,#000 72%,transparent 99%);
  mask-image:linear-gradient(to bottom,#000 72%,transparent 99%)}
.dash__frame iframe{display:block;width:100%;height:100%;border:0;
  /* a picture of software, not software */
  pointer-events:none}
@media (prefers-reduced-motion:no-preference){
  .dash{transition:box-shadow .6s var(--ease)}
}
/* On a phone, scaling the 1400px desktop layout down to 342 puts the labels
   at three pixels — an image of a dashboard rather than a dashboard. The file
   is responsive, so render it at phone width instead and crop to the numbers:
   you get the real thing at a size you can actually read, which is also how
   the client will look at it on a phone. */
@media (max-width:700px){
  .dash{--dashW:440px;--dashH:820px;border-radius:14px}
}

/* ============ inside one call ============
   The page's best content used to be three more columns of prose describing
   a conversation. A call is a sequence in time, so it is set as one: the
   dialogue down the left, and what the receptionist DID in the margin under
   each of its turns — because the behaviour is the product, not the wording.
   Ends on the text that lands, which the site promises four times and never
   showed anywhere until now. */
.callwrap{display:grid;grid-template-columns:1.4fr .6fr;gap:clamp(2.5rem,5vw,4.5rem);
  align-items:start;margin-top:clamp(3rem,6vh,4.5rem)}

.script{list-style:none;margin:0;padding:0}
.script__meta,.script__end{font-size:.8125rem;line-height:1.5;color:var(--ink-3)}
.script__meta{padding-bottom:1.15rem;border-bottom:1px solid var(--rule)}
.script__end{padding-top:1.15rem}
.script__end b{color:var(--ink);font-weight:600}

.turn{display:grid;grid-template-columns:6rem 1fr;gap:1.25rem;
  padding:1.1rem 0;border-bottom:1px solid var(--rule-soft)}
.turn__who{font-size:.6875rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;
  color:var(--ink-3);padding-top:.32rem}
.turn--ai .turn__who{color:var(--accent)}
/* the caller recedes, the receptionist carries the weight — you should be
   able to read only the dark lines and still follow what it did */
.turn__line{font-size:1.0625rem;line-height:1.55;color:var(--ink-2)}
.turn--ai .turn__line{color:var(--ink);font-weight:500}
.turn__note{margin-top:.6rem;padding-left:.9rem;border-left:2px solid var(--rule);
  font-size:.8125rem;line-height:1.5;color:var(--ink-3)}

/* the artifact. Follows you down the transcript, so the thing the call
   produces is on screen the whole time the call is happening. */
.sms{position:sticky;top:calc(52px + 1.5rem)}
.sms__cap{font-size:.8125rem;line-height:1.5;color:var(--ink-3);margin-bottom:1rem;max-width:30ch}
.sms__card{background:var(--ink);color:#fff;border-radius:20px;padding:1.35rem 1.4rem;
  font-size:.9375rem;line-height:1.6;box-shadow:0 26px 54px -32px rgba(0,0,0,.65)}
.sms__from{display:block;font-size:.6875rem;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:rgba(255,255,255,.45);margin-bottom:.85rem}
.sms__card b{display:block;font-weight:600;margin-bottom:.5rem}
.sms__card p{margin:0 0 .5rem;color:rgba(255,255,255,.72)}
.sms__card p:last-child{margin-bottom:0}
@media (max-width:900px){
  .callwrap{grid-template-columns:1fr;gap:2.5rem}
  .sms{position:static}
  .sms__card{max-width:24rem}
}
@media (max-width:560px){
  .turn{grid-template-columns:1fr;gap:.35rem}
  .turn__who{padding-top:0}
}

/* ============ industries ============
   The first and only photography on the page. Four tiles, generous, and
   the images are all the same shot from different rooms — a phone ringing
   while somebody works. That repetition is the argument. */
/* Two across, at the footage's own 16:9. A four-across portrait grid meant
   cropping a cinematic frame to a slot and then scaling it up past its own
   resolution — soft images on a page whose whole argument is precision. */
.tiles{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(1rem,1.8vw,1.5rem);margin-top:clamp(3rem,6vh,4.5rem)}

/* A real button, not a figure. Hover previews the clip, click pins it playing,
   and a keyboard tab does the same as a hover — so the interaction exists on
   touch and for anyone not using a mouse, not just on pointer hardware. */
.tile{position:relative;display:block;width:100%;margin:0;padding:0;border:0;
  border-radius:18px;overflow:hidden;background:#0b0b0c;aspect-ratio:16/9;
  font:inherit;color:inherit;text-align:left;cursor:pointer;-webkit-tap-highlight-color:transparent}
.tile img,.tile video{width:100%;height:100%;object-fit:cover;display:block}
.tile img{transition:transform 1.4s var(--ease)}
.tile:hover img{transform:scale(1.04)}
/* the clip sits over the still and cross-fades in; the still is never removed,
   so there is no black flash while the video decodes its first frame */
.tile video{position:absolute;inset:0;opacity:0;transition:opacity .55s var(--ease)}
.tile.is-playing video{opacity:1}
.tile.is-playing img{transform:scale(1.04)}

/* the affordance — without it nothing says these move */
.tile__play{position:absolute;top:1rem;right:1rem;width:34px;height:34px;border-radius:50%;
  display:grid;place-items:center;color:#fff;
  background:rgba(0,0,0,.32);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  border:1px solid rgba(255,255,255,.22);
  transition:opacity .45s var(--ease),transform .45s var(--ease)}
.tile__play svg{width:12px;height:12px;margin-left:1px}
.tile:hover .tile__play{transform:scale(1.06)}
.tile.is-playing .tile__play{opacity:0;transform:scale(.9)}

.tile__label{position:absolute;inset:auto 0 0 0;padding:2.5rem 1.5rem 1.5rem;
  background:linear-gradient(to top,rgba(0,0,0,.78),rgba(0,0,0,0));color:#fff}
.tile__label b{display:block;font-size:1.1875rem;font-weight:600;letter-spacing:-.02em}
.tile__label span{display:block;margin-top:.3rem;font-size:.875rem;color:rgba(255,255,255,.74)}
@media (max-width:700px){ .tiles{grid-template-columns:1fr} }

/* ============ coverage ============
   Set at the same weight as the body, wide apart. Eight place names given
   room read as reach; crammed together they read as a directory listing. */
/* Two full chapter paddings met at this seam — up to 176px from the tiles and
   another 176 before the cities — which put roughly a third of a screen of
   nothing between a caption and a heading. Both halves cut; the hairline is
   what separates the sections, not the void. */
.coverage{border-top:1px solid var(--rule-soft);padding-top:clamp(3.5rem,8vh,6rem)}
#who{padding-bottom:clamp(3rem,7vh,5rem)}
.cities{list-style:none;margin:clamp(2.5rem,6vh,3.75rem) 0 0;padding:0;
  display:flex;flex-wrap:wrap;justify-content:center;gap:1rem clamp(1.5rem,3.5vw,3rem)}
.cities li{font-size:clamp(1.0625rem,1.5vw,1.25rem);letter-spacing:-.02em;color:var(--ink)}

/* ============ the number ============ */
.call{text-align:center}
.call__num{display:inline-block;margin:1.75rem 0 .5rem;
  font-size:clamp(2.25rem,6vw,4.25rem);font-weight:600;letter-spacing:-.04em;line-height:1;
  transition:color .35s var(--ease)}
.call__num:hover{color:var(--accent)}

/* ============ footer ============ */
.foot{border-top:1px solid var(--rule-soft);padding-block:3rem;background:var(--band)}
.foot__in{display:flex;flex-wrap:wrap;gap:1.5rem;justify-content:space-between;align-items:center}
.foot a{color:var(--ink-3);font-size:.8125rem;transition:color .3s var(--ease)}
.foot a:hover{color:var(--ink)}
.foot__links{display:flex;flex-wrap:wrap;gap:1.5rem}
.foot__legal{font-size:.8125rem;color:var(--ink-3)}

@media (prefers-reduced-motion:reduce){
  *{animation-duration:.001ms!important;transition-duration:.001ms!important}
  .r{opacity:1;transform:none;filter:none}
  .tile:hover img{transform:none}
}

/* ============================================================
   SITE COMPONENTS
   Everything below is used by the pages beyond the landing page.
   ============================================================ */

/* ---------- page hero ----------
   Smaller than the home display type. A subpage that shouts as loudly as
   the front door flattens the hierarchy of the whole site. */
.phero{padding-top:calc(52px + clamp(3.5rem,9vh,6rem));padding-bottom:clamp(2.5rem,6vh,4rem)}
/* A page hero already ends in its own breathing room, so the chapter under it
   does not need a second full one. Unfixed, the two paddings stack to ~240px
   and every interior page opens with a hole between the lede and the first
   real content. Adjacent-sibling rather than per-page, so it can't be missed
   on the next page somebody adds.

   Not when the background changes, though: inside a band or a dark block that
   padding is the block's own interior margin, not a gap between two things on
   the same white field. Trim it there and the kicker sits 73px off the top
   edge of a full-bleed panel, which reads as a mistake. */
/* A hero already ends in its own generous padding, so the section under it does
   not need a full --chapter on top as well — that stacked ~172px of dead space
   under the heading. Tinted bands get the same treatment as plain chapters:
   the band reads as a background change, not a reason to push content down.
   .dark keeps the full run-in, where the colour break is the point. */
.phero + .chapter:not(.dark){padding-top:clamp(2rem,5vh,3.25rem)}
.phero .display{font-size:clamp(2.4rem,5.6vw,4.25rem);letter-spacing:-.04em}
.phero .lede{margin-top:1.5rem}

/* ---------- prose (legal, long form) ---------- */
.prose{max-width:68ch}
.prose h2{font-size:clamp(1.375rem,2.4vw,1.75rem);letter-spacing:-.028em;margin:2.75rem 0 .85rem}
.prose h2:first-child{margin-top:0}
.prose h3{font-size:1.125rem;letter-spacing:-.02em;margin:2rem 0 .6rem}
.prose p{margin:0 0 1.1rem;color:var(--ink-2);font-size:1.0625rem;line-height:1.65}
.prose ul,.prose ol{margin:0 0 1.25rem;padding-left:1.25rem;color:var(--ink-2);font-size:1.0625rem;line-height:1.65}
.prose li{margin-bottom:.5rem}
.prose a{color:var(--accent);text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px}
.prose strong{color:var(--ink);font-weight:600}
.prose__meta{font-size:.8125rem;color:var(--ink-3);margin-bottom:2.5rem}

/* ---------- pricing ---------- */
.tiers{display:grid;grid-template-columns:repeat(5,1fr);gap:clamp(.75rem,1.2vw,1rem);
  margin-top:clamp(3rem,6vh,4.5rem);align-items:stretch}
.tier{display:flex;flex-direction:column;padding:1.75rem 1.35rem;border:1px solid var(--rule);
  border-radius:16px;background:var(--paper);transition:border-color .4s var(--ease),transform .45s var(--ease),box-shadow .45s var(--ease)}
.tier:hover{border-color:rgba(0,0,0,.22);transform:translateY(-3px);box-shadow:0 18px 40px -28px rgba(0,0,0,.4)}
.tier--pick{border-color:var(--ink);position:relative}
.tier__tag{position:absolute;top:-.7rem;left:1.35rem;background:var(--ink);color:#fff;
  font-size:.625rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;
  padding:.28rem .6rem;border-radius:999px}
.tier__name{font-size:.75rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
.tier__price{font-size:clamp(1.875rem,3vw,2.5rem);font-weight:600;letter-spacing:-.04em;line-height:1;margin:1rem 0 .3rem}
.tier__price span{font-size:.9375rem;font-weight:400;letter-spacing:-.01em;color:var(--ink-3)}
.tier__meta{font-size:.875rem;color:var(--ink-2);line-height:1.5;margin-bottom:1.5rem}
.tier__meta b{color:var(--ink);font-weight:600}
.tier .btn{margin-top:auto;height:42px;font-size:.9375rem;padding:0 1.1rem}
@media (max-width:1080px){ .tiers{grid-template-columns:repeat(3,1fr)} }
@media (max-width:760px){ .tiers{grid-template-columns:1fr} }

/* what every plan includes, regardless of size */
.included{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem 2.5rem;
  margin-top:clamp(3rem,6vh,4rem);padding-top:2rem;border-top:1px solid var(--rule)}
.included li{list-style:none;font-size:.9375rem;color:var(--ink-2);
  padding-left:1.5rem;position:relative;line-height:1.5}
.included li::before{content:"";position:absolute;left:0;top:.55em;width:8px;height:2px;background:var(--accent)}
.included{padding-left:0;margin-bottom:0}
@media (max-width:760px){ .included{grid-template-columns:1fr} }

/* ---------- pick-card + ladder ----------
   One recommended plan as a card, every other size as a light ladder beside
   it. Used by BOTH pricing models on the page — the minute plans and the door
   bands — which is the point: five equal cards asked the reader to compare
   five things and do arithmetic, and having two different card systems on one
   page made it worse. One shape, one decision, the rest available but quiet.

   Names are deliberately model-agnostic (.pickCard, .ladder__label) because
   this is no longer only about doors or only about a setup fee. */
.priceSplit{display:grid;grid-template-columns:1.15fr 1fr;gap:clamp(2.5rem,6vw,5rem);
  align-items:start;margin-top:clamp(2.5rem,5vh,3.5rem)}
.pickCard{border:1px solid var(--rule);border-radius:16px;background:var(--paper);
  padding:clamp(1.6rem,2.6vw,2.1rem)}
/* .pickCard p is one class plus one type and outranks a bare .pickCard__price,
   which quietly renders the price at body size. Scoped to two classes so the
   number wins. */
.pickCard .pickCard__price{font-size:clamp(2.25rem,4vw,3rem);font-weight:600;letter-spacing:-.045em;
  line-height:1;margin:.9rem 0 .1rem}
.pickCard .pickCard__price span{font-size:.9375rem;font-weight:400;letter-spacing:-.01em;color:var(--ink-3)}
.pickCard p{font-size:.9375rem;color:var(--ink-2);line-height:1.6;margin:1.1rem 0 0}
.pickCard .btn{margin-top:1.6rem;height:42px;font-size:.9375rem;padding:0 1.1rem}
/* the one we actually recommend; everything else is a row in the ladder */
.pickCard--pick{position:relative;border-color:var(--ink);box-shadow:0 22px 48px -34px rgba(0,0,0,.45)}

.ladder{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule)}
.ladder li{display:flex;align-items:baseline;justify-content:space-between;gap:1.5rem;
  padding:1.05rem 0;border-bottom:1px solid var(--rule-soft)}
.ladder__label{font-size:1.0625rem;color:var(--ink);letter-spacing:-.014em}
.ladder__label b{font-weight:600}
.ladder__price{font-size:clamp(1.375rem,2.2vw,1.75rem);font-weight:600;letter-spacing:-.04em;
  line-height:1;white-space:nowrap;font-variant-numeric:tabular-nums}
.ladder__price span{font-size:.875rem;font-weight:400;letter-spacing:-.01em;color:var(--ink-3)}
@media (max-width:860px){ .priceSplit{grid-template-columns:1fr;gap:2.5rem} }

/* ---------- pricing: three cards, then the full grid ----------
   Modelled on how the competition presents this, because it is genuinely the
   clearest way to show it: a few cards for the decision, then one grid for the
   detail. The grid is the argument here — every feature row is a tick on every
   plan, which is the opposite of a competitor whose custom prompting and
   full-service setup switch on at $500/mo. A grid of all ticks looks flat until
   you have just read theirs. */
.pcards{display:grid;grid-template-columns:repeat(3,1fr);gap:1.25rem;
  margin-top:clamp(2.5rem,5vh,3.5rem);align-items:start}
.pcard{border:1px solid var(--rule);padding:1.75rem 1.5rem 1.5rem;display:flex;
  flex-direction:column;gap:.5rem;height:100%}
.pcard--pick{border-color:var(--ink);border-width:1.5px}
.pcard__tag{display:inline-block;align-self:flex-start;font-size:.6875rem;
  font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--accent);
  border:1px solid currentColor;border-radius:999px;padding:.25rem .6rem;margin-bottom:.4rem}
.pcard__name{font-size:1.0625rem;font-weight:600;letter-spacing:-.015em;margin:0}
.pcard__price{font-size:clamp(2.25rem,4vw,2.9rem);font-weight:600;letter-spacing:-.04em;
  line-height:1;margin:.35rem 0 0;font-variant-numeric:tabular-nums}
.pcard__price span{font-size:1rem;font-weight:500;letter-spacing:-.01em;color:var(--ink-3)}
.pcard__vol{font-size:.9375rem;color:var(--ink-2);margin:.5rem 0 0}
.pcard__note{font-size:.875rem;color:var(--ink-3);margin:.9rem 0 1.4rem;line-height:1.55}
.pcard .btn{margin-top:auto;width:100%;text-align:center}

/* Six columns will not restack into anything readable, so it scrolls inside its
   own box rather than pushing the page sideways. */
.pgridWrap{overflow-x:auto;margin-top:clamp(3rem,6vh,4.5rem);
  -webkit-overflow-scrolling:touch}
.pgrid{width:100%;min-width:44rem;border-collapse:collapse;font-size:.9375rem}
.pgrid th,.pgrid td{padding:.85rem 1rem;text-align:center;
  border-bottom:1px solid var(--rule-soft)}
.pgrid thead th{font-size:.8125rem;font-weight:600;color:var(--ink-3);
  border-bottom-color:var(--rule);white-space:nowrap}
.pgrid thead th.is-ours{color:var(--ink)}
.pgrid tbody th{text-align:left;font-weight:400;color:var(--ink-2);width:34%;
  white-space:normal}
.pgrid .pgrid__group th{font-size:.6875rem;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3);padding-top:2rem;border-bottom-color:var(--rule)}
.pgrid td{color:var(--ink);font-variant-numeric:tabular-nums}
/* Scoped to td, not left as a bare class: `.pgrid td` is class+type and
   silently outranks `.pgrid__yes`, so the ticks rendered ink instead of
   accent. Same trap as `.setup .setup__fee` further down this file. */
.pgrid td.pgrid__yes{color:var(--accent);font-size:1.05rem;line-height:1}
.pgrid__price{font-weight:600}

@media (max-width:860px){ .pcards{grid-template-columns:1fr;max-width:26rem} }

/* ---------- comparison ---------- */
.cmp{width:100%;border-collapse:collapse;margin-top:clamp(3rem,6vh,4.5rem);font-size:1rem}
.cmp caption{text-align:left;font-size:.75rem;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3);padding-bottom:1.25rem}
.cmp th,.cmp td{text-align:left;padding:1.1rem 1rem;border-bottom:1px solid var(--rule-soft);vertical-align:top}
.cmp thead th{font-size:.8125rem;font-weight:600;color:var(--ink-3);letter-spacing:0;border-bottom-color:var(--rule)}
.cmp tbody th{font-weight:400;color:var(--ink-2);width:34%}
.cmp td{color:var(--ink-2)}
.cmp td.is-ours{color:var(--ink);font-weight:500}
.cmp thead th.is-ours{color:var(--ink)}
@media (max-width:700px){
  /* caption is in this list on purpose. Without it the <caption> keeps
     display:table-caption inside a table that is no longer a table, and
     browsers shrink-wrap it — on the pricing page it rendered 75px wide
     on a 375px phone, one or two uppercase words per line, from launch
     until 2026-09-01. */
  .cmp,.cmp caption,.cmp tbody,.cmp tr,.cmp td,.cmp th{display:block}
  .cmp thead{display:none}
  .cmp tr{padding:1.25rem 0;border-bottom:1px solid var(--rule-soft)}
  .cmp th,.cmp td{border:0;padding:.15rem 0;width:auto}
  .cmp tbody th{font-weight:600;color:var(--ink);margin-bottom:.4rem}
  .cmp td::before{content:attr(data-l) " — ";color:var(--ink-3)}
}

/* ---------- faq ---------- */
/* capped at 72ch so a question never runs the full shell width, and centred in
   whatever it sits in rather than hugging the left edge with the spare width
   piled up on the right */
.faq{margin-top:clamp(3rem,6vh,4.5rem);max-width:72ch}
/* Six and six. Two separate .faq lists rather than one grid of items,
   because a shared grid ties the columns' row heights together and opening a
   question on one side leaves a hole beside its neighbour. */
.faqGrid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(2rem,4vw,3.5rem);
  margin-top:clamp(3rem,6vh,4.5rem);align-items:start}
.faqGrid .faq{margin-top:0;max-width:none}
@media (max-width:860px){
  .faqGrid{grid-template-columns:1fr;gap:0}
  /* stacked, the first list's closing rule meets the second list's opening
     one and draws a double line across the seam */
  .faqGrid .faq:first-child details:last-of-type{border-bottom:0}
}
.faq details{border-top:1px solid var(--rule)}
.faq details:last-of-type{border-bottom:1px solid var(--rule)}
.faq summary{list-style:none;cursor:pointer;padding:1.5rem 2.5rem 1.5rem 0;position:relative;
  font-size:clamp(1.0625rem,1.6vw,1.25rem);font-weight:600;letter-spacing:-.022em;
  transition:color .3s var(--ease)}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--accent)}
/* the plus/minus, drawn in CSS so there is no icon file to keep in sync */
.faq summary::after,.faq summary::before{content:"";position:absolute;right:.35rem;top:50%;
  background:var(--ink-3);transition:transform .4s var(--ease),opacity .3s var(--ease)}
.faq summary::before{width:13px;height:1.5px;margin-top:-.75px}
.faq summary::after{width:1.5px;height:13px;right:6.1px;margin-top:-6.5px}
.faq details[open] summary::after{transform:rotate(90deg);opacity:0}
.faq__a{padding:0 2.5rem 1.75rem 0}
.faq__a p{margin:0 0 .9rem;color:var(--ink-2);font-size:1.0625rem;line-height:1.65}
.faq__a p:last-child{margin-bottom:0}

/* ---------- industries ---------- */
.inds{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(1.75rem,3vw,2.75rem);
  margin-top:clamp(3rem,6vh,4.5rem)}
.ind{padding-top:1.5rem;border-top:1px solid var(--rule)}
.ind h3{font-size:1.1875rem;letter-spacing:-.022em;margin-bottom:.6rem}
.ind p{font-size:.9375rem;color:var(--ink-2);line-height:1.6}
@media (max-width:860px){ .inds{grid-template-columns:1fr 1fr} }
@media (max-width:560px){ .inds{grid-template-columns:1fr} }

/* An .ind that is itself a link — used for the competitor comparison cards on
   the pricing page. The whole card is the target rather than four words of it,
   and the top rule takes the accent on hover because it is the only line the
   card already has; adding a border or a shadow on hover would make these the
   only two boxes on the site that look like buttons. */
a.ind{display:block;color:inherit;transition:border-top-color .3s var(--ease)}
a.ind h3,a.ind .ind__go{transition:color .3s var(--ease)}
/* The whole card lights up, not just the link inside it — the card is the
   target, so the card is what should answer the cursor. Keyboard focus gets
   the same treatment; a hover-only affordance is invisible to anyone tabbing. */
a.ind:hover,a.ind:focus-visible{border-top-color:var(--accent)}
a.ind:hover h3,a.ind:focus-visible h3{color:var(--accent)}
a.ind:focus-visible{outline:2px solid var(--accent);outline-offset:6px}
/* nowrap so the arrow never drops to a line of its own, which reads as a
   stray character rather than as part of the link */
.ind__go{display:inline-block;margin-top:1rem;font-size:.9375rem;color:var(--accent);
  white-space:nowrap}

/* Two cards, not three. This lives after the .inds media queries on purpose:
   an inline grid-template-columns on the element would have won against them
   and left the pair side by side at 360px, each card four words wide. */
.inds--two{grid-template-columns:repeat(2,1fr)}
@media (max-width:560px){ .inds--two{grid-template-columns:1fr} }

/* ---------- booking picker (/book.html) ----------
   Flat, ruled, no cards and no shadows — the rest of the site draws structure
   with hairlines and this has to look like it belongs, not like an embedded
   third-party scheduler, which is the whole reason it exists. */
.bk{margin-top:clamp(2.5rem,5vh,3.5rem)}
.bk__live{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* The day strip scrolls sideways rather than wrapping. A wrapped strip
   re-flows every time a day is chosen and the row you are reading moves. */
.bk__weekNav{display:flex;align-items:center;gap:1rem;margin-bottom:1.1rem}
.bk__weekLabel{font-size:.9375rem;font-weight:600;letter-spacing:-.01em;min-width:11ch}
.bk__arrow{width:2rem;height:2rem;display:grid;place-items:center;background:none;
  border:1px solid var(--rule);color:var(--ink-2);font:inherit;font-size:1.1rem;
  line-height:1;cursor:pointer;transition:border-color .2s var(--ease),color .2s var(--ease)}
.bk__arrow:hover:not(:disabled){border-color:var(--ink-3);color:var(--ink)}
.bk__arrow:disabled{opacity:.3;cursor:default}

/* A week is at most five days, so they share the row evenly. The old strip
   scrolled sideways because it held sixteen. */
.bk__days{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:.5rem;
  padding-bottom:.75rem;border-bottom:1px solid var(--rule);max-width:34rem}
.bk__day{display:flex;flex-direction:column;align-items:center;gap:.15rem;
  padding:.7rem .4rem .8rem;background:none;border:0;cursor:pointer;
  border-bottom:2px solid transparent;color:var(--ink-3);font:inherit;
  transition:color .2s var(--ease),border-color .2s var(--ease)}
.bk__day:hover{color:var(--ink)}
.bk__day.is-on{color:var(--ink);border-bottom-color:var(--accent)}
.bk__day.is-empty{opacity:.35}
.bk__dayName{font-size:.6875rem;letter-spacing:.1em;text-transform:uppercase}
.bk__dayNum{font-size:1.25rem;font-weight:600;letter-spacing:-.02em}
.bk__dayMon{font-size:.6875rem;letter-spacing:.06em;text-transform:uppercase}

/* Capped at the same measure as the day row so the two read as one control
   rather than a narrow header over a wide field. */
.bk__slots{display:grid;grid-template-columns:repeat(auto-fill,minmax(6.75rem,1fr));
  gap:.6rem;margin-top:1.75rem;max-width:34rem}
.bk__slot{padding:.8rem .5rem;background:none;border:1px solid var(--rule);
  color:var(--ink-2);font:inherit;font-size:.9375rem;cursor:pointer;
  transition:border-color .2s var(--ease),color .2s var(--ease)}
.bk__slot:hover{border-color:var(--ink-3);color:var(--ink)}
.bk__slot.is-on{border-color:var(--accent);color:var(--ink);font-weight:600}
.bk__empty{grid-column:1/-1;font-size:.9375rem;color:var(--ink-3);padding:.6rem 0}

/* The form carries .lead as well, which supplies the field styling — inputs,
   textarea, focus rings, the consent row. Scoped .bk .bk__form here so these
   four properties beat .lead's own margin-top, which is defined later. Width is
   deliberately left to .lead so both forms on this page are the same measure. */
.bk .bk__form{margin-top:clamp(2.25rem,4.5vh,3rem);padding-top:clamp(2rem,4vh,2.5rem);
  border-top:1px solid var(--rule)}
.bk__when{font-size:.75rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--accent);margin:0 0 .35rem}
.bk__note{font-size:1.375rem;font-weight:600;letter-spacing:-.02em;margin:0 0 1.75rem}
.bk__err{margin-top:1rem;font-size:.9375rem;color:#B3260A}

.bk__done{border-top:1px solid var(--rule);padding-top:clamp(2rem,4vh,2.5rem);
  margin-top:clamp(2.25rem,4.5vh,3rem);max-width:44rem}
.bk__done h3{font-size:clamp(1.5rem,2.6vw,2rem);letter-spacing:-.025em;margin:0 0 .9rem}
.bk__doneWhen{font-weight:600;color:var(--ink)}

@media (max-width:560px){
  .bk__slots{grid-template-columns:repeat(auto-fill,minmax(5.5rem,1fr))}
}

/* ---------- ad landing page ----------
   Mobile first and genuinely so: this traffic is effectively all phones. The
   call button is the biggest thing on the screen because tapping it is one
   gesture and hearing the receptionist is the entire pitch. */
.lphero{padding-block:clamp(1.5rem,4vh,2.5rem) clamp(3rem,8vh,5rem)}
.lpmark{display:inline-block;font-weight:600;font-size:1.0625rem;letter-spacing:-.02em;
  color:var(--ink);margin-bottom:clamp(2.5rem,7vh,4.5rem)}
.lpmark em{font-style:normal;color:var(--ink-3);font-weight:500}
.lph1{font-size:clamp(2.1rem,6.2vw,4.2rem);line-height:1.02;letter-spacing:-.04em;
  font-weight:600;margin:0;max-width:18ch}
.lplede{font-size:clamp(1.0625rem,2vw,1.3125rem);line-height:1.5;color:var(--ink-2);
  max-width:44ch;margin:clamp(1.25rem,3vh,1.75rem) 0 0}

.lpcta{display:flex;flex-wrap:wrap;gap:.85rem;margin-top:clamp(2rem,5vh,2.75rem)}
/* Two lines inside one button: the verb, then the number itself, because on a
   phone the number is the thing being tapped and it should look like it. */
.lpcall{display:inline-flex;flex-direction:column;align-items:center;gap:.1rem;
  padding-block:.95rem;line-height:1.2}
.lpcall span{font-size:.8125rem;opacity:.85;letter-spacing:.02em}
.lpcall b{font-size:1.25rem;font-weight:600;letter-spacing:-.01em;
  font-variant-numeric:tabular-nums}
.lpnote{font-size:.875rem;color:var(--ink-3);max-width:46ch;margin-top:1.5rem;line-height:1.5}

.lpfoot{background:var(--band);border-top:1px solid var(--rule-soft);
  padding-block:clamp(2.5rem,5vh,3.5rem);text-align:center}
.lpfoot__word{font-weight:600;font-size:1.0625rem;letter-spacing:-.02em;margin:0}
.lpfoot__word em{font-style:normal;color:var(--ink-3);font-weight:500}
.lpfoot__links{display:flex;flex-wrap:wrap;gap:1.25rem;justify-content:center;
  margin:1.1rem 0 0}
.lpfoot__links a{font-size:.9375rem;color:var(--ink-2)}
.lpfoot__links a:hover{color:var(--ink)}
.lpfoot__base{font-size:.8125rem;color:var(--ink-3);margin:1.4rem 0 0}

@media (max-width:560px){
  /* Full-width targets. A thumb reaching across a phone should not have to aim. */
  .lpcta{flex-direction:column;align-items:stretch}
  .lpcta .btn{width:100%;text-align:center;justify-content:center}

  /* The picker has to be the first thing, not the thing after a scroll. On a
     375x812 phone the default hero pushed it to ~940px — just past the fold,
     which is the worst possible place for it. These numbers are tuned so the
     "Pick a time" heading is on screen when the page loads. Re-measure if the
     headline or the lede changes length. */
  .lphero{padding-block:1rem 1.5rem}
  .lpmark{margin-bottom:1.75rem}
  .lph1{font-size:2rem;letter-spacing:-.035em}
  .lplede{font-size:1rem;margin-top:1rem}
  .lpcta{margin-top:1.5rem}
  .lpnote{margin-top:1rem;font-size:.8125rem}
  /* The picker section follows the hero directly, so it does not need its own
     full chapter padding on top as well. */
  .lphero + .chapter{padding-top:1.75rem}
}

/* ---------- site footer ---------- */
.sitefoot{background:var(--band);border-top:1px solid var(--rule-soft);padding-block:clamp(3.5rem,7vh,5rem)}
/* Product carries six links and set as one column it was the tallest thing in
   the footer by a wide margin, dragging every other column's whitespace down
   with it. Split three-and-three it costs half the height, and its cell is
   given the extra width that split needs. */
/* Five blocks, so five columns. It declared four for years, which dropped Legal
   onto a second row on its own and left three empty cells beside it — about
   215px of blank footer. */
.sitefoot__grid{display:grid;grid-template-columns:1.3fr 1.25fr .95fr 1.05fr .8fr;gap:2rem}
/* auto-flow column with three fixed rows fills DOWN then across, so the order
   still reads 1-2-3 / 4-5-6 rather than zig-zagging */
.sitefoot__two{grid-template-columns:1fr 1fr;grid-template-rows:repeat(3,auto);
  grid-auto-flow:column;column-gap:1.5rem}
/* Three fixed rows fits exactly six. A seventh item opens a THIRD column and
   the whole footer cell wraps into narrow ragged strips — this has happened
   once already. Any list longer than six needs its own row count. */
.sitefoot__two--4{grid-template-rows:repeat(4,auto)}
.sitefoot h4{font-size:.75rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);margin:0 0 1.1rem}
.sitefoot ul{list-style:none;margin:0;padding:0;display:grid;gap:.7rem}
/* marks only, so they need a hit area a finger can find — the glyph is 19px
   but the tap target is 40, which is the minimum worth shipping on a phone */
.social{display:flex !important;gap:.35rem;margin-top:1.1rem}
.social a{display:inline-flex;align-items:center;justify-content:center;
  width:40px;height:40px;margin-left:-10px;color:var(--ink-3);
  transition:color .3s var(--ease)}
.social a:hover{color:var(--ink)}
.social svg{width:19px;height:19px;display:block}
.sitefoot a{font-size:.9375rem;color:var(--ink-2);transition:color .3s var(--ease)}
.sitefoot a:hover{color:var(--ink)}
.sitefoot__blurb{font-size:.9375rem;color:var(--ink-2);max-width:30ch;line-height:1.55;margin:.9rem 0 0}
.sitefoot__word{font-weight:600;font-size:1.0625rem;letter-spacing:-.02em}
.sitefoot__word em{font-style:normal;color:var(--ink-3);font-weight:500}
.sitefoot__base{display:flex;flex-wrap:wrap;gap:1rem;justify-content:space-between;
  margin-top:clamp(2.5rem,5vh,3.5rem);padding-top:1.75rem;border-top:1px solid var(--rule-soft);
  font-size:.8125rem;color:var(--ink-3)}
/* Drops to two columns well before the old 860px: five columns share the row
   now, and below ~1080px the last of them is squeezed under 100px, which wraps
   "Terms of service" onto two lines. */
@media (max-width:1080px){ .sitefoot__grid{grid-template-columns:1fr 1fr} }
@media (max-width:520px){
  .sitefoot__grid{grid-template-columns:1fr}
  /* one column wide, the split has no width to work with and the two halves
     collide — Product goes back to a single list here */
  .sitefoot__two{grid-template-columns:1fr;grid-template-rows:none;grid-auto-flow:row}
}

/* ---------- the phone number's hover card ----------
   Hovering the nav number explains what actually happens if you ring it, which
   is the question that stops people calling a number on a website.

   Three things this must not break:
   - It is an enhancement over a working tel: link. The link dials with or
     without it, and with JS off nothing here is required.
   - `hover: none` kills it entirely. On a phone, tapping the number must dial,
     not open a card you then have to dismiss — and the mobile nav panel has no
     room for it anyway.
   - It sits over the black hero on the home page, so it carries its own light
     background and ink rather than inheriting the dark nav's colours. */
.navtel{position:relative;display:inline-block}
.telcard{position:absolute;top:calc(100% + .85rem);right:0;width:20.5rem;
  background:var(--paper,#fff);border:1px solid var(--rule);
  box-shadow:0 18px 50px rgba(0,0,0,.13);padding:1.35rem 1.4rem 1.5rem;
  display:flex;flex-direction:column;text-align:left;z-index:60;
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .22s var(--ease),transform .22s var(--ease),visibility .22s}
.navtel:hover .telcard,.navtel:focus-within .telcard{opacity:1;visibility:visible;transform:none}
.telcard__top{font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
/* White on the accent at 24px/600 is large text, where AA wants 3:1 and this
   clears it. Do not drop the weight or the size without re-checking that. */
.telcard__num{display:block;margin-top:.85rem;padding:.9rem .5rem;text-align:center;
  background:var(--accent);font-size:1.5rem;font-weight:600;letter-spacing:-.02em;
  color:#fff;font-variant-numeric:tabular-nums;
  transition:background-color .2s var(--ease)}
.telcard__num:hover{background:#C7430D;color:#fff}
.telcard__steps{list-style:none;counter-reset:s;margin:1.25rem 0 0;padding:0;
  display:grid;gap:.7rem}
.telcard__steps li{counter-increment:s;position:relative;padding-left:1.9rem;
  font-size:.9375rem;color:var(--ink-2);line-height:1.45}
.telcard__steps li::before{content:counter(s);position:absolute;left:0;top:.05rem;
  width:1.25rem;height:1.25rem;border-radius:50%;background:var(--band);
  color:var(--ink-3);font-size:.6875rem;display:grid;place-items:center}
.telcard__rule{display:block;height:1px;background:var(--rule-soft);margin:1.25rem 0}
.telcard__row{display:block;font-size:.875rem;color:var(--ink-3);line-height:1.45;
  padding-left:1rem;position:relative}
.telcard__row + .telcard__row{margin-top:.8rem}
.telcard__row b{display:block;font-weight:600;color:var(--ink);margin-bottom:.1rem}
.telcard__row::before{content:"";position:absolute;left:0;top:.45rem;width:.45rem;
  height:.45rem;border-radius:50%;background:var(--accent)}
.telcard__row--alt::before{background:var(--ink-3)}

/* No hover, no card — and the mobile nav panel has nowhere to put it. */
@media (hover: none){ .telcard{display:none} }
@media (max-width:900px){ .telcard{display:none} }

/* ---------- the Industries dropdown ----------
   Eight pages used to hang off a single link on industries.html. This puts
   them on every page in the site.

   Three things it must not break:
   - The Industries link still works and still goes to the page. The menu is
     an addition; on a phone a tap opens the page exactly as before.
   - It opens on hover AND on keyboard focus, so it is reachable by tab.
   - Below 900px the nav becomes a panel and this is hidden entirely — the
     panel has no room for a 17-link menu, and the industries page it links to
     carries the same lists anyway. */
.navhas{position:relative}
.navmenu{position:absolute;top:calc(100% + 1.35rem);left:50%;transform:translateX(-50%) translateY(-6px);
  background:var(--paper,#fff);border:1px solid var(--rule);box-shadow:0 18px 50px rgba(0,0,0,.13);
  padding:1.6rem 1.75rem 1.25rem;z-index:60;min-width:34rem;
  opacity:0;visibility:hidden;
  transition:opacity .2s var(--ease),transform .2s var(--ease),visibility .2s}
.navhas:hover .navmenu,.navhas:focus-within .navmenu{
  opacity:1;visibility:visible;transform:translateX(-50%)}
/* A gap between the bar and the panel would close the menu as the cursor
   crosses it. This bridges it without being visible. */
.navmenu::before{content:"";position:absolute;left:0;right:0;top:-1.35rem;height:1.35rem}
.navmenu__in{display:grid;grid-template-columns:1.15fr .85fr;gap:2.25rem}
.navmenu__col{display:flex;flex-direction:column;gap:.55rem}
.navmenu__h{font-size:.6875rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);margin:0 0 .35rem}
.navmenu__col a{font-size:.9375rem;color:var(--ink-2);white-space:nowrap;
  transition:color .2s var(--ease)}
.navmenu__col a:hover{color:var(--accent)}
.navmenu__foot{margin:1.4rem 0 0;padding-top:1rem;border-top:1px solid var(--rule-soft)}
.navmenu__foot a{font-size:.875rem;color:var(--ink-3)}
.navmenu__foot a:hover{color:var(--ink)}

@media (max-width:900px){ .navmenu{display:none} }
@media (hover:none){ .navmenu{display:none} }

/* nav: mark the page you are on */
.nav__links a[aria-current="page"]{color:var(--ink)}

/* ---------- mask reveal ----------
   The line rises out of a hidden edge rather than fading in. It is the most
   expensive-looking reveal there is and it costs one transform — no blur, no
   opacity, nothing that forces a repaint. Used where the craft should show. */
.rise{display:block;overflow:hidden;padding-bottom:.08em}
.rise>span{display:block;transform:translateY(112%);
  transition:transform 1.25s var(--ease);transition-delay:var(--d,0ms)}
.is-in .rise>span{transform:none}
html:not(.js) .rise>span{transform:none}

/* ---------- the price as the headline ----------
   On a pricing page the number is the argument. Tabular figures so the digits
   sit on the same rhythm as everything else set in this face. */
/* ---------- the pricing hero ----------
   Dark and full-bleed, the same room as the landing hero. Pricing was the one
   page on the site with no visual of any kind — a very large number floating
   in half a screen of white.

   Built to work with OR without the image. The background is a near-black
   base plus an optional photo layered under a scrim, so the type is legible
   the moment the page renders and stays legible if the image never arrives,
   is still loading, or is blocked. Nothing here depends on the asset
   existing: drop the file in, set --priceArt, and it appears. */
.priceHero{--priceArt:url("/assets/price-hero.jpg");
  position:relative;background:#050506;color:#fff;overflow:hidden;
  padding-top:calc(52px + clamp(4rem,11vh,7.5rem));padding-bottom:clamp(4rem,10vh,7rem)}
/* MIRRORED, deliberately. The render lights the left — the lamp, the plant,
   the phone all sit in the left third, which is exactly where the headline
   goes. Flipped, the lit desk lands right of centre and the type gets the
   darkest part of the frame to sit on. Nothing in the photograph reads as
   handed, so there is nothing to give the flip away. */
.priceHero__art{position:absolute;inset:0;pointer-events:none;
  background-image:var(--priceArt,none);
  background-size:cover;background-position:50% 62%;
  transform:scaleX(-1);z-index:1;
  opacity:var(--priceArtOpacity,.92)}
/* the scrim is what guarantees contrast on the left third whatever the photo
   turns out to be — without it a bright frame would swallow the number */
.priceHero::before{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:
    linear-gradient(to right,rgba(5,5,6,.94) 0%,rgba(5,5,6,.82) 34%,rgba(5,5,6,.3) 66%,rgba(5,5,6,.12) 100%),
    linear-gradient(to bottom,rgba(5,5,6,.86) 0%,rgba(5,5,6,0) 30%)}
/* settle to solid black at the foot so the white page below starts clean */
.priceHero::after{content:"";position:absolute;inset:auto 0 0 0;height:22%;z-index:2;pointer-events:none;
  background:linear-gradient(to bottom,rgba(5,5,6,0),#050506 88%)}
@supports (background-image:image-set("a.webp" type("image/webp"))){
  .priceHero{--priceArt:image-set("/assets/price-hero.webp" type("image/webp"))}
}
.priceHero > .shell{position:relative;z-index:3}
.priceHero .kicker{color:var(--accent-lift)}
.priceHero .lede{color:rgba(255,255,255,.74)}
.priceHero .against{border-top-color:rgba(255,255,255,.16)}
.priceHero .against b{color:#fff}
.priceHero .body{color:rgba(255,255,255,.62)}

.bigprice{font-size:clamp(3.5rem,11vw,8.5rem);letter-spacing:-.055em;line-height:.95;
  font-variant-numeric:tabular-nums}
.priceHero .bigprice em{color:rgba(255,255,255,.55)}
/* The size lives on the MASK, not on the <em> inside it. Each .rise is a
   block and its line box is set by its own strut — so with the shrink applied
   to the em, the second line reserved a 140px box for 44px type and left a
   hole under the number. Sizing the mask collapses the strut with it. */
.bigprice .rise:last-child{font-size:clamp(1.5rem,3.4vw,2.75rem)}
.bigprice em{font-style:normal;color:var(--ink-3);font-weight:500;
  letter-spacing:-.03em}
.against{margin-top:clamp(2rem,4vh,2.75rem);padding-top:1.5rem;
  border-top:1px solid var(--rule-soft);max-width:46ch}
.against b{color:var(--ink);font-weight:600}
.against a{color:var(--accent)}

/* ============================================================
   THE DARK HERO
   A black landing hero over a white site. The nav rides transparent
   with light type while it is over the hero, then becomes the normal
   white bar the moment you leave it.
   ============================================================ */
/* Pure #000, not near-black. The waves are matte black material and the only
   thing separating them from the ground is their own charcoal shading — lift
   the ground even to #050506 and the darkest folds go lighter than the room
   they sit in, which reads as a sticker rather than a solid.

   No isolation:iso here. The planes are siblings in the section's own stacking
   context and they need to interleave: deep wave 1, type 2, near wave 3,
   buttons 4. */
.heroDark{position:relative;min-height:100svh;overflow:hidden;background:#000;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding-top:calc(52px + clamp(2rem,6vh,4rem));padding-bottom:clamp(3rem,8vh,5rem)}

/* ---------- the two wave planes ----------
   Absolutely positioned, so the flex column above lays out the headline and
   the buttons as if the waves weren't there. Anchored bottom-centre and sized
   in vw: the image is 3:1 and must never be squashed, because the occlusion
   line IS its silhouette — distort it and the folds stop matching their own
   shading. */
/* ANCHORED TO THE MIDDLE OF THE HERO, NOT ITS BOTTOM, AND OFFSET IN vw.

   This is the difference between an occlusion that holds and one that only
   looked right on the window it was tuned on. The type is sized in vw and
   centred in the hero; hang the wave off the BOTTOM instead and, on a
   wider-but-not-taller window, the type grows downward while the wave's
   features stay put — so the folds climb back up into ANSWERED, which is the
   exact complaint that got them lowered in the first place.

   Anchor both to the same origin and scale both by the same unit, and the
   proportion of a letter a fold covers is the same at 1280, 1600 and 1920. */
.wave{position:absolute;left:50%;pointer-events:none;user-select:none;
  --x:0vw;--rise:0vw;
  width:var(--w);top:calc(50% + var(--rise));
  will-change:transform}
.wave img{display:block;width:100%;height:auto}

/* Behind the type. Bigger, lower, softened and dimmed — distance, not a
   second subject. It reads as the far side of the same material. */
.wave--deep{--w:176vw;--rise:-25.1vw;--x:6vw;z-index:1;
  opacity:.34;filter:blur(4px) brightness(.5);
  transform:translate3d(calc(-50% + var(--x)),0,0);
  animation:waveDeep 71s cubic-bezier(.42,0,.58,1) infinite}

/* In front of the type. This one does the work: its alpha is the mask, so
   width, bottom and shift are not decoration — together they decide which
   letters the folds cut across. These three numbers were solved for, not
   nudged: the silhouette's top edge was sampled out of the image's own alpha
   channel and searched against the two lines of type until the folds graze
   the underside of ANSWERED and leave EVERY CALL clean. Change one and the
   occlusion changes with it, so re-check the words before shipping.

   Dimmed with brightness, never opacity: opacity would let the letters ghost
   through the fold that is supposed to be hiding them. */
.wave--front{--w:130vw;--rise:-20.1vw;--x:-8vw;z-index:3;filter:brightness(.85);
  transform:translate3d(calc(-50% + var(--x)),0,0);
  animation:waveFront 47s cubic-bezier(.42,0,.58,1) infinite}

/* Slow drift, different rates and directions, so the two planes separate in
   depth as they move and the boundary across the letters keeps changing.
   Small amplitudes on purpose — this should be something you notice on the
   second look, not motion competing with the headline. Percentages are of the
   layer's own box, so the drift scales with the viewport instead of getting
   frantic on a phone. */
@keyframes waveFront{
  0%,100%{transform:translate3d(calc(-50% + var(--x)),0,0)}
  50%    {transform:translate3d(calc(-50% + var(--x) - 2.4%),-1.9%,0)}
}
@keyframes waveDeep{
  0%,100%{transform:translate3d(calc(-50% + var(--x)),0,0)}
  50%    {transform:translate3d(calc(-50% + var(--x) + 2.1%),1.4%,0)}
}
@media (prefers-reduced-motion:reduce){
  .wave--front,.wave--deep{animation:none}
}

/* ---------- the phone hero ----------
   Not the desktop crop scaled down. A landscape ribbon at a third of the
   width loses its rim light to subpixels and reads as a grey smudge, and no
   amount of shifting fixes that — so the phone gets its own portrait render,
   composed for the shape, with the material already sitting low in the frame.

   It is opaque, so both wave planes come off entirely here: there is nothing
   to occlude with and two dead <img> layers would just be bytes. Occlusion is
   a desktop effect. */
@media (max-width:700px){
  .heroDark{background:#000 url("/assets/wave-phone.jpg") no-repeat 50% 100%;
    background-size:cover}
  .wave{display:none}
}
/* the webp is half the jpg; the jpg above stays as the fallback */
@supports (background-image:image-set("a.webp" type("image/webp"))){
  @media (max-width:700px){
    .heroDark{background-image:image-set("/assets/wave-phone.webp" type("image/webp"))}
  }
}

/* One scrim only, and it sits UNDER everything: it keeps the top of the frame
   honest black so the headline has a clean field, and it dies out well before
   the waves. The old radial scrim under the type is gone — this material has
   no specular threads to fight. */
.heroDark::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:linear-gradient(to bottom,#000 0%,rgba(0,0,0,.4) 24%,rgba(0,0,0,0) 46%)}

/* Slow fade, nothing else. No rise, no blur — against a surface this calm, a
   sliding headline reads as busy. The copy simply arrives. */
.fadein{opacity:0;transition:opacity 1.6s cubic-bezier(.33,0,.2,1);transition-delay:var(--d,0ms)}
.is-in .fadein,.fadein.is-in{opacity:1}
html:not(.js) .fadein{opacity:1}

.heroDark .display{color:#fff;letter-spacing:-.045em}
/* One line, set in caps, as big as the line will take. Each word is its own
   mask, so they sit inline-block rather than block — and on bottom baseline,
   or the masks stagger vertically instead of sitting on one line. It wraps on
   a narrow phone, which is fine: the words still arrive in order.

   No text-shadow. A glow behind white letters on black is the tell that they
   are pasted on top; here they are supposed to be IN the room, and the near
   wave is what proves it.

   The size is measured, not guessed: EVERY CALL is the longer of the two
   lines and sets 612px per 100px of font-size at this weight and tracking, so
   15.2vw fills the frame down to about a 50px margin either side. Line-height
   under 1 because two lines of display caps want to read as one block. */
.heroWords{position:relative;z-index:2;margin:0;text-align:center;
  text-transform:uppercase;font-size:min(15.2vw,17rem);font-weight:800;
  letter-spacing:-.034em;line-height:.9;color:#fff}
.heroWords__line{display:block;white-space:nowrap}
.heroWords .rise{display:inline-block;vertical-align:bottom}

/* Above the near wave. A button you cannot see is a button nobody presses. */
.heroDark__act{position:relative;z-index:4;
  margin-top:clamp(2.5rem,7vh,4.5rem)}
.heroDark .kicker{color:var(--accent-lift)}
.heroDark .lede{color:rgba(255,255,255,.72)}
.heroDark .facts{border-top-color:rgba(255,255,255,.13)}
.heroDark .facts span{color:rgba(255,255,255,.48)}
.heroDark .btn--line{border-color:rgba(255,255,255,.28);color:#fff;background:rgba(255,255,255,.03)}
/* accent-lift rather than accent: the darker orange goes muddy against black. */
.heroDark .btn--line:hover{border-color:var(--accent-lift);color:var(--accent-lift);background:rgba(255,90,31,.12)}

/* the seam: settle to solid black before the page turns white. z-index 5 puts
   it over both wave planes AND the buttons, so the hero always ends in clean
   black no matter where a drifting fold happens to be. */
.heroDark::after{content:"";position:absolute;inset:auto 0 0 0;height:16%;z-index:5;
  background:linear-gradient(to bottom,rgba(0,0,0,0),#000 86%);pointer-events:none}

.nav--dark{background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none;
  border-bottom-color:transparent}
.nav--dark .nav__logo,.nav--dark .nav__word{color:#fff}
.nav--dark .nav__word em{color:rgba(255,255,255,.55)}
.nav--dark .nav__links a{color:rgba(255,255,255,.72)}
.nav--dark .nav__links a:hover,.nav--dark .nav__links a[aria-current="page"]{color:#fff}
.nav--dark .nav__tel{color:#fff}
.nav--dark .nav__cta{color:var(--accent-lift)}

/* ============================================================
   WEBSITE DESIGN — the second service
   A dark band late in a white page. It bookends the black hero, and
   the mockup's own background is the same near-black, so the desk
   floats in the section rather than sitting in a box on it.
   ============================================================ */
.dark{background:#050506;color:#fff;position:relative}
.dark .h2{color:#fff}
.dark .lede{color:rgba(255,255,255,.72)}
.dark .kicker{color:var(--accent-lift)}
.dark .cap{color:rgba(255,255,255,.42)}
.dark .btn--line{border-color:rgba(255,255,255,.28);color:#fff;background:rgba(255,255,255,.03)}
.dark .btn--line:hover{border-color:var(--accent-lift);color:var(--accent-lift);background:rgba(255,90,31,.12)}

.shot{margin-top:clamp(3rem,7vh,5rem);position:relative}
.shot img{width:100%;height:auto;display:block}
/* feather the edges so the mockup dissolves into the section instead of
   ending on a visible seam */
.shot::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(to right,#050506 0%,rgba(5,5,6,0) 14%,rgba(5,5,6,0) 86%,#050506 100%),
    linear-gradient(to bottom,#050506 0%,rgba(5,5,6,0) 12%,rgba(5,5,6,0) 88%,#050506 100%)}

.dark .steps .step{border-top-color:rgba(255,255,255,.16)}
.dark .steps .step__n{color:rgba(255,255,255,.42)}
.dark .steps .h3{color:#fff}
.dark .steps .body{color:rgba(255,255,255,.62)}

/* The live screen inside the mockup. These four numbers were read off a
   coordinate grid laid over the image — screen glass runs x 519-1050, y 304-630
   of 1536x1024 — because eyeballing it left the clip sitting on the bezel.
   Percentages, so it stays locked to the glass at any rendered size. */
.shot__screen{position:absolute;left:33.79%;top:29.69%;width:34.57%;height:31.84%;
  object-fit:cover;object-position:38% 0;display:block;
  opacity:0;transition:opacity .8s var(--ease)}
.shot__screen.is-live{opacity:1}

/* ---------- the push-in ----------
   A slow dolly toward the monitor while the site plays inside it. The origin
   is the CENTRE OF THE GLASS, not of the photo — read off the same numbers as
   .shot__screen above (33.79 + 34.57/2, 29.69 + 31.84/2) — so the move
   converges on the screen rather than drifting off the desk.

   One-way, and it HOLDS at the end rather than looping or alternating. Two
   earlier versions were wrong: alternating spends half its life zooming out,
   which is not what "zooming in" means, and 8.5% over 34s is a quarter of a
   percent per second — six pixels in three seconds of watching, which is no
   effect at all. 32% over 14s reads as an actual push.

   The photo is 1536px wide rendered at ~846, so even at 1.32 it is still
   sampling under its native resolution and stays sharp. Past about 1.8 it
   would start to soften. */
.shotZoom{position:relative;overflow:hidden}
/* margin:0 and not margin-top:0 — a <figure> carries a browser default of
   1em 40px, which insets the photo from its own clipping frame and throws the
   transform-origin percentages off the glass they're measured against */
.shotZoom .shot{margin:0;transform-origin:51.08% 45.61%;will-change:transform}
.shotZoom.is-zooming .shot{animation:shotPush 14s cubic-bezier(.22,0,.32,1) forwards}
@keyframes shotPush{ from{transform:scale(1)} to{transform:scale(1.32)} }
/* the photo's own feather scales out of the frame, so the wrapper carries it */
.shotZoom::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(to right,#050506 0%,rgba(5,5,6,0) 14%,rgba(5,5,6,0) 86%,#050506 100%),
    linear-gradient(to bottom,#050506 0%,rgba(5,5,6,0) 12%,rgba(5,5,6,0) 88%,#050506 100%)}
@media (prefers-reduced-motion:reduce){
  .shotZoom.is-zooming .shot{animation:none}
}

/* the whole showcase is a link to the web design page */
.shotLink{display:block;color:inherit;position:relative;
  transition:transform .6s var(--ease)}
.shotLink:hover{transform:translateY(-4px)}
.shotCue{display:inline-flex;align-items:center;gap:.5rem;margin-top:1.75rem;
  font-size:1.0625rem;font-weight:500;color:#fff;
  transition:color .35s var(--ease)}
.shotCue svg{width:14px;height:14px;transition:transform .45s var(--ease)}
.shotLink:hover .shotCue{color:var(--accent-lift)}
.shotLink:hover .shotCue svg{transform:translateX(5px)}

/* ---------- websites page hero ----------
   The mockup leads and the copy sits under it. Still capped by viewport
   height as well as width, so it can never overflow a short laptop — but
   generously, because on this page the work IS the pitch. The headline now
   sits just below the fold on a laptop, which is the trade for the size. */
.webHero{background:#050506;color:#fff;
  padding-top:calc(52px + clamp(2rem,5vh,3.5rem));padding-bottom:clamp(3rem,7vh,5rem)}
/* the cap moves to the clipping frame, so the box the photo zooms inside of
   stays exactly the size the photo used to be */
.webHero .shotZoom{max-width:min(1340px, 94vh);margin:clamp(3rem,7vh,5rem) auto 0}
.webHero__copy{margin-top:clamp(2.5rem,5vh,3.5rem)}
/* h1 defaults to 600 weight; .lede never sets one, so it needs saying here or
   the sentence renders bold and stops matching the rest of the page */
h1.lede{font-weight:400}
.webHero .display{color:#fff;margin-inline:auto}
.webHero .kicker{color:var(--accent-lift)}
.webHero .lede{color:rgba(255,255,255,.72)}
.webHero .cap{color:rgba(255,255,255,.42)}

/* ---------- the web design panel ----------
   Its own screen in the scroll, not another block in the flow. Full viewport
   height, everything centred in it, so it arrives as a distinct moment
   between the receptionist story and the close. */
#web{min-height:100svh;display:flex;align-items:center;
  padding-block:clamp(4rem,9vh,7rem)}

/* The mockup is capped by VIEWPORT HEIGHT, not width, so the panel always
   fits one screen. Capping it by max-width alone would overflow on a short
   laptop. Aspect ratio is never touched — the clip's position is a percentage
   of this box, so squashing it would drag the video off the glass. */
.shotLink .shot{max-width:min(1100px, 68vh);margin:0 auto}

.webCopy{margin-top:clamp(2rem,4.5vh,3.25rem);text-align:center}
.webCopy .steps{text-align:left;margin-top:clamp(2rem,4vh,3rem)}
.webCopy .shotCue{margin-top:clamp(1.75rem,3.5vh,2.5rem)}
/* One idea per panel. The three supporting points used to live here and made
   the section 1231px on a 950px screen — which is not a panel, it is a page
   that happens to start at the top. The work and one sentence carry it. */

/* ── Booking form ─────────────────────────────────────────────────────────
   Added 2026-08-26. The site had no form styles at all, because until now
   every route to a human was a phone number or a calendar link. That left a
   gap: the visitor who won't call and isn't ready to book had nowhere to
   land, on a site selling "never miss a lead."
   Inputs inherit the page's own type rather than the browser's, which is the
   whole reason for the font declarations — a system-font input beside Archivo
   reads as a third-party embed. */
.lead { display: grid; gap: 1rem; max-width: 34rem; margin-top: 2rem; }
.lead__row { display: grid; gap: 1rem; grid-template-columns: 1fr 1fr; }
.lead label { display: block; font: inherit; }
.lead__lab {
  display: block; font-size: .72rem; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted, #6C6862); margin-bottom: .45rem;
}
.lead input, .lead textarea, .lead select {
  width: 100%; font: inherit; font-size: 1rem; color: inherit;
  background: transparent;
  border: 1px solid rgba(0,0,0,.18); border-radius: 6px;
  padding: .75rem .9rem;
  transition: border-color .18s ease, box-shadow .18s ease;
  -webkit-appearance: none; appearance: none;
}
.lead textarea { min-height: 6.5rem; resize: vertical; }
.lead input:focus, .lead textarea:focus, .lead select:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(232,80,15,.16);
}
.lead input::placeholder, .lead textarea::placeholder { color: rgba(0,0,0,.34); }
.lead__note { font-size: .84rem; color: var(--muted, #6C6862); margin: 0; }
.lead__hp { position: absolute; left: -9999px; }
.chapter.dark .lead input, .chapter.dark .lead textarea,
.chapter.dark .lead select { border-color: rgba(255,255,255,.22); }
.chapter.dark .lead input::placeholder,
.chapter.dark .lead textarea::placeholder { color: rgba(255,255,255,.4); }
@media (max-width: 560px) { .lead__row { grid-template-columns: 1fr; } }

/* Consent checkbox. Deliberately not styled away to a custom control — a
   carrier reviewer needs to see a real, unchecked checkbox. */
.lead__consent { display: grid; grid-template-columns: auto 1fr; gap: .7rem; align-items: start; }
.lead__consent input[type="checkbox"] {
  width: 1.05rem; height: 1.05rem; margin: .2rem 0 0; flex: none;
  -webkit-appearance: checkbox; appearance: checkbox; accent-color: var(--accent);
}
.lead__consent span { font-size: .84rem; line-height: 1.55; color: var(--muted, #6C6862); }
.lead__consent a { color: var(--accent); text-underline-offset: 2px; }
