/* #hero. Prefix every selector with #hero.

   One composition, worked out here in CSS so it holds with no JS. hero.js only adds the scrub on top, as transforms.
   Everything is measured from the arch plate: the opening's centre sits on the viewport's centre and the top of the
   balustrade (--floor) sets where the plate hangs, so the plate can be smaller than cover in height with --edge-cap's
   dissolve standing in for the wall above it. Custom properties resolve where they are used, so cqw means #hero's width. */

#hero{
  container-type:inline-size;
  --W:100cqw;
  --H:100svh;
  --hero:min(var(--size-hero),calc(var(--W) * .15));   /* holds each line of the headline inside the opening under 373px */

  /* arch-frame.webp, measured from its alpha. */
  --a-ratio:.562857;
  --a-crown:.0584;
  --a-floor:.8788;
  --a-centre:.49375;
  --a-left:.1193;
  --a-show:.78;                 /* how much of the balustrade stays in view */
  --aw:max(calc(var(--W) * 1.0127),min(calc(var(--H) * 1.7766),max(calc(var(--W) * 1.22),calc(var(--H) * 1.457))));

  /* Derived from the plate. */
  --ah:calc(var(--aw) * var(--a-ratio));
  --floor:calc(var(--H) - var(--ah) * (1 - var(--a-floor)) * var(--a-show));
  --ay:calc(var(--floor) - var(--ah) * var(--a-floor));
  --ax:calc(var(--W) / 2 - var(--aw) * var(--a-centre));
  --crown:calc(var(--ay) + var(--ah) * var(--a-crown));
  --open-l:calc(var(--ax) + var(--aw) * var(--a-left));

  /* The phone: --ph is the whole device. */
  --ph:min(1040px,calc(var(--H) * .95),calc((var(--W) - 16px) / .488));
  --bz:calc(var(--ph) * .0095);
  --sh:calc(var(--ph) * .913);
  --sw:calc(var(--sh) * .5142857);
  --pw:calc(var(--sw) + 2 * var(--bz));
  --phone-from:.8;

  /* The stack in the opening, and how much of the phone shows under it. */
  --gap-a:clamp(14px,2.4svh,28px);
  --gap-b:clamp(16px,2.8svh,32px);
  --cta-h:72px;
  --stack:calc(var(--hero) * 1.96 + var(--gap-a) + var(--size-body) * 3.1 + var(--gap-b) + var(--cta-h));
  --sky-top:max(var(--crown),72px);    /* the crown, or the header when a wide screen pushes the crown off the top */
  --peek:calc(var(--ph) * .135 * var(--phone-from));       /* the status bar and the app's top row, cut between rows of the app, never through one */
  --phone-rest:calc(var(--floor) - var(--peek));
  --stack-top:max(72px,calc((var(--crown) + var(--phone-rest) - var(--stack)) / 2));
  --phone-top:max(var(--phone-rest),calc(var(--stack-top) + var(--stack) + 12px));   /* on a short window the buttons win, and the phone starts behind the balustrade */

  /* Moon: right of the headline, halfway between its second line and the arch, with the bay's glitter under it. */
  --mw:min(calc(var(--fw) * .0408),calc(var(--aw) * .082));
  --moon-x:calc(var(--W) / 2 + var(--hero) * 1.65 + var(--aw) * .14);
  --moon-y:calc(var(--stack-top) + var(--stack) * .74);   /* below the headline's baseline, or it reads as a full stop */

  /* Far plate: a little over cover so it has room to rise, and it ends anchored to the bottom. */
  --fw:max(calc(var(--W) * 1.02),calc(var(--H) * 1.8832));
  --fh:calc(var(--fw) * .562857);
  --fx:clamp(calc(var(--W) - var(--fw)),calc(var(--moon-x) - var(--fw) * .8193),0px);
  /* Its hills (.615 down the plate) stay under the tagline: on 21:9 and wider the bottom anchor alone puts them behind it. */
  --fy:min(0px,max(calc(var(--H) * 1.06 - var(--fh)),calc(var(--stack-top) + var(--stack) - var(--cta-h) + 24px - var(--fh) * .615)));

  /* Near plate: the whole pavilion stands on the balustrade, left of the phone and under the buttons. */
  --band:calc(var(--floor) - var(--stack-top) - var(--stack));
  --phone-left:calc((var(--W) - var(--pw) * var(--phone-from)) / 2);
  --nw:min(calc(var(--aw) * .7),calc(var(--band) * 4.05),calc((var(--phone-left) - var(--open-l)) * 3.3));
  --nx:calc(max(var(--open-l),0px) - var(--nw) * .03);
  --ny:calc(var(--floor) + var(--ah) * .012 - var(--nw) * .525);

  z-index:2;   /* above the next section's .edge, which would dissolve the captions at the release; .hero-ground does that job here */
  background:var(--ink);
}

