/*
 * Current, compact homepage hero.
 *
 * One small, fixed-size Guru pulls the visible film into the page. The opening
 * pose is deliberately static. Motion begins only when the visitor scrolls.
 */

:root{
  --hero-guru-h:132px;
  --hero-guru-ratio:1.0714286;
  --hero-panel-edge:14px;
}

.hero-film{
  position:relative;
  min-height:100svh;
  background:var(--white);
}

/* svh is the viewport with the mobile browser chrome EXPANDED, lvh with it
   COLLAPSED. Both are STATIC - the browser resolves each one once and never
   revises it - so a sticky box locked to either is right in one chrome state
   and wrong in the other, while the position:fixed WhatsApp dock is always
   measured against the live visible viewport. That mismatch is the dead white
   band that opens under the grey panel once you start scrolling, with the dock
   sitting in it.

   max() of the static floor and the live --vvh (js/viewport.js) resolves it:
   lvh is the tallest the unit system claims the viewport gets, --vvh is the
   height it ACTUALLY is right now, and taking the larger means the panel can
   only ever be too tall, never too short. Because it only adds height, a
   mid-scroll update cannot shift the document or open a new gap, and with JS
   off every rule falls back to the plain lvh behaviour.

   Every child in here is positioned in % of the stage, so they scale with it. */
.hero-film-stage{
  position:sticky;
  top:0;
  height:100svh;
  overflow:hidden;
  background:var(--white);
}

@supports (height: 100lvh){
  .hero-film-stage{height:max(100lvh, var(--vvh, 0px))}
}

.hero-film-stage::before{
  content:"";
  position:absolute;
  z-index:0;
  inset:var(--hero-panel-edge);
  border-radius:30px;
  background:var(--cloud);
}

.hero-film-copy{
  position:absolute;
  z-index:4;
  left:clamp(56px,7.6vw,124px);
  top:46%;
  width:min(672px,49vw);
  transform:translateY(-50%);
  will-change:opacity,transform;
}

.hero-film-copy h1{
  margin:0;
  font-size:clamp(3.18rem,4.92vw,5.04rem);
  line-height:1.01;
  letter-spacing:-.04em;
  font-weight:700;
}

.hero-film-copy h1 span{color:var(--teal)}

.hero-film-copy p{
  max-width:43ch;
  margin-top:20px;
  color:var(--muted);
  font-size:clamp(18px,1.62vw,20.4px);
  line-height:1.48;
}

.hero-film-guru-rig{
  position:absolute;
  z-index:8;
  left:0;
  top:0;
  width:calc(var(--hero-guru-h) * var(--hero-guru-ratio));
  height:var(--hero-guru-h);
  pointer-events:none;
  transform-origin:center bottom;
  will-change:transform;
  contain:layout style;
  overflow:visible;
}

.hero-film-guru-rig img{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:contain;
  object-position:center bottom;
  image-rendering:auto;
  backface-visibility:hidden;
  opacity:0;
}

.hero-film-guru-rig img[data-on]{opacity:1}

.hero-film-card{
  position:absolute;
  z-index:5;
  left:calc(57% - 14px);
  top:20%;
  width:43%;
  height:57%;
  margin:0;
  overflow:hidden;
  isolation:isolate;
  contain:paint;
  border-radius:24px;
  background:var(--ink);
  box-shadow:0 46px 95px -58px rgb(25 23 28 / .72);
  transform:translate3d(34vw,0,0);
  will-change:left,top,width,height,border-radius;
}

.hero-film-card video{
  position:absolute;
  inset:-2px;
  display:block;
  width:calc(100% + 4px);
  height:calc(100% + 4px);
  max-width:none;
  object-fit:cover;
  transform:translateZ(0);
}

.hero-film-overlay{
  position:absolute;
  z-index:2;
  inset:0;
  display:flex;
  align-items:flex-end;
  padding:clamp(34px,5vw,72px);
  color:var(--white);
  opacity:0;
  pointer-events:none;
  will-change:opacity;
}

.hero-film-overlay::before{
  content:"";
  position:absolute;
  inset:0;
  background:linear-gradient(to top,rgb(16 12 22 / .78),rgb(16 12 22 / .18) 48%,transparent 74%);
}

.hero-film-overlay>div{position:relative;z-index:1;max-width:min(780px,72vw)}

.hero-film-overlay h2{
  max-width:14ch;
  color:var(--white);
  font-size:clamp(2.7rem,5.2vw,5rem);
  line-height:.96;
  letter-spacing:-.04em;
}

.hero-film-overlay p{
  max-width:44ch;
  margin-top:18px;
  color:rgb(255 255 255 / .86);
  font-size:clamp(15px,1.35vw,18px);
  line-height:1.48;
}

.hero-film-link{
  display:inline-flex;
  align-items:center;
  gap:8px;
  margin-top:22px;
  color:var(--white);
  font-size:14px;
  font-weight:750;
  text-decoration:none;
}

