/* ==========================================================================
   JakeScalesAI
   Transcribed from design/JakeScalesAI Landing.dc.html
   Mobile hero = option 1a. Desktop hero = option 2a. Results = 4a.
   Popups = 3a (Learn With Me) and 3b (Your Free Toolkit).
   Colours, type, radii and timings all come from that canvas.
   ========================================================================== */

:root{
  /* palette, straight from the canvas */
  --cream:#fdfaf0;
  --ink:#221c10;
  --ink-hover:#33301f;
  --muted:#6e6450;
  --terracotta:#b45f2a;
  --terracotta-hover:#9c4f20;
  --line:#e8dfc6;
  --white:#ffffff;
  --faint:#a39a78;
  --stripe-a:#f3edda;
  --stripe-b:#f8f3e4;
  --stripe-dark-a:#2c2517;
  --stripe-dark-b:#332b1b;
  --track:#f0ead6;

  --font:'SF Pro Display',-apple-system,BlinkMacSystemFont,sans-serif;

  --shadow-cta-dark:0 6px 16px rgba(29,26,16,.22);
  --shadow-cta-terra:0 6px 16px rgba(180,95,42,.28);
  --shadow-dialog:0 24px 60px rgba(29,26,16,.28);

  /* motion */
  --ease-out:cubic-bezier(.16,1,.3,1);
  --ease-canvas:cubic-bezier(.4,.1,.2,1);
  --t-press:90ms;
  --t-feedback:180ms;
  --t-state:240ms;
  --t-view:600ms;

  /* rotating word: canvas speedMs 2200 x 6 words */
  --rot-step:2.2s;
  --rot-cycle:13.2s;

  --u:1px; /* desktop scale unit, set in the desktop query */
}

*,*::before,*::after{box-sizing:border-box}

html,body{min-height:100%}   /* min, so a tall hero can extend the page */
body{
  margin:0;
  background:var(--cream);
  color:var(--ink);
  font-family:var(--font);
  -webkit-font-smoothing:antialiased;
}

.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

:focus-visible{
  outline:2px solid var(--terracotta);
  outline-offset:3px;
  box-shadow:0 0 0 6px rgba(180,95,42,.12);
  transition:box-shadow var(--t-feedback) ease;
}

button{font-family:inherit}