/* Portrait: the tall arch. */
@media (max-aspect-ratio:5/6){
  #hero{
    --a-ratio:1.5;
    --a-crown:.0783;
    --a-floor:.9079;
    --a-centre:.4984;
    --a-left:.081;
    --a-show:.62;
    --aw:max(calc(var(--W) * 1.0032),min(calc(var(--H) * .6667),calc(var(--W) * 1.3)));
    --peek:calc(var(--ph) * .315 * var(--phone-from));
    --moon-x:calc(var(--W) / 2 + var(--hero) * 1.5 + var(--aw) * .2);
    --moon-y:calc(var(--stack-top) + var(--hero) * .45);
    --phone-from:.7;
  }
}

/* Between the buttons and the arch's own edge on smaller landscape screens. */
@media (min-aspect-ratio:5/6) and (max-width:1199px){
  #hero{--moon-x:calc(var(--W) / 2 + var(--hero) * 1.65 + var(--aw) * .19)}
}

/* Phones: everything stacks, so the moon goes above the headline and the phone starts small enough to read as a phone.
   Moon and stack hang from --sky-top, not the crown, so a window that crops the crown off still clears the header's cap. */
@media (max-width:700px) and (max-aspect-ratio:5/6){
  #hero{
    --hero:min(var(--size-hero),calc(var(--W) * .125));   /* the opening is narrower than In your hands. at the 56px minimum */
    --phone-from:.68;
    --stack-top:calc(var(--sky-top) + var(--aw) * .17 + 18px);
    --peek:max(52px,calc(var(--ph) * .085));
    --mw:calc(var(--aw) * .09);
    --moon-x:calc(var(--W) / 2 + var(--aw) * .115);
    --moon-y:calc(var(--sky-top) + var(--aw) * .1 + 8px);
    --nw:min(calc(var(--aw) * 1.26),calc(var(--band) * 3.4));
    --ny:calc(var(--floor) + 2px - var(--nw) * .5618);
  }
}

#hero .hero-stage{position:relative}

/* The layers. Each sits in the stage at its first-frame place. */
#hero .hero-far,#hero .hero-moon,#hero .hero-near,#hero .hero-arch img{position:absolute;max-width:none;height:auto;pointer-events:none;user-select:none;-webkit-user-select:none}
#hero .hero-far{z-index:1;left:var(--fx);top:var(--fy);width:var(--fw)}
#hero .hero-moon{z-index:2;left:calc(var(--moon-x) - var(--mw) / 2);top:calc(var(--moon-y) - var(--mw) / 2);width:var(--mw)}
#hero .hero-near{z-index:3;left:var(--nx);top:var(--ny);width:var(--nw);transform-origin:0 100%}
#hero .hero-ground{position:absolute;z-index:4;inset:auto 0 0;height:0;background:var(--ink);pointer-events:none}
#hero .hero-ground::before{content:'';position:absolute;inset:auto 0 100%;height:calc(80 * var(--art-px));background:url('../art/edge-ink.webp') repeat-x 0 100% / calc(512 * var(--art-px)) calc(80 * var(--art-px));image-rendering:pixelated}
#hero .hero-phone{z-index:5;width:var(--pw);height:var(--ph)}
#hero .hero-captions{z-index:5}
#hero .hero-arch img{z-index:6;left:var(--ax);top:var(--ay);width:var(--aw);transform-origin:calc(var(--aw) * var(--a-centre)) calc((var(--crown) + var(--floor)) / 2 - var(--ay))}
#hero .edge-cap{z-index:7;--cap:max(44px,calc(var(--ay) + 4px))}