.hero-film-link .ds-arrow{
  width:14px;
  height:14px;
  fill:none;
  stroke:currentColor;
  stroke-width:1.4;
  stroke-linecap:round;
  stroke-linejoin:round;
}

.hero-film-overlay:not([aria-hidden="true"]){pointer-events:auto}

.hero-film-badge{
  position:absolute;
  left:18px;
  bottom:17px;
  padding:8px 11px;
  border-radius:999px;
  background:rgb(255 255 255 / .9);
  color:var(--ink);
  font-size:10px;
  font-weight:800;
  letter-spacing:.08em;
  text-transform:uppercase;
}

/* The film resolves into the system: film first, booking website second. */
.system-journey{
  position:relative;
  z-index:10;
  min-height:100svh;
  background:var(--white);
}

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

.system-journey-stage{
  position:relative;
  min-height:100svh;
  overflow:hidden;
  background:var(--white);
}

.system-journey-stage::before{
  content:"";
  position:absolute;
  inset:var(--hero-panel-edge);
  border-radius:30px;
  background:var(--cloud);
}

.system-journey[data-ready]{
  /* Each middle service gets a full-stage reveal and a readable hold before
     the final booking screen takes over. */
  height:760svh;
  margin-top:-100svh;
}

.system-journey[data-ready] .system-journey-stage{
  position:sticky;
  top:0;
  height:100svh;
}

/* Same collapsing-chrome fix as .hero-film-stage above. The overlap that
   pulls this section over the hero's last viewport has to move to the same
   unit, or the two stages no longer meet edge to edge.

   margin-top deliberately stays on plain lvh while the stage takes the live
   max(). margin-top is LAYOUT: re-writing it as the chrome collapses would
   move every section below this one and jump the scroll position under the
   reader. The stage's own height is paint plus a sticky release point, so
   growing it costs nothing. */
@supports (height: 100lvh){
  .system-journey[data-ready] .system-journey-stage{height:max(100lvh, var(--vvh, 0px))}
  .system-journey[data-ready]{margin-top:-100lvh}
}

.journey-gallery{
  position:absolute;
  z-index:1;
  inset:0;
  margin:0;
  padding:0;
  list-style:none;
  perspective:1800px;
  perspective-origin:50% 48%;
}

.journey-tile{
  position:absolute;
  z-index:1;
  inset:48px;
  margin:0;
  overflow:hidden;
  border-radius:28px;
  background:var(--ink);
  box-shadow:0 28px 72px -48px rgb(25 23 28 / calc(.3 + var(--card-focus,.7)*.32));
  filter:blur(var(--enter-blur,0)) saturate(calc(.84 + var(--card-focus,.7)*.16));
  transform-origin:center;
  backface-visibility:hidden;
  will-change:transform,clip-path,opacity,filter;
}

.journey-step{display:none}

.system-journey[data-ready] .journey-step{display:block}
.system-journey[data-ready] .journey-step--website,
.system-journey[data-ready] .journey-step--google{display:grid}

.journey-tile--film video{
  position:absolute;
  inset:-2px;
  width:calc(100% + 4px);
  height:calc(100% + 4px);
  max-width:none;
  object-fit:cover;
  transform:translateZ(0) scale(var(--media-scale,1.02));
  transform-origin:center;
}

.journey-tile--film{
  color:var(--white);
  text-decoration:none;
}

.journey-step-link{
  position:absolute;
  inset:0;
  display:block;
  color:inherit;
  text-decoration:none;
}

.journey-film-shade{
  position:absolute;
  inset:0;
  background:linear-gradient(to top,rgb(16 12 22 / .78),rgb(16 12 22 / .12) 56%,transparent 78%);
}

.journey-film-copy{
  position:absolute;
  z-index:1;
  left:clamp(34px,5vw,72px);
  bottom:clamp(34px,5vw,70px);
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  max-width:620px;
  color:var(--white);
  opacity:var(--film-copy-opacity,1);
}

.journey-film-copy strong{
  font-size:clamp(2.7rem,5.2vw,5rem);
  line-height:.96;
  letter-spacing:-.04em;
}

.journey-film-copy>span:not(.journey-film-go){
  margin-top:18px;
  color:rgb(255 255 255 / .86);
  font-size:clamp(15px,1.35vw,18px);
}

.journey-film-go{
  margin-top:22px;
  font-size:14px;
  font-weight:750;
}

.journey-step-face{
  position:absolute;
  z-index:6;
  inset:0;
  display:flex;
  flex-direction:column;
  justify-content:flex-end;
  padding:48px calc(34px + var(--face-inset,0px)) calc(76px + var(--face-inset-y,0px));
  color:var(--white);
  background:linear-gradient(to top,rgb(15 12 20 / calc(.84 - var(--stage-fill,0)*.48)),rgb(15 12 20 / calc(.04 - var(--stage-fill,0)*.04)) 70%);
  opacity:calc(var(--step-face-opacity,0)*var(--copy-opacity,1));
  transform:translate3d(0,var(--copy-shift,0),0);
  pointer-events:none;
}