/* brand selection: the default grey reads as a glitch against cream */
::selection{background:rgba(180,95,42,.85);color:#fdfaf0}
input::selection,textarea::selection{background:rgba(180,95,42,.28);color:inherit}


/* drawn icons, one consistent stroke */
.ico{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;
     stroke-linecap:round;stroke-linejoin:round;display:block}
.ico-sm{width:14px;height:14px;display:inline-block;vertical-align:-2px}

/* view continuity: the entering view arrives from the side it came from,
   mirroring the canvas's horizontal landing <-> results slide */
/* page-slide: enter from one edge while the old page leaves by the other */
/* distances are viewport-based: the views are narrow centred columns, so a
   percentage of their own width would strand them mid-screen */
@keyframes view-in-right{from{transform:translate3d(100vw,0,0)}to{transform:none}}
@keyframes view-in-left{from{transform:translate3d(-100vw,0,0)}to{transform:none}}
@keyframes view-out-left{from{transform:none}to{transform:translate3d(-100vw,0,0)}}
@keyframes view-out-right{from{transform:none}to{transform:translate3d(100vw,0,0)}}
.view-enter-fwd{animation:view-in-right var(--t-view) var(--ease-canvas) both}
.view-enter-back{animation:view-in-left var(--t-view) var(--ease-canvas) both}
.view-leave-fwd{animation:view-out-left var(--t-view) var(--ease-canvas) both}
.view-leave-back{animation:view-out-right var(--t-view) var(--ease-canvas) both}
.view-pinned{position:absolute;top:0;left:0;right:0;pointer-events:none}
body{position:relative;overflow-x:clip}   /* the sliding pages never widen the page */
/* no scrollbar flicker while the pages travel */
html.view-sliding{overflow-y:clip}
.view[hidden]{display:none}

/* ==========================================================================
   HERO — mobile (canvas 1a) is the base; desktop (2a) is the media query
   ========================================================================== */
.view-hero{
  display:flex;
  flex-direction:column;
  width:100%;
  max-width:430px;
  margin:0 auto;
  /* MIN-height, not height: on a normal window this is exactly one screen
     and the video absorbs the slack, but on a short one the hero grows to
     whatever it needs and the page scrolls instead of clipping the panel.
     The 560px floor stops a very short window crushing the hero into a
     strip; max() keeps both floors in one declaration. */
  min-height:max(560px, 100svh);
  /* no overflow:hidden here. That was what cut the video panel off rather
     than letting the page scroll to it. */
  overflow-x:clip;
  padding:clamp(16px, calc(6.67svh - 26.67px), 28px) 24px 0;
}

/* --------------------------------------------------------------------------
   FITTING THE HERO INTO A PHONE
   The escape hatch above was never meant to fire on an ordinary phone, but it
   fired on every one of them. Measured at 375 wide: the hero's smallest
   possible content was 803px, because every vertical number in it was fixed.
   No phone browser has 803px to give. A device that reports 812 CSS px of
   screen only leaves about 635 for the page once Safari's own bars are on
   screen, and 100svh is exactly that smaller number, so the hero always
   outgrew the viewport and the page always scrolled.
   So the fixed numbers become a ramp. Every clamp below reads
     clamp(FLOOR, calc(A * 1svh + OFFSET), DESIGN)
   and is solved so the value IS the design number at 100svh = 820px and has
   reached its floor by 100svh = 640px. A tall window is untouched, a phone
   compresses smoothly, and a window shorter than the floors still scrolls
   rather than clipping, which is what the hatch was for.
   -------------------------------------------------------------------------- */

/* Three columns rather than flex + space-between: with a 4-letter pill on one
   side and a 7-letter one on the other, space-between centres the wordmark
   between THEM, which puts it off the centre of the page. 1fr auto 1fr pins it
   to the middle column and lets the pills take whatever they need either
   side. */
.m-topbar{
  display:grid;
  grid-template-columns:1fr auto 1fr;
  align-items:center;
  gap:10px;
  flex:none;
}
.m-topbar .pill-blog{justify-self:start}
.m-topbar .pill-m:last-child{justify-self:end}
/* .pill carries a 16px bottom margin for its old home above the headline.
   Inside a bar that margin is just a lopsided row. */
.m-topbar .pill{margin-bottom:0}
.d-topbar{display:none}

.wordmark{font-weight:700;letter-spacing:-.02em;color:var(--ink);line-height:1}
.wordmark-m{font-size:15px}
.wordmark-d{font-size:calc(18 * var(--u))}
.wordmark-ai{color:var(--terracotta)}

/* Mobile rhythm: `margin-top:auto` sends ALL leftover height to this one
   place, above the headline, so the CTA-to-video gap below stays exactly 24px
   at every viewport instead of stretching. padding-top is the floor. */
.hero-center{
  text-align:center;margin-top:auto;flex:none;
  padding-top:clamp(0px, calc(24.44svh - 156.44px), 44px);
}

/* "See our Results" pill */
.pill{
  display:inline-flex;align-items:center;gap:6px;
  height:32px;padding:0 14px;border-radius:999px;
  background:var(--white);border:1px solid var(--line);
  color:var(--muted);
  font:500 13px/1 var(--font);
  text-decoration:none;
  margin-bottom:16px;
  transition:border-color var(--t-feedback) ease,color var(--t-feedback) ease,
             transform var(--t-feedback) var(--ease-out);
}
.pill:hover{transform:translate3d(0,-1px,0)}
.pill:active{transform:translate3d(0,0,0) scale(.985);transition-duration:var(--t-press)}
.pill span{transition:transform var(--t-feedback) var(--ease-out)}
.pill:hover span{transform:translate3d(3px,0,0)}
.pill-m:hover{border-color:var(--ink);color:var(--ink)}
/* The arrow follows the direction of travel. Blog is to the LEFT, so its
   arrow leans left on hover; the generic .pill rule pushes it right. */
.pill-blog:hover span{transform:translate3d(-3px,0,0)}
.pill-blog:hover{border-color:var(--ink);color:var(--ink)}
/* The Results pill moved out of .hero-center and into .m-topbar on 09-03, when
   Blog joined it there. The ramp that used to hold it off the headline is gone
   with it: the ~48px it occupied now flows into .hero-center's `margin-top:auto`,
   so the hero has MORE room than before and the no-scroll floor can only have
   improved. */
.pill-d{display:none}
/* results page back control: same pill, arrow on the left, no bottom margin */
.pill-back{margin-bottom:0;cursor:pointer}
.pill-back:hover{border-color:var(--ink);color:var(--ink)}
.pill-back:hover span{transform:translate3d(-3px,0,0)}

/* headline */
.hero-h1{margin:0;font-weight:400}
.hero-h1-static{
  display:block;
  font:700 clamp(42px, calc(5.56svh + 6.44px), 52px)/1.05 var(--font);
  letter-spacing:-.035em;
  color:var(--ink);
}

/* Rotating word. Fixed box, absolutely stacked words: the width never changes,
   so the line cannot reflow. Pure CSS keyframes, so nothing can stall it. */
.rotator{
  display:block;
  position:relative;
  overflow:hidden;
  /* the box stays taller than the word's own line box at both ends of the
     ramp, so a compressed word is never clipped by its own frame */
  height:clamp(48px, calc(6.67svh + 5.33px), 60px);
  margin-top:2px;
}
.rot-word{
  position:absolute;left:0;right:0;text-align:center;
  font:700 clamp(42px, calc(5.56svh + 6.44px), 52px)/1.1 var(--font);
  letter-spacing:-.035em;
  color:var(--terracotta);
  opacity:0;
  will-change:transform,opacity;
  animation:rot var(--rot-cycle) linear infinite both;
  animation-delay:calc(var(--i) * var(--rot-step));
}
/* one word holds for 2.2s of a 13.2s cycle: in over 4.2%, hold to 16.7%, out by 20.8% */
@keyframes rot{
  0%     {opacity:0;transform:translate3d(0,110%,0)}
  4.17%  {opacity:1;transform:translate3d(0,0,0)}
  16.67% {opacity:1;transform:translate3d(0,0,0)}
  20.83% {opacity:0;transform:translate3d(0,-110%,0)}
  100%   {opacity:0;transform:translate3d(0,-110%,0)}
}

.hero-sub{
  margin:clamp(8px, calc(3.33svh - 13.33px), 14px) auto 0;
  max-width:300px;
  /* Jake's call: the lead-in is a size smaller than the closing phrase so the
     wrap lands where he wants it. It also buys back a line of height on a
     phone, which the hero needs. */
  font:400 15.5px/1.5 var(--font);
  color:var(--muted);
  text-wrap:pretty;
}

/* CTAs */
.hero-ctas{
  display:flex;flex-direction:column;gap:10px;padding:0 8px;flex:none;
  margin-top:clamp(12px, calc(7.78svh - 37.78px), 26px);
}
/* the two hero buttons ride the ramp; every other .btn-primary on the site,
   dialogs included, keeps its own fixed height */
.hero-ctas .btn{height:clamp(46px, calc(3.33svh + 24.67px), 52px)}
/* "N spots left!" sticker on the primary CTA's top-left corner. Lives inside
   the button, so clicking it opens Learn With Me like the rest of the button. */
.btn-primary{position:relative}
.spots-tag{
  /* -14 rather than -4: the sticker reaches up into the subtitle's last line,
     and at 375 wide the pill was landing on the first letter of "this is for
     you." Ten pixels further left clears the centred line at every phone
     width and the arrow still crosses the button's top-left corner, which is
     the whole point of it. Desktop sets its own offset below.
     The 7px gap is on the hero ramp too, for the reason the ramp exists. This
     sticker hangs ABOVE the button, so it eats into the subtitle's last line
     and pays nothing for it: no layout box knows it is there. On a tall phone
     the CTA block's own 26px top margin covers that reach, but the ramp takes
     that margin down to 12px on a short one, and the pill then lands on the
     closing line. Measured on main at 375x635: the pill sat 11.1px into it,
     and at 320x568 it covered the whole line. So the gap and the pill's own
     size compress on the same ramp as everything else, which buys back 13px
     of reach and costs the layout nothing. Coupled to the CTA margin below:
     raise that floor and this can relax again. */
  position:absolute;left:-14px;
  bottom:calc(100% + clamp(0px, calc(3.89svh - 24.89px), 7px));
  display:flex;flex-direction:row;align-items:flex-start;gap:3px;
  pointer-events:auto;cursor:pointer;  /* part of the button: hover and click land on it */
  transform:rotate(-4deg);
  color:var(--ink);
  z-index:2;
}
.spots-pill{
  display:inline-block;
  /* on the same ramp as the gap above, and for the same reason: a smaller
     pill is a shorter reach into the subtitle. Design values at 100svh 820,
     floors by 640. */
  padding:clamp(4px, calc(1.11svh - 3.11px), 6px)
          clamp(9px, calc(1.67svh - 1.67px), 12px);
  border-radius:999px;
  background:var(--ink);color:var(--cream);
  font:700 clamp(11.5px, calc(0.83svh + 6.2px), 13px)/1 var(--font);
  letter-spacing:.01em;
  white-space:nowrap;
  box-shadow:0 2px 8px rgba(29,26,16,.18);
}
/* the arrow sits left of the pill and hooks down-right at the button's
   top-left corner */
/* The arrow, not the pill, is what decides how far this sticker reaches: the
   tag is a flex-start row, so the pill hangs from the tag's top and the tag is
   as tall as the arrow's 17px offset plus its 22px body. Shrinking the pill
   alone moved the overlap by 7px of the 11 that was needed and no further,
   because the pill's top never moved. So the arrow rides the ramp too, and the
   hook still crosses the button's top-left corner because the offset and the
   body come down together. */
.spots-arrow{
  width:clamp(17px, calc(2.778svh - 0.78px), 22px);
  height:clamp(17px, calc(2.778svh - 0.78px), 22px);
  flex:none;
  margin-top:clamp(12px, calc(2.778svh - 5.78px), 17px);
  margin-right:-3px;
}
/* Below 375 the sticker cannot solve this sideways. The closing line is a
   fixed 94px centred in the column, so the narrower the phone the closer its
   first glyph comes to the pill; at 320 the pill would have to start 9px off
   the left of the screen to clear it. So these widths take the compressed end
   of the ramp above at every height, which puts the sticker beside the button
   rather than up in the paragraph, and 8px further left on top. Measured at
   320, 340 and 361 by 568 through 896: no contact anywhere. */
@media (max-width:374px){
  .spots-tag{left:-22px;bottom:100%}
  .spots-pill{padding:4px 9px;font-size:11.5px}
  .spots-arrow{width:17px;height:17px;margin-top:12px}
}
@media (min-width:900px){
  .spots-tag{left:calc(-18 * var(--u));bottom:calc(100% + 8 * var(--u))}
  .spots-pill{font-size:calc(13.5 * var(--u));padding:calc(6 * var(--u)) calc(12 * var(--u))}
  .spots-arrow{width:calc(22 * var(--u));height:calc(22 * var(--u));margin-top:calc(17 * var(--u))}
}
.btn{
  display:flex;align-items:center;justify-content:center;gap:8px;
  border-radius:14px;
  text-decoration:none;
  cursor:pointer;
  transition:background var(--t-state) ease,border-color var(--t-state) ease,
             color var(--t-state) ease,box-shadow var(--t-state) ease,
             transform var(--t-feedback) var(--ease-out);
}
.btn:hover{transform:translate3d(0,-1px,0)}
.btn:active{transform:translate3d(0,1px,0) scale(.99);transition-duration:var(--t-press)}
.btn-arrow{font-size:17px;transition:transform var(--t-feedback) var(--ease-out)}
/* Sending state. The pause this covers is DELIBERATE and perceptual: the
   request leaves on the click, but turning the screen over in the same frame
   read as nothing having happened, so the button holds for a beat and says so.
   The spinner replaces the arrow rather than sitting beside it, so the button
   keeps its width and the row does not shift. */
.btn-spin{display:none;width:16px;height:16px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:btn-spin .62s linear infinite}
.btn.is-sending{pointer-events:none}
.btn.is-sending .btn-arrow{display:none}
.btn.is-sending .btn-spin{display:inline-block}
@keyframes btn-spin{to{transform:rotate(360deg)}}
.btn:hover .btn-arrow{transform:translate3d(3px,0,0)}
.btn-primary{
  height:52px;border:none;
  background:var(--ink);color:var(--cream);
  font:600 16px/1 var(--font);
  box-shadow:var(--shadow-cta-dark);
}
.btn-primary:hover{background:var(--ink-hover);box-shadow:0 10px 22px rgba(29,26,16,.28)}
.btn-secondary{
  height:52px;
  background:var(--white);border:1.5px solid var(--line);
  color:var(--ink);
  font:600 16px/1 var(--font);
}
.btn-secondary:hover{border-color:var(--ink);color:var(--ink)}

/* --------------------------------------------------------------------------
   VIDEO — one rule for both layouts.
   The wrap absorbs all free vertical space and the player fills it at its own
   aspect ratio, so leftover room grows the video instead of opening a gap.
   -------------------------------------------------------------------------- */
/* Mobile: the panel is full bleed to the column edges (canvas 1a) and the
   video is width-led at 16:9, so it takes all the width available. The gap
   above it is a fixed 24px; leftover height lives above the headline. */
.hero-video-wrap{
  flex:none;
  /* tightened from 24px: the legal row now lives inside the panel, so the
     panel starts a little higher to pay for it */
  padding-top:clamp(8px, calc(3.33svh - 13.33px), 14px);
  width:calc(100% + 48px);
  margin-left:-24px;
  margin-right:-24px;
  display:flex;justify-content:center;align-items:flex-end;
}
.video-panel{
  position:relative;               /* anchors the absolute legal row */
  width:100%;
  /* The video is width-led, so on a phone its height is decided by the column
     width and nothing else, and 16:9 across a full-bleed 390px column is 205px
     the hero does not have. Capping the PANEL's width is how the picture is
     given a height budget without breaking its ratio: the player still fills
     the panel at 16:9, the panel just stops being full bleed on a viewport
     too short to afford it. 26px is the panel's own 12px sides plus its
     hairline border, so the number in the cap is the picture's height.
     A tall phone never reaches the cap and stays edge to edge. */
  max-width:min(100%, calc(clamp(148px, calc(51.11svh - 183px), 240px) * 16 / 9 + 26px));
  display:flex;
  border-radius:28px 28px 0 0;
  overflow:hidden;
  background:var(--white);
  border:1px solid var(--line);
  border-bottom:none;
  /* extra bottom padding is the room the legal row sits in */
  /* ONE number owns the footer's room. The panel reserves this band below the
     video and the footer fills exactly it, so the space above the controls and
     the space below them are the same by construction rather than by two
     numbers that have to be kept in agreement. */
  --foot-band:60px;
  padding:12px 12px var(--foot-band);
  box-shadow:0 -8px 24px rgba(0,0,0,.06);
}

/* Holds the picture. The player is width-led at every size now, so this is a
   centring row and nothing more. */
.hero-player-area{width:100%;display:flex;justify-content:center}

/* Terms and Privacy, sitting under the picture on the panel's white. Quiet
   by design: reachable and honest, never competing with the two CTAs.
   ABSOLUTE, and that is still worth keeping: out of flow the row cannot push
   the picture out of frame however long the wording gets, and the panel's
   bottom padding reserves exactly the band it sits in. */

/* --------------------------------------------------------------------------
   TABLET, HELD UPRIGHT
   Between the phone column and the desktop composition there was nothing, so
   an iPad in portrait was served the phone: a 430px column adrift in 768, a
   52px headline in a 1024px-tall window, and `margin-top:auto` handing every
   one of the leftover pixels to a single band above the headline. Measured on
   768x1024 before this block: 229px of empty cream above the results pill,
   and 385px of it at 820x1180.
   So this tier widens the column, puts the type on a ramp of its own, and
   changes where the slack goes: the video wrap becomes the flexible box, the
   way it already is on desktop, so leftover height grows the picture instead
   of the gap. What the picture cannot use is split between a modest band above
   the headline and the space over the card, rather than all landing in one
   place. Height is in the query because 600-899 CSS px is also where a phone
   in landscape lives, and a phone in landscape wants the opposite of this.
   -------------------------------------------------------------------------- */
@media (min-width:600px) and (max-width:899px) and (min-height:760px){
  .view-hero{
    /* the wrap's full bleed is this column plus the 24px gutters on both
       sides, so the panel is 48px wider than whatever this says */
    max-width:min(700px, 92vw);
    /* height, not only min-height, and it is the size container below that
       needs it: a box whose height comes from a min-height stretch has no
       height to publish, and 100cqh reads 0. Same number the min-height on the
       base rule already resolves to, so nothing moves; a hero too tall for it
       still overflows and the page still scrolls, which is what the base rule
       was protecting. */
    height:max(560px, 100svh);
  }
  /* one number for the headline, and the rotator's frame is derived from it
     rather than tracked alongside it */
  .hero-center{
    --hero-type:clamp(56px, 8.6vw, 76px);
    /* padding is the floor this band never goes below; the auto margin here
       and the one under the CTAs split whatever height the card cannot spend,
       so the slack shows up as two ordinary gaps instead of one dead band.
       See WHERE THE SPARE HEIGHT GOES on the desktop side, same bargain. */
    margin-top:auto;
    padding-top:clamp(0px, calc(16svh - 148px), 96px);
  }
  .hero-h1-static,.rot-word{font-size:var(--hero-type)}
  .rotator{height:calc(var(--hero-type) * 1.16);margin-top:3px}
  .hero-sub{
    margin-top:18px;
    max-width:min(520px, 78%);
    font-size:18px;
  }
  /* side by side: at this width two buttons in a row read as a pair of
     choices, and the row buys the picture a button's worth of height */
  .hero-ctas{
    flex-direction:row;justify-content:center;
    gap:14px;
    margin-top:30px;
    margin-bottom:auto;
    padding:0;
  }
  .hero-ctas .btn{height:58px;padding:0 30px;font-size:17px;border-radius:16px}
  .hero-video-wrap{
    flex:1 1 auto;
    min-height:0;
    padding-top:18px;
    /* the tallest this box can usefully be: this padding, the card's 73px of
       chrome, and a 16:9 picture as wide as the column allows. The column is
       the max-width above and the picture is that less the card's 26px of
       sides; both numbers are named again on the panel rule below. Anything
       taller would be height the card cannot spend, and the two auto margins
       above are what spends it instead. */
    max-height:calc(18px + 73px + (min(700px, 92vw) - 26px) * 9 / 16);
    /* same bargain as the desktop wrap: the card reads the leftover height
       out of this container rather than deciding its own size. See THE CARD
       MEASURES ITS OWN ROOM. */
    container-type:size;
  }
  .video-panel{
    /* 73px is the card's chrome above and below the picture at phone sizes:
       1px top border, 12px padding, and the 60px footer band. 26px is the two
       12px sides plus the two hairlines. Both follow --foot-band and the
       padding on the base rule.
       The floor is the promise that this card is a card: if the leftover
       height ever went to nothing the width would follow it down, and a
       card with no width is the sliver this whole change is about. Below the
       floor the card overflows and the page scrolls, which is the honest
       failure. */
    max-width:max(320px, calc((100cqh - 73px) * 16 / 9 + 26px));
  }
}

/* --------------------------------------------------------------------------
   PHONE, TURNED SIDEWAYS
   A handset in landscape has around 375px of viewport height and the hero's
   smallest honest content is 636, so this is the one shape where the escape
   hatch is meant to fire and the page is meant to scroll. Nothing below tries
   to defeat that. What it does is make the scroll shorter and the fold worth
   looking at: the two CTAs sit side by side, the way they already do on
   desktop, which is a whole button and a gap of height back. Measured at
   812x375: 261px of scroll before, 205 after.
   The width floor keeps this off a small phone held upright, where a row of
   two buttons would be cramped.
   -------------------------------------------------------------------------- */
@media (min-width:560px) and (max-width:899px) and (max-height:540px){
  .view-hero{
    /* 430 was a portrait column and it left the two buttons no room to sit
       beside each other: both labels broke onto a second line. 560 is what
       the pair needs at their own width, and it stops the whole hero reading
       as a phone screenshot pasted into the middle of a wide screen. The
       paragraph keeps its own 300px, so only the button row uses the extra. */
    max-width:560px;
  }
  .hero-ctas{
    flex-direction:row;justify-content:center;
    gap:12px;
  }
  /* they were full-bleed columns a moment ago, so they need their own sides,
     and their own width: a shrinking flex item would break the label again */
  .hero-ctas .btn{flex:none;padding:0 26px;white-space:nowrap}
}

/* ==========================================================================
   POLICY VIEWS. In-page views to the LEFT of the hero, so they use the same
   slide as Results rather than a document navigation. The document itself is
   fetched from /privacy, /terms and /refunds, so the text below is styled
   here but authored there.
   ========================================================================== */
.view-legal{
  width:100%;
  max-width:760px;
  margin:0 auto;
  padding:28px 24px 64px;
}
.legal-topbar{
  display:grid;
  grid-template-columns:1fr auto 1fr;
  align-items:center;
  gap:12px;
}
.legal-topbar .wordmark{grid-column:2;justify-self:center}
.pill-back-right{grid-column:3;justify-self:end;margin-bottom:0;cursor:pointer}
.pill-back-right:hover{border-color:var(--ink);color:var(--ink)}
.pill-back-right:hover span{transform:translate3d(3px,0,0)}


/* --------------------------------------------------------------------------
   BLOG VIEW. Reuses .view-legal's frame -- same width, same top bar, same side
   of the hero -- so the two left-hand views are one layout rather than two
   that happen to look alike.

   The rows themselves are NOT styled here. blog.css owns everything under
   .blog-list and .post, because the generated pages at /blog use the same
   markup and one of the two lists would drift the first time either was
   touched. Anything added here must be about WHERE THE VIEW SITS, not what a
   row looks like.
   -------------------------------------------------------------------------- */
/* The view takes blog.css's frame rather than .view-legal's 760px, so the row
   titles sit on the same vertical as the Back pill above them and the #blog
   view and /blog are the same column at the same width. Declared after
   .view-legal, which it overrides at equal specificity. */
.view-blog{max-width:var(--frame)}

.blog-view-body{margin-top:34px}
/* blog.css sizes these for a standalone page that has its own top padding;
   inside the view the topbar above has already provided it. */
.view-blog .blog-head{padding-top:0}
.view-blog .blog-list{margin-top:22px}
.blog-note{
  margin:40px 0 0;
  font:400 16px/1.6 var(--font);
  color:var(--muted);
}
.blog-note a{color:var(--terracotta);text-decoration:underline;text-underline-offset:2px}

.legal-doc{margin-top:34px}
.legal-doc .doc-head{text-align:center}
.legal-doc h1{
  margin:0;
  font:700 clamp(30px,4.6vw,40px)/1.15 var(--font);
  letter-spacing:-.035em;
  color:var(--ink);
  text-wrap:balance;
}
.legal-doc .updated{margin:12px 0 0;font:500 13.5px/1.5 var(--font);color:var(--muted)}
.legal-doc .doc{
  margin:30px 0 0;
  padding:clamp(24px,4vw,44px);
  background:var(--white);
  border:1px solid var(--line);
  border-radius:18px;
}
.legal-doc section{margin:32px 0 0}
.legal-doc section:first-child{margin-top:0}
.legal-doc h2{
  margin:0 0 12px;
  font:700 clamp(19px,2.4vw,22px)/1.25 var(--font);
  letter-spacing:-.025em;
  color:var(--ink);
}
.legal-doc h3{margin:22px 0 6px;font:600 16.5px/1.35 var(--font);color:var(--ink)}
.legal-doc p{margin:0 0 13px;font:400 17px/1.7 var(--font);color:var(--ink);text-wrap:pretty}
.legal-doc p:last-child{margin-bottom:0}
.legal-doc strong{font-weight:600}
.legal-doc ul{margin:0 0 13px;padding:0;list-style:none}
.legal-doc li{
  position:relative;margin:0 0 9px;padding-left:20px;
  font:400 17px/1.7 var(--font);color:var(--ink);text-wrap:pretty;
}
.legal-doc li:last-child{margin-bottom:0}
.legal-doc li::before{
  content:"";position:absolute;left:2px;top:.72em;
  width:6px;height:6px;border-radius:50%;background:var(--terracotta);
}
.legal-doc a{color:var(--terracotta);text-decoration:underline;text-underline-offset:2px}
.legal-doc .callout{
  margin:16px 0;
  padding:16px 18px;
  background:var(--cream);
  border:1px solid var(--line);
  border-radius:12px;
  font-size:16px;
  color:var(--muted);
}
.legal-doc .callout strong{
  display:block;margin-bottom:4px;color:var(--ink);
  font-weight:700;letter-spacing:-.01em;
}
/* the standalone page's own footer nav is not wanted inside the view */
.legal-doc .foot{display:none}

/* --- contact ------------------------------------------------------------ */
.contact-doc{text-align:center}
/* Everything in here reads as plain black text that happens to be
   clickable. The .legal-doc rule above underlines links in terracotta,
   which is right inside a policy document and wrong on a contact card, so
   it is overridden rather than loosened at the source. */
.contact-doc a,
.contact-doc a:hover{text-decoration:none;color:var(--ink)}

.contact-email{
  display:inline-block;
  padding:4px 10px;
  margin:-4px -10px;
  border-radius:10px;
  font:700 clamp(22px,3.2vw,30px)/1.2 var(--font);
  letter-spacing:-.03em;
  /* no underline, so the hover tint is what says "this is a control" */
  transition:background var(--t-state) ease;
}
.contact-email:hover{background:rgba(180,95,42,.08)}
/* .contact-doc prefix is load-bearing: `.legal-doc p` sets margin 0 0 13px
   and outranks a bare .contact-note, which killed the auto side margins.
   The text stayed centred inside its own 46ch box while the box itself sat
   left, so the paragraph read as off-centre against the card. */
.contact-doc .contact-note{
  margin:12px auto 0;
  max-width:46ch;
  font:400 16px/1.6 var(--font);
  color:var(--muted);
  text-wrap:pretty;
}
.contact-h2{
  margin:34px 0 16px;
  padding-top:26px;
  border-top:1px solid var(--line);
  font:600 13px/1 var(--font);
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--muted);
}
.contact-socials{display:flex;flex-direction:column;gap:8px;text-align:left}
.contact-social{
  display:flex;
  align-items:center;
  gap:12px;
  padding:12px 14px;
  border:1.5px solid var(--line);
  border-radius:12px;
  text-decoration:none;
  color:var(--ink);
  transition:border-color var(--t-state) ease,background var(--t-state) ease,
             transform var(--t-feedback) var(--ease-out);
}
.contact-social:hover{
  border-color:var(--brand,var(--terracotta));
  background:color-mix(in srgb,var(--brand,var(--terracotta)) 7%,transparent);
  transform:translate3d(0,-1px,0);
}
.contact-social-icon{display:inline-flex;color:var(--brand,var(--ink))}
.contact-social-icon svg{width:20px;height:20px;display:block;fill:currentColor}
.contact-social-name{font:600 15px/1.2 var(--font);letter-spacing:-.01em}
.contact-social-at{
  margin-left:auto;
  /* black like the rest of the card; hierarchy comes from size and weight
     rather than from greying it out */
  color:var(--ink);
  font:400 13.5px/1.2 var(--font);
  color:var(--muted);
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}
@media (max-width:439px){
  .contact-social-at{display:none}   /* the name is enough on a phone */
}