/* A small squarish window has no room for the moon clear of both the arch and the headline, so it goes rather than collide. */
@media (max-width:700px) and (min-aspect-ratio:5/6) and (max-aspect-ratio:5/4) and (max-height:580px){
  #hero .hero-moon{display:none}
}

/* The stack. It sits in the opening above the phone, on the sky. */
#hero .hero-intro{position:absolute;z-index:8;inset:var(--stack-top) 0 auto;display:flex;flex-direction:column;align-items:center;padding-inline:max(16px,var(--gutter));text-align:center;pointer-events:none}
#hero h1{font-size:var(--hero);pointer-events:auto}
#hero h1 br{display:none}
#hero .hero-line{display:block;overflow:clip;padding-bottom:.16em;margin-bottom:-.16em;white-space:nowrap}
#hero .hero-line>span{display:block}
#hero .hero-lede{margin-top:var(--gap-a);color:var(--fg-2);pointer-events:auto}
#hero .cta{--cta-justify:center;margin-top:var(--gap-b)}
#hero .cta-status{width:fit-content;margin-inline:auto;padding:4px 10px;border-radius:8px;background:rgb(27 43 65 / .82)}   /* it can land on the bright water */
/* Pinned to the first frame already. A scroll here would walk the runway until the intro leaves, shutting the menu that took focus. */
#hero .hero-intro :is(a,button){scroll-margin:0}

/* The device: a slim body, with the app on the same Ink ground as its status bar. */
#hero .hero-phone-body{width:100%;height:100%;padding:var(--bz);border-radius:calc(var(--ph) * .064);background:var(--ink-soft);box-shadow:inset 0 0 0 1px rgb(141 177 193 / .45),0 calc(var(--ph) * .03) calc(var(--ph) * .08) rgb(27 43 65 / .5)}
#hero .hero-phone-screen{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden;border-radius:calc(var(--ph) * .0545);background:var(--ink)}
#hero .hero-phone-status{position:relative;flex:none;display:flex;align-items:center;justify-content:space-between;height:calc(var(--ph) * .042);padding:calc(var(--ph) * .006) calc(var(--ph) * .036) 0;color:var(--paper);font-size:calc(var(--ph) * .0174);line-height:1;font-weight:600;font-variant-numeric:tabular-nums}
#hero .hero-phone-island{position:absolute;left:50%;top:calc(var(--ph) * .0085);width:calc(var(--ph) * .112);height:calc(var(--ph) * .028);margin-left:calc(var(--ph) * -.056);border-radius:999px;background:var(--ink-soft)}
#hero .hero-phone-signal{display:flex;align-items:center;gap:calc(var(--ph) * .005)}
#hero .hero-phone-signal svg{width:calc(var(--ph) * .022);height:auto;fill:currentColor}
#hero .hero-phone-window{position:relative;flex:none;width:var(--sw);height:var(--sh);overflow:hidden;background:var(--ink)}
#hero .hero-phone-window iframe{transition:opacity 180ms linear;position:absolute;inset:0 auto auto 0;display:block;width:360px;height:700px;border:0;overflow:hidden;color-scheme:dark;transform:scale(var(--phone-scale,1));transform-origin:0 0}
#hero .hero-phone-poster{position:absolute;inset:0;z-index:1;width:100%;height:100%;max-width:none;transition:opacity 200ms linear}
#hero .hero-phone-window iframe.is-switching{opacity:0}
#hero .hero-phone-poster.is-gone{opacity:0;pointer-events:none}
#hero .hero-phone-home{flex:none;display:grid;place-items:center;height:calc(var(--ph) * .026)}
#hero .hero-phone-home>span{width:calc(var(--ph) * .14);height:calc(var(--ph) * .0056);border-radius:999px;background:var(--paper)}
#hero .hero-phone-window:has(iframe:focus-visible),#hero .hero-phone-window.is-kb{outline:2px solid var(--paper);outline-offset:-2px}

