/* ============================================================
   SIX SCENES - the demo site's hero (2026-09-13)
   Six scenes play in the pinned hero, one per scroll (or on their own on a
   first visit): QUOTES, MANAGE THE JOB, FIND IT, YOUR ACCOUNTS, "Helping you
   build better.", then the home hero assembles around the same phone.
   Motion is time-based and driven from scenes.js by classes and a pose tween.
   Everything here that hides something is scoped to html.has-intro, so without
   the intro (no JS, reduced motion, Save-Data) the finished hero just shows.
   ============================================================ */

/* ---------- the phone, one 3D object ----------
   --pu is the size of one design unit: the body is 300 x 623 units (iPhone 15 Pro
   proportions, 8.25 mm deep = 35 units), so the client's 1179 x 2556 screenshots
   fill the 277 x 600 screen exactly. Layout size is the scene size; the pose
   transform (scenes.js) moves and scales it, so it is rasterised large and only
   ever scaled down. */
:root{--pu0:calc(84vh / 623);--pu:var(--pu0);--p3k:1}
.hero-stage .p3{
  position:absolute;left:50%;top:50%;
  width:calc(300*var(--pu));height:calc(623*var(--pu));
  margin:calc(-311.5*var(--pu)) 0 0 calc(-150*var(--pu));
  perspective:calc(1300*var(--pu));perspective-origin:50% 42%;
  transform-origin:50% 50%;pointer-events:none;
}
/* Crispness (2026-09-14): a promise that the phone and its glass move lets the browser keep
   them as their own layers, and the screens then come out sharp once the phone is scaled
   down (the login and the features act went from about 85% to 96-99% of a perfect resize
   on Theo's 125% laptop; the full-size scenes are unchanged). Only these two: the others
   made no difference. */