/* The row spans the video and every gap in it is identical. Both of those at
   once needs all six controls to be SIBLINGS in one flex row: with the
   channels wrapped in their own box the row had only two children, so
   space-between put all the slack in one place and left a void in the middle.
   display:contents on the two wrappers dissolves their boxes and promotes the
   five rings and the button to direct children, and space-between then divides
   the leftover width into five equal gaps by itself. Nothing computes a gap,
   which is why it stays equal at every resolution.
   left/right MATCH THE PANEL'S OWN PADDING, and that is load-bearing: the
   footer is absolute so its offsets come off the padding box, while the video
   sits one padding-length into the content box. Same number, same edge. Change
   the panel padding and you must change these with it.
   --foot-gap is the FLOOR, not the gap: it only applies once the card is too
   narrow for the controls, where it keeps them from touching. */
.panel-foot{
  /* a SMALL fixed gap now, not the leftover. Under space-between the leftover
     width became the gap, so a wide card pushed the rings apart; here the
     rings grow into that width instead and the gap stays where it is set. */
  --foot-gap:clamp(3px,.55vw,6px);
  position:absolute;
  /* Centred in the band WITHOUT being given its height, which matters: the row
     stays shrink-wrapped to the ring, so the button can still stretch to the
     ring's height rather than to the whole band. Placing the row's bottom edge
     halfway up the band and then pushing it down by half its own height puts
     its centre on the band's centre, so the space above the controls and the
     space below them are equal at whatever size the fluid ring resolves to. */
  left:12px;right:12px;
  bottom:calc(var(--foot-band) / 2);
  transform:translateY(50%);
  /* A CONTAINER, so the button can size itself against this row rather than
     against the viewport. That distinction is the whole point here: on desktop
     the panel is height-led, so a short window makes the card narrow while the
     viewport stays wide. Any vw-based clamp reads "wide" and the button keeps a
     minimum the card cannot afford, which pushed the row past the video's edge.
     Safe to declare: this element is absolutely positioned with both left and
     right set, so its inline size already comes from those offsets and never
     from its contents, which is exactly what inline-size containment requires. */
  container-type:inline-size;
  display:flex;
  align-items:center;
  justify-content:flex-start;
  flex-wrap:nowrap;
  gap:var(--foot-gap);
}
/* the two wrapper boxes are dissolved so all six controls are flex siblings and
   one gap governs the whole row */
.social-row,
.policies-half{display:contents}
/* The button takes whatever the rings do not. Something has to absorb the
   leftover on a wide card, and a slightly roomy button reads better than five
   rings drifting apart. min-width keeps its text on one line: it is the ring
   that gives on a narrow card, never the wording. */
.policies{flex:1 1 auto;min-width:min-content;align-self:stretch}
.policies-btn{width:100%}

/* --- social channels --- */
/* Each channel wears its own colour on hover: the ring and the glyph both
   take the platform's brand, which index.js sets per icon as --brand. The
   resting state stays quiet so five colours never shout at once. */