/* Captions, left and right of the phone. */
#hero .hero-caption-title{font-family:var(--font-display);font-optical-sizing:auto;font-size:clamp(40px,4.6vw,72px);font-weight:400;line-height:1;letter-spacing:-.025em;text-wrap:balance}
#hero .hero-caption-note{display:block;margin-top:.5em;font-family:var(--font-body);font-size:var(--size-body);line-height:1.4;font-weight:500;letter-spacing:0;color:var(--paper-72)}
#hero .hero-screens{display:flex;flex-direction:column;align-items:flex-start;pointer-events:auto}
#hero .hero-screens button{min-height:44px;font-family:var(--font-display);font-optical-sizing:auto;font-size:clamp(28px,3vw,46px);line-height:1.2;letter-spacing:-.02em;color:rgb(244 242 236 / .55);text-align:left;touch-action:manipulation;transition:color var(--hover-out) var(--ease-out),transform var(--hover-out) var(--ease-out)}
#hero .hero-screens button[aria-pressed="true"]{color:var(--paper)}
@media (hover:hover) and (pointer:fine){
  #hero .hero-screens button:hover{color:var(--paper);transform:translateX(8px);transition-duration:var(--hover-in)}
}

/* Scrubbed: a pinned stage in a tall runway. Only here. */
html.js:not(.rm) #hero{height:260svh}
html.js:not(.rm) #hero .hero-stage{position:sticky;top:0;height:var(--H);overflow:clip}
html.js:not(.rm) #hero .hero-phone{position:absolute;left:calc((var(--W) - var(--pw)) / 2);top:var(--phone-top);transform-origin:50% 0;transform:scale(var(--phone-from))}
html.js:not(.rm) #hero .hero-captions{position:absolute;inset:0;pointer-events:none;opacity:0;--cap-gap:clamp(32px,4vw,120px);--cap-w:calc(var(--W) / 2 - var(--pw) / 2 - var(--cap-gap) - var(--gutter))}
/* Pavilion Wallet. at about 5 ems has to fit the column, or a tall narrow window breaks it a word a line. */
html.js:not(.rm) #hero .hero-caption-title{font-size:min(clamp(40px,4.6vw,72px),calc(var(--cap-w) / 5.2))}
html.js:not(.rm) #hero .hero-caption-title{position:absolute;right:calc(50% + var(--pw) / 2 + var(--cap-gap));top:var(--cap-y,50%);width:calc(var(--W) / 2 - var(--pw) / 2 - var(--cap-gap) - var(--gutter));text-align:right;transform:translateY(-50%)}
html.js:not(.rm) #hero .hero-screens{position:absolute;left:calc(50% + var(--pw) / 2 + var(--cap-gap));top:var(--cap-y,50%);width:calc(var(--W) / 2 - var(--pw) / 2 - var(--cap-gap) - var(--gutter));max-width:320px;transform:translateY(-50%);pointer-events:auto}
html.js:not(.rm) #hero .hero-wallet-mark{position:absolute;left:0;top:calc((100% - var(--H)) * .84);width:1px;height:1px;outline:none}
html.js:not(.rm) #hero .hero-far,html.js:not(.rm) #hero .hero-near,html.js:not(.rm) #hero .hero-arch img,html.js:not(.rm) #hero .hero-phone,html.js:not(.rm) #hero .hero-intro,html.js:not(.rm) #hero .hero-moon{will-change:transform}

/* Entrance, once per page load. Art is simply there; hero.js adds is-entered once the plates have decoded. */
html.js:not(.rm) #hero .hero-line>span{transition:transform 700ms var(--ease-out)}
html.js:not(.rm) #hero .hero-line:last-of-type>span{transition-delay:90ms}
html.js:not(.rm) #hero .hero-lede{transition:opacity 700ms var(--ease-out) 160ms,transform 700ms var(--ease-out) 160ms}
html.js:not(.rm) #hero .cta{transition:opacity 700ms var(--ease-out) 220ms,transform 700ms var(--ease-out) 220ms}
html.js:not(.rm) #hero .hero-phone-body{transition:transform 800ms var(--ease-out) 120ms}
html.js:not(.rm) #hero:not(.is-entered) .hero-line>span{transform:translateY(128%)}
html.js:not(.rm) #hero:not(.is-entered) :is(.hero-lede,.cta){opacity:0;transform:translateY(10px)}
html.js:not(.rm) #hero:not(.is-entered) .hero-phone-body{transform:translateY(40px)}
/* Art is simply there: all at once, never the moon and an empty phone ahead of the plates. No transition, this is not an effect. */
html.js:not(.rm) #hero:not(.is-entered) :is(.hero-far,.hero-moon,.hero-near,.hero-arch img,.hero-phone){visibility:hidden}
/* Reloaded mid-scene: everything is at its place from the start. */
html.js:not(.rm) #hero.no-entrance :is(.hero-line>span,.hero-lede,.cta,.hero-phone-body){transition:none}