.journey-step-copy{display:block}

.journey-step-copy strong{
  font-size:clamp(3.1rem,4.6vw,4.7rem);
  line-height:1;
  letter-spacing:-.04em;
}

/* Decorative full-bleed layers. They sit over the step-2 copy column, so without
   this they swallow the clicks on its two CTAs. */
/* The card face is the real scene, shrunk - a clone of .journey-browser or
   .journey-google-scene that hero-film.js drops in here and scales to the
   window the clip-path actually leaves visible. So the mini is bounded by
   --face-inset, not by the tile box: the tile is always full size and the card
   is a crop of it, so inset:0 here would centre the mini on a rectangle the
   viewer cannot see.
   It must be GONE before the full-size scene fades up, or the same page
   cross-fades against itself at two sizes and reads as a ghost. step-face-opacity
   alone decays across fill 0-0.9, far too slow for that; the multiplier below
   clears the mini by fill 0.25, and --scene-reveal only leaves 0 after that. */
.journey-step-mini{
  position:absolute;
  z-index:4;
  inset:var(--face-inset-y,0) var(--face-inset,0) calc(var(--face-inset-y,0px) + var(--mini-foot,80px));
  display:grid;
  place-items:center;
  opacity:calc(var(--step-face-opacity,0) * max(0,1 - var(--stage-fill,0)*4));
  pointer-events:none;
}

/* The clone keeps its expanded pixel size (JS writes it from the live scene's
   own offsetWidth/Height) and is scaled down whole, so the card is a true
   miniature rather than the same layout re-flowed at card width. */
.journey-step-mini-inner{
  transform:scale(var(--mini-scale,.3));
  transform-origin:center;
}

/* Undo the stage rules the clone inherits by sitting inside the tile: grid
   placement, the stretch, and the --scene-reveal opacity that keeps the real
   scene hidden while the tile is still a card. */
.journey-step-mini .journey-browser,
.journey-step-mini .journey-google-browser{
  position:relative;
  aspect-ratio:auto;
  box-shadow:0 30px 70px -42px rgb(25 23 28 / .55);
  z-index:auto;
  inset:auto;
  grid-column:auto;
  grid-row:auto;
  align-self:auto;
  justify-self:auto;
  min-height:0;
  width:100%;
  height:100%;
  opacity:1;
  transform:none;
}


.journey-google-scene{
  position:absolute;
  z-index:4;
  inset:0;
  display:grid;
  place-items:center;
  padding:clamp(28px,4vw,62px);
  background:#eef3fb;
  opacity:clamp(0,calc(var(--step-face-opacity,0) + var(--stage-fill,0)*1.6),1);
  pointer-events:none;
}

.journey-google-browser{
  width:min(100%,1120px);
  aspect-ratio:16/9;
  overflow:hidden;
  border-radius:16px;
  background:var(--white);
  color:#202124;
  box-shadow:0 34px 72px -48px rgb(14 11 18 / .48);
  transform:translateY(calc((1 - var(--scene-reveal,0))*18px)) scale(calc(.97 + var(--scene-reveal,0)*.03));
  transform-origin:center;
}

.journey-google-bar{
  height:15%;
  display:flex;
  align-items:center;
  gap:3%;
  padding:0 3%;
  border-bottom:1px solid #eceff1;
}

