/* Envesta — envesta.app
   Palette and type from envesta-advertising-brief.md.
   Rebuilt Aug 2026 after the original site was found to have no source. */
:root{
  --deep:#0C352A; --green:#114A3C; --green-lt:#175B45;
  --cream:#FDF9F0; --cream-2:#F6EDE4; --beige:#E9DAC5; --paper:#F8F4EC;
  --gold:#B9913F; --gold-lt:#D8BC82; --ink:#20302A;
  --muted:#6B7C74; --rule:rgba(32,48,42,.12);
  --serif:Lora,Georgia,"Times New Roman",serif;
  --sans:Poppins,system-ui,-apple-system,sans-serif;
  --wrap:1140px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--cream);color:var(--ink);font:400 16.5px/1.7 var(--sans);-webkit-font-smoothing:antialiased}
img{max-width:100%;height:auto;display:block}
a{color:inherit}
.wrap{max-width:var(--wrap);margin:0 auto;padding:0 22px}

/* ---------- type ---------- */
h1,h2,h3{font-family:var(--serif);font-weight:400;letter-spacing:-.015em;margin:0;text-wrap:balance}
h1{font-size:clamp(38px,6.4vw,68px);line-height:1.04}
h2{font-size:clamp(28px,4.2vw,44px);line-height:1.12}
h3{font-size:clamp(19px,2vw,23px);line-height:1.28}
em{font-style:italic;color:var(--gold)}
.eyebrow{font:500 11.5px/1 var(--sans);letter-spacing:.22em;text-transform:uppercase;color:var(--gold);margin:0 0 16px}
.lede{font-size:clamp(17px,1.9vw,20px);color:var(--muted);max-width:56ch;margin:18px 0 0}
.rule{width:52px;height:2px;background:var(--gold);border-radius:2px;margin:20px 0}
.rule.mid{margin-left:auto;margin-right:auto}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;gap:.6em;justify-content:center;
  min-height:52px;padding:0 30px;border-radius:99px;border:1.5px solid transparent;
  font:600 15px/1 var(--sans);text-decoration:none;cursor:pointer;transition:.18s;
}
.btn-gold{background:var(--gold);color:#fff}
.btn-gold:hover{background:#a67f33}
.btn-ghost{border-color:rgba(253,249,240,.4);color:var(--cream)}
.btn-ghost:hover{border-color:var(--gold-lt);color:var(--gold-lt)}
.btn-dark{background:var(--green);color:var(--cream)}
.btn-dark:hover{background:var(--deep)}
/* .btn-outline was the header desktop door (DESKTOP-LIVE §3); the door is now a plain footer link (.fadmin). Kept for reuse. */
.btn-outline{border-color:var(--gold);color:var(--gold-lt);background:transparent}
.btn-outline:hover{border-color:var(--gold-lt);color:var(--cream);background:rgba(185,145,63,.14)}

/* ---------- nav ---------- */
.topbar{background:var(--deep);color:var(--cream);font:500 12.5px/1 var(--sans);text-align:center;padding:11px 20px}
.topbar a{color:var(--gold-lt)}
nav{position:sticky;top:0;z-index:50;background:rgba(12,53,42,.97);backdrop-filter:blur(10px);color:var(--cream)}
nav .wrap{display:flex;flex-wrap:wrap;align-items:center;gap:14px 26px;min-height:70px}
.brand{font:400 21px/1 var(--serif);color:var(--cream);text-decoration:none;letter-spacing:.01em;flex:none}
.brand span{display:block;font:500 8.5px/1 var(--sans);letter-spacing:.24em;color:var(--gold-lt);margin-top:5px}
.navlinks{
  display:flex;flex-wrap:wrap;gap:8px 18px;width:100%;order:3;
  padding:0 0 13px;margin:-4px 0 0;font:500 13.5px/1 var(--sans);
}
.navlinks a{color:rgba(253,249,240,.82);text-decoration:none;transition:.15s}
.navlinks a:hover{color:var(--gold-lt)}
nav .btn{min-height:42px;padding:0 20px;font-size:13.5px;margin-left:auto}
.navbtns{display:flex;gap:8px;margin-left:auto;flex:none}
.navbtns .btn{margin-left:0}
@media(max-width:560px){.navbtns{width:100%;order:2;margin:-2px 0 0}.navbtns .btn{min-height:38px;padding:0 14px;font-size:12.5px}}
@media(min-width:940px){
  .navlinks{width:auto;order:0;padding:0;margin-left:auto;font-size:14px;gap:26px}
  .navbtns{margin-left:0}
}

/* ---------- ad visitors (30 Sept 2026) ---------------------------------------
   A visitor who arrived from an ad gets the logo and ONE button: no nav links, and the
   header button reads "Start free trial" rather than "Sign up / Log in". The <head> script
   on index, sign-up and get adds html.ad; without it nothing here applies. On a phone the
   button stays beside the logo instead of dropping to its own row. */
.nav-ad{display:none}
html.ad .navlinks,html.ad .nav-std{display:none}
html.ad .nav-ad{display:inline}
html.ad .navbtns{width:auto;order:0;margin:0 0 0 auto}

/* ---------- hero ------------------------------------------------------------
   The Library scene. Not a photograph and not an image model: three
   procedurally rendered layers — the walnut case with every book placed and
   shaded individually and gold foil on the spines, the window light off-frame
   right in three panes thick with air, and the dust turning in it. Rendered at
   4K and shipped as WebP: 199KB for all four assets, which is lighter than the
   single 680KB phone screenshot this hero used to lean on.

   The render sources are not in this repo (they are session work, hero/*.py) —
   the assets in img/hero/ are the deliverable.
--------------------------------------------------------------------------- */
.hero{
  position:relative;isolation:isolate;overflow:hidden;
  min-height:clamp(560px,86svh,880px);
  display:flex;align-items:center;
  background:#04100E;color:var(--cream);
  padding:clamp(48px,7vw,92px) 0;
}

/* The parallax transform lives on .lyr and the ambient drift on the inner
   .lyr-img, so the two never fight over `transform`. */
.scene{position:absolute;inset:0;z-index:0;pointer-events:none}
.lyr{
  position:absolute;inset:-7% -9%;
  transform:translate3d(var(--px,0px),var(--py,0px),0);
  will-change:transform;
}
.lyr-img{
  position:absolute;inset:0;
  background-repeat:no-repeat;background-size:cover;
  /* Every layer shares this position, so the window light in one sits exactly
     on the beam in the next at ANY viewport aspect. Exposed as a custom
     property because the phone breakpoint changes it and the script reads it. */
  background-position:var(--bgx,78%) var(--bgy,50%);
}
.lyr-case  .lyr-img{background-image:url("/img/hero/case.webp")}
.lyr-beam  .lyr-img{background-image:url("/img/hero/beam.webp")}
.lyr-motes .lyr-img{background-image:url("/img/hero/motes.webp")}

/* The window itself, off-frame past the top-right corner. Anchored to the
   corner rather than a percentage, which is aspect-independent. */
.bloom{
  position:absolute;right:-16%;top:-22%;width:62vmax;height:62vmax;z-index:0;
  background:radial-gradient(closest-side,
      rgba(255,226,168,.34) 0%, rgba(255,206,132,.17) 30%,
      rgba(201,154,61,.06) 56%, transparent 74%);
  mix-blend-mode:screen;pointer-events:none;
}

/* ---------- the candle field ------------------------------------------------
   A live chart running behind the type. The axis is FIXED and a finished
   candle never moves again except sideways — only the rightmost one is still
   forming, its high and low ratcheting outward as it goes.

   DELIBERATELY UNLABELLED and it must stay that way: no axis, no figures, no
   ticker, no last-price marker. Note for whoever picks this up — a red/green
   candle chart on a financial promotion reads as market performance, which is
   a different proposition from decoration. It belongs in the solicitor
   conversation with the s21 work.
--------------------------------------------------------------------------- */
.candles{
  position:absolute;inset:10% 0 3%;z-index:0;overflow:hidden;opacity:.33;
  pointer-events:none;
  /* faint where the headline sits, full strength across the sweep */
  -webkit-mask-image:linear-gradient(135deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,.46) 26%,#000 58%);
          mask-image:linear-gradient(135deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,.46) 26%,#000 58%);
  animation:cdIn 1.6s cubic-bezier(.19,1,.22,1) .5s backwards;
}
.candles svg{position:absolute;inset:0;width:100%;height:100%}
.candles line{stroke-width:1.4;vector-effect:non-scaling-stroke}
.cd-up{fill:rgba(132,180,140,.62);stroke:rgba(132,180,140,.62)}
.cd-dn{fill:rgba(186,98,86,.62);stroke:rgba(186,98,86,.62)}
.cd-live rect{stroke-width:0}
/* no `to` value: the field fades up to whatever opacity the breakpoint sets */
@keyframes cdIn{from{opacity:0}}

/* filmic grain + a vignette that keeps the type on settled ground */
.grain{
  position:absolute;inset:-40px;z-index:0;opacity:.16;mix-blend-mode:overlay;
  pointer-events:none;
  background-image:url("/img/hero/grain.webp");background-size:180px 180px;
}
.vig{
  position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    linear-gradient(92deg, rgba(4,16,14,.92) 0%, rgba(4,16,14,.62) 30%, rgba(4,16,14,0) 58%),
    linear-gradient(to top, rgba(4,16,14,.66) 0%, rgba(4,16,14,0) 30%);
}

/* ---------- the copy on top ---------- */
.hero .wrap{position:relative;z-index:2;width:100%}
.hero .copy{max-width:min(680px,92%)}
.hero .eyebrow{color:var(--gold-lt)}
/* sized for "Learn to invest, / with people who are learning too." (30 Sept 2026) — the
   old two-word lines ran to 92px, which would put this headline on five lines */
.hero h1{
  color:var(--cream);
  font-size:clamp(36px,5.2vw,68px);line-height:1.06;letter-spacing:-.018em;
}
.hero h1 em{color:var(--gold-lt)}
.ln{display:block;overflow:hidden}
.ln>span{display:block}
.hero .rule{margin:26px 0 0;transform-origin:left center}
.hero .lede{color:rgba(253,249,240,.78);max-width:52ch;margin:22px 0 0}
.hero-cta{display:flex;flex-wrap:wrap;gap:14px;margin-top:34px}
.hero-note{font-size:13px;color:rgba(253,249,240,.55);margin:20px 0 0}
/* the offer, right under the button: free trial, no card, the price and the risk line.
   Inside .hero-cta so it arrives with the button in the entrance; flex-basis puts it on
   its own line. Also used under the #join button. */
.offer-note{font:400 13.5px/1.6 var(--sans);color:rgba(253,249,240,.76);max-width:50ch;margin:16px 0 0}
.offer-note strong{font-weight:600;color:var(--cream)}
.hero-cta .offer-note{flex-basis:100%;margin:0}
.center .offer-note{margin-left:auto;margin-right:auto}

/* ---------- entrance --------------------------------------------------------
   THE PAGE SHIPS VISIBLE. Script adds `anim` (which hides what is about to
   animate) and then `go` (which plays it). If the script never runs, runs
   early, or throws, the hero still renders complete and merely does not
   animate in. Parking content at opacity:0 in the stylesheet and relying on JS
   to reveal it is how a hero ends up blank — which is exactly what happened
   once while this was being built.
--------------------------------------------------------------------------- */
.hero.anim .ln>span,
.hero.anim .eyebrow,
.hero.anim .lede,
.hero.anim .hero-cta{opacity:0}
.hero.anim .ln>span{transform:translateY(108%)}
.hero.anim .rule{transform:scaleX(0)}
.hero.anim .lyr{opacity:0}

.hero.go .lyr{animation:layerIn 1.9s cubic-bezier(.19,1,.22,1) forwards}
.hero.go .lyr-beam{animation-delay:.14s}
.hero.go .lyr-motes{animation-delay:.24s}
.hero.go .eyebrow{animation:fadeUp .9s cubic-bezier(.19,1,.22,1) .45s forwards}
.hero.go .ln:nth-of-type(1)>span{animation:lineUp 1.15s cubic-bezier(.19,1,.22,1) .55s forwards}
.hero.go .ln:nth-of-type(2)>span{animation:lineUp 1.15s cubic-bezier(.19,1,.22,1) .70s forwards}
.hero.go .rule{animation:ruleIn .9s cubic-bezier(.19,1,.22,1) 1.00s forwards}
.hero.go .lede{animation:fadeUp .9s cubic-bezier(.19,1,.22,1) 1.08s forwards}
.hero.go .hero-cta{animation:fadeUp .9s cubic-bezier(.19,1,.22,1) 1.22s forwards}

@keyframes layerIn{from{opacity:0;transform:translate3d(0,0,0) scale(1.075)}
                     to{opacity:1;transform:translate3d(var(--px,0px),var(--py,0px),0) scale(1)}}
@keyframes lineUp{from{opacity:0;transform:translateY(108%)}to{opacity:1;transform:translateY(0)}}
@keyframes fadeUp{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}
@keyframes ruleIn{from{transform:scaleX(0)}to{transform:scaleX(1)}}

/* ---------- ambient ---------------------------------------------------------
   Under about 60s a loop reads as static; 30-50s is the band where motion
   registers without distracting. There is no pointer parallax by design — the
   scene lives on its own and does not react to the mouse.
--------------------------------------------------------------------------- */
.lyr-beam  .lyr-img{animation:driftA 46s ease-in-out infinite alternate}
.lyr-motes .lyr-img{animation:driftB 34s ease-in-out infinite alternate}
@keyframes driftA{from{transform:translate(-1.4%,-.5%)}to{transform:translate(1.4%,.5%)}}
@keyframes driftB{from{transform:translate(2.2%,2.6%)}to{transform:translate(-2.2%,-2.6%)}}

/* the light dims and lifts as if something passes the window outside */
.lyr-beam{animation:weather 27s ease-in-out infinite}
@keyframes weather{0%,100%{opacity:.80}38%{opacity:1}64%{opacity:.62}}
.bloom{animation:breathe 13s ease-in-out infinite alternate}
@keyframes breathe{from{opacity:.80;transform:scale(.97)}to{opacity:1;transform:scale(1.06)}}

@media (prefers-reduced-motion:reduce){
  .hero.anim .ln>span,.hero.anim .eyebrow,.hero.anim .lede,
  .hero.anim .hero-cta,.hero.anim .lyr{opacity:1}
  .hero.anim .ln>span{transform:none}
  .hero.anim .rule{transform:none}
  .hero.go .lyr,.hero.go .eyebrow,.hero.go .ln>span,.hero.go .rule,
  .hero.go .lede,.hero.go .hero-cta,
  .lyr-beam .lyr-img,.lyr-motes .lyr-img,.bloom,.lyr-beam,.candles{animation:none}
  .lyr{transform:none}
}

@media (max-width:880px){
  /* a tall crop would land the type in the middle of the shelves — pull the
     scene right so the headline sits on the dark room and the beam stays in.
     Vertical framing cannot be tuned here: the crop is height-limited, so
     --bgy has no effect on a phone. */
  .hero .lyr-img{--bgx:90%}
  .hero{min-height:clamp(520px,84svh,760px)}
  .candles{opacity:.5}
  .bloom{right:-22%;top:-14%;width:105vmax;height:105vmax}
  .vig{background:
    linear-gradient(180deg, rgba(3,14,12,.72) 0%, rgba(3,14,12,.30) 34%, rgba(3,14,12,0) 58%),
    linear-gradient(to top, rgba(3,14,12,.86) 0%, rgba(3,14,12,0) 46%)}
  .hero .copy{max-width:100%}
}

/* ---------- page banner -----------------------------------------------------
   Every inner page opens with the same block — eyebrow, heading, rule, lede,
   inside a `band-deep center` section. Adding `pagehead` puts the Library
   scene behind that block, so the site reads as one place rather than a good
   homepage bolted onto plain pages.

   It reuses the HOMEPAGE'S OWN LAYERS, so on any page reached from the home
   page they are already in cache and this costs nothing to load.

   NO JAVASCRIPT, deliberately. There is no entrance to play and nothing to
   reveal, so there is no state in which this banner can fail to appear — that
   failure mode cost two rounds on the hero and is designed out here rather
   than guarded against.

   *** THE CROP, and it is the opposite of the hero's. These bands are WIDE and
   SHORT, so `cover` fits the image by WIDTH and overflows vertically: --bgy
   chooses which shelf you are looking at and --bgx does almost nothing. On the
   hero the box is 16:9 and --bgx is the one that matters. Each page sets its
   own --bgy inline, so they read as different parts of the same room — LOWER
   numbers are HIGHER up the case and catch more of the window light. ***

   `band-deep` keeps its flat green underneath, so if the images never arrive
   the banner degrades to exactly what these pages looked like before.
--------------------------------------------------------------------------- */
.pagehead{
  position:relative;isolation:isolate;overflow:hidden;
  min-height:clamp(230px,31vh,350px);
  display:flex;align-items:center;
}
.pagehead>.wrap{position:relative;z-index:1;width:100%}
.ph-scene{position:absolute;inset:0;z-index:0;pointer-events:none}
.ph-case,.ph-beam,.ph-motes{
  position:absolute;inset:0;
  background-repeat:no-repeat;
  /* NOT `cover`. At `cover` a wide short band fits the image by width exactly,
     so there is no horizontal overflow and --bgx does nothing — the whole
     16:9 room gets squashed into a strip and only the lit right-hand side
     reads. Oversizing past 100% makes BOTH axes overflow, which gives two
     usable knobs and shows a detail of the room rather than all of it. */
  background-size:165%;
  background-position:var(--bgx,70%) var(--bgy,50%);
}
.ph-case {background-image:url("/img/hero/case.webp")}
.ph-beam {background-image:url("/img/hero/beam.webp")}
.ph-motes{background-image:url("/img/hero/motes.webp");opacity:.65}

/* The type is CENTRED on these pages, so the scrim cannot be one-sided the way
   the hero's is. Darker top and bottom blends the band into the nav above and
   the cream section below; the middle stays open enough for the shelves to
   read behind the words. */
.ph-veil{
  position:absolute;inset:0;
  background:linear-gradient(180deg,
    rgba(4,16,14,.90) 0%, rgba(4,16,14,.52) 34%,
    rgba(4,16,14,.56) 66%, rgba(4,16,14,.92) 100%);
}
.pagehead .eyebrow{color:var(--gold-lt)}
.pagehead h2{color:var(--cream)}
.pagehead .lede{color:rgba(253,249,240,.8)}

/* the only motion: dust turning, slowly enough to notice but not to distract */
.ph-motes{animation:phDrift 52s ease-in-out infinite alternate}
@keyframes phDrift{from{transform:translate(1.1%,1.3%)}to{transform:translate(-1.1%,-1.3%)}}

@media (prefers-reduced-motion:reduce){ .ph-motes{animation:none} }

@media (max-width:880px){
  /* a phone crops this band much tighter, so open the scrim a little or the
     scene disappears entirely behind the words */
  .pagehead{min-height:clamp(200px,26vh,300px)}
  /* a phone band is far smaller, so it needs a much bigger zoom before there
     is any room left to move the crop around in */
  .ph-case,.ph-beam,.ph-motes{background-size:260%}
  .ph-veil{background:linear-gradient(180deg,
    rgba(4,16,14,.88) 0%, rgba(4,16,14,.60) 38%,
    rgba(4,16,14,.64) 64%, rgba(4,16,14,.90) 100%)}
}

/* ---------- sections ---------- */
section{padding:clamp(64px,8vw,108px) 0}
section.tight{padding:clamp(44px,5vw,70px) 0}
.band-cream2{background:var(--cream-2)}
.band-deep{background:var(--deep);color:var(--cream)}
.band-deep h2,.band-deep h3{color:var(--cream)}
.band-deep .lede{color:rgba(253,249,240,.72)}
.center{text-align:center}
.center .lede{margin-left:auto;margin-right:auto}

/* ---------- surfaces ---------- */
.surface{display:grid;gap:34px;align-items:center;padding:clamp(38px,5vw,64px) 0;border-bottom:1px solid var(--rule)}
.surface:last-child{border-bottom:0}
@media(min-width:900px){
  .surface{grid-template-columns:1fr 1fr;gap:64px}
  .surface:nth-child(even) .surface-text{order:2}
}
.surface-shot{justify-self:center;max-width:290px;border-radius:26px;filter:drop-shadow(0 26px 44px rgba(32,48,42,.22))}
.surface h3{margin-bottom:10px}
.surface p{color:var(--muted);margin:0;max-width:46ch}

/* ---------- the app shots, in 3D ------------------------------------------
   Same motion language as the Lounge phones: the shots sit turned slightly in
   space rather than flat on the page, and settle square as they scroll in.
   They ALTERNATE with the layout — the row order flips on even rows, so each
   shot turns in from the side it actually sits on, which reinforces the
   left/right rhythm instead of fighting it.

   DELIBERATELY GENTLER THAN THE LOUNGE, and only two acts: turn in, then
   settle and stay. The Lounge is the showpiece and earns a full in-hold-out;
   four more dramatic exits stacked down one page would read as a fairground
   and pull attention off the copy beside them. Restraint here is what keeps
   the Lounge feeling like the moment.
-------------------------------------------------------------------------- */
.surface{perspective:1200px;perspective-origin:50% 50%}
/* AXIS ORDER MATTERS AND I GOT IT WRONG FIRST TIME: `overflow: <x> <y>`, so
   `clip visible` clips SIDEWAYS only — a shot turning in space can never
   widen the page, while its drop-shadow still bleeds vertically. `visible
   clip` is the exact opposite and clips the shadow instead.
   And `clip`, never `hidden`: hidden would make this section a scroll
   container and the shots' `animation-timeline: view()` would freeze, which
   is the same bug that cost a round on .stage. */
.surface-shots-clip{overflow:clip visible}
.surface-shot{transform-style:preserve-3d}

@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .surface-shot{
      animation:shotIn linear both;
      animation-timeline:view();
      animation-range-start:cover 8%;
      animation-range-end:cover 52%;
    }
    .surface:nth-child(even) .surface-shot{animation-name:shotInAlt}
  }
  /* image on the RIGHT of the row: turns in from the right */
  @keyframes shotIn{
    from{ transform:rotateY(-19deg) rotateX(7deg) translateX(46px) translateY(26px) scale(.93); opacity:.55 }
    to  { transform:rotateY(-5deg)  rotateX(1deg) translateX(0)    translateY(0)    scale(1);   opacity:1 }
  }
  /* image on the LEFT of the row: mirrored, so it turns in from the left */
  @keyframes shotInAlt{
    from{ transform:rotateY(19deg) rotateX(7deg) translateX(-46px) translateY(26px) scale(.93); opacity:.55 }
    to  { transform:rotateY(5deg)  rotateX(1deg) translateX(0)     translateY(0)    scale(1);   opacity:1 }
  }
}
/* the resting pose, for no-support and reduced-motion: still turned a little,
   because the slight turn is what stops them reading as flat pasted rectangles */