.hero-stage .p3,.p3-front{will-change:transform}
.p3-world{position:absolute;inset:0;transform-style:preserve-3d;transform:rotateX(-3deg)}
.p3-phone{position:absolute;inset:0;transform-style:preserve-3d;transform:rotateY(-21deg)}
.p3-l{position:absolute;inset:0;display:block;border-radius:calc(50*var(--pu))}
.p3-l:nth-child(1){transform:translateZ(calc(-17.50*var(--pu)));background:linear-gradient(90deg,rgb(116,118,122),rgb(150,151,154) 50%,rgb(136,138,141))}
.p3-l:nth-child(2){transform:translateZ(calc(-15.00*var(--pu)));background:linear-gradient(90deg,rgb(133,135,139),rgb(167,168,171) 50%,rgb(153,155,158))}
.p3-l:nth-child(3){transform:translateZ(calc(-12.50*var(--pu)));background:linear-gradient(90deg,rgb(147,149,153),rgb(181,182,185) 50%,rgb(167,169,172))}
.p3-l:nth-child(4){transform:translateZ(calc(-10.00*var(--pu)));background:linear-gradient(90deg,rgb(159,161,165),rgb(193,194,197) 50%,rgb(179,181,184))}
.p3-l:nth-child(5){transform:translateZ(calc(-7.50*var(--pu)));background:linear-gradient(90deg,rgb(168,170,174),rgb(202,203,206) 50%,rgb(188,190,193))}
.p3-l:nth-child(6){transform:translateZ(calc(-5.00*var(--pu)));background:linear-gradient(90deg,rgb(175,177,181),rgb(209,210,213) 50%,rgb(195,197,200))}
.p3-l:nth-child(7){transform:translateZ(calc(-2.50*var(--pu)));background:linear-gradient(90deg,rgb(179,181,185),rgb(213,214,217) 50%,rgb(199,201,204))}
.p3-l:nth-child(8){transform:translateZ(calc(0.00*var(--pu)));background:linear-gradient(90deg,rgb(204,206,210),rgb(238,239,242) 50%,rgb(224,226,229))}
.p3-l:nth-child(9){transform:translateZ(calc(2.50*var(--pu)));background:linear-gradient(90deg,rgb(204,206,210),rgb(238,239,242) 50%,rgb(224,226,229))}
.p3-l:nth-child(10){transform:translateZ(calc(5.00*var(--pu)));background:linear-gradient(90deg,rgb(175,177,181),rgb(209,210,213) 50%,rgb(195,197,200))}
.p3-l:nth-child(11){transform:translateZ(calc(7.50*var(--pu)));background:linear-gradient(90deg,rgb(168,170,174),rgb(202,203,206) 50%,rgb(188,190,193))}
.p3-l:nth-child(12){transform:translateZ(calc(10.00*var(--pu)));background:linear-gradient(90deg,rgb(159,161,165),rgb(193,194,197) 50%,rgb(179,181,184))}
.p3-l:nth-child(13){transform:translateZ(calc(12.50*var(--pu)));background:linear-gradient(90deg,rgb(147,149,153),rgb(181,182,185) 50%,rgb(167,169,172))}
.p3-l:nth-child(14){transform:translateZ(calc(15.00*var(--pu)));background:linear-gradient(90deg,rgb(133,135,139),rgb(167,168,171) 50%,rgb(153,155,158))}
.p3-l:nth-child(15){transform:translateZ(calc(17.50*var(--pu)));background:linear-gradient(90deg,rgb(116,118,122),rgb(150,151,154) 50%,rgb(136,138,141))}
.p3-back{position:absolute;inset:0;display:block;border-radius:calc(50*var(--pu));
  transform:translateZ(calc(-17.6*var(--pu))) rotateY(180deg);background:linear-gradient(160deg,#cfd2d6,#a9adb3)}
/* side buttons stand out of the band, facing sideways */
.p3-btn{position:absolute;display:block;width:calc(15*var(--pu));border-radius:calc(4*var(--pu));
  background:linear-gradient(90deg,#9ca0a6,#e6e8eb 45%,#b7bbc0)}
.p3-btn.r{left:calc(100% - 7.5*var(--pu));transform:translateX(calc(2.2*var(--pu))) rotateY(90deg)}
.p3-btn.l{left:calc(-7.5*var(--pu));transform:translateX(calc(-2.2*var(--pu))) rotateY(-90deg)}
.b-side{top:calc(190*var(--pu));height:calc(96*var(--pu))}
.b-action{top:calc(138*var(--pu));height:calc(34*var(--pu))}
.b-vup{top:calc(196*var(--pu));height:calc(58*var(--pu))}
.b-vdn{top:calc(268*var(--pu));height:calc(58*var(--pu))}
/* the glass: a thin bright rim, black border, the screen, the island.
   Sharp screens (2026-09-14): on desktop the glass is laid out --p3k times its size and its own
   transform draws it back down, so the browser rasterises the screens big and shrinks them - the
   full-size scenes went from 84-92% to 93-100% of a perfect resize on Theo's 125% laptop. Only the
   glass: the whole phone at 1.5x halved the frame rate through the scene changes, this costs none.
   Anything inside sized in px (the brand act's house screen) is scaled by site.js via --ds. */
.p3-front{position:absolute;left:50%;top:50%;--pu:calc(var(--pu0) * var(--p3k));
  width:calc(300*var(--pu));height:calc(623*var(--pu));margin:calc(-311.5*var(--pu)) 0 0 calc(-150*var(--pu));
  border-radius:calc(50*var(--pu));transform:translateZ(calc(17.6*var(--pu0))) scale(calc(1 / var(--p3k)));
  background:#050506;box-shadow:inset 0 0 0 calc(1.6*var(--pu)) #c9ccd1,inset 0 0 0 calc(2.6*var(--pu)) #7d8187}
.p3-screen{position:absolute;inset:calc(11.5*var(--pu));border-radius:calc(38.5*var(--pu));overflow:hidden;background:#fff}
.p3-img{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .5s ease}
.p3-img.is-on{opacity:1}
/* without the intro (reduced motion, Save-Data, no JS) the finished hero just stands: login screen */
html:not(.has-intro) .p3-img{opacity:0}
html:not(.has-intro) .p3-img[data-scr="5"]{opacity:1}
/* EACH SCREEN ROUNDS ITS OWN CORNERS on desktop (2026-10-01). Theo, after a scroll back to the hero: "look at the
   corners breaking and coming out of the screen". Layers Chrome composites on their own get the screen's rounded clip
   only when the layers are combined, and his Chrome dropped it there: the images' square corners showed past the
   phone's rounded frame (it never showed in headless, even on his graphics card). Rounded in their own pixels, nothing
   square is left to poke out, whatever Chrome composites. Desktop only: on phones the screens slide inside the glass,
   and corners of their own would show mid-slide. The act's screens below inherit the same radius. */
html.has-intro .p3-screen>.p3-img{border-radius:inherit}
.p3-house{display:grid;place-items:center;background:#fff}
/* the mark at the size the clip rests at before its light (87pu at the clip's 1.3x, so the clip's first frame lands
   on it without a jump); the clip itself then grows it to ~134pu - the "bit bigger" Theo asked for comes from Erin's
   animation. The video (.mk-video, site.css) fills the screen over this image, the fallback if it never plays. */
.p3-house img{grid-area:1/1;width:calc(87*var(--pu));height:calc(87*var(--pu));object-fit:contain}
/* THE BRAND PLATE - the story's first screen (2026-09-30): the logo on white, centred, sized in --pu so it holds its
   proportions at every phone size. The line under it was dropped the same day (Theo: "remove the text under the logo on
   the phone screen just keep the text next to and under the phone") - the headline carries it. */
.p3-brand{display:grid;place-items:center;align-content:center;background:#fff;padding:0 calc(28*var(--pu))}
.p3-brand img{width:calc(196*var(--pu));height:auto}
.p3-island{position:absolute;left:50%;top:calc(19.5*var(--pu));z-index:6;display:block;width:calc(86*var(--pu));height:calc(25*var(--pu));
  margin-left:calc(-43*var(--pu));border-radius:999px;background:#000}
.p3-island i{position:absolute;right:calc(8*var(--pu));top:50%;display:block;width:calc(9*var(--pu));height:calc(9*var(--pu));
  margin-top:calc(-4.5*var(--pu));border-radius:50%;background:radial-gradient(circle at 35% 35%,#3a4a6a 0,#141a28 45%,#05070b 70%)}
/* the brands act's screens sit over the phone's own, edge to edge. html.has-intro in front, or site.css's
   html.has-intro .house-screen (inset 8px, a bigger radius) wins and the screen under it shows at the corners.
   Their radius is the screen's own (inherit, 2026-10-01 - was 0 and relied on the screen's clip; see above) */
html.has-intro .p3-screen .house-screen,html.has-intro .p3-screen .feat-screen,.p3-screen .feat-screen{inset:0;border-radius:inherit}
/* ...and read as the same phone: the status bar off the client's own screenshot (the login screen the
   hero ends on), and no coloured glow round the mark (Theo, 2026-09-13) */
.p3-screen .p3-sb{position:absolute;left:0;top:0;z-index:2;display:block;width:100%;height:auto}
.p3-screen .house-screen::before{display:none}
/* THE RINGS ARE GONE (2026-10-01). The day's history: an 8% grey line ("very very feint"), 55% brand lines ("too
   strong now i dont like it"), a ripple ("looks better but still not a huge fan"). The brief underneath was "the
   screen was flat and boring" - and rings at any strength answered it with decoration. What answers it is depth and
   content, in site.css: a soft neutral shadow under the mark, a slow float, and the brand's line under its name.
   The three spans stay in index.html, hidden here, so nothing else needs to change. */
.p3-screen .hs-halo{display:none}
/* the feature screens: the client's screenshots, crossfaded */
.feat-screen .fs-img{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:cover;border-radius:inherit;opacity:0;transition:opacity .45s ease}
.feat-screen .fs-img.is-on{opacity:1}
/* the act owns the phone: the hero's own screens go once the house has faded in over them, so the act's
   crossfades never show the login screen through (site.js toggles .act-owns) */
.p3-screen.act-owns .p3-img{visibility:hidden;transition:opacity .5s ease,visibility 0s linear .45s}

/* the floor stays put under the phone; scenes.js turns the shadows with the phone */
.p3-floor{position:absolute;left:50%;top:100%;width:0;height:0;transform-style:preserve-3d;
  transform:translateY(calc(.6*var(--pu))) rotateX(90deg)}
.p3-sh{position:absolute;left:0;top:0;display:block;transform-origin:0 0}
.s-amb{width:calc(336*var(--pu));height:calc(71*var(--pu));border-radius:999px;background:rgba(10,30,24,.13);
  filter:blur(calc(18*var(--pu)));transform:translate(calc(16*var(--pu)),calc(-6*var(--pu))) rotate(21deg) translate(-50%,-50%)}
.s-con{width:calc(306*var(--pu));height:calc(41*var(--pu));border-radius:999px;background:rgba(10,30,24,.40);
  filter:blur(calc(5*var(--pu)));transform:translate(calc(3*var(--pu)),0) rotate(21deg) translate(-50%,-50%)}
.s-core{width:calc(291*var(--pu));height:calc(19*var(--pu));border-radius:999px;background:rgba(10,30,24,.55);
  filter:blur(calc(1.8*var(--pu)));transform:rotate(21deg) translate(-50%,-50%)}
.s-cast{width:100px;height:100px;opacity:0;
  background:linear-gradient(to bottom,rgba(10,30,24,.22),rgba(10,30,24,0) 80%);filter:blur(calc(12*var(--pu)))}

/* ---------- the labels, in the phone's own 3D space ----------
   They start behind the phone and slide out past its edge, so the body hides them
   on the way: left-hand labels move right to left, right-hand ones left to right.
   2026-09-13 (Theo): white with a thin border in their colour, black Poppins Regular,
   smaller, and sitting a little over the phone's edge rather than clear of it.
   The right-hand ones get an extra turn: the camera looks at them from the left, which
   makes them read nearly front-on while the left ones read at the phone's angle. -18deg
   evens that out. Turned like that, Chromium buried their inner end in the phone's edge
   until they stood well forward (84 units; 48 still clipped), and standing forward makes
   them a touch bigger in perspective, so --lsc takes that back off. */
.sc-labels{position:absolute;inset:0;transform-style:preserve-3d;pointer-events:none}
.sc-label{position:absolute;top:calc(var(--ly)*100%);white-space:nowrap;
  --lz:calc(22*var(--pu));--lrot:0deg;--lsc:1;
  transform:translate3d(0,-50%,var(--lz)) rotateY(var(--lrot)) scale(var(--lsc));
  transition:transform .85s cubic-bezier(.2,.8,.2,1)}
.sl-l{right:calc(100% - 26*var(--pu))}
.sl-r{left:calc(100% - 26*var(--pu));--lz:calc(84*var(--pu));--lrot:-18deg;--lsc:.95}
.sc-label b{display:block;padding:calc(8.5*var(--pu)) calc(16*var(--pu));border-radius:999px;
  font:400 calc(13*var(--pu))/1 var(--font-b);letter-spacing:.005em;background:#fff;color:#111;
  border:calc(1.6*var(--pu)) solid var(--lbd,#111);
  box-shadow:0 calc(10*var(--pu)) calc(24*var(--pu)) rgba(10,30,24,.16);
  animation:sl-float calc(4.6s + var(--li)*.55s) ease-in-out calc(var(--li)*-.9s) infinite alternate}
@keyframes sl-float{from{transform:translateY(calc(-4*var(--pu)))}to{transform:translateY(calc(5*var(--pu)))}}
html.has-intro .sl-l{transform:translate3d(calc(100% + 60*var(--pu)),-50%,calc(-30*var(--pu))) rotateY(var(--lrot)) scale(var(--lsc))}
html.has-intro .sl-r{transform:translate3d(calc(-100% - 60*var(--pu)),-50%,calc(-30*var(--pu))) rotateY(var(--lrot)) scale(var(--lsc))}
html.has-intro .sc-label.is-in{transform:translate3d(0,-50%,var(--lz)) rotateY(var(--lrot)) scale(var(--lsc))}

/* ---------- the hero copy the last scene assembles ---------- */
.sc-h1{font-weight:400}
.sc-h1 .hw,.sc-h1 .hwi{display:inline-block}
.sc-h1 .hw{transform-origin:0 50%}
.sc-h1 .hwi{transform-origin:0 0}
.sc-h1 .hw-better{font-weight:700;color:#0d9488}
html.has-intro .sc-h1{opacity:0}
html.has-intro .sc-h1.is-in{opacity:1}
/* THE BRAND OPENING'S HEADLINE (2026-09-30) travels like the scenes' words - in from the left and out the same way, on
   the same curve (.sc-text) - instead of appearing and vanishing where it stands (Theo: "the text also just disappears
   it doesnt slide in and out like the other text"). It stays lit while it leaves, so site.js can drop is-in and let it
   ride out. site.js also sets an inline translate that drops it to the MIDDLE of the phone ("the text next to the phone
   sits a bit high on the first screen"): the store buttons and the trust line still hold their space underneath, which
   is what pushed it high. Both are cleared once it is off screen, so the end's handover is untouched. */
html.has-intro .sc-h1.sc-open{opacity:1;transform:translateX(-80vw);transition:transform 1.05s cubic-bezier(.16,.84,.24,1)}
html.has-intro .sc-h1.sc-open.is-in{transform:none}
/* wipes: left to right for the kicker and the trust line */
html.has-intro .sc-wipe{clip-path:inset(-10% 100% -10% 0);transition:clip-path .8s cubic-bezier(.65,0,.35,1)}
html.has-intro .sc-wipe.is-in{clip-path:inset(-10% 0 -10% 0)}
/* the store buttons wipe up out of their own box, one after the other */
.sc-pills .store-badge{overflow:hidden}
html.has-intro .sc-pills .store-badge img{transform:translateY(106%);transition:transform .6s cubic-bezier(.2,.8,.2,1)}
html.has-intro .sc-pills .store-badge.is-in img{transform:none}

/* the menu drops in with the finished hero */
html.has-intro .site-head{transition:transform .7s cubic-bezier(.2,.8,.2,1),background .3s ease,box-shadow .3s ease}
/* THE HEADER is away for the whole intro and comes down with the finished hero (html.sc-menu), the way it always did.
   It was briefly down for the brand opening too (2026-09-30, first pass) and Theo would not have it: "remove the menu on
   desktop it looks a bit cramped when the phones grow... i want the phones and text to be the center of attention. the
   menu draws the eye away. the menu must show when the video is done, like it used too." Phones never hid it. */
html.has-intro:not(.sc-menu) .site-head{transform:translateY(-120%)}

/* the old intro's stage fade would fight the phone's entrance */
html.has-intro .hero-wrap .hero-stage{animation:none !important}

/* ---------- the scene text ---------- */
.sc-layer{display:none}
html.has-intro .sc-layer{display:block;position:absolute;inset:0;z-index:3;pointer-events:none}
.sc-h{margin:0;font:700 clamp(2.1rem,4.2vw,5.2rem)/1.02 var(--font-d);letter-spacing:-.005em;text-transform:uppercase;color:#111}
.sc-b{margin:.28em 0 0;font:400 clamp(1rem,2.05vw,2.5rem)/1.25 'Poppins',var(--font-d);color:#111}
.sc-text{position:absolute;top:50%;translate:0 -50%}
.sc-t1,.sc-t3{left:10vw}
.sc-t4{left:7vw}
/* slides: in from beyond the left edge, out the same way */
.sc-text{transition:transform 1.05s cubic-bezier(.16,.84,.24,1);transform:translateX(-80vw)}
.sc-text.is-in{transform:none}

/* side text: emerges from behind the phone through a mask on the phone's edge */
.sc-side{position:absolute}
/* site.js places these beside the phone after the first paint; moving a painted box counts as a layout
   shift (0.12 on phones), so they stay hidden until placed (mobile audit, 2026-09-14) */
html.has-intro .sc-side:not(.is-placed){visibility:hidden}
.sc-side .sc-mask{overflow:hidden;padding:.12em .2em}
.sc-side .sc-in{transition:transform .8s cubic-bezier(.2,.8,.2,1)}
.sd-l{text-align:right}
.sd-l .sc-in{transform:translateX(106%)}
.sd-r .sc-in{transform:translateX(-106%)}
.sc-side.is-in .sc-in{transform:none}
.sc-side .sc-h{font-size:clamp(1.6rem,2.7vw,3.4rem)}
.sc-side .sc-b{font-size:clamp(.95rem,1.35vw,1.7rem)}
.sc-t4l .sc-b{margin:0;font-size:clamp(1.05rem,2.2vw,2.7rem)}
/* scene sizes measured off the reference videos */
.sc-t3 .sc-h{font-size:clamp(1.9rem,3.4vw,4.2rem);line-height:1.08}
.sc-t4 .sc-h{font-size:clamp(1.7rem,2.9vw,3.6rem)}
.sc-t4 .sc-b{font-size:clamp(.95rem,1.5vw,1.9rem)}
.sc-t4l{translate:0 -50%}
/* a scene reached without the journey (return visit, restore, resize): no transitions */
html.sc-instant .sc-layer *,html.sc-instant .sc-layer,html.sc-instant .hero-copy *,html.sc-instant .p3 *,html.sc-instant .site-head{transition:none !important}

/* FIND IT. PRICE IT. BUY IT. - faint, then each takes its turn, all three in ink: BUY IT. is no longer coral (Theo,
   2026-09-18, on the phone's story first - "please change the orange buy it. to be consistent with the rest of the
   other headers" - then "yes match desktop too") */
.sc-l3{color:#cdd3d0;transition:color .45s ease}
.sc-l3.is-hot{color:#111}

/* "Helping you build" types in from the right, the line makes room, "better." lands bold */
.sc-type{position:absolute;left:0;width:58vw;top:50%;margin:0;translate:0 -50%;text-align:center;
  font:400 clamp(1.6rem,3.2vw,3.9rem)/1.2 'Poppins',var(--font-d);color:#111;white-space:nowrap}
.st-line{display:inline-block;transition:transform .75s cubic-bezier(.2,.8,.2,1)}
.sc-type .tw{display:inline-block}
.sc-type .tw i{display:inline-block;font-style:normal;opacity:0;transform:translateX(.45em);
  transition:opacity .32s ease,transform .32s ease}
.sc-type .tw i.on{opacity:1;transform:none}
.sc-type .ty-b{font-weight:700;color:#111;transition:color .6s ease}
.sc-type.is-teal .ty-b{color:#0d9488}

/* ---------- desktop hero layout around the phone ---------- */
@media (min-width:1024px){
  :root{--p3k:1.5}
  html.has-intro .hero{height:100vh;min-height:0;overflow:hidden}
  .hero-stage{height:67vh;align-self:center}
  /* the phone is drawn 84vh tall for the scenes; the still hero sizes it to its stage */
  html:not(.has-intro) .hero-stage .p3{transform:scale(.798)}
  html.has-intro .hero-wrap{height:calc(100vh + 5 * 80vh + 240vh)}
}

/* ---------- still 3D phones: Features, Why Thuso, Download (desktop) ----------
   2026-09-14 (Theo): those pages swapped their old hand-built screens for the client's screenshots,
   and on desktop each phone is the hero's 3D phone turned toward its copy - left of the phone
   normally, right of it in the Features page's flipped sections. These phones never move, so their
   floor shadows are drawn once (feat-shadow-l/-r.webp, rendered from the live ones): the live shadows
   are blurred by the GPU on every frame, and with a phone per section the Features page stuttered as
   it scrolled. Phones and tablets keep the flat device (its screenshot styled by site.css .device-shot). */
.p3-shot{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:cover}
.still-p3{display:none}
@media (min-width:1024px){
  .feat-stage .device-feat,.dl-stage .device-hero{display:none}
  .still-p3{display:block;position:relative;--pu0:calc(min(78vh, 600px) / 623);--pu:var(--pu0);
    width:calc(300*var(--pu));height:calc(623*var(--pu));margin:calc(12*var(--pu)) auto calc(46*var(--pu))}
  .still-p3 .p3{position:absolute;inset:0;perspective:calc(1300*var(--pu));perspective-origin:50% 42%;
    pointer-events:none;will-change:transform}
  .feat-flip .still-p3 .p3-phone{transform:rotateY(21deg)}
  .still-p3::before{content:"";position:absolute;left:-14.61%;top:86.08%;width:156.79%;height:20.5%;
    background:url(../img/feat-shadow-l.webp) 0 0/100% 100% no-repeat;pointer-events:none}
  .feat-flip .still-p3::before{left:-21.53%;width:156.1%;height:20.25%;background-image:url(../img/feat-shadow-r.webp)}
  /* the Download page's QR card sits under the phone's shadow */
  .dl-stage .still-p3{margin-bottom:calc(30*var(--pu))}
}

/* ---------- mobile: the same scenes, stacked ---------- */
@media (max-width:1023px){
  :root{--pu0:calc(54vh / 623)}
  /* svh, not vh: vh is the screen with the browser bar HIDDEN, so with the bar showing the finished hero's
     last line sat under it on small phones (375x667: "Backed by" hidden, badges on the edge). svh is the
     height with the bar showing; the vh line before each is the fallback (mobile audit, 2026-09-14) */
  html.has-intro .hero{height:100vh;height:100svh;min-height:0;padding:0;overflow:hidden}
  html.has-intro .hero-inner{height:100%;justify-content:flex-start;padding-top:calc(8vh + 44px);padding-top:calc(8svh + 44px)}
  .hero-stage{height:46vh;height:46svh;margin:0 0 18px}
  html:not(.has-intro) .hero-stage .p3{transform:scale(.852)}
  /* phones and tablets show the finished hero straight on: no tilt back either (site.js sets the turn to 0) */
  html:not(.has-intro) .hero-stage .p3-world{transform:none}
  html.has-intro .hero-wrap{height:calc(100vh + 5 * 70vh);height:calc(100svh + 5 * 70vh)}
  .sc-text{left:0 !important;right:0;top:9vh;translate:none;text-align:center;padding-inline:20px}
  /* full-width lines: the slide has to clear the whole screen */
  .sc-text{transform:translateX(-115vw)}
  .sc-h{font-size:clamp(1.7rem,8.4vw,2.6rem)}
  .sc-b{font-size:clamp(.95rem,4.2vw,1.2rem)}
  .sc-type{width:100%;top:11vh;translate:none;font-size:clamp(1.25rem,6.4vw,1.8rem)}
  .sc-side .sc-h{font-size:clamp(1.05rem,5vw,1.5rem)}
  .sc-side .sc-b{font-size:clamp(.8rem,3.6vw,1rem)}
  .sc-t4l .sc-b{font-size:clamp(.78rem,3.4vw,.95rem)}
  .sc-label b{font-size:calc(15*var(--pu));padding:calc(9*var(--pu)) calc(14*var(--pu))}
  /* there is no room beside a phone this size: the labels overlap its edges */
  .sl-l{right:calc(100% - 64*var(--pu))}
  .sl-r{left:calc(100% - 64*var(--pu))}
  /* ...so hidden, each waits centred behind the phone rather than just past its far edge */
  .sl-r{--lrot:-12deg}
  html.has-intro .sl-l{transform:translate3d(calc(50% + 86*var(--pu)),-50%,calc(-30*var(--pu))) rotateY(var(--lrot)) scale(var(--lsc))}
  html.has-intro .sl-r{transform:translate3d(calc(-50% - 86*var(--pu)),-50%,calc(-30*var(--pu))) rotateY(var(--lrot)) scale(var(--lsc))}
  /* scene 2's two lines span the screen (site.js), so they take the other scenes' margin -
     they sat 3px from the edges (mobile review, 2026-09-14) */
  .sc-t2a,.sc-t2b{padding-inline:20px}
}

/* ---------- very short screens, bar showing (an SE is 592px tall then): the phone's stage gives up some
   height so the finished hero's trust line keeps clear of the bar. Inert from about 630px up, and not
   for phones held sideways, which have their own poses (mobile audit, 2026-09-14) ---------- */
@media (max-width:1023px) and (min-height:501px){
  .hero-stage{height:min(46svh, calc(100svh - 340px))}
}

/* ---------- phones and tablets, no intro: the finished hero fills the first screen, copy centred (Theo, 2026-09-15) ----------
   The phone takes the height the copy leaves, so the stack fills the screen on any phone. Before, the phone
   was sized off vh (the screen with the browser bar HIDDEN) inside a stage sized off svh (bar showing): on a
   real phone it spilled out of its slot onto the header and the headline, and left an empty band under
   "Backed by". Everything here is svh, which also holds still while the bar comes and goes. */
@media (max-width:1023px){
  html:not(.has-intro) .hero{
    --sv:1vh;
    --gap-top:clamp(12px, calc(3.4 * var(--sv)), 40px);     /* header to phone */
    --gap-phone:clamp(18px, calc(4.2 * var(--sv)), 50px);   /* phone and its shadow to the headline */
    --gap-badges:clamp(14px, calc(3 * var(--sv)), 30px);    /* headline to the badges */
    --gap-trust:clamp(12px, calc(2.6 * var(--sv)), 26px);   /* badges to "Backed by" */
    --gap-end:clamp(16px, calc(4 * var(--sv)), 48px);       /* "Backed by" to the bottom of the screen */
    padding:0;
  }
  html:not(.has-intro) .hero-inner{
    min-height:100vh;min-height:100svh;box-sizing:border-box;
    padding-top:calc(64px + var(--gap-top));padding-bottom:var(--gap-end);
    justify-content:center;text-align:center;
  }
  /* without container units (old browsers) the stage keeps a set height and the stack centres in the screen */
  html:not(.has-intro) .hero-stage{--stage-h:calc(44 * var(--sv));height:var(--stage-h);flex:none;margin:0 0 var(--gap-phone)}
  /* --pu0 as well as --pu: the glass (.p3-front) sizes and lifts itself off --pu0, and a --pu of its own
     alone left it behind the phone's band - a blank grey phone */
  html:not(.has-intro) .hero-stage .p3{--pu0:calc(var(--stage-h) / 623 / .852);--pu:var(--pu0)}
  html:not(.has-intro) .hero-copy .display{font-size:clamp(1.95rem, min(12vw, calc(7.4 * var(--sv))), 3.2rem)}
  /* the break holds "Helping you / build better." at every width, tablets included */
  html:not(.has-intro) .hero-copy .display br{display:revert}
  html:not(.has-intro) .hero-copy .store-pills{justify-content:center;margin-top:var(--gap-badges)}
  html:not(.has-intro) .hero-trust{margin-top:var(--gap-trust)}
}
@supports (height:1svh){
  @media (max-width:1023px){ html:not(.has-intro) .hero{--sv:1svh} }
}
/* the stage takes all the height the copy leaves and the phone is drawn to it (then scaled down .852 as
   before). Floors: a small phone never shrinks below ~180px - on the shortest screens and phones held
   sideways the stack runs past the fold instead. Ceiling: 60% of the screen on tall phones and tablets,
   where the spare height centres the stack. */
@supports (height:1cqh){
  @media (max-width:1023px){
    html:not(.has-intro) .hero-stage{container-type:size;flex:1 1 0;height:auto;
      min-height:clamp(180px, calc(40 * var(--sv)), 260px);max-height:calc(60 * var(--sv))}
    html:not(.has-intro) .hero-stage .p3{--pu0:calc(100cqh / 623 / .852);--pu:var(--pu0)}
  }
}
/* tablets upright: phone-sized type looked lost beside a phone this tall */
@media (min-width:600px) and (max-width:1023px) and (min-height:700px){
  html:not(.has-intro) .hero-copy .display{font-size:clamp(3.2rem, 7.4vw, 4.6rem)}
  html:not(.has-intro) .hero-copy .store-badge{--bh:50px}
  html:not(.has-intro) .hero-trust{font-size:15.5px}
}

/* ---------- tablets upright: the same stack, sized for the bigger screen (2026-09-14) ----------
   At phone sizes the type capped out, so an iPad showed small lines and wide empty bands. */
@media (min-width:600px) and (max-width:1023px) and (min-height:700px){
  .sc-text,.sc-t2a,.sc-t2b{padding-inline:6vw}
  .sc-h{font-size:clamp(2.6rem,6.6vw,3.8rem)}
  .sc-b{font-size:clamp(1.2rem,3vw,1.6rem)}
  .sc-side .sc-h{font-size:clamp(1.7rem,4.4vw,2.6rem)}
  .sc-side .sc-b{font-size:clamp(1.1rem,2.8vw,1.5rem)}
  .sc-t4l .sc-b{font-size:clamp(1.05rem,2.6vw,1.4rem)}
  .sc-type{font-size:clamp(2rem,5.2vw,3rem)}
}

/* ---------- phones held sideways: no scroll prompt (it sat under the phone at 844x390); site.js also
   gives the phone a smaller, higher pose there ---------- */
@media (max-width:1023px) and (max-height:500px){
  .hf-cue{display:none}
}

/* ---------- phones and tablets: THE STORY (Theo, 2026-09-17) ----------
   First brief: "the desktop hero section feels so alive and the mobile is just a very very nice normal website".
   Second, after a first build that kept the headline on screen and put the scenes' words small beside the phone
   (rejected - "I dont like it at all"): "use that area [the headline, buttons and subline] for the copy in the
   animation and then when its done the helping you build better transitions it to the hero page... like on the
   desktop animation." Third, on the story once live: the sublines "on different spots next to the phone and not
   under the heading", the phone "a bit bigger for the animation and when its done it goes and sits facing
   forward as it does now, and the same size", and "tilt left and right for when the screens changes".
   Fourth (2026-09-18, phones and tablets only - "desktop functions perfectly"): headings that "speak more to the
   user/visitor", regular with the last words bold, each on one line; MANAGE PROJECTS on the Features page's project
   screen; and the sublines gone "so that the phone can be bigger and the attention stays on either the phone or
   the heading that appears underneath".
   So: the phone stands where the finished hero has it, rises into place while its screen wakes, and for the story
   it stands 18% BIGGER than it rests, its top edge where it was, so it grows down towards the heading. The area
   under it - where the headline, the store buttons and the trust line will land - plays the story's HEADINGS,
   big and centred, in from the left and out the same way, while the phone shows each scene's screen and turns
   to one side, then the other. Last, the phone turns to face forward and settles to its resting size while "Helping you build better." types itself in on ONE line where the headings played - then
   the headline's words are laid exactly over the typed ones and released, so the line SPLITS IN TWO AND STACKS
   into the headline's place (the desktop's own handover, his ask). "better." is teal in both, so the swap shows
   no colour change; the store buttons wipe up, the trust line wipes in and the phone shows login: the finished
   hero, exactly as before, and NOTHING moves again after that.
   The page is never pinned - a scroll simply finishes the story; dots and Skip sit where the trust line lands;
   a tap steps on. A same-session return (html.mh-arrive) skips the story: the phone rises and the copy arrives
   inside 1.5s. Reduced motion and Save-Data get the still hero as always. index.html's head gate sets
   html.m-live plus mh-story or mh-arrive; site.js section 11 runs the story and sets mh-big (the phone grown)
   for its length and mh-rest once the hero has assembled. */
.mh-copy,.mh-ui,.mh-wake,.mh-img{display:none}
/* the headline's letters are wrapped in <i> for the typing (site.js): upright, always, story or not */
.sc-h1 .hwi i{display:inline-block;font-style:normal}
@media (max-width:1023px){
  /* --mh-ph is the phone's resting height (the stage is 100cqh where container units exist), --mh-k how much bigger
     it stands for the story. 1.18: the room under the phone is much the same in pixels on every phone, so one size
     keeps the heading 36px or more clear of it from a 320 to an upright tablet (47 on Theo's 360x663). */
  html.m-live:not(.has-intro) .hero-stage{--mh-ph:var(--stage-h);--mh-k:1;touch-action:pan-y pinch-zoom}
  html.mh-big:not(.has-intro) .hero-stage{--mh-k:1.18}
  /* THE PHONE rises and settles, then floats, barely, for as long as the page is open (both on the world inside
     the phone object, so the fit-to-stage scale on .p3 is free for the story's size) */
  html.m-live:not(.has-intro) .hero-stage .p3-world{animation:mh-rise 1s cubic-bezier(.2,.8,.2,1) .05s both,mh-float 6.5s ease-in-out 1.1s infinite alternate}
  /* for the story the phone stands bigger, its top edge where it was: it scales from its centre, so the translate
     puts back the half that would go up and all the growth goes down towards the heading. It comes back to its
     resting size as the headline types in (the top edge stays put all the way: both parts ease together). */
  html.m-live:not(.has-intro) .hero-stage .p3{transition:transform .95s cubic-bezier(.2,.8,.2,1)}
  html.mh-big:not(.has-intro) .hero-stage .p3{transform:translateY(calc(var(--mh-ph) * (var(--mh-k) - 1) / 2)) scale(calc(.852 * var(--mh-k)))}
  /* the turn: site.js sets the angle per scene (left, then right), the shadows follow; both ease. Before the
     script runs the phone already stands at the first scene's angle (or straight, on a return), so the first
     paint is the pose the story opens on - not the desktop's -21 and a swing */
  html.mh-story:not(.has-intro) .p3-phone{transform:rotateY(-13deg)}
  html.mh-arrive:not(.has-intro) .p3-phone{transform:rotateY(0deg)}
  /* THE OPENING (Theo + Chris, 2026-09-30: "start off with the thuso brand ... and then scroll into the functions"):
     the story opens on the hero itself - the headline with the phone facing forward at its RESTING size (no mh-big)
     showing the brand plate, and no store buttons. site.js holds it, then the headline rides out to the left (the
     .mh-slide rules below), the phone grows and turns, and the journey walks on. */
  html.mh-open:not(.has-intro) .p3-phone{transform:rotateY(0deg)}
  html.m-live:not(.has-intro) .p3-phone,html.m-live:not(.has-intro) .p3-sh{transition:transform .95s cubic-bezier(.2,.8,.2,1)}
  /* its screen wakes: a dark pane over it from the first paint, gone by the time the phone has settled */
  html.m-live:not(.has-intro) .mh-wake{display:block;position:absolute;inset:0;z-index:5;background:#0b0d10;
    animation:mh-wake .7s ease-out .38s both;pointer-events:none}
  /* THE SCREENS - the next slides up into the phone as the last lifts away. Until site.js owns the screen
     (.mh-js) the story shows Quotes, the scene it opens on, and a return shows login. Transitions exist only once
     the script owns the screen: never at load. */
  /* The story's own screen (.mh-img, MANAGE PROJECTS - the Features page's project screen) is laid like the phone's
     and plays by the same rules; it is hidden everywhere else, the desktop included. */
  html.m-live:not(.has-intro) .mh-img{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:cover}
  html.m-live:not(.has-intro) .p3-img,html.m-live:not(.has-intro) .mh-img{opacity:0;transform:translateY(9%);transition:none}
  html.mh-open:not(.has-intro) .p3-screen:not(.mh-js) .p3-brand,
  html.mh-story:not(.mh-open):not(.has-intro) .p3-screen:not(.mh-js) .p3-img[data-scr="0"],
  html.mh-arrive:not(.has-intro) .p3-screen:not(.mh-js) .p3-img[data-scr="5"],
  html.m-live:not(.has-intro) .p3-img.mh-on,html.m-live:not(.has-intro) .mh-img.mh-on{opacity:1;transform:none}
  html.m-live:not(.has-intro) .p3-screen.mh-js .p3-img,html.m-live:not(.has-intro) .p3-screen.mh-js .mh-img{transition:opacity .5s ease,transform .6s cubic-bezier(.2,.8,.2,1)}
  html.m-live:not(.has-intro) .p3-screen.mh-js .p3-img.mh-out,html.m-live:not(.has-intro) .p3-screen.mh-js .mh-img.mh-out{opacity:0;transform:translateY(-5%);transition:opacity .4s ease,transform .5s ease}
  /* (the coloured glow behind the phone, one colour per scene, was removed on 2026-09-18 - Theo: "remove it". It was too
     faint to see: about a 10% tint at the phone's edge, 2% on average beside it) */
  /* THE RETURN VISIT - the copy arrives with the phone: words up, buttons up out of their box, the trust line wipes */
  html.mh-arrive:not(.has-intro) .sc-h1 .hw{animation:mh-word .65s cubic-bezier(.2,.8,.2,1) both}
  html.mh-arrive:not(.has-intro) .sc-h1 .hw:nth-of-type(1){animation-delay:.34s}
  html.mh-arrive:not(.has-intro) .sc-h1 .hw:nth-of-type(2){animation-delay:.42s}
  html.mh-arrive:not(.has-intro) .sc-h1 .hw:nth-of-type(3){animation-delay:.50s}
  html.mh-arrive:not(.has-intro) .sc-h1 .hw:nth-of-type(4){animation-delay:.58s}
  html.mh-arrive:not(.has-intro) .sc-pills .store-badge img{animation:mh-badge .6s cubic-bezier(.2,.8,.2,1) both}
  html.mh-arrive:not(.has-intro) .sc-pills .store-badge:nth-child(1) img{animation-delay:.74s}
  html.mh-arrive:not(.has-intro) .sc-pills .store-badge:nth-child(2) img{animation-delay:.86s}
  html.mh-arrive:not(.has-intro) .sc-wipe{animation:mh-wipe .8s cubic-bezier(.65,0,.35,1) 1s both}
  /* THE STORY'S HEADINGS - the copy area is the stage. It spans the screen and clips, so the words slide in from
     beyond the screen's edge (the desktop's slide) without widening the page. They sit low in the area, under
     the grown phone. The headline, buttons and trust line keep their room underneath - hidden, not gone - so
     nothing moves when the hero assembles. */
  html.mh-story:not(.has-intro) .hero-copy{position:relative}
  html.mh-story:not(.has-intro) .mh-copy{display:block;position:absolute;top:0;bottom:30px;left:calc(50% - 50vw);right:calc(50% - 50vw);overflow:hidden;pointer-events:none}
  .mh-sc{position:absolute;left:0;right:0;top:60%;translate:0 -50%;padding-inline:20px;text-align:center;
    transform:translateX(-115vw);transition:transform .9s cubic-bezier(.16,.84,.24,1)}
  .mh-sc.is-in{transform:none}
  .mh-sc.is-out{transition:transform .5s cubic-bezier(.5,0,.8,.4)}
  /* ONE SIZE for every heading, set by the longest so each holds ONE line (Theo, 2026-09-18: "make sure it sits in
     one line you can adjust all the video headers sizes to keep it consistent"). They speak to the visitor now,
     regular with the last words bold ("QUOTE FASTER. (FASTER. - IN BOLD)"), and FIND IT. PRICE IT. BUY IT. runs on
     one line like the rest: "CONNECT WITH CLIENTS." is the longest at 11.99em in Poppins caps, the line is the
     screen less 20px a side, so /12.25 leaves a little margin - 22.9px at 320, 26.1 at 360, 28.6 at 390. */
  .mh-h{margin:0;font:400 min(clamp(1.7rem, 8.4vw, 2.6rem), calc((100vw - 40px) / 12.25))/1.05 var(--font-d);letter-spacing:-.005em;text-transform:uppercase;color:#111;white-space:nowrap}
  .mh-h b{font-weight:700}
  /* FIND IT. PRICE IT. BUY IT. - faint, then each takes its turn along the line, all three in the headings' ink: BUY IT.
     is bold like every heading's last words, not coral (Theo, 2026-09-18: "please change the orange buy it. to be
     consistent with the rest of the other headers"). The desktop scene matches ("yes match desktop too"). */
  .mh-l3{color:#cdd3d0;transition:color .45s ease}
  .mh-l3.is-hot{color:#111}
  /* THE LAST BEAT - the line types on ONE line where the headings played, then hands over to the headline. Sized
     to the screen: the whole phrase measures 11.86em at the headline's tracking. It does not slide in like the
     headings; the letters do the work, and .mh-tline shifts so "Helping you build" types in centred. */
  .mh-sc.mh-sc-type{transform:none;transition:none;top:58%}
  .mh-type{margin:0;font:400 min(2.2rem, calc((100vw - 44px) / 11.86))/1.2 var(--font-d);letter-spacing:-.02em;
    color:#111;white-space:nowrap}
  .mh-tline{display:inline-block;transition:transform .7s cubic-bezier(.2,.8,.2,1)}
  .mh-type .tw{display:inline-block}
  .mh-type .tw i{display:inline-block;font-style:normal;opacity:0;transform:translateX(.45em);
    transition:opacity .32s ease,transform .32s ease}
  .mh-type .tw i.on{opacity:1;transform:none}
  .mh-type .ty-b{font-weight:700;color:#111;transition:color .6s ease}
  .mh-type.is-teal .ty-b{color:#0d9488}
  /* THE HEADLINE waits, then flies out of the typed line: site.js lays each of its words exactly over the typed
     word (transform carries and scales, translate lifts - the desktop's overlay) and releases them, so the line
     splits in two and stacks. "better." is teal in both, so the swap itself shows no colour change. */
  html.mh-story:not(.has-intro) .sc-h1:not(.is-in){opacity:0}
  /* the opening's headline slides in from the left and leaves the same way, like every heading after it (Theo,
     2026-09-30) - it used to fade in where it stood and fade out again */
  html.m-live:not(.has-intro) .sc-h1.mh-slide{opacity:1;transform:translateX(-115vw);transition:transform .9s cubic-bezier(.16,.84,.24,1)}
  html.m-live:not(.has-intro) .sc-h1.mh-slide.mh-in{transform:none}
  /* (the dots and Skip used to be hidden for the brand beat; Theo, 2026-09-30: "i want to see it from the start on
     desktop and mobile" - so they stand from the first frame, with no dot lit until the first scene) */
  html.mh-story:not(.has-intro) .sc-pills .store-badge img{transform:translateY(106%);transition:transform .6s cubic-bezier(.2,.8,.2,1)}
  html.mh-story:not(.has-intro) .sc-pills .store-badge.is-in img{transform:none}
  html.mh-story:not(.has-intro) .sc-wipe{clip-path:inset(-10% 100% -10% 0);transition:clip-path .8s cubic-bezier(.65,0,.35,1)}
  html.mh-story:not(.has-intro) .sc-wipe.is-in{clip-path:inset(-10% 0 -10% 0)}
  /* the dots and Skip sit where the trust line will land, and fade as it wipes in */
  html.mh-story:not(.has-intro) .mh-ui{display:flex;position:absolute;left:0;right:0;bottom:-2px;height:26px;align-items:center;justify-content:center;gap:18px;transition:opacity .4s ease}
  html.mh-story:not(.has-intro) .mh-ui.is-done{opacity:0;pointer-events:none}
  .mh-dots{display:flex;gap:7px}
  .mh-dots i{display:block;width:6px;height:6px;border-radius:50%;background:rgba(17,17,17,.18);transition:background .3s ease,transform .3s ease}
  .mh-dots i.on{background:#0d9488;transform:scale(1.25)}
  .mh-skip{appearance:none;border:0;background:none;margin:0;padding:6px 8px;font:700 12px/1 var(--font-d);letter-spacing:.12em;text-transform:uppercase;color:var(--sub);cursor:pointer}
  /* NO SCROLL-AWAY: the finished hero - phone, headline, store buttons and trust line - sits on the page and scrolls
     with it like any other content (Theo, 2026-09-18: the copy "must sit on the page please it musnt fade out",
     then "make the phone sit still too when scrolling but only for mobile"). The story's first build had the
     copy lag 22px and fade, and the phone lift 34px and shrink 6%, as the hero left the screen. Both are gone.
     Phones and tablets only: the desktop's pinned intro is its own thing and is untouched. */
}
@supports (height:1cqh){
  @media (max-width:1023px){
    /* (the cap that kept 100px beside the phone for the sublines went with them on 2026-09-18: on tall screens the
       resting phone is the still hero's size again - a 390x844 draws it 228px wide, not 200) */
    html.m-live:not(.has-intro) .hero-stage{--mh-ph:100cqh}
  }
}

/* tablets upright: the story's type scales with the bigger screen (the same sizes the stacked scenes used) */
@media (min-width:600px) and (max-width:1023px) and (min-height:700px){
  .mh-h{font-size:min(clamp(2.6rem, 6.6vw, 3.8rem), calc((100vw - 40px) / 12.25))}
  .mh-type{font-size:min(3.4rem, calc((100vw - 80px) / 11.86))}
}
@keyframes mh-rise{from{transform:translateY(7%) scale(.94)}to{transform:none}}
@keyframes mh-float{from{transform:translateY(0)}to{transform:translateY(4px)}}
@keyframes mh-wake{from{opacity:1}to{opacity:0}}
@keyframes mh-word{from{opacity:0;transform:translateY(.5em)}to{opacity:1;transform:none}}
@keyframes mh-badge{from{transform:translateY(106%)}to{transform:none}}
@keyframes mh-wipe{from{clip-path:inset(-10% 100% -10% 0)}to{clip-path:inset(-10% 0 -10% 0)}}

@media (prefers-reduced-motion:reduce){
  .sc-label b{animation:none}
}