.journey-google-word{font-size:clamp(12px,1.55vw,22px);font-weight:700;letter-spacing:-.04em}
.journey-google-word i{font-style:normal}
.journey-google-word i:nth-child(1),.journey-google-word i:nth-child(4){color:#4285f4}
.journey-google-word i:nth-child(2),.journey-google-word i:nth-child(6){color:#ea4335}
.journey-google-word i:nth-child(3){color:#fbbc05}
.journey-google-word i:nth-child(5){color:#34a853}

.journey-google-search{
  width:55%;
  height:58%;
  display:flex;
  align-items:center;
  justify-content:space-between;
  padding:0 2%;
  border:1px solid #dfe1e5;
  border-radius:999px;
  box-shadow:0 2px 7px rgb(60 64 67 / .12);
  font-size:clamp(7px,.95vw,14px);
}

.journey-google-search b{
  position:relative;
  width:clamp(8px,1.1vw,15px);
  height:clamp(8px,1.1vw,15px);
  border:2px solid #5f6368;
  border-radius:50%;
}

.journey-google-search b::after{
  content:"";
  position:absolute;
  right:-5px;
  bottom:-2px;
  width:6px;
  height:2px;
  background:#5f6368;
  transform:rotate(45deg);
}

.journey-google-result{
  height:85%;
  display:grid;
  grid-template-columns:1.18fr .82fr;
  gap:2.5%;
  padding:2.6% 3% 3%;
}

.journey-google-photos{
  min-width:0;
  display:grid;
  grid-template-columns:1.6fr .75fr;
  grid-template-rows:1fr 1fr;
  gap:3px;
  overflow:hidden;
  border-radius:12px;
}

.journey-google-photos img{width:100%;height:100%;object-fit:cover}
.journey-google-photos img:first-child{grid-row:1/3}

.journey-google-profile{
  min-width:0;
  padding:2% 1%;
}

.journey-google-profile>strong{
  display:block;
  font-size:clamp(14px,2.1vw,30px);
  font-weight:500;
  line-height:1;
  letter-spacing:-.025em;
}

.journey-google-rating{
  display:flex;
  align-items:center;
  gap:2%;
  margin-top:3%;
  font-size:clamp(6px,.8vw,12px);
}

.journey-google-rating i{color:#f9ab00;font-style:normal;letter-spacing:1px}
.journey-google-rating small{color:#5f6368;font-size:inherit}
.journey-google-type{display:block;margin-top:2%;color:#70757a;font-size:clamp(6px,.78vw,12px)}

.journey-google-actions{
  display:flex;
  gap:5%;
  margin:7% 0 6%;
}

.journey-google-actions>b{
  display:grid;
  justify-items:center;
  gap:5px;
  color:#1a73e8;
  font-size:clamp(5px,.65vw,10px);
  font-weight:500;
}

.journey-google-actions i{
  width:clamp(21px,2.8vw,38px);
  height:clamp(21px,2.8vw,38px);
  display:grid;
  place-items:center;
  border-radius:50%;
  background:#e8f0fe;
}

.journey-google-actions svg{width:45%;height:45%;fill:none;stroke:currentColor;stroke-width:1.8}

.journey-google-info{
  display:grid;
  gap:clamp(5px,.75vw,11px);
  padding-top:5%;
  border-top:1px solid #eceff1;
  font-size:clamp(6px,.75vw,11px);
}

.journey-google-info b{font-weight:500}
.journey-google-availability{
  display:block;
  margin-top:6%;
  padding:4% 5%;
  border-radius:9px;
  background:#f8fafd;
  color:#1a73e8;
  font-size:clamp(6px,.78vw,12px);
  font-weight:700;
}

.journey-step--bookings{
  background:var(--mist);
  color:var(--ink);
}

.journey-wave-guru{
  position:absolute;
  z-index:10;
  left:0;
  top:0;
  width:clamp(108px,9vw,138px);
  height:auto;
  opacity:0;
  transform:translate3d(-200px,0,0);
  transform-origin:55% 78%;
  pointer-events:none;
  will-change:transform,opacity;
}

/* Steps 2 and 3 share one stage and reveal contract. */
.journey-tile--website,
.journey-step--google{
  --website-reveal:var(--scene-reveal,0);
  z-index:2;
  display:grid;
  grid-template-columns:minmax(260px,.72fr) minmax(0,1.28fr);
  gap:clamp(30px,4vw,64px);
  align-items:center;
  padding:clamp(34px,5vw,72px);
  background:#fbfafe;
  color:var(--ink);
}

/* Step 3 leads with the Google proof, then lands on the explanation. The
   asymmetry distinguishes it from step 2 without changing the filled bounds. */
.journey-step--google{
  grid-template-columns:minmax(0,1.15fr) minmax(280px,.85fr);
}

.journey-step--google .journey-google-scene{
  grid-column:1;
  grid-row:1;
}

.journey-step--google .journey-marketing-copy{
  grid-column:2;
  grid-row:1;
  width:min(100%,34rem);
  justify-self:end;
}

.journey-website-copy,
.journey-marketing-copy{
  position:relative;
  z-index:calc(2 + var(--stage-fill,0)*5);
  /* Relay, not crossfade: the copy column is the LAST layer in. It waits until the
     browser scene is most of the way up, so the three text layers never share a beat.
     That 0.55 offset is the whole reason step 2 reads clean instead of washed out. */
  --copy-in:clamp(0,calc((var(--website-reveal,1) - .55) / .45),1);
  opacity:var(--copy-in);
  transform:translate3d(0,calc((1 - var(--copy-in)) * 18px),0);
}

.journey-website-copy h2,
.journey-marketing-copy h2{
  max-width:9ch;
  margin:0;
  color:var(--ink);
  font-size:clamp(2.6rem,4.5vw,4.7rem);
  line-height:.98;
  letter-spacing:-.04em;
}

.journey-website-copy p,
.journey-marketing-copy p{
  max-width:39ch;
  margin-top:22px;
  color:var(--muted);
  font-size:clamp(15px,1.35vw,18px);
  line-height:1.48;
}

.journey-website-actions{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:12px 22px;
  margin-top:28px;
}

.journey-website-actions a{
  display:inline-flex;
  align-items:center;
  gap:8px;
  color:var(--ink);
  font-size:14px;
  font-weight:750;
  text-decoration:none;
}

.journey-website-actions a:first-child{
  min-height:48px;
  padding:0 18px;
  border-radius:999px;
  background:var(--signal-yellow);
}

.journey-website-actions .ds-arrow{
  width:14px;
  height:14px;
  fill:none;
  stroke:currentColor;
  stroke-width:1.4;
  stroke-linecap:round;
  stroke-linejoin:round;
}

.journey-step--google .journey-google-scene{
  position:relative;
  z-index:1;
  inset:auto;
  align-self:stretch;
  min-height:420px;
  overflow:hidden;
  border-radius:calc(16px + var(--stage-fill,0)*10px);
  opacity:var(--scene-reveal,1);
  transform:translateZ(0) scale(calc(1 + (1 - var(--scene-reveal,1))*.04));
  transform-origin:center;
  contain:layout;
}

.journey-browser{
  --browser-bar-h:calc(42px + var(--stage-fill,0)*20px);
  pointer-events:none;
  position:relative;
  z-index:calc(1 + var(--stage-fill,0)*6);
  align-self:stretch;
  min-height:420px;
  overflow:hidden;
  border-radius:calc(16px + var(--stage-fill,0)*10px);
  background:var(--white);
  box-shadow:0 30px 70px -42px rgb(25 23 28 / .55);
  opacity:var(--scene-reveal,1);
  transform:translateZ(0) scale(calc(1 + (1 - var(--scene-reveal,1))*.04));
  transform-origin:center;
  contain:layout;
}

.journey-browser-bar{
  height:var(--browser-bar-h,42px);
  display:flex;
  align-items:center;
  gap:calc(7px + var(--stage-fill,0)*4px);
  padding:0 calc(14px + var(--stage-fill,0)*10px);
  background:var(--white);
}

.journey-browser-bar i{
  width:calc(8px + var(--stage-fill,0)*4px);
  height:calc(8px + var(--stage-fill,0)*4px);
  border-radius:50%;
  background:#d8d5de;
}

.journey-browser-bar span{
  margin-left:calc(7px + var(--stage-fill,0)*4px);
  color:#77727e;
  font-size:calc(11px + var(--stage-fill,0)*6px);
  font-weight:650;
}

.journey-browser-page{
  position:absolute;
  inset:var(--browser-bar-h,42px) 0 0;
  overflow:hidden;
  background:#17131e;
}

.journey-browser-page>img{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:cover;
}

.journey-browser-page::after{
  content:"";
  position:absolute;
  inset:0;
  background:linear-gradient(90deg,rgb(14 11 18 / .68),transparent 66%);
}

.journey-browser-nav,
.journey-browser-copy{
  position:absolute;
  z-index:2;
  left:calc(28px + var(--stage-fill,0)*22px);
  right:calc(28px + var(--stage-fill,0)*22px);
  color:var(--white);
}

.journey-browser-nav{
  top:calc(24px + var(--stage-fill,0)*16px);
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:calc(18px + var(--stage-fill,0)*16px);
  font-size:calc(11px + var(--stage-fill,0)*6px);
}

.journey-browser-nav strong{font-size:calc(15px + var(--stage-fill,0)*11px)}
.journey-browser-nav span{margin-left:auto;color:rgb(255 255 255 / .76)}
.journey-browser-nav b{padding:calc(9px + var(--stage-fill,0)*5px) calc(12px + var(--stage-fill,0)*8px);border-radius:999px;background:var(--signal-yellow);color:var(--ink)}

.journey-browser-copy{
  bottom:calc(34px + var(--stage-fill,0)*22px);
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  max-width:calc(360px + var(--stage-fill,0)*230px);
}

.journey-browser-copy small{font-size:calc(11px + var(--stage-fill,0)*5px);text-transform:uppercase;letter-spacing:.08em}
.journey-browser-copy strong{margin-top:calc(9px + var(--stage-fill,0)*6px);font-size:calc(clamp(1.7rem,2.7vw,3rem) + var(--stage-fill,0)*1.15rem);line-height:1;letter-spacing:-.035em}
.journey-browser-copy b{margin-top:calc(16px + var(--stage-fill,0)*8px);padding:calc(10px + var(--stage-fill,0)*5px) calc(13px + var(--stage-fill,0)*9px);border-radius:999px;background:var(--white);color:var(--ink);font-size:calc(11px + var(--stage-fill,0)*5px)}

@media(max-width:900px){
  :root{
    --hero-guru-h:94px;
    --hero-panel-edge:8px;
  }

  .hero-film{min-height:100svh}

  .hero-film-stage::before{border-radius:24px}

  .hero-film-copy{
    left:30px;
    right:30px;
    top:36%;
    width:auto;
  }

  .hero-film-copy h1{font-size:clamp(2.55rem,11.6vw,4rem)}
  .hero-film-copy p{max-width:36ch;font-size:15px}

  /* Home position is flush right (26% + 56% + the gutter = the screen), but
     the card starts pushed an EXTRA half of its own width past that, so only
     half of it is visible on first paint and the Guru hauls the rest into
     view. The numbers here are the static, pre-JS state of measure() in
     js/hero-film.js and are derived the same way:
       home left    = 26vw - 6
       flush travel = (100vw - 14 - width) - home left = 18vw - 8
       overflow     = width * .5 = 28vw
       travel       = 18vw - 8 + 28vw = 46vw - 8 */
  .hero-film-card{
    left:calc(26% - 6px);
    top:58%;
    width:56%;
    height:30%;
    min-height:196px;
    border-radius:20px;
    box-shadow:none;
    clip-path:inset(0 round 20px);
    transform:translate3d(calc(46vw - 8px),0,0);
  }

  /* 44px is the tap-target floor, not a target. The link's own text is 21px tall. */
  .hero-film-link{min-height:44px;align-items:center}

  .hero-film-overlay{padding:28px 26px 118px}
  .hero-film-overlay>div{max-width:none}
  .hero-film-overlay h2{font-size:clamp(2.45rem,11vw,3.7rem)}
  .hero-film-overlay p{font-size:15px}

  .system-journey-stage::before{border-radius:24px}
  /* The longer mobile track prevents normal touch scrolling from skipping the
     website and SEO holds. */
  .system-journey[data-ready]{height:680svh}

  .journey-tile{
    inset:14px;
    border-radius:20px;
    box-shadow:none;
  }

  /* Type here is sized for the CARD, not the screen. The card is ~80vw, so the
     desktop-scale 2.8rem headline was breaking "Direct-booking website" across
     three cramped lines. */
  .journey-step-face{
    inset:0;
    /* The bottom padding is NOT decoration: the tile is clip-masked 10.5% top and
       bottom in the row (85.7px of the 816px element), easing to 7.353% at full
       fill (60px), so 26px of that reserve stops being dead space as it fills. */
    padding:26px 22px calc(116px - var(--stage-fill,0)*26px);
  }

  /* Type is sized for the CARD: 275px wide in the row, 362px filled. Both ends
     get their own value rather than one compromise size. */
  .journey-step-copy strong{font-size:calc(2.08rem + var(--stage-fill,0)*.28rem);line-height:1.04;letter-spacing:-.02em}

  /* Step 3 is a portrait result on phones. Keeping the desktop 16:9 browser
     here left more than half the focal hold blank. */
  .journey-google-scene{padding:64px 12px 12px}
  .journey-google-browser{width:100%;height:100%;aspect-ratio:auto;border-radius:12px;box-shadow:none}
  .journey-google-bar{height:10%;padding-inline:14px;gap:12px}
  .journey-google-word{font-size:14px}
  .journey-google-search{width:auto;min-width:0;flex:1;height:36px;padding-inline:12px;font-size:10px}
  .journey-google-search b{width:10px;height:10px;border-width:1.5px}
  .journey-google-search b::after{right:-4px;bottom:-1px;width:5px;height:1.5px}
  /* The profile column now carries the whole listing (name through the
     availability line) in the lower half of a portrait frame, so it gets the
     larger of the two rows and the type steps down to match. */
  .journey-google-result{height:90%;grid-template-columns:1fr;grid-template-rows:minmax(0,.86fr) minmax(0,1.14fr);gap:10px;padding:10px 12px 12px}
  .journey-google-photos{border-radius:9px;gap:3px}
  .journey-google-profile{padding:4px 2px;overflow:hidden}
  .journey-google-profile>strong{font-size:19px}
  .journey-google-rating,.journey-google-type{font-size:9px}
  .journey-google-actions{margin:4% 0 3%}
  .journey-google-actions>b{font-size:7px}
  .journey-google-actions i{width:23px;height:23px}
  .journey-google-info{gap:6px;padding-top:4%;font-size:9px}
  .journey-google-availability{margin-top:3%;padding:8px 10px;border-radius:7px;font-size:9px}
  .journey-wave-guru{width:104px}

  .journey-film-copy{
    left:26px;
    right:26px;
    bottom:110px;
  }

  .journey-film-copy strong{font-size:clamp(2.45rem,11vw,3.7rem)}

  /* Portrait fill, arranged like the hero: copy first and hard left, the mock
     under it and pushed right. Both tiles take the SAME arrangement so they
     read as a pair rather than two unrelated compositions. The block padding
     matches the step face's clip reserve (85.7px in the row, 60px filled) so
     neither row ever lands outside the visible card. */
  .journey-tile--website,
  .journey-step--google{
    grid-template-columns:1fr;
    grid-template-rows:auto minmax(0,1fr);
    gap:calc(14px + var(--stage-fill,0)*6px);
    /* Bumped from 92px so the heading clears the floating mobile header with
       real breathing room instead of sitting flush under it. */
    padding:calc(140px - var(--stage-fill,0)*26px) 20px;
  }

  .journey-website-copy,
  .journey-marketing-copy{
    grid-column:1;
    grid-row:1;
    justify-self:start;
    width:100%;
    padding:0 4px;
  }

  /* The mock is the second beat: bottom of the card, inset from the left so the
     copy above it keeps the left edge to itself. */
  .journey-tile--website>.journey-browser,
  .journey-step--google>.journey-google-scene{
    grid-column:1;
    grid-row:2;
    justify-self:end;
    width:92%;
    min-height:0;
  }

  /* Beats the desktop `.journey-step--google .journey-marketing-copy` column
     rule on specificity. Without it the copy stays in column 2 and the scene
     lands in an implicit 0px column. */
  .journey-step--google .journey-marketing-copy{
    grid-column:1;
    grid-row:1;
    width:100%;
    justify-self:start;
  }

  .journey-website-copy h2,
  .journey-marketing-copy h2{max-width:15ch;font-size:clamp(1.85rem,7.4vw,2.6rem);line-height:1.02}
  .journey-website-copy p,
  .journey-marketing-copy p{max-width:34ch;margin-top:11px;font-size:13.5px;line-height:1.44}
  .journey-website-actions{margin-top:15px}
  /* Both links go live at fill now, not just the pill, so both need the 44px floor. */
  /* 46, not 44: the tile carries a live scale transform, so a rect measured
     mid-journey lands fractionally under whatever is declared here. */
  .journey-website-actions a{min-height:46px}
  .journey-website-actions a:first-child{padding:0 15px}
  .journey-browser-nav span{display:none}

  .journey-step--google>.journey-google-scene{padding:0}

  /* The browser mock is a landscape frame on desktop. Here it is ~322 x 330,
     so the chrome shrinks and the page scrim turns vertical: the desktop 90deg
     wash only darkens the left third, which on a near-square page leaves the
     bottom copy sitting on raw photo. */
  .journey-browser{--browser-bar-h:calc(30px + var(--stage-fill,0)*14px)}
  .journey-browser-bar{gap:calc(6px + var(--stage-fill,0)*3px);padding:0 calc(11px + var(--stage-fill,0)*5px)}
  .journey-browser-bar i{width:calc(7px + var(--stage-fill,0)*3px);height:calc(7px + var(--stage-fill,0)*3px)}
  .journey-browser-bar span{margin-left:calc(6px + var(--stage-fill,0)*3px);font-size:calc(10px + var(--stage-fill,0)*3px)}

  .journey-browser-page::after{
    background:linear-gradient(to top,rgb(14 11 18 / .8),rgb(14 11 18 / .3) 46%,rgb(14 11 18 / .34));
  }

  .journey-browser-nav,
  .journey-browser-copy{
    left:calc(14px + var(--stage-fill,0)*8px);
    right:calc(14px + var(--stage-fill,0)*8px);
  }

  .journey-browser-nav{
    top:calc(12px + var(--stage-fill,0)*8px);
    gap:calc(10px + var(--stage-fill,0)*8px);
    font-size:calc(10px + var(--stage-fill,0)*3px);
  }

  .journey-browser-nav strong{font-size:calc(13px + var(--stage-fill,0)*6px)}
  .journey-browser-nav b{padding:calc(7px + var(--stage-fill,0)*3px) calc(10px + var(--stage-fill,0)*4px)}

  .journey-browser-copy{
    bottom:calc(14px + var(--stage-fill,0)*10px);
    max-width:none;
  }

  .journey-browser-copy small{font-size:calc(9px + var(--stage-fill,0)*2px)}
  .journey-browser-copy strong{margin-top:calc(6px + var(--stage-fill,0)*4px);font-size:calc(1.35rem + var(--stage-fill,0)*.5rem)}
  .journey-browser-copy b{margin-top:calc(11px + var(--stage-fill,0)*5px);padding:calc(8px + var(--stage-fill,0)*3px) calc(12px + var(--stage-fill,0)*4px);font-size:calc(10px + var(--stage-fill,0)*3px)}

  /* Thin header rules moved to css/site.css so every page gets the same
     compact mobile header, not just this one. */
}

/* Phone hero headline. home-hero-pricing.css sets an unqualified
   width:min(760px,54vw) and a 4.65vw font, which on a phone leaves the h1 a
   210px column and shatters "Your place. Your guests." into four one-word
   lines. Re-qualify both through .hero-film so this wins on specificity, not
   source order, and size the type so each of the two spans holds ONE line:
   the lead measures 10.18em wide, so font-size = (viewport - gutters) / 10.4. */
@media(max-width:768px){
  .hero-film .hero-film-copy{
    left:24px;
    right:24px;
    width:auto;
  }

  .hero-film .hero-film-copy h1{
    font-size:clamp(1.6rem,calc(9.45vw - 4.4px),3.18rem);
    line-height:1.06;
    letter-spacing:-.035em;
  }
}


@media(prefers-reduced-motion:reduce){
  .hero-film-copy,
  .hero-film-card,
  .hero-film-guru-rig,
  .hero-film-overlay,
  .journey-tile{will-change:auto}

  .system-journey[data-ready]{height:auto;margin-top:0}
  .system-journey[data-ready] .system-journey-stage{position:relative;height:auto;min-height:100svh;padding:110px 48px}
  .system-journey[data-ready] .journey-gallery{position:relative;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:24px}
  .system-journey[data-ready] .journey-step{
    --step-face-opacity:1;
    --stage-fill:0;
    --scene-reveal:0;
    --website-reveal:0;
    position:relative;
    inset:auto;
    display:block!important;
    aspect-ratio:1.6;
    transform:none!important;
    clip-path:none!important;
    opacity:1!important;
  }
  .system-journey[data-ready] .journey-website-copy,
  .system-journey[data-ready] .journey-marketing-copy,
  .system-journey[data-ready] .journey-browser{display:none}
}

@media(max-width:900px) and (prefers-reduced-motion:reduce){
  .system-journey[data-ready] .system-journey-stage{padding:84px 20px 40px}
  .system-journey[data-ready] .journey-gallery{grid-template-columns:1fr;gap:20px}
  .system-journey[data-ready] .journey-step{width:min(78vw,320px);margin-inline:auto;aspect-ratio:9/16}
  /* Nothing is clip-masked here (clip-path:none above), so the clip reserve in
     the two padding rules is pure dead space. Reclaim it: the static end state
     is four legible cards, never a tile parked mid-fill. */
  .system-journey[data-ready] .journey-step-face{padding:22px 20px 26px}
  .system-journey[data-ready] .journey-tile--website,
  .system-journey[data-ready] .journey-step--google{padding:20px}
}

/* Phone only (<=768px). Measured at 390x844: every animated thing in the
   journey - tiles, the Step 4 push, and the "0% commission." payoff - has
   settled by raw progress .86, leaving ~685px (81svh) of scroll where nothing
   moves. Lowering the height on its own does NOT fix that: every window in
   renderJourney() is a FRACTION of the span, so a shorter section just replays
   the same sequence faster and keeps the same 14% dead tail. So the height cut
   here is paired with JOURNEY_PHONE_SCALE in js/hero-film.js, which multiplies
   the journey's raw progress by (new span / 580svh) and hands renderJourney the
   same absolute pacing it had at 680svh. Net: identical animation speed, the
   payoff still lands and then holds for ~31svh (~263px) before the section
   releases. Change one of the two numbers and you must change the other.
   Tablet (769-900px) is deliberately left on the 680svh rule above. */
@media(max-width:768px){
  .system-journey[data-ready]{height:630svh}
}

/* --- Tile 1 and tile 4 carry real captures, not coded mocks --------------- */

/* The screenshot already contains the site's own nav, hero and CTA, so the
   scrim and the overlaid copy that dressed the mock would double them up. */
.journey-browser--real .journey-browser-page{background:var(--cloud)}
.journey-browser--real .journey-browser-page::after{display:none}

.journey-browser--real .journey-browser-page>img{
  object-fit:cover;
  /* Anchored left and top. The tile frame is far taller than the 16:10 capture,
     so cover crops the sides hard; centring it cut the logo off one edge and
     the hero headline off the other. Left-anchored, the crop falls on the sky
     and the lake, which carry nothing. */
  object-position:left top;
}

/* The CRM shot replaces a 900px-wide coded replica that was scaled by
   --channel-scale. An image needs no scale factor: it fills the panel and
   crops the few percent of aspect-ratio difference off the bottom. */
.channels-shot{
  width:100%;
  height:100%;
  display:block;
  object-fit:cover;
  object-position:left top;
}

/* --- Mobile: the tiles state what they are, not everything they contain --- */
@media (max-width:700px){
  /* A 1600px-wide app screen inside a phone-width card renders 9px type that
     reads as noise. The shot stays, framed on the part that carries meaning:
     the rail and the conversation list. */
  .channels-shot{object-position:left top;object-fit:cover;transform:scale(1.35);transform-origin:left top}

  /* The browser tile keeps the capture unscaled. scale(1.18) with a centred
     origin pushed the site's own nav and hero headline past the left edge of
     the frame, so the shot's text read as broken words over the tile copy. */
  .journey-browser--real .journey-browser-page>img{transform:none}

  /* The chrome earns nothing at this size. */
  .journey-browser--real .journey-browser-bar span{max-width:52vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
}