.social-row a,
.social-row .is-pending{
  display:inline-flex;
  align-items:center;justify-content:center;
  /* Rings SIZE THEMSELVES from the row: flex-basis 0 with grow means the five
     of them split whatever the button does not need, so they get bigger as the
     card gets wider instead of the gap getting bigger.
     square always, because aspect-ratio drives the height off that width.
     max-width is set by the strip's height, not by taste: the panel reserves a
     fixed band under the video and a ring taller than the band would sit on the
     picture. Here the band is a flat 60px and 44 is that rule with the numbers
     already worked out; on desktop the band is fluid, so the desktop block
     restates this cap as arithmetic against --foot-band instead.
     min-width is the tap target on a cramped card. */
  /* grow 2 against the button's 1: free width is shared, and on a phone the
     rings never reach their cap, so an even split left them smaller than a
     comfortable tap target. Weighting them means the ring wins that space and
     the button still absorbs whatever is left once the rings cap out. */
  flex:2 1 0;
  width:auto;min-width:26px;max-width:44px;
  aspect-ratio:1;height:auto;
  border:1.5px solid var(--line);
  border-radius:9px;
  color:var(--ink);
  transition:color var(--t-state) ease,border-color var(--t-state) ease,
             background var(--t-state) ease,
             transform var(--t-feedback) var(--ease-out);
}
.social-row a:hover,
.social-row a:focus-visible{
  color:var(--brand,var(--terracotta));
  border-color:var(--brand,var(--terracotta));
  /* 8% of the brand over the card, so the tint belongs to the platform too.
     Dropped silently by engines without color-mix, leaving ring and glyph. */
  background:color-mix(in srgb,var(--brand,var(--terracotta)) 8%,transparent);
  transform:translate3d(0,-1px,0);
}
.social-row a:active{transform:translate3d(0,0,0) scale(.94);transition-duration:var(--t-press)}
/* a channel with no link yet: present, obviously inert, never clickable */
.social-row .is-pending{
  color:var(--faint);
  border-style:dashed;
  cursor:default;
}
/* solid brand glyphs, sized to read at a glance rather than to whisper */
.social-row svg{width:17px;height:17px;display:block;fill:currentColor}


/* --- one policies control, bottom right --- */
.policies{position:relative}
/* Same ring as the channels beside it: same 1.5px hairline, same 10px
   corner, same height, so the two halves of the footer read as one row of
   controls rather than icons plus a bare word. */
.policies-btn{
  /* no fixed height: the ring is fluid, so the button matches it by stretching
     to the flex line's height instead of carrying a number that would drift */
  height:100%;
  /* cqw, not vw: measured against the footer row, so a narrow card genuinely
     shrinks the button and the rings keep their tap target */
  padding:0 clamp(8px,3cqw,17px);
  border:1.5px solid var(--line);
  border-radius:9px;
  background:var(--white);
  /* nowrap is the requirement: "Terms & Policies" stays on one line at
     every width, and the row shrinks around it rather than breaking it */
  white-space:nowrap;
  font:600 clamp(10.5px,4.2cqw,13.5px)/1.2 var(--font);
  letter-spacing:-.01em;
  color:var(--ink);
  cursor:pointer;
  transition:color var(--t-state) ease,border-color var(--t-state) ease,
             background var(--t-state) ease,
             transform var(--t-feedback) var(--ease-out);
}
.policies-btn:hover,
.policies.is-open .policies-btn{
  color:var(--terracotta);
  border-color:var(--terracotta);
  background:rgba(180,95,42,.08);
}
.policies-btn:hover{transform:translate3d(0,-1px,0)}
.policies-btn:active{transform:translate3d(0,0,0) scale(.97);transition-duration:var(--t-press)}

/* Opens upward: the control sits at the bottom of the panel, and the panel
   runs to the bottom of the screen, so downward has nowhere to go. */
.policies-menu{
  position:absolute;
  right:0;bottom:calc(100% + 8px);
  min-width:196px;
  padding:8px;
  background:var(--white);
  border:1px solid var(--line);
  border-radius:14px;
  box-shadow:0 10px 30px -8px rgba(34,28,16,.22);
  display:flex;
  flex-direction:column;
  z-index:3;
  opacity:0;
  transform:translate3d(0,6px,0);
  pointer-events:none;
  /* visibility, not just opacity. opacity:0 still leaves the links FOCUSABLE,
     and because [hidden] is overridden to display:flex below, the hidden
     attribute was not removing them either: one Tab from the button landed on
     an invisible "Privacy policy" link and a keyboard user lost the focus ring
     for four stops. visibility:hidden takes them out of the tab order, and the
     0s delay behind the state duration lets the fade finish before it applies,
     so nothing snaps. */
  visibility:hidden;
  transition:opacity var(--t-state) var(--ease-out),
             transform var(--t-state) var(--ease-out),
             visibility 0s linear var(--t-state);
}
.policies-menu[hidden]{display:flex}      /* hidden drives state, not display */
.policies.is-open .policies-menu{
  opacity:1;
  transform:none;
  pointer-events:auto;
  visibility:visible;
  transition-delay:0s;
}
.policies-menu a{
  padding:9px 12px;
  border-radius:9px;
  font:500 13.5px/1.3 var(--font);
  color:var(--ink);
  text-decoration:none;
  white-space:nowrap;
  transition:background var(--t-state) ease,color var(--t-state) ease;
}
.policies-menu a:hover{background:var(--cream);color:var(--terracotta)}

@media (max-width:439px){
  /* left/right stay on the panel padding so the ends keep landing on the
     video's edges; only the controls themselves come down a size */
  .social-row a,
  .social-row .is-pending{min-width:24px;max-width:42px}
  .social-row svg{width:15px;height:15px}
}

/* ==========================================================================
   VIDEO PLAYER (custom controls, cream + terracotta)
   ========================================================================== */
/* Every slot is 16:9, driven by aspect-ratio and never by a fixed height, so
   the frame is correct at every width. Width-led by default. */
.player{
  position:relative;
  width:100%;
  height:auto;
  aspect-ratio:16/9;
  max-width:100%;
  border-radius:20px;
  overflow:hidden;
  background:var(--ink);
  display:block;
  flex:none;
}

.player-video{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
  display:block;
  background:var(--ink);
}

/* big poster play button, shown until first play */
.player-start{
  position:absolute;inset:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
  border:none;background:rgba(34,28,16,.28);
  cursor:pointer;
  transition:opacity var(--t-state) ease,background var(--t-state) ease;
}
.player-start:hover{background:rgba(34,28,16,.18)}
.player.is-started.is-playing .player-start{opacity:0;pointer-events:none}
.player-start-disc{
  width:62px;height:62px;border-radius:50%;
  background:var(--cream);
  display:flex;align-items:center;justify-content:center;
  box-shadow:0 8px 20px rgba(0,0,0,.28);
  transition:transform var(--t-feedback) var(--ease-out);
}
.player-start:hover .player-start-disc{transform:scale(1.06)}
.player-start-disc .ico{width:24px;height:24px;stroke:none;fill:var(--ink);margin-left:3px}

/* control bar */
.player-bar{
  position:absolute;left:0;right:0;bottom:0;
  display:flex;align-items:center;gap:8px;
  padding:8px 10px;
  background:linear-gradient(to top,rgba(34,28,16,.88),rgba(34,28,16,0));
  opacity:0;
  transform:translate3d(0,6px,0);
  transition:opacity var(--t-state) ease,transform var(--t-state) var(--ease-out);
}
.player:hover .player-bar,
.player.is-started:not(.is-playing) .player-bar,
.player:focus-within .player-bar{opacity:1;transform:none}
/* Every rule above needs a mouse or a focus ring to show the bar, so on a
   phone the controls had no way in at all while the video was playing: no
   pause, no scrub, no volume, no fullscreen. Touch has its own reveal, the
   tap handled in index.js, and `is-idle` is what it clears. Scoped to
   hover:none so the desktop bar keeps behaving exactly as it did. */
@media (hover:none){
  .player.is-started.is-playing:not(.is-idle) .player-bar{opacity:1;transform:none}
}
/* playing with no pointer activity: controls step out of the way until the mouse moves */
.player.is-playing.is-idle .player-bar{opacity:0;transform:translate3d(0,6px,0);pointer-events:none}
.player.is-playing.is-idle{cursor:none}

.player-btn{
  flex:none;
  width:30px;height:30px;
  display:flex;align-items:center;justify-content:center;
  border:none;border-radius:8px;
  background:transparent;color:var(--cream);
  cursor:pointer;
  transition:background var(--t-feedback) ease,transform var(--t-feedback) var(--ease-out);
}
.player-btn:hover{background:rgba(253,250,240,.16)}
.player-btn:active{transform:scale(.92);transition-duration:var(--t-press)}
.player-btn .ico{width:16px;height:16px}

/* scrub bar with buffered range */
.player-scrub{
  position:relative;flex:1 1 auto;min-width:0;
  height:16px;display:flex;align-items:center;
  cursor:pointer;background:none;border:none;padding:0;
}
.player-track{
  position:relative;width:100%;height:4px;border-radius:2px;
  background:rgba(253,250,240,.28);overflow:hidden;
  transform-origin:center;
  transition:transform .15s var(--ease-out);
}
/* Jake's touch: the track thickens on hover. scaleY rather than a height
   tween, so it stays a compositor-only change. 4px * 1.5 = 6px. */
.player-scrub:hover .player-track{transform:scaleY(1.5)}

/* ---- hover scrub preview, ported from Jake's Homeflix player ---- */
.player-preview{
  position:absolute;
  bottom:22px;left:0;
  width:160px;
  display:flex;flex-direction:column;align-items:center;gap:6px;
  transform:translateX(-50%) translateY(6px) scale(.97);
  opacity:0;
  pointer-events:none;
  z-index:10;
  transition:opacity .18s var(--ease-out),transform .18s var(--ease-out);
}
.player-preview.is-on{opacity:1;transform:translateX(-50%) translateY(0) scale(1)}
.player-preview-frame{
  width:100%;
  aspect-ratio:16/9;
  object-fit:cover;
  display:block;
  background:var(--ink);
  border:2px solid var(--cream);
  border-radius:10px;
  box-shadow:0 10px 28px rgba(29,26,16,.45);
}
.player-preview-time{
  background:var(--ink);
  color:var(--cream);
  font:700 12px/1 var(--font);
  font-variant-numeric:tabular-nums;
  letter-spacing:.01em;
  padding:5px 11px;border-radius:999px;
  box-shadow:0 4px 12px rgba(29,26,16,.35);
}
.player-compact .player-preview{width:120px}
.player-buffered{
  position:absolute;left:0;top:0;bottom:0;
  background:rgba(253,250,240,.34);
  transform-origin:left center;transform:scaleX(0);
  transition:transform var(--t-state) linear;
  width:100%;
}
.player-progress{
  position:absolute;left:0;top:0;bottom:0;
  background:var(--terracotta);
  transform-origin:left center;transform:scaleX(0);
  width:100%;
}
.player-scrub:focus-visible .player-track{outline:2px solid var(--terracotta);outline-offset:3px}

/* ---- volume group: slider reveals on hover / focus-within ----
   The reveal animates a grid track, not width/margin, so no layout thrash and
   the collapsed state costs no space. */
.player-vol{
  position:relative;
  display:inline-flex;align-items:center;
}
/* the slider lives in a small panel that rises above the speaker icon */
.player-vol-pop{
  position:absolute;left:50%;bottom:100%;
  padding:10px 8px 14px;            /* bottom padding bridges the gap to the button so hover holds */
  transform:translate3d(-50%,6px,0);
  opacity:0;pointer-events:none;
  transition:opacity var(--t-feedback) var(--ease-out),transform var(--t-feedback) var(--ease-out);
  z-index:12;
}
.player-vol-pop::before{
  content:"";position:absolute;inset:0 0 8px;
  background:rgba(34,28,16,.92);border:1px solid rgba(253,250,240,.18);
  border-radius:10px;
}
.player-vol:hover .player-vol-pop,
.player-vol.is-open .player-vol-pop,
.player-vol:focus-within .player-vol-pop{opacity:1;pointer-events:auto;transform:translate3d(-50%,0,0)}
/* while dragging the scrub, the controls stay put and the cursor says so */
.player.is-scrubbing{cursor:grabbing}
/* Fullscreen: black from the first frame (no cream corners flashing), and
   the video fills the screen, letterboxed by object-fit rather than the box */