.surface-shot{transform:rotateY(-5deg) rotateX(1deg)}
.surface:nth-child(even) .surface-shot{transform:rotateY(5deg) rotateX(1deg)}

/* ---------- results ---------- */
.results{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px;margin-top:34px}
.res{background:rgba(253,249,240,.06);border:1px solid rgba(216,188,130,.24);border-radius:8px;padding:20px 18px;text-align:center}
.res b{display:block;font:400 clamp(24px,3vw,32px)/1 var(--serif);color:var(--gold-lt)}
.res span{display:block;font:500 12px/1 var(--sans);letter-spacing:.1em;text-transform:uppercase;color:rgba(253,249,240,.6);margin-top:9px}

/* ---------- testimonials ---------- */
.quotes{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:18px;margin-top:38px}
.quote{background:#fff;border:1px solid var(--rule);border-radius:8px;padding:26px 24px;box-shadow:0 1px 2px rgba(32,48,42,.04)}
.quote p{font:400 17px/1.6 var(--serif);margin:0 0 16px;color:var(--ink)}
.quote cite{font:500 12px/1 var(--sans);letter-spacing:.09em;text-transform:uppercase;color:var(--muted);font-style:normal}

/* ---------- faq ---------- */
.faq{max-width:780px;margin:38px auto 0}
details{border-bottom:1px solid var(--rule)}
summary{cursor:pointer;list-style:none;padding:20px 34px 20px 0;font:500 17px/1.45 var(--sans);position:relative}
summary::-webkit-details-marker{display:none}
summary::after{content:"+";position:absolute;right:6px;top:19px;font:400 24px/1 var(--sans);color:var(--gold)}
details[open] summary::after{content:"\2013"}
details p{margin:0 0 22px;color:var(--muted);max-width:64ch}

/* ---------- form ---------- */
.signup{max-width:520px;margin:34px auto 0;display:grid;gap:12px}
.signup input{
  height:54px;padding:0 20px;border-radius:99px;border:1.5px solid rgba(253,249,240,.22);
  background:rgba(253,249,240,.06);color:var(--cream);font:400 15px/1 var(--sans);
}
.signup input::placeholder{color:rgba(253,249,240,.45)}
.signup input:focus{outline:none;border-color:var(--gold-lt)}
.signup .btn{width:100%}
.formnote{font-size:12.5px;color:rgba(253,249,240,.5);text-align:center;margin:4px 0 0}
.formnote a{color:var(--gold-lt);text-decoration:underline;text-underline-offset:2px}

.signup button:disabled{opacity:.5;cursor:progress}

/* Honeypot. Off-screen rather than display:none or type=hidden — bots fill
   those happily; this one only a script is likely to find. */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* Marketing opt-in — its own checkbox, never pre-ticked. */
.optin{
  display:flex;gap:11px;align-items:flex-start;text-align:left;
  font:400 13.5px/1.5 var(--sans);color:rgba(253,249,240,.78);
  margin:2px 0 2px;cursor:pointer;
}
.optin input{
  flex:0 0 auto;width:17px;height:17px;margin:1px 0 0;accent-color:var(--gold);cursor:pointer;
}
.formerr{
  font:400 13px/1.5 var(--sans);text-align:center;margin:2px 0 0;
  color:#ffb4a2;
}
.signup-done{
  max-width:520px;margin:34px auto 0;padding:26px 24px;border-radius:8px;
  border:1.5px solid rgba(216,188,130,.34);background:rgba(253,249,240,.06);
}
.signup-done p{margin:0;font:400 16px/1.6 var(--serif);color:var(--cream)}
.signup-done p + p{margin-top:8px;font-size:14px;color:rgba(253,249,240,.72)}

/* ---------- /get — store badges and the QR ---------- */
.getgrid{
  display:grid;gap:38px;margin-top:8px;align-items:start;
  grid-template-columns:1fr;
}
@media(min-width:720px){ .getgrid{grid-template-columns:1.15fr .85fr;gap:52px} }
.getcol{text-align:center}
@media(min-width:720px){ .getcol{text-align:left} .qrcol{text-align:center} }
.geth{font:500 11px/1 var(--sans);letter-spacing:.18em;text-transform:uppercase;color:var(--muted);margin:0 0 20px}
.storerow{display:flex;flex-wrap:wrap;gap:14px 16px;align-items:center;justify-content:center}
@media(min-width:720px){ .storerow{justify-content:flex-start} }
/* Official store artwork, embedded as data URIs at build time so the page makes
   no third-party request. The two badges are drawn to different safe-area rules,
   hence the small height difference rather than a shared box. */
.storebadge{display:inline-block;line-height:0;border-radius:8px}
.storebadge img{display:block;height:47px;width:auto}
.storebadge.gp img{height:61px;margin:-7px -8px}
.storebadge:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.qrcard{
  display:inline-block;padding:14px;background:#fff;border:1px solid var(--rule);
  border-radius:12px;box-shadow:0 1px 2px rgba(32,48,42,.04);line-height:0;
}
.qrcard .qr{display:block;width:180px;height:180px}
.getnote{font:400 12.5px/1.6 var(--sans);color:var(--muted);margin:16px 0 0}

/* ---------- footnote / disclaimers ---------- */
.footnote{font:400 11.5px/1.55 var(--sans);color:var(--muted);max-width:70ch;margin:18px 0 0}
.band-deep .footnote{color:rgba(253,249,240,.42)}
.footnote.mid{margin-left:auto;margin-right:auto;text-align:center}

/* ---------- footer ---------- */
footer{background:var(--deep);color:rgba(253,249,240,.72);padding:64px 0 34px;font-size:14px}
.fgrid{display:grid;gap:34px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}
footer h4{font:500 11px/1 var(--sans);letter-spacing:.18em;text-transform:uppercase;color:var(--gold-lt);margin:0 0 16px}
footer ul{list-style:none;margin:0;padding:0;display:grid;gap:10px}
footer a{color:rgba(253,249,240,.72);text-decoration:none}
footer a:hover{color:var(--gold-lt)}
.fbrand{font:400 22px/1 var(--serif);color:var(--cream)}
.fbrand span{display:block;font:500 8.5px/1 var(--sans);letter-spacing:.24em;color:var(--gold-lt);margin-top:6px}
.fbase{border-top:1px solid rgba(253,249,240,.12);margin-top:44px;padding-top:24px;font-size:11.5px;line-height:1.7;color:rgba(253,249,240,.45)}


/* ===== lounge phones (from components/lounge-phones.html) ===== */

/* ============================================================
   Envesta — "a room behind you" section
   Rebuilt for the web from envesta-spot-lounge-chat-14s_4.mp4.
   Palette and type from envesta-advertising-brief.md.

   THE LIVE-PRICE CHIP IS INTENTIONAL. It shows a real feature of
   the app - $TICKER chips resolve to a live quote inside a message.
   Note for whoever picks this up: envesta-advertising-brief.md and
   the ad README treat "a ticker with a price attached" as something
   to keep out of advertising, and it is the stated reason the Lounge
   rooms were never filmed. Keeping it here is a decision taken with
   that known, not an oversight - do NOT quietly remove it, and do
   not quietly copy it into paid ad creative either. Raise it with
   the solicitor handling the s21 position.
   ============================================================ */
*{box-sizing:border-box}

.stage{
  /* `clip`, NOT `hidden`, and it matters: overflow:hidden makes this section a
     SCROLL CONTAINER, and the phones' `animation-timeline: view()` then
     measures against a box that never scrolls — so the scroll choreography
     freezes mid-pose and never advances. overflow:clip clips identically
     without creating a scroll container, so the timeline resolves against the
     page. Anything using view() must have no overflow:hidden/auto/scroll
     ancestor between it and the real scroller. */
  position:relative;overflow:clip;
  padding:clamp(56px,9vw,110px) 20px clamp(48px,7vw,90px);
  background:
    radial-gradient(120% 80% at 50% 8%,  rgba(23,91,69,.55) 0%, rgba(12,53,42,0) 62%),
    radial-gradient(90%  70% at 50% 100%,rgba(17,74,60,.45) 0%, rgba(12,53,42,0) 70%),
    var(--deep);
}
/* faint film grain, as in the spot */
.stage::after{
  content:"";position:absolute;inset:0;pointer-events:none;opacity:.05;
  background-image:radial-gradient(rgba(255,255,255,.7) .5px,transparent .5px);
  background-size:3px 3px;
}
.inner{max-width:1120px;margin:0 auto;position:relative;z-index:1;text-align:center}

h2.kicker{
  font:400 clamp(30px,5.2vw,52px)/1.16 var(--serif);
  margin:0 0 18px;letter-spacing:-.01em;text-wrap:balance;color:var(--cream);
}
h2.kicker em{font-style:italic;color:var(--gold-lt)}
.rule{width:54px;height:2px;background:var(--gold);margin:0 auto 14px;border-radius:2px}
.eyebrow{
  font:500 12px/1 var(--sans);letter-spacing:.22em;text-transform:uppercase;
  color:var(--gold-lt);margin:0 0 20px;
}

/* ---------------- the phones ---------------- */
.phones{
  display:flex;justify-content:center;align-items:flex-end;
  gap:clamp(-40px,-2vw,0px);margin:clamp(26px,4vw,44px) auto clamp(22px,3vw,34px);
  /* The perspective was already here and doing NOTHING, because the phones
     only ever used a flat 2D rotate(). Giving them real rotateY/translateZ is
     what turns three overlapping rectangles into three objects standing in a
     space — you start seeing their edges, and the gold hairline on each one
     becomes a lit edge rather than a border. */
  perspective:1400px;
  perspective-origin:50% 42%;
}
.phone{
  --w:clamp(190px,23vw,268px);
  width:var(--w);aspect-ratio:9/19.5;flex:none;position:relative;
  border-radius:calc(var(--w)*.14);
  background:linear-gradient(160deg,#2b3f38,#101f1a 60%);
  padding:calc(var(--w)*.028);
  box-shadow:
    0 2px 3px rgba(0,0,0,.5),
    0 30px 60px -22px rgba(0,0,0,.75),
    0 0 0 1px rgba(216,188,130,.14);
  transform-style:preserve-3d;
  /* NOTE the float uses `translate`, NOT `transform`. That separation is
     load-bearing: it leaves `transform` free for the 3D pose below, so the
     idle bob and the scroll movement never fight over one property. */
  animation:float 7s ease-in-out infinite;
}
.phone.side{display:none}

/* The resting pose. This is what everyone sees if the scroll animation below
   is unsupported or switched off, so it has to be the good composition on its
   own — the movement is a bonus, never the thing that makes it work. */
.phone.left {
  --w:clamp(150px,17vw,206px); z-index:1; opacity:.86; animation-delay:-2.3s;
  transform:rotateY(24deg) rotateX(4deg) translateZ(-70px) rotate(-3deg) translateY(26px);
}
.phone.right{
  --w:clamp(150px,17vw,206px); z-index:1; opacity:.86; animation-delay:-4.6s;
  transform:rotateY(-24deg) rotateX(4deg) translateZ(-70px) rotate(3deg) translateY(26px);
}
.phone.main{
  z-index:2;
  transform:rotateY(0deg) rotateX(2deg) translateZ(20px);
}
@media (min-width:820px){ .phone.side{display:block} }

/* The side phones are depth, not content. Fill them so they are not blank
   slabs, then blur and shade them so the eye stays on the middle one. */
.phone.side .screen{filter:blur(1.6px) saturate(.92)}
.phone.side .track{animation:none}
.phone.side .screen::after{
  content:"";position:absolute;inset:0;z-index:4;pointer-events:none;
  background:linear-gradient(180deg,rgba(12,53,42,.34),rgba(12,53,42,.52));
}

@keyframes float{
  0%,100%{ translate:0 0 }
  50%    { translate:0 -13px }
}

/* ---------------- scroll choreography ---------------------------------------
   The three phones start further back and more steeply angled, then swing
   round and forward into their resting pose as the section comes up the
   screen. Scroll position drives it directly, so it tracks your finger rather
   than playing on a timer.

   DELIBERATELY NO JAVASCRIPT AND NO LIBRARY. This is CSS `animation-timeline:
   view()`, which is the same effect GSAP ScrollTrigger is usually pulled in
   for — and ScrollTrigger means three.js-scale dependencies on a site that
   currently ships as static HTML. Browsers without support simply show the
   resting pose above, which is why that pose had to stand alone.

   `animation-range` runs from the section entering the viewport to it being
   just over half covered, so the movement is finished by the time you are
   actually reading the phones — it does not keep sliding while you look.
-------------------------------------------------------------------------- */
@supports (animation-timeline:view()){
  /* Scroll choreography, in three acts across the whole time the section is on
     screen (`cover 0%` to `cover 100%`):

       IN    0-28%    the phones come up from the right, turned away, well back
                      and small, and swing round to face you
       HOLD  28-70%   they sit still. This is the point of the whole thing —
                      the chat thread is on its own 26s loop, so what you watch
                      during the hold is the room talking, not the animation
       OUT   70-100%  they turn away again and slide off to the left as the
                      section leaves the top of the screen

     The hold is the longest act deliberately. An effect that never rests gives
     you nothing to read; the movement exists to deliver the phones and then
     get out of the way.

     Each phone has its own stop percentages, so they arrive and leave one
     after another rather than moving as a block. `.stage` is overflow:clip, so
     they slide out of the section's own edge and never widen the page.
  */
  @media (prefers-reduced-motion:no-preference){
    .phone{ animation:float 7s ease-in-out infinite, actNarrow linear both;
            animation-timeline:auto, view();
            /* LONGHANDS, and `normal` not `auto` for the float's slot —
               `animation-range: auto, ...` is invalid and voids silently. */
            animation-range-start:normal, cover 0%;
            animation-range-end:normal, cover 100%; }
  }
  @media (prefers-reduced-motion:no-preference) and (min-width:820px){
    .phone.main { animation-name:float, actM }
    .phone.left { animation-name:float, actL }
    .phone.right{ animation-name:float, actR }
  }

  @keyframes actM{
    0%   { transform:rotateY(-30deg) rotateX(15deg) translateX(210px) translateY(64px) translateZ(-330px) scale(.84); opacity:.30 }
    28%  { transform:rotateY(0deg)   rotateX(2deg)  translateX(0)     translateY(0)    translateZ(20px)   scale(1);   opacity:1 }
    70%  { transform:rotateY(0deg)   rotateX(2deg)  translateX(0)     translateY(0)    translateZ(20px)   scale(1);   opacity:1 }
    100% { transform:rotateY(34deg)  rotateX(10deg) translateX(-330px) translateY(-46px) translateZ(-320px) scale(.82); opacity:0 }
  }
  @keyframes actL{
    0%   { transform:rotateY(58deg) rotateX(16deg) translateX(170px)  translateY(86px) translateZ(-390px) rotate(-10deg); opacity:.16 }
    32%  { transform:rotateY(24deg) rotateX(4deg)  translateX(0)      translateY(26px) translateZ(-70px)  rotate(-3deg);  opacity:.86 }
    66%  { transform:rotateY(24deg) rotateX(4deg)  translateX(0)      translateY(26px) translateZ(-70px)  rotate(-3deg);  opacity:.86 }
    100% { transform:rotateY(66deg) rotateX(10deg) translateX(-430px) translateY(-24px) translateZ(-400px) rotate(-13deg); opacity:0 }
  }
  @keyframes actR{
    0%   { transform:rotateY(-58deg) rotateX(16deg) translateX(300px)  translateY(86px) translateZ(-390px) rotate(10deg); opacity:.16 }
    36%  { transform:rotateY(-24deg) rotateX(4deg)  translateX(0)      translateY(26px) translateZ(-70px)  rotate(3deg);  opacity:.86 }
    74%  { transform:rotateY(-24deg) rotateX(4deg)  translateX(0)      translateY(26px) translateZ(-70px)  rotate(3deg);  opacity:.86 }
    100% { transform:rotateY(6deg)   rotateX(10deg) translateX(-300px) translateY(-34px) translateZ(-380px) rotate(-8deg); opacity:0 }
  }
  /* one phone, centred: the turn is smaller so it does not read as toppling,
     but the push back, the rise and the slide off are just as big */
  @keyframes actNarrow{
    0%   { transform:rotateY(-22deg) rotateX(14deg) translateX(140px)  translateY(56px) translateZ(-280px) scale(.86); opacity:.30 }
    28%  { transform:rotateY(0deg)   rotateX(2deg)  translateX(0)      translateY(0)    translateZ(0)      scale(1);   opacity:1 }
    70%  { transform:rotateY(0deg)   rotateX(2deg)  translateX(0)      translateY(0)    translateZ(0)      scale(1);   opacity:1 }
    100% { transform:rotateY(26deg)  rotateX(10deg) translateX(-230px) translateY(-40px) translateZ(-270px) scale(.84); opacity:0 }
  }
}

.screen{
  position:relative;height:100%;width:100%;overflow:hidden;
  border-radius:calc(var(--w)*.115);background:var(--paper);
  display:flex;flex-direction:column;
}
.notch{
  position:absolute;top:calc(var(--w)*.022);left:50%;translate:-50% 0;
  width:34%;height:calc(var(--w)*.075);background:#0a1512;
  border-radius:99px;z-index:5;
}
/* app chrome */
.appbar{
  background:var(--green);color:var(--cream);flex:none;
  padding:calc(var(--w)*.115) calc(var(--w)*.05) calc(var(--w)*.035);
  font-size:calc(var(--w)*.046);
}
.appbar .back{color:var(--gold-lt);font-weight:600}
.appbar .where{opacity:.72;margin-left:.4em}
.roomhdr{
  background:var(--green);color:var(--cream);flex:none;min-width:0;
  display:flex;align-items:center;gap:calc(var(--w)*.038);
  padding:0 calc(var(--w)*.05) calc(var(--w)*.055);
}
.roomav{
  width:calc(var(--w)*.115);height:calc(var(--w)*.115);border-radius:50%;flex:none;
  background:radial-gradient(circle at 34% 30%,#2c5f4e,#0e2f26);
  border:1px solid rgba(216,188,130,.5);
  display:grid;place-items:center;font:600 calc(var(--w)*.045)/1 var(--sans);color:var(--gold-lt);
}
.roomname{font:600 calc(var(--w)*.058)/1.2 var(--sans);white-space:nowrap}
.roomsub{font-size:calc(var(--w)*.038);opacity:.68;margin-top:.15em;white-space:nowrap}
.online{
  margin-left:auto;flex:none;white-space:nowrap;background:rgba(216,188,130,.16);
  border:1px solid rgba(216,188,130,.32);border-radius:99px;
  padding:calc(var(--w)*.016) calc(var(--w)*.042);
  font:500 calc(var(--w)*.038)/1 var(--sans);color:var(--gold-lt);
  display:flex;align-items:center;gap:.45em;
}
.online i{width:.42em;height:.42em;border-radius:50%;background:#5FBF9B;display:block}

/* ---------------- the scrolling thread ---------------- */
.thread{position:relative;flex:1;overflow:hidden;background:var(--paper)}
.thread::before,.thread::after{
  content:"";position:absolute;left:0;right:0;height:12%;z-index:3;pointer-events:none;
}
.thread::before{top:0;background:linear-gradient(var(--paper),rgba(248,244,236,0))}
.thread::after{bottom:0;background:linear-gradient(rgba(248,244,236,0),var(--paper))}

.track{
  display:flex;flex-direction:column;text-align:left;
  padding:calc(var(--w)*.04) calc(var(--w)*.05);
  animation:scrollup 26s linear infinite;
}
@keyframes scrollup{
  from{ transform:translateY(0) }
  to  { transform:translateY(-50%) }   /* list is duplicated, so -50% loops seamlessly */
}
.phone:hover .track,.stage:focus-within .track{animation-play-state:paused}

.msg{display:flex;gap:calc(var(--w)*.035);margin-bottom:calc(var(--w)*.055)}
.av{
  width:calc(var(--w)*.105);height:calc(var(--w)*.105);border-radius:50%;flex:none;
  display:grid;place-items:center;color:#fff;
  font:600 calc(var(--w)*.042)/1 var(--sans);
}
.av.c{background:linear-gradient(150deg,#7a6a52,#4d4034)}
.av.m{background:linear-gradient(150deg,#3f5f52,#22392f)}
.av.d{background:linear-gradient(150deg,#6b5540,#3d3125)}
.who{font:600 calc(var(--w)*.046)/1.2 var(--sans);color:var(--green-lt)}
.at{font:400 calc(var(--w)*.037)/1.2 var(--sans);color:#94a09a;margin-left:.5em}
.said{
  font:400 calc(var(--w)*.047)/1.45 var(--sans);color:var(--ink);
  margin-top:.25em;
}
.said + .said{margin-top:.5em}

/* live $TICKER chip - the app resolves a ticker inside a message to a
   quote. See the note at the top of this file before changing it. */
.tick{
  display:inline-flex;align-items:baseline;gap:.45em;white-space:nowrap;
  background:#FBE9E6;border:1px solid rgba(176,58,42,.16);border-radius:6px;
  padding:.08em .45em;margin:0 .1em;vertical-align:baseline;
  font:600 calc(var(--w)*.044)/1.35 var(--sans);color:var(--ink);
}
.tick .mv{color:#B03A2A;font-weight:600}

.composer{
  flex:none;background:var(--paper);border-top:1px solid rgba(32,48,42,.1);
  display:flex;align-items:center;gap:calc(var(--w)*.035);
  padding:calc(var(--w)*.045) calc(var(--w)*.05);
}
.field{
  flex:1;background:#EFE9DD;border-radius:99px;
  padding:calc(var(--w)*.032) calc(var(--w)*.05);
  font:400 calc(var(--w)*.042)/1 var(--sans);color:#8d968f;
}
.send{
  width:calc(var(--w)*.09);height:calc(var(--w)*.09);border-radius:50%;flex:none;
  background:var(--gold);display:grid;place-items:center;
  font:700 calc(var(--w)*.045)/1 var(--sans);color:#fff;
}

/* ---------------- caption + risk ---------------- */
.caption{
  font:400 clamp(17px,2.2vw,22px)/1.5 var(--serif);color:var(--cream);
  margin:0 auto;max-width:32ch;
}
.caption b{color:var(--gold-lt);font-weight:500}
.risk{
  font:400 12.5px/1.6 var(--sans);color:rgba(253,249,240,.52);
  max-width:60ch;margin:clamp(22px,3vw,34px) auto 0;
}
/* Sits with the risk line wherever a screenshot shows a price. If this
   component is reused, this sentence travels with it. */
.risk .illus{display:block;margin-bottom:.5em;color:rgba(253,249,240,.62)}

@media (prefers-reduced-motion:reduce){
  .track{animation:none}
  .phone{animation:none}
}

/* ---------------- legal pages ----------------
   The four legal pages carry long verbatim prose from the previous site.
   Body text is deliberately narrower and a shade smaller than marketing copy. */
.legal{font-size:15.5px}
.legal p{margin:0 0 18px}
.legal h3{margin:38px 0 14px}
.legal h3:first-child{margin-top:0}
.legal ul{margin:0 0 18px;padding-left:1.2em}
.legal li{margin:0 0 10px}
.legal a{color:var(--gold);text-decoration:underline;text-underline-offset:2px}
.legal-updated{color:var(--muted);font-size:14px;letter-spacing:.01em}

/* ---------- the store block (sign-up panel 3, /get-the-app) ----------
   One markup, three layouts, chosen by data-platform on <html> (js/store.js):
   the visitor's own store first and full width, the other underneath as the
   secondary; a desktop gets both, side by side, and the browser link. */
.storeblock{max-width:520px;margin:30px auto 0;display:grid;gap:12px}
.storeblock .storebtn{width:100%}
.storeblock .web{display:none;font-size:14.5px;text-align:center;margin:6px 0 0}
.storeblock .web a{color:var(--gold-lt);text-decoration:underline;text-underline-offset:2px}
html[data-platform="ios"] .storeblock .android,
html[data-platform="android"] .storeblock .ios{order:2;background:transparent;border-color:rgba(253,249,240,.4);color:var(--cream)}
html[data-platform="ios"] .storeblock .android:hover,
html[data-platform="android"] .storeblock .ios:hover{border-color:var(--gold-lt);color:var(--gold-lt)}
html[data-platform="desktop"] .storeblock{grid-template-columns:1fr 1fr}
html[data-platform="desktop"] .storeblock .web{display:block;grid-column:1/-1}
@media(max-width:560px){ html[data-platform="desktop"] .storeblock{grid-template-columns:1fr} }
/* /desktop: Mac + Windows side by side, both always shown. The page's inline UA check sets data-dl on the
   block: that platform's button goes first, the other becomes the outline secondary. Stacks on phones. */
.dlblock{grid-template-columns:1fr 1fr}
.dlblock .web{display:block;grid-column:1/-1}
.dlblock[data-dl="win"] .win{order:-1}
.dlblock[data-dl="mac"] .win,
.dlblock[data-dl="win"] .mac{background:transparent;border-color:rgba(253,249,240,.4);color:var(--cream)}
.dlblock[data-dl="mac"] .win:hover,
.dlblock[data-dl="win"] .mac:hover{border-color:var(--gold-lt);color:var(--gold-lt)}
@media(max-width:560px){ .dlblock{grid-template-columns:1fr} }
/* the light bands (the sign-up panels sit on a deep band; /get-the-app on cream) */
.band-cream2 .storeblock .web a{color:var(--green)}
.band-cream2 .storeblock .android, .band-cream2 .storeblock .ios{color:var(--cream)}
html[data-platform="ios"] .band-cream2 .storeblock .android,
html[data-platform="android"] .band-cream2 .storeblock .ios{border-color:var(--green);color:var(--green)}

/* ---------- /sign-up — the one-page form, then "you're in" (plus the waiting list when full) ---------- */
.su-panel{display:none}
.su-panel.on{display:block}
.su-steps{display:flex;gap:6px;justify-content:center;margin:0 0 26px}
.su-steps i{width:28px;height:4px;border-radius:99px;background:rgba(253,249,240,.2)}
.su-steps i.on{background:var(--gold)}
.signup .flabel{display:block;text-align:left;font:500 11.5px/1 var(--sans);letter-spacing:.18em;text-transform:uppercase;color:var(--gold-lt);margin:6px 0 -4px 20px}
.signup input[type="date"]{color-scheme:dark;-webkit-appearance:none;appearance:none}
.signup input[type="date"]:invalid{color:rgba(253,249,240,.45)}
/* ATTRIB-V1 — the "Where did you hear about us?" select, dressed exactly as the inputs, with its own
   gold chevron (the native one is grey on the dark ground). :invalid is the disabled "Choose one"
   placeholder still selected, dimmed like a placeholder; color-scheme:dark keeps the dropped-down
   list dark in Chrome and Firefox (Safari and the phones draw their own picker). */
.signup select{
  height:54px;width:100%;padding:0 50px 0 20px;border-radius:99px;border:1.5px solid rgba(253,249,240,.22);
  background:rgba(253,249,240,.06) url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23D8BC82' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 20px center/16px 16px;
  color:var(--cream);font:400 15px/1 var(--sans);color-scheme:dark;cursor:pointer;
  -webkit-appearance:none;appearance:none;
}
.signup select:focus{outline:none;border-color:var(--gold-lt)}
.signup select:invalid{color:rgba(253,249,240,.45)}
.signup select option{color:var(--cream);background:#0C352A}
.signup select option[disabled]{color:rgba(253,249,240,.45)}
.su-agree{display:flex;gap:12px;align-items:flex-start;text-align:left;max-width:520px;margin:26px auto 0;font:400 15px/1.55 var(--sans);color:rgba(253,249,240,.86);cursor:pointer}
.su-agree input{flex:0 0 auto;width:19px;height:19px;margin:3px 0 0;accent-color:var(--gold);cursor:pointer}
.su-agree a{color:var(--gold-lt);text-decoration:underline;text-underline-offset:2px}
/* the terms tick now sits INSIDE the one-page form (30 Sept 2026), so it has to be undressed
   from `.signup input` (pill height, padding, border, fill) — 0,2,1 beats 0,1,1 */
.signup .su-agree{margin:8px 0 4px;padding:0 6px;font-size:14px}
.signup .su-agree input{height:19px;width:19px;padding:0;border:0;border-radius:0;background:none}
.su-done{font:500 clamp(28px,4vw,40px)/1.15 var(--serif);color:var(--cream);margin:22px 0 0}
.su-done em{color:var(--gold-lt)}

/* ---------- footer: the admin door — a plain link, the last thing on the page ---------- */
.fadmin{margin:18px 0 0;font-size:12.5px;text-align:center}
.fadmin a{color:rgba(253,249,240,.45);text-decoration:none}
.fadmin a:hover{color:var(--gold-lt);text-decoration:underline;text-underline-offset:2px}

/* ---------- /sign-up — when every place is taken (CAP-FULL-V1) ---------- */
/* the few-places-left line, under the p1 lede and the p2 heading; hidden unless 0 < left < 20 */
.su-left{font:500 14px/1.5 var(--sans);letter-spacing:.02em;color:var(--gold-lt);text-align:center;margin:14px 0 0}
/* held back for the one spaces_left read at load, so a full site never flashes the terms panel.
   The script lifts it on the answer, or after a short wait — a slow read gets today's page. */
.su-wait .su-panel,.su-wait .su-steps{visibility:hidden}