/* Once the intro starts to leave, nothing in it can be pressed. */
html.js:not(.rm) #hero .hero-intro.is-leaving,html.js:not(.rm) #hero .hero-intro.is-leaving *{pointer-events:none!important}
/* The peek of the phone is one target until the phone has arrived: pressing it walks you there. */
html.js:not(.rm) #hero .hero-phone:not(.is-up){cursor:pointer}
html.js:not(.rm) #hero .hero-phone:not(.is-up) iframe{pointer-events:none}

/* Phones and narrow tablets: captions under the phone, on a ground that rises to meet them. The header would sit on the
   app's own lockup here, so it steps aside while the phone is up. */
@media (max-width:900px) and (min-height:561px){
  #hero{--ph:min(1040px,calc(var(--H) - 112px),calc((var(--W) - 16px) / .488));--cap-h:min(calc(var(--H) - var(--ph) - 18px),clamp(92px,13svh,136px));--phone-end:max(10px,calc((var(--H) - var(--ph) - var(--cap-h)) / 2))}
  html.js:not(.rm) #hero .hero-captions{inset:calc(var(--phone-end) + var(--ph) + 6px) 0 auto;height:var(--cap-h);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;padding-inline:8px;text-align:center}
  html.js:not(.rm) #hero .hero-caption-title,html.js:not(.rm) #hero .hero-screens{position:static;width:auto;max-width:none;text-align:center;transform:none}
  html.js:not(.rm) #hero .hero-caption-title br{display:none}
  html.js:not(.rm) #hero .hero-caption-title{font-size:clamp(24px,7vw,40px)}
  html.js:not(.rm) #hero .hero-screens{flex-direction:row;flex-wrap:wrap;justify-content:center;gap:0 clamp(9px,3.4vw,16px)}
  html.js:not(.rm) #hero .hero-screens button{font-family:var(--font-body,inherit);font-size:clamp(14px,3.9vw,16px);font-weight:500;letter-spacing:0}
  html.js:not(.rm) #hero .hero-screens button[aria-pressed="true"]{font-weight:700}
  html.js:not(.rm) #hero .hero-ground{height:calc(var(--H) - var(--phone-end) - var(--ph) * .96)}
}
/* The phone stands nearly the height of the window, so the header steps aside while it's up. */
html.js.hero-phone-up:not(.rm) body:not(.menu-open) .site-header:not(:has(:focus-visible)) .masthead{transform:translateY(-110%)}
/* On a short window Paper at 72% reaches the hills. */
@media (max-height:640px){
  #hero .hero-lede{color:var(--paper)}
}