.player:fullscreen{border-radius:0;background:#000;width:100%;height:100%;aspect-ratio:auto}
.player:fullscreen .player-video{width:100%;height:100%;object-fit:contain;background:#000;border-radius:0}
.player::backdrop{background:#000}
/* controls hug the picture's real edges inside the letterbox */
.player:fullscreen .player-bar{
  left:var(--fsx,0);right:var(--fsx,0);bottom:var(--fsy,0);
  padding-left:14px;padding-right:14px;
}
.player:fullscreen .player-file{left:calc(var(--fsx,0) + 10px);top:calc(var(--fsy,0) + 8px)}
.player.is-scrubbing .player-bar{opacity:1;transform:none}
.player.is-scrubbing .player-track,.player-scrub:active .player-track{transform:scaleY(1.6)}
.player-scrub{touch-action:none}

.player-volume{
  position:relative;
  writing-mode:vertical-lr;direction:rtl;   /* vertical, up is louder */
  width:18px;height:84px;
  margin:0;
  accent-color:var(--terracotta);
  background:transparent;
  cursor:pointer;
}
.player-volume:focus-visible{outline:2px solid var(--terracotta);outline-offset:3px}

.player-time{
  flex:none;
  font:500 11.5px/1 var(--font);
  color:var(--cream);
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
}

/* the intended real filename stays visible */
.player-file{
  position:absolute;left:10px;top:8px;
  margin:0;
  font:500 11px/1 var(--font);
  color:var(--cream);
  background:rgba(34,28,16,.55);
  padding:4px 7px;border-radius:6px;
  pointer-events:none;
  transition:opacity var(--t-state) ease;
}
.player.is-started .player-file{opacity:0}

/* very small players (result cards) drop the time readout */
.player-compact .player-time{display:none}
.player-compact .player-file{font-size:10px;left:8px;top:6px}

/* ==========================================================================
   HERO — desktop (canvas 2a), 1440x820 above the fold
   ========================================================================== */
@media (min-width:900px){
  :root{
    /* Canvas 2a is a 1200x820 composition. 0.12195svh == 820u == the full
       viewport height, so the hero scales to fill the fold as 2a intends.
       The vw term keeps 1296u (1200 + 48u gutters) inside the viewport width;
       the cap stops the type ballooning on very large displays.
       svh rather than vh, and the same everywhere below: a tablet in landscape
       reaches this breakpoint too, and there vh is the height the page would
       have with the browser's own bars retracted, which is more than the
       visitor can see. A desktop window has no such bars, so svh == vh and
       nothing above 900px on a laptop moves. */
    --u:min(0.12195svh, 0.077vw, 1.45px);
  }

  .view-hero{
    max-width:calc(1200 * var(--u));
    height:100svh;
    min-height:600px; /* short windows scroll instead of crushing the hero */
    padding:calc(32 * var(--u)) calc(48 * var(--u)) 0;
  }

  .m-topbar{display:none}
  /* Three columns, the same bargain as .m-topbar: space-between would centre
     the wordmark between the two PILLS, and those are different widths ("Blog"
     against "See our Results"), so it would sit off the page centre by half
     their difference. 1fr auto 1fr pins it to the middle of the page. */
  .d-topbar{
    display:grid;
    grid-template-columns:1fr auto 1fr;
    align-items:center;
    gap:calc(16 * var(--u));
    flex:none;
    /* Held to the same frame as the blog's bar rather than run out to the
       hero's padding edges. At full width the two pills sat 1212px apart on a
       1440 screen while the hero's own text column is 483px, so they read as
       two things stranded in the corners rather than as one bar.

       The padding is what makes the pills LAND in the same place as the blog's,
       not just the width: /blog's bar insets its pill by its own --pad, so
       matching --frame alone still left the two 24px apart. With both, the Blog
       pill here and the Back pill in the #blog view sit on the same vertical,
       and the slide between them does not shift the bar. (/blog used to sit a
       further 7px in because it reserved a scrollbar gutter; since 2026-09-07
       the blog pages hide their scrollbar exactly as this page does, and the
       bar's size, top edge and pills come from blog.css's ONE BAR tokens on
       every page, this one included.) */
    width:100%;
    max-width:var(--frame);
    padding-inline:var(--pad);
    margin-inline:auto;
  }
  .d-topbar .pill-blog{justify-self:start}
  .d-topbar .wordmark-d{justify-self:center}
  .d-topbar .pill-d:not(.pill-blog){justify-self:end}

  .pill-m{display:none}
  .pill-d{
    display:inline-flex;
    height:calc(36 * var(--u));
    padding:0 calc(16 * var(--u));
    gap:calc(6 * var(--u));
    font:500 calc(13.5 * var(--u))/1 var(--font);
    margin-bottom:0;
  }
  .pill-d:hover{border-color:var(--ink);color:var(--ink)}
  .pill-back{
    height:calc(36 * var(--u));
    padding:0 calc(16 * var(--u));
    gap:calc(6 * var(--u));
    font:500 calc(13.5 * var(--u))/1 var(--font);
  }

  .hero-h1-static{
    font:700 calc(76 * var(--u))/1.02 var(--font);
    letter-spacing:-.04em;
  }
  .rotator{height:calc(86 * var(--u));margin-top:calc(2 * var(--u))}
  .rot-word{font:700 calc(76 * var(--u))/1.1 var(--font);letter-spacing:-.035em}

  .hero-sub{
    margin:calc(18 * var(--u)) auto 0;
    max-width:calc(440 * var(--u));
    font:400 calc(19 * var(--u))/1.5 var(--font);
  }

  .hero-ctas{
    flex-direction:row;justify-content:center;
    gap:calc(14 * var(--u));
    margin-top:calc(32 * var(--u));
    padding:0;
  }
  /* two selectors deep, because the phone ramp on .hero-ctas .btn outranks a
     single class and would otherwise follow the hero onto the desktop */
  .btn-primary,.btn-secondary,.hero-ctas .btn{
    height:calc(54 * var(--u));
    padding:0 calc(32 * var(--u));
    border-radius:calc(14 * var(--u));
    font:600 calc(16.5 * var(--u))/1 var(--font);
  }
  /* desktop primary is the dark button, not terracotta */
  .btn-primary{background:var(--ink);color:var(--cream);box-shadow:var(--shadow-cta-dark)}
  .btn-primary:hover{background:var(--ink-hover);box-shadow:0 10px 22px rgba(29,26,16,.28)}
  .btn-secondary:hover{border-color:var(--ink);color:var(--ink)}
  .btn-arrow{font-size:calc(17 * var(--u))}

  /* --------------------------------------------------------------------
     WHERE THE SPARE HEIGHT GOES
     Canvas 2a's 64u above the headline is a floor, so it is padding. The two
     auto margins are what happens above it: on a window shaped like the
     canvas the card uses every leftover pixel and both margins resolve to
     zero, which is why nothing on a laptop moves. On a window far taller than
     it is wide there is height the card cannot spend, because a 16:9 picture
     that tall would have to be wider than the screen. Two auto margins split
     that surplus in half rather than letting all of it pile up in one band,
     which is the band Jake photographed on the iPad. The cap that leaves any
     surplus to split is the wrap's max-height below; without it flex-grow
     takes the lot and the auto margins get nothing. */
  .hero-center{margin-top:auto;padding-top:calc(64 * var(--u))}
  .hero-ctas{margin-bottom:auto}

  /* Desktop: canvas 2a leaves 31px between the CTA row and the panel, then the
     panel runs to the bottom edge. The wrap still takes all leftover height, so
     spare room grows the video and never the gap; what changed is WHICH box
     measures that room. See THE CARD MEASURES ITS OWN ROOM below. */
  .hero-video-wrap{
    flex:1 1 auto;
    min-height:0;
    width:100%;
    margin-left:0;margin-right:0;
    padding-top:calc(31 * var(--u));
    /* The tallest this box can usefully be, which is the card at the full
       width of the column. Read it left to right: this padding, then the
       card's 1px top border and 12u, then a 16:9 picture as wide as the
       column allows, then the footer's 64u band. The column is the hero's
       1200u less its two 48u gutters, and the picture is that less the
       card's two 12u sides and two hairlines. Every one of those numbers is
       set elsewhere in this block; change one and change this.
       Without the cap, flex-grow takes all the leftover height whether the
       card can spend it or not, and the surplus becomes a gap above the
       card. With it, the surplus stays free for the auto margins above. */
    max-height:calc(31 * var(--u) + 1px + 12 * var(--u)
                    + (1104 * var(--u) - 24 * var(--u) - 2px) * 9 / 16
                    + 54 * var(--u));
    /* --------------------------------------------------------------------
       THE CARD MEASURES ITS OWN ROOM
       This card used to be height-led: `height:100%` on the panel, `height:100%
       width:auto` on the player, and the 16:9 ratio carrying that height back
       out to a width. Every pixel of the card's WIDTH therefore arrived from
       one aspect-ratio transfer inside a flex item, and the only thing in the
       card that is in normal flow is the player itself (the picture is
       absolutely positioned, the legal row is absolutely positioned). So an
       engine that declines that one transfer gives the player a width of zero,
       and `width:auto` shrink-wraps the panel to its padding: a white strip of
       24u + 2px, running the full height of this wrap. That is the vertical
       sliver on the iPad, and blocking the script that mounts the player
       reproduces it here to the pixel — 18.6px wide at 900 CSS px.
       So the transfer is gone. This wrap is a size container, which means it
       publishes the leftover height flexbox already gave it as 100cqh, and the
       card takes its width from that number below. Nothing in the card decides
       the card's size any more, in either axis, which is why the picture can no
       longer collapse and can no longer be squashed off 16:9.
       Safe to declare: this wrap's height comes from `flex:1 1 auto` against a
       hero with a definite height, never from its contents, which is what size
       containment requires. Container units are Safari 16, the same floor the
       legal row inside this very card already sets with its own container. */
    container-type:size;
  }
  .video-panel{
    /* The picture's height is everything this wrap has, less the card's own
       chrome: 1px of top border, 12u of padding above the picture and the
       footer's band below it. Width is that height at 16:9 plus the two 12u
       sides and the two hairlines. Change any of the four numbers on the
       padding line below and this line has to move with it.
       The floor is the promise that this card is a card: if the leftover
       height ever went to nothing the width would follow it down, and a card
       with no width is the sliver this whole change is about. Below the floor
       the card overflows and the page scrolls, which is the honest failure. */
    max-width:max(calc(260 * var(--u)), calc((100cqh - 66 * var(--u) - 1px) * 16 / 9 + 24 * var(--u) + 2px));
    width:100%;
    height:auto;
    border-radius:calc(28 * var(--u)) calc(28 * var(--u)) 0 0;
    /* bottom pad is the legal row's room; the other three stay the canvas 12.
       54u IS DERIVED, NOT CHOSEN: the ring's cap below is 30u, and 12u above it
       and 12u below it is the same air this card already gives its own sides.
       30 + 12 + 12 = 54, and every one of those numbers is on this page.
       It was 64u, which is a white shelf: 24.4px above and below a 44px ring at
       2560x1440, 18.9px around a 33.9px ring at 1920x919 -- more room than
       anything else on the card gets, under the smallest thing on it. The owner
       called it on 2026-09-09 ("way too much space").
       The 10u this frees does not turn into a gap somewhere else. The two lines
       above spend it on the picture: same viewport, same card height, a picture
       6% bigger at every desktop size (1920x919: 335x188.5 -> 355x199.7). */
    --foot-band:calc(54 * var(--u));
    padding:calc(12 * var(--u)) calc(12 * var(--u)) var(--foot-band);
    box-shadow:0 -8px 24px rgba(29,26,16,.08);
  }
  /* same number as the panel's side padding above, so the footer's two ends
     sit exactly on the video's left and right edges */
  .panel-foot{left:calc(12 * var(--u));right:calc(12 * var(--u))}
  /* THE RING'S CAP IS THE BAND, rather than a number kept in step with it by
     hand. The base rule caps the ring at 44px and says outright that the two
     are coupled ("Raise one and you must raise the other") -- a rule that holds
     exactly until somebody moves the band, which is this commit. Proof it was
     load-bearing: at 900x500 the 39px ring already filled the 39px band edge to
     edge, and cutting the band to 54u with the flat cap left in place put the
     ring 4px INTO the picture and 4px PAST the card's bottom edge.
     Written against --foot-band it cannot: whatever the band resolves to, 12u
     is left above the ring and 12u below it. At the top of u's range the cap
     comes out at 43.5px, which is the 44 the base rule had picked by hand, so
     nothing visibly changes on a large screen. min-width still wins on a
     cramped card, because a tap target is worth more than a tidy gap. */
  .social-row a,
  .social-row .is-pending{max-width:calc(var(--foot-band) - 24 * var(--u))}
  /* the player keeps the base rule's width-led 16:9 on desktop too now, so the
     only thing left to say here is the radius */
  .view-hero .player{border-radius:calc(20 * var(--u))}
}

/* ==========================================================================
   RESULTS (canvas 4a)
   ========================================================================== */
.view-results{
  width:100%;
  max-width:430px;
  margin:0 auto;
  min-height:100vh;
  padding:28px 24px 32px;
  display:flex;
  flex-direction:column;
}
/* three columns so the wordmark sits on the page centre no matter how wide
   the back pill gets. Column 3 is empty and simply balances column 1. */
.results-topbar{display:grid;grid-template-columns:1fr auto 1fr;align-items:center}
.results-topbar > :first-child{justify-self:start}
.results-topbar .wordmark{justify-self:center}
.icon-btn{
  background:none;border:none;padding:0;
  color:var(--muted);
  cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  transition:color var(--t-feedback) ease,transform var(--t-feedback) var(--ease-out);
}
.icon-btn:hover{color:var(--ink)}
.icon-btn:active{transform:scale(.9);transition-duration:var(--t-press)}
#results-back:hover{transform:translate3d(-2px,0,0)}

.results-head{text-align:center;margin-top:32px}
.results-h1{
  margin:0;
  font:700 40px/1.05 var(--font);
  letter-spacing:-.035em;
  color:var(--ink);
}
.results-sub{
  margin:10px auto 0;max-width:62ch;
  font:400 15px/1.5 var(--font);
  color:var(--muted);
}

.results-list{display:flex;flex-direction:column;gap:16px;margin-top:28px}

/* ---- two-sided flip card ------------------------------------------------
   HEIGHT STRATEGY: both faces sit in the SAME CSS grid cell (grid-area 1/1),
   so they stay in normal flow and the container height resolves to the taller
   face automatically. No fixed height and no height animation, so the card
   cannot jump mid-flip and nothing but `transform` is ever animated. */
.card-persp{perspective:1400px}
.card-flip{
  display:grid;
  transform-style:preserve-3d;
  transform:rotateY(0deg);
  transition:transform .6s cubic-bezier(.4,.2,.2,1);
}
.card-flip.is-flipped{transform:rotateY(180deg)}

.card-face{
  grid-area:1/1;              /* stacked, both faces size the grid */
  backface-visibility:hidden;
  -webkit-backface-visibility:hidden;
  border-radius:20px;
  display:flex;flex-direction:column;
  min-width:0;
}

/* ---- front: information-led -------------------------------------------- */
/* front face is a plain container; the button inside is the control */
.card-front{
  align-items:center;text-align:center;
  gap:10px;padding:26px 24px 24px;
  background:var(--white);
  border:1px solid var(--line);
}

/* circle photo slot, always 1:1 */
.avatar{
  width:64px;height:64px;aspect-ratio:1/1;border-radius:50%;
  display:grid;place-items:center;flex:none;
  background:var(--track);color:var(--terracotta);
  font:700 24px/1 var(--font);letter-spacing:-.02em;
  object-fit:cover;
}
.card-name{
  margin:4px 0 0;
  font:700 20px/1.15 var(--font);letter-spacing:-.02em;color:var(--ink);
}
.card-social{
  font:500 13.5px/1.2 var(--font);color:var(--terracotta);
  text-decoration:none;
  transition:color var(--t-state) ease;
}
a.card-social:hover{color:var(--ink);text-decoration:underline}
a.card-social:focus-visible{outline:2px solid var(--terracotta);outline-offset:3px;border-radius:4px}
span.card-social{color:var(--muted)}
.card-links{
  display:flex;align-items:center;justify-content:center;flex-wrap:wrap;
  gap:6px 10px;
}
.card-links-sep{
  display:inline-block;width:3px;height:3px;border-radius:50%;
  background:var(--muted);opacity:.55;flex:none;
  font-size:0;line-height:0;      /* the dot is the box, not a glyph */
}
.card-social,.card-offer{display:inline-flex;align-items:center;gap:5px}
.ico-link{width:14px;height:14px;flex:none}
.card-offer{
  font:500 13.5px/1.2 var(--font);color:var(--ink);
  text-decoration:none;
  transition:color var(--t-state) ease,border-color var(--t-state) ease;
}
.card-offer:hover{color:var(--terracotta)}
.card-offer:focus-visible{outline:2px solid var(--terracotta);outline-offset:3px;border-radius:4px}
.card-desc{
  margin:2px 0 0;max-width:46ch;
  font:400 14px/1.5 var(--font);color:var(--muted);
  text-wrap:pretty;
}

/* the only focusable element on the front; fills the panel width */
.card-cta{
  margin-top:auto;align-self:stretch;width:100%;
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  height:46px;padding:0 18px;
  border:1.5px solid var(--line);border-radius:12px;
  background:var(--cream);color:var(--ink);
  font:600 14.5px/1 var(--font);
  cursor:pointer;
  transition:border-color var(--t-state) ease,color var(--t-state) ease,
             background var(--t-state) ease,
             transform var(--t-feedback) var(--ease-out);
}
.card-cta:hover{
  border-color:var(--terracotta);color:var(--terracotta);
  background:var(--white);
  transform:translate3d(0,-1px,0);
}
.card-cta:active{transform:translate3d(0,0,0) scale(.99);transition-duration:var(--t-press)}
.card-cta .ico{width:15px;height:15px;margin-left:1px}

/* ---- back: nothing but the video and a way back ------------------------ */
.card-back{
  transform:rotateY(180deg);
  gap:10px;padding:14px;
  background:var(--ink);
  justify-content:center;
}
.card-back-media{
  border-radius:12px;overflow:hidden;
  background:repeating-linear-gradient(-45deg,var(--stripe-dark-a),var(--stripe-dark-a) 10px,var(--stripe-dark-b) 10px,var(--stripe-dark-b) 20px);
}
.card-back-media .player{width:100%;height:auto;border-radius:12px}
.card-back-btn{
  flex:none;align-self:stretch;width:100%;
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  height:40px;padding:0 14px;
  border:1px solid rgba(253,250,240,.28);border-radius:10px;
  background:transparent;color:var(--cream);
  font:600 13px/1 var(--font);
  cursor:pointer;
  transition:border-color var(--t-state) ease,background var(--t-state) ease,
             transform var(--t-feedback) var(--ease-out);
}
.card-back-btn:hover{border-color:var(--cream);background:rgba(253,250,240,.10)}
.card-back-btn:active{transform:scale(.98);transition-duration:var(--t-press)}

/* a face that is rotated away is also inert, so it cannot be tabbed into */
.card-face[inert]{pointer-events:none}

@media (min-width:900px){
  /* wider column so the testimony paragraphs wrap onto fewer lines */
  .view-results{padding-bottom:64px;max-width:500px}
  .card-desc{max-width:none}
}

/* ==========================================================================
   POPUPS (canvas 3a + 3b)
   ========================================================================== */
.scrim{
  position:fixed;inset:0;z-index:50;
  /* dvh, not the inset alone. A phone sizes a fixed box to the viewport it
     would have with the browser's own bars retracted, so a dialog centred in
     it hangs lower than the visitor can actually see, and what lands on the
     bottom of the dialog is the CTA. dvh is whatever is on screen right now,
     which is the only height worth centring in. Engines without it ignore
     the line and behave as before. */
  max-height:100dvh;
  display:flex;align-items:center;justify-content:center;
  padding:20px;
  /* canvas framed the popups on #e6e0ca; a live modal needs a real scrim, so
     this is the canvas ink at low alpha */
  background:rgba(34,28,16,.42);
  overflow-y:auto;
  opacity:0;
  transition:opacity var(--t-state) ease;
}
.scrim[hidden]{display:none}
.scrim.is-open{opacity:1}

.dialog{
  width:min(440px, 100%);
  /* same reason as the scrim's max-height: vh is the phone's tallest possible
     viewport, not the one in front of the visitor */
  max-height:calc(100dvh - 40px);
  /* the dialog is never its own scroll surface: inner panes are sized to fit
     and scroll invisibly when they must */
  overflow:clip;
  background:var(--white);
  border:1px solid var(--line);
  border-radius:24px;
  box-shadow:var(--shadow-dialog);
  padding:24px;
  margin:auto;
  opacity:0;
  transform:translate3d(0,10px,0) scale(.985);
  transition:opacity var(--t-state) ease,transform 320ms var(--ease-out);
}
.scrim.is-open .dialog{opacity:1;transform:none}
/* the Learn With Me dialog never scrolls itself: the pane is sized to fit and
   the active slide scrolls inside, with its bar hidden (still scrollable) */
.dialog-learn-with-me{overflow:clip}
.dialog-learn-with-me .slide{scrollbar-width:none}
.dialog-learn-with-me .slide::-webkit-scrollbar{display:none}
.scrim.is-closing,.scrim.is-closing .dialog{transition-duration:160ms}

.slide-head{display:flex;justify-content:space-between;align-items:center;flex:none}
.eyebrow{font:600 11.5px/1 var(--font);letter-spacing:.08em;color:var(--faint)}
.close-btn{color:var(--faint)}
.close-btn:hover{color:var(--ink)}
.link-btn{
  background:none;border:none;padding:0;
  font:500 13px/1 var(--font);color:var(--muted);
  cursor:pointer;
  display:inline-flex;align-items:center;gap:5px;
  transition:color var(--t-feedback) ease,transform var(--t-feedback) var(--ease-out);
}
.link-btn:hover{color:var(--ink);transform:translate3d(-2px,0,0)}

.dlg-h2{
  margin:14px 0 6px;
  font:700 26px/1.1 var(--font);
  letter-spacing:-.03em;color:var(--ink);
}
.dlg-h2-sm{font-size:24px;line-height:1.15}
.dlg-p{
  margin:0 0 16px;
  font:400 14.5px/1.5 var(--font);
  color:var(--muted);
  text-wrap:pretty;
}
.dlg-p-tight{margin-bottom:12px}
.dlg-p-sm{font-size:14px;margin-bottom:14px}

.dlg-cta{
  /* Positioned, and that is not decoration. The player above it is
     position:relative, so it paints in the positioned layer, which sits ABOVE
     an ordinary block that comes later in the markup. The moment the two
     boxes touch, and on a phone the gap here is only about 18px of slack, the
     video's dark control bar lands on top of "Pick a time" and even takes the
     tap. Measured: force a 12px overlap and elementFromPoint at the button
     returns .player-bar; with this z-index it returns the button. */
  position:relative;z-index:1;
  margin-top:auto;width:100%;height:50px;flex:none;
  border:none;border-radius:14px;
  background:var(--ink);color:var(--cream);
  font:600 16px/1 var(--font);
}
/* and a floor under that slack, so the two can never actually meet: the auto
   margin above collapses to nothing the moment the slide runs out of room */
.dialog .player{margin-bottom:14px}
.dlg-cta:hover:not(:disabled){background:var(--ink-hover)}
.dlg-cta:disabled{opacity:.55;cursor:not-allowed}
.dlg-cta-sm{height:48px;border-radius:12px;font-size:14.5px;margin-top:10px}

/* --- Learn With Me, two sliding pages -------------------------------------- */
/* Canvas `pagesStyle` animates height between the two page heights. Kept as
   designed: the reveal is the point of the two-page popup. `contain` keeps the
   height tween from reflowing the page contents. */
.pages{
  /* clip, not hidden: a hidden overflow box is still a scroll container and
     focus/scroll-into-view can shove the slide track sideways. clip cannot
     be scrolled at all. hidden stays as the fallback for old engines. */
  overflow:hidden;
  overflow:clip;
  height:384px;
  transition:height .55s var(--ease-canvas);
  contain:layout paint;
  /* 6px bleed, cancelled by slide padding below: the clip edges sit past the
     inputs' 4px focus ring instead of slicing it */
  margin:0 -6px;
}
/* dvh here for the same reason the dialog uses it: these two heights and the
   dialog's cap have to agree about what the viewport is, or the taller steps
   get clipped by the cap on a phone */
.pages.is-step2{height:min(560px,72dvh)}
.pages.is-step3{height:min(560px,72dvh)}
.slides{
  display:flex;width:300%;
  transform:translateX(0);
  transition:transform .55s var(--ease-canvas);
}
.slides.is-step2{transform:translateX(-33.3333%)}
.slides.is-step3{transform:translateX(-66.6667%)}
.slide{
  width:33.3333%;flex-shrink:0;box-sizing:border-box;
  display:flex;flex-direction:column;
  height:100%;
  overflow-y:auto;
  /* returns the 6px the .pages bleed added, so content width is unchanged
     while this scroll container's own clip edge clears the focus ring */
  padding:0 6px;
  /* reserve the bar on both sides so content stays centred and nothing
     shifts when the scrollbar appears */
  scrollbar-gutter:stable both-edges;
  -webkit-overflow-scrolling:touch;
}
.slides{height:100%}

.dots{display:flex;justify-content:center;gap:6px;margin-top:16px}
.dot{
  width:6px;height:6px;border-radius:3px;background:var(--line);
  transition:width .35s ease,background .35s ease;
}
.dot-on{width:20px;background:var(--ink)}

/* Cal.com inline embed */

/* --- quiz ---------------------------------------------------------------- */
/* Canvas `quizWrapStyle` animates height as the question changes; contained so
   the tween clips rather than reflowing the options. */
/* 6px horizontal bleed (padding cancelled by margin): the clip edge sits past
   the inputs' 4px focus ring instead of slicing its left and right sides */
/* flex:none is load-bearing: the dialog is a flex column, so without it the
   wrap gets SHRUNK below the height sizeQuiz just measured and the last
   answer ends up under the panel's bottom edge. The height is computed, not
   negotiable. */
.quiz-wrap{flex:none;overflow:hidden;overflow-y:auto;scrollbar-width:none;transition:height .55s var(--ease-canvas);contain:layout paint;padding:0 6px;margin:0 -6px}
.quiz-wrap::-webkit-scrollbar{display:none}
.progress{height:6px;border-radius:3px;background:var(--track);margin-bottom:16px;overflow:hidden}
/* scaleX rather than width: same visual, no layout cost (detector L683) */
.progress-fill{
  height:6px;border-radius:3px;background:var(--ink);
  width:100%;
  transform:scaleX(0);transform-origin:left center;
  transition:transform .35s ease;
}
.quiz-options{display:flex;flex-direction:column;gap:8px}
.quiz-option{
  /* never let a flex column squash an answer: this is what clipped the last
     option on narrow viewports */
  flex:none;
  padding:14px 16px;border-radius:12px;
  cursor:pointer;text-align:left;
  font:500 14.5px/1.3 var(--font);
  color:var(--ink);
  background:var(--cream);
  border:1.5px solid var(--line);
  transition:background var(--t-state) ease,border-color var(--t-state) ease,
             transform var(--t-feedback) var(--ease-out);
  animation:qopt 320ms var(--ease-out) both;
  animation-delay:calc(var(--i,0) * 45ms);
}
@keyframes qopt{from{opacity:0;transform:translate3d(0,8px,0)}to{opacity:1;transform:none}}
/* question swap slides like the Learn With Me steps: a static ghost of the old
   question glides out while the new one arrives from the other side */
#quiz-wrap{position:relative}
/* flow-root: child margins stay inside the box sizeQuiz measures.
   The bottom padding is breathing room, and it lives HERE rather than on
   the wrap on purpose: sizeQuiz measures this element, so padding here is
   counted into the height the wrap is given. Padding on the wrap would be
   subtracted from that height instead and clip the last answer again. */
#quiz-inner{display:flow-root;padding-bottom:10px}
/* offsets are from the padding box, so the bleed is subtracted back out */
.quiz-ghost{position:absolute;top:0;left:6px;right:6px;pointer-events:none}
.q-out-left{animation:q-slide-out-l .55s var(--ease-canvas) both}
.q-out-right{animation:q-slide-out-r .55s var(--ease-canvas) both}
#quiz-inner.q-in-right{animation:q-slide-in-r .55s var(--ease-canvas) both}
#quiz-inner.q-in-left{animation:q-slide-in-l .55s var(--ease-canvas) both}
/* the slide is the motion: options do not re-stagger on top of it */
#quiz-inner.q-in-right .quiz-option,#quiz-inner.q-in-left .quiz-option{animation:none;opacity:1}
@keyframes q-slide-in-r{from{transform:translate3d(106%,0,0)}to{transform:none}}
@keyframes q-slide-in-l{from{transform:translate3d(-106%,0,0)}to{transform:none}}
@keyframes q-slide-out-l{from{transform:none}to{transform:translate3d(-106%,0,0)}}
@keyframes q-slide-out-r{from{transform:none}to{transform:translate3d(106%,0,0)}}
.quiz-option:hover{border-color:var(--ink);transform:translate3d(2px,0,0)}
.quiz-option:active{transform:translate3d(2px,0,0) scale(.99);transition-duration:var(--t-press)}
.quiz-option.is-sel{background:var(--white);border-color:var(--ink)}
.quiz-back{display:inline-flex;margin-top:14px}
.quiz-back[hidden]{display:none}

/* ---- capture fields: both stacked and always visible ---- */
.capture-fields{display:flex;flex-direction:column;gap:14px;margin-bottom:4px}
.capture-field{display:flex;flex-direction:column;gap:7px}
.capture-label{
  font:600 12.5px/1.35 var(--font);
  color:var(--muted);
}

.text-input{
  width:100%;height:48px;border-radius:12px;
  border:1.5px solid var(--line);
  background:var(--cream);
  padding:0 14px;
  font:400 14.5px/1 var(--font);
  color:var(--ink);
  outline:none;
  transition:border-color var(--t-state) ease;
}
.text-area{height:auto;min-height:84px;padding:12px 14px;line-height:1.45;resize:vertical}
.text-input:focus{border-color:var(--ink)}
/* inputs get a calm ring, not the terracotta control ring */
.text-input:focus-visible{outline:none;box-shadow:0 0 0 4px rgba(34,28,16,.08)}
.quiz-success[hidden]{display:none}
.quiz-upsell{
  margin:18px 0 10px;
  padding-top:16px;
  border-top:1px solid var(--line);
  font:400 13.5px/1.5 var(--font);
  color:var(--muted);
  text-wrap:pretty;
}
.quiz-upsell-btn{width:100%;height:44px;font-size:14.5px;border-radius:12px}
#quiz-resource-link{text-decoration:none;margin-top:0}

.quiz-status{margin:10px 0 0;font:400 13px/1.4 var(--font);color:var(--muted)}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* ==========================================================================
   Reduced motion — hold one word, drop the movement, keep everything usable
   ========================================================================== */
/* ==========================================================================
   BOOKING UI (step 2 of the Learn With Me popup)
   Our own picker. No iframe. Mobile: calendar, then times, then form.
   Desktop: calendar left, times right, form beneath.
   ========================================================================== */
.bk{display:flex;flex-direction:column;gap:14px;min-width:0}

.bk-status{
  margin:0;min-height:0;
  font:500 12.5px/1.4 var(--font);
  color:var(--muted);
;white-space:normal;overflow-wrap:anywhere}
.bk-status:empty{display:none}

/* page 2 is a single column: calendar, then the times row, then the button
   pinned to the bottom so the page has no dead space under it. */
.bk{display:flex;flex-direction:column;gap:14px;min-width:0;flex:1 1 auto}
/* the action stays on screen at the bottom of the dialog however tall the
   calendar gets, so it is never stranded below the fold */
.bk-foot{
  position:sticky;bottom:0;z-index:2;
  margin-top:auto;flex:none;
  padding-top:10px;
  background:var(--white);
}
.bk-choose{width:100%;flex:none;margin-top:0}
.bk-choose:disabled{opacity:.45;cursor:not-allowed}

/* ---- calendar ---- */
.bk-cal{min-width:0}
.bk-cal-head{
  display:flex;align-items:center;justify-content:space-between;
  gap:8px;margin-bottom:10px;
}
.bk-month{
  font:600 14.5px/1 var(--font);
  color:var(--ink);
  text-align:center;flex:1;
}
.bk-nav{
  flex:none;width:32px;height:32px;
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--line);border-radius:9px;
  background:var(--cream);color:var(--muted);
  cursor:pointer;
  transition:border-color var(--t-state) ease,color var(--t-state) ease,
             transform var(--t-feedback) var(--ease-out);
}
.bk-nav:hover{border-color:var(--terracotta);color:var(--terracotta)}
.bk-nav:active{transform:scale(.94);transition-duration:var(--t-press)}

.bk-dow{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;margin-bottom:6px}
.bk-dow span{
  text-align:center;
  font:600 10.5px/1 var(--font);
  color:var(--faint);
}

.bk-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}
.bk-day{
  aspect-ratio:1/1;min-width:0;
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--line);border-radius:9px;
  background:var(--cream);color:var(--ink);
  font:500 13px/1 var(--font);
  cursor:pointer;
  transition:border-color var(--t-state) ease,background var(--t-state) ease,
             color var(--t-state) ease,transform var(--t-feedback) var(--ease-out);
}
.bk-day:hover:not(:disabled){border-color:var(--terracotta);color:var(--terracotta)}
.bk-day:active:not(:disabled){transform:scale(.94);transition-duration:var(--t-press)}
.bk-day.is-sel{background:var(--ink);border-color:var(--ink);color:var(--cream)}
.bk-day.is-sel:hover{color:var(--cream)}
/* days with no slots: visibly muted and not operable */
.bk-day.is-closed{
  background:transparent;border-color:transparent;
  color:var(--faint);opacity:.45;cursor:default;
}
.bk-day.is-blank{border:none;background:none;cursor:default}
.bk-day.is-today{box-shadow:inset 0 0 0 1.5px var(--terracotta)}
.bk-day.is-today.is-sel{box-shadow:none}