/* Small phones and short windows: slightly shorter buttons, still above the 44px target, so the pavilion keeps its place. */
@media (max-width:700px) and (max-height:640px){
  #hero{--cta-h:60px}
  #hero :is(.cta-button,.cta-input,.cta-submit){min-height:48px}
}
/* Short and wide, like a phone on its side. */
@media (max-height:560px) and (min-width:520px){
  #hero{--hero:min(var(--size-hero),15svh);--cta-h:60px;--gap-a:0px;--stack-top:max(60px,calc((var(--H) + 40px - var(--stack)) / 2));--fy:0px}
  #hero .hero-lede{display:none}
  #hero :is(.cta-button,.cta-input,.cta-submit){min-height:48px}
}
/* Narrow and very short: everything tightens so both stay on the stage. */
@media (max-width:519px) and (max-height:400px){
  #hero{--hero:48px;--stack-top:56px;--gap-a:10px;--gap-b:12px;--cta-h:56px}
  #hero .hero-lede{font-size:15px;line-height:1.3}
  #hero :is(.cta-button,.cta-input,.cta-submit){min-height:44px}
}
/* A short desktop window: the moon moves out, clear of the words. */
@media (max-height:720px) and (min-width:520px){
  #hero{--moon-x:calc(var(--W) / 2 + max(var(--hero) * 1.65 + var(--aw) * .14,410px))}
}
@media (max-height:560px){
  #hero .hero-moon{display:none}
}
/* A folded phone: the title gives way to the buttons, which wrap to two rows here. */
@media (max-width:319px){
  html.js:not(.rm) #hero .hero-caption-title{display:none}
}
@media (min-width:2400px){
  #hero{--ph:min(1800px,calc(var(--H) * .95));--cta-h:calc(clamp(56px,2.566vw,99px) + 16px)}
  #hero .hero-screens button{font-size:clamp(46px,2vw,72px);min-height:1.3em}
  #hero .hero-caption-title{font-size:clamp(72px,3.4vw,120px)}
  html.js:not(.rm) #hero .hero-caption-title{font-size:min(clamp(72px,3.4vw,120px),calc(var(--cap-w) / 5.2))}
}

/* Too short for the arch to frame anything, at 300% zoom say: it would only run through the words. */
@media (max-height:320px){
  html.rm #hero :is(.hero-arch,.hero-moon,.edge-cap){display:none}
}

/* One finished state in normal flow: no JS, a failed module or reduced motion. The art stage, then the phone on Ink. */
html:not(.js) #hero,html.rm #hero{--H:max(100svh,600px);--phone-from:1}
html:not(.js) #hero .hero-stage,html.rm #hero .hero-stage{overflow:clip}
html:not(.js) #hero .hero-intro,html.rm #hero .hero-intro{position:relative;inset:auto;padding-top:var(--stack-top);height:var(--H)}
html:not(.js) #hero :is(.hero-far,.hero-moon,.hero-near,.hero-ground,.hero-arch img,.edge-cap,.hero-intro,.hero-phone,.hero-captions,.hero-line>span,.hero-lede,.cta,.hero-phone-body),html.rm #hero :is(.hero-far,.hero-moon,.hero-near,.hero-ground,.hero-arch img,.edge-cap,.hero-intro,.hero-phone,.hero-captions,.hero-line>span,.hero-lede,.cta,.hero-phone-body){transform:none!important;opacity:1!important;visibility:visible!important}
html:not(.js) #hero .hero-arch img,html.rm #hero .hero-arch img{clip-path:inset(0 0 calc(var(--ah) + var(--ay) - var(--H)) 0)}
html:not(.js) #hero .hero-far,html.rm #hero .hero-far{clip-path:inset(0 0 calc(var(--fh) + var(--fy) - var(--H)) 0)}
html:not(.js) #hero .hero-ground,html.rm #hero .hero-ground{inset:var(--H) 0 auto;height:0;z-index:7}
/* Enough air that with the phone centred the art has left the viewport, so the header never rests on its dissolve. */
html:not(.js) #hero .hero-phone,html.rm #hero .hero-phone{position:relative;margin:clamp(48px,calc((var(--H) - var(--ph)) / 2),120px) auto 0}
html:not(.js) #hero .hero-captions,html.rm #hero .hero-captions{position:relative;display:flex;flex-direction:column;align-items:center;gap:8px;padding:40px var(--gutter) 96px;text-align:center}
html:not(.js) #hero .hero-wallet-mark,html.rm #hero .hero-wallet-mark{position:absolute;left:0;top:var(--H);outline:none}
/* The screen buttons need the app, which needs JS. Without motion they sit in a row under the phone. */
html:not(.js) #hero .hero-screens{display:none}
html.rm #hero .hero-screens{flex-direction:row;flex-wrap:wrap;justify-content:center;gap:0 clamp(12px,3vw,28px)}

/* Words that can land on the plates' water or hills on a wide or short window get an Ink halo. On flat sky it is invisible. */
#hero :is(.hero-lede,.hero-caption-title,.hero-screens button){text-shadow:0 0 .2em var(--ink),0 0 .45em var(--ink),0 0 .9em rgb(27 43 65 / .7)}