.bk-empty{
  margin:12px 0 0;
  font:400 13px/1.5 var(--font);
  color:var(--muted);
}
.bk-empty[hidden]{display:none}

/* the calendar dims while its month is loading */
.bk.is-loading .bk-grid{opacity:.45;transition:opacity var(--t-state) ease}

/* ---- times ---- */
.bk-times-pane{min-width:0}
.bk-sub{
  margin:0 0 8px;
  font:600 13.5px/1.2 var(--font);
  color:var(--ink);
}
/* One upright row. Horizontal scroll, scrollbar hidden but scrollable, with
   an edge fade so it is obviously scrollable. */
.bk-times-scroll{
  position:relative;
  min-width:0;
  /* the fade is a mask so it works over any background */
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 14px,#000 calc(100% - 22px),transparent 100%);
  mask-image:linear-gradient(to right,transparent 0,#000 14px,#000 calc(100% - 22px),transparent 100%);
}
.bk-times{
  display:flex;flex-wrap:nowrap;gap:7px;
  min-width:0;
  overflow-x:auto;
  overflow-y:hidden;
  scroll-snap-type:x proximity;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior-x:contain;
  scrollbar-width:thin;              /* visible when the chips overflow */
  scrollbar-color:var(--bar-thumb) transparent;
  padding:2px 14px 8px 14px;
}
.bk-times::-webkit-scrollbar{height:6px}
.bk-times::-webkit-scrollbar-track{background:transparent}
.bk-times::-webkit-scrollbar-thumb{background:var(--bar-thumb);border-radius:999px}
.bk-times::-webkit-scrollbar-thumb:hover{background:var(--bar-thumb-hover)}
.bk-time{
  flex:0 0 auto;
  scroll-snap-align:start;
  white-space:nowrap;
  /* guard: writing-mode inherits, and the volume slider uses vertical-lr.
     Pin the chips upright so it can never leak in here. */
  writing-mode:horizontal-tb;
  text-orientation:mixed;
  padding:9px 13px;
  border:1px solid var(--line);border-radius:10px;
  background:var(--cream);color:var(--ink);
  font:600 13px/1 var(--font);
  cursor:pointer;
  transition:border-color var(--t-state) ease,background var(--t-state) ease,
             color var(--t-state) ease,transform var(--t-feedback) var(--ease-out);
}
.bk-time:hover{border-color:var(--terracotta);color:var(--terracotta)}
.bk-time:active{transform:scale(.97);transition-duration:var(--t-press)}
.bk-time.is-sel{background:var(--ink);border-color:var(--ink);color:var(--cream)}

.bk-hint{margin:0;font:400 13px/1.5 var(--font);color:var(--muted)}
.bk-tz{margin:10px 0 0;font:400 12px/1.4 var(--font);color:var(--faint)}
.bk-tz:empty{display:none}

/* ---- details form ---- */
.bk-form{
  display:flex;flex-direction:column;gap:12px;
  padding-top:6px;
  min-width:0;
}
.bk-form[hidden]{display:none}
.bk-field{display:flex;flex-direction:column;gap:6px;min-width:0}
.bk-chosen-bar{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding-bottom:12px;margin-bottom:2px;
}
.bk-chosen{margin:0;min-width:0;overflow-wrap:anywhere}
/* the pane now hugs content, so auto margins no longer supply spacing */
.slide-1 .dlg-cta{margin-top:18px}
.bk-form .dlg-cta{margin-top:14px}
.bk-change{flex:none}
.bk-form{flex:none}
.bk-form .dlg-cta{margin-top:auto}
.bk-chosen{
  margin:0;
  font:600 14px/1.4 var(--font);
  color:var(--ink);
}
/* ---- dropdowns ----------------------------------------------------------
   The closed control is a button that matches .text-input on every measurable
   thing, and the open list is ours (index.js, bkSelects). It has to be: a
   native <select> hands its popup to the operating system, which will not
   round it, will not take these colours, and flips it UPWARD the moment it
   decides the room below is short.

   The rules below still dress the <select> itself, because that is what a
   visitor with no script gets, and it should still look like the form. */
select.text-input{
  appearance:none;-webkit-appearance:none;
  padding-right:38px;
  /* a stroked chevron in the site's icon language, not the two stacked CSS
     triangles this used to draw. Inline SVG so it inherits nothing and cannot
     drift from --muted. */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236e6448' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  /* centred rather than pinned 21px from the top: the old offset was tuned to a
     48px control and slid off-centre the moment the height changed */
  background-position:right 13px center;
  background-size:15px 15px;
  background-repeat:no-repeat;
  cursor:pointer;
  /* keeps the OS from rendering the popup list in dark mode over cream */
  color-scheme:light;
}
select.text-input:hover{border-color:var(--muted)}
/* the placeholder row reads as a prompt, the real answers read as answers */
select.text-input:has(option[value=""]:checked){color:var(--muted)}
select.text-input option{background:var(--white);color:var(--ink)}
select.text-input option:disabled{color:var(--faint)}

/* .sel wraps the pair. The <select> only steps aside once index.js has
   actually built the button, so a thrown script leaves a working control
   rather than an invisible one. */
.sel{position:relative;min-width:0}
.sel.is-live > select.text-input{display:none}
.sel > .sel-btn{display:none}
.sel.is-live > .sel-btn{display:flex}

/* Every measurable property here comes from .text-input, which the button also
   carries; this adds only what a <button> needs and a <input> does not. */
.sel-btn{
  align-items:center;justify-content:space-between;gap:10px;
  padding-right:13px;
  text-align:left;
  cursor:pointer;
  /* a button does not inherit the form's font the way an input does */
  font:400 14.5px/1 var(--font);
  -webkit-appearance:none;appearance:none;
}
.sel-btn:hover{border-color:var(--muted)}
.sel-btn[aria-expanded="true"]{border-color:var(--ink)}
.sel-face{
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--ink);
}
.sel-btn[data-placeholder="true"] .sel-face{color:var(--muted)}
.sel-chev{
  flex:none;width:15px;height:15px;color:var(--muted);
  transition:transform var(--t-state) var(--ease-out);
}
.sel-btn[aria-expanded="true"] .sel-chev{transform:rotate(180deg)}

/* The list is a child of <body>, not of the form: Step 3 scrolls inside
   .slide and .pages both clips and paints-contains, so anything left inside
   would be cut off, fixed positioning included. Out here it can lie over the
   dialog's border, which is the point. z-index clears the scrim's 50. */
.sel-list{
  position:fixed;z-index:60;
  overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  padding:6px;
  background:var(--white);
  border:1.5px solid var(--line);
  border-radius:14px;
  box-shadow:var(--shadow-dialog);
  color-scheme:light;
}
.sel-list[hidden]{display:none}
/* The open reveal. An ANIMATION rather than a transition on purpose: the list
   is display:none while closed, and you cannot transition out of that, so a
   transition would need a reflow-then-classname dance in the open path. The
   animation simply runs when the element first renders.
   clip-path does the expanding, which is why the rows do not stretch: scaling
   the box would distort every label inside it. The translate is a small lift
   on top so it reads as coming from the control rather than fading in place,
   and the origin is the top because the list ALWAYS opens downward.
   Nothing here touches layout, so place() and makeRoom() keep measuring the
   same numbers mid-animation: clip-path does not move the box at all, and both
   of them read the BUTTON's rect and the list's scrollHeight, never the list's
   own transformed rect. */
.sel-list:not([hidden]){
  transform-origin:top center;
  animation:sel-open 190ms var(--ease-out) both;
}
@keyframes sel-open{
  from{opacity:0;transform:translateY(-6px);clip-path:inset(0 0 100% 0)}
  to  {opacity:1;transform:none;clip-path:inset(0 0 0 0)}
}
.sel-opt{
  display:flex;align-items:center;
  /* 44px: a thumb target, and the same row on a desktop pointer */
  min-height:44px;
  padding:8px 12px;
  border-radius:10px;
  font:400 14.5px/1.3 var(--font);
  color:var(--ink);
  cursor:pointer;
  text-wrap:pretty;
}
/* is-active is the row the keyboard or the pointer is on. One class for both,
   so nothing depends on hover, which a phone does not have. */
.sel-opt.is-active{background:var(--terracotta);color:var(--white)}
.sel-opt[aria-selected="true"]{font-weight:600}
.sel-opt[aria-disabled="true"]{color:var(--muted);cursor:default}
.sel-opt[data-placeholder="true"]{color:var(--muted)}
.sel-opt[aria-disabled="true"].is-active,
.sel-opt[data-placeholder="true"].is-active{color:var(--white)}
.bk-error{
  margin:0;
  font:500 13px/1.45 var(--font);
  color:var(--terracotta);
}
.bk-error[hidden]{display:none}
/* Text opt-in: a real checkbox, unchecked, with the disclosure carriers read
   beside it. Same size as the field labels so it reads as part of the form,
   not as fine print. */
.bk-sms{display:flex;align-items:flex-start;gap:10px;cursor:pointer}
.bk-sms input{flex:none;width:18px;height:18px;margin:0;accent-color:var(--ink);cursor:pointer}
.bk-sms span{font:400 12.5px/1.5 var(--font);color:var(--muted)}
.bk-sms a{color:var(--ink)}

/* ---- sent ---- */
.bk-done{
  display:flex;flex-direction:column;gap:8px;
  padding-top:16px;border-top:1px solid var(--line);
}
.bk-done[hidden]{display:none}
.bk-done-when{margin:0;font:600 14px/1.4 var(--font);color:var(--ink)}
.bk-done-note{margin:0;font:400 13.5px/1.55 var(--font);color:var(--muted);text-wrap:pretty}

/* ---- desktop: calendar left, times right ---- */
@media (min-width:640px){
  /* desktop: calendar centred at a comfortable width, times still a row below */
  .bk-cal{max-width:380px;margin-left:auto;margin-right:auto;width:100%}
}

/* ==========================================================================
   SCROLLBARS — site palette, both engines.
   Standard properties first, then the WebKit pseudo-elements. Rounded thumb,
   no stepper buttons. The times row stays hidden (rule above); this covers
   every scrollbar that does show.
   ========================================================================== */
:root{
  --bar-track:var(--track);
  --bar-thumb:rgba(180,95,42,.55);   /* muted terracotta at rest */
  --bar-thumb-hover:var(--terracotta);
}

/* The page scrolls without ever showing a bar (Jake's call); inner surfaces
   keep their styled thin bars. */
html{scrollbar-width:none}
html::-webkit-scrollbar{display:none}
/* .bk-times shows a thin bar when the chips overflow (Jake's call) */
.scrim,.dialog,.slide,.view-results,.card-media,
.player-preview,textarea.text-input{
  scrollbar-width:thin;
  scrollbar-color:var(--bar-thumb) var(--bar-track);
}
/* NOT .quiz-wrap and NOT .bk-times: their bars are hidden by design, and a
   later thin rule here would silently re-show them in Firefox */

::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:var(--bar-track);border-radius:8px}
::-webkit-scrollbar-thumb{
  background:var(--bar-thumb);
  border-radius:8px;
  border:2px solid var(--bar-track);   /* inset so the thumb reads rounded */
}
::-webkit-scrollbar-thumb:hover{background:var(--bar-thumb-hover)}
::-webkit-scrollbar-corner{background:var(--bar-track)}
/* no steppers */
::-webkit-scrollbar-button{display:none;width:0;height:0}

/* on the dark faces the track would glare, so tone it down there */
.card-media,.player-preview{
  --bar-track:rgba(253,250,240,.14);
}

@media (prefers-reduced-motion:reduce){
  /* the list still opens, it just arrives rather than expands */
  .sel-list:not([hidden]){animation:none}
  /* the ring still marks the sending state, it just stops turning */
  .btn-spin{animation:none}
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-delay:0ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    transition-delay:0ms !important;
    scroll-behavior:auto !important;
  }
  /* the rotator holds the first word instead of cycling */
  .rot-word{animation:none !important;opacity:0;transform:none}
  .rot-word:first-child{opacity:1}
  .btn:hover,.btn:active,.pill:hover,.pill:active,
  .quiz-option:hover,.quiz-option:active,
  .card-cta:hover,.card-cta:active,.card-back-btn:active,
  .link-btn:hover,.icon-btn:active,#results-back:hover,
  .btn:hover .btn-arrow,.pill:hover span,
  .player-btn:active,.player-start:hover .player-start-disc{transform:none}
  .dialog{opacity:1;transform:none}
  .player-bar{opacity:1;transform:none}
  /* the preview bubble appears instantly; it keeps translateX(-50%) so it
     stays centred on the cursor */
  .player-preview{transition:none !important}
  .player-preview.is-on{transform:translateX(-50%)}
  .player-scrub:hover .player-track{transform:none}
  .player-vol{transition:none !important}
  /* no rotation: the faces swap instantly, behaviour is unchanged */
  .card-flip{transition:none !important}
}
