/* ==========================================================================
   Zenlo — hero stage.
   One section, two modes:
     static    (default: tablet, phone, reduced motion, no JS) — the photo hero.
     stage     (html.stage-on, >=1025px) — the same hero pinned for 320vh while scroll
               drives --s-* variables written by js/motion.js. This file only maps those
               variables to opacity / transform; nothing here animates by itself, so
               scrolling back retraces the same values.
   Structure follows Concept B's `stage__col`; type and colour stay V1.
   ========================================================================== */

:root {
  --head-h: 89px;       /* header height: 88px content + 1px rule */
  --band-h: 76px;       /* process strip + bottom padding, so overlays centre with the copy */
}

@media (max-width: 780px) {
  :root { --head-h: 77px; }
}

/* ---------- static hero ---------- */

.stage {
  position: relative;
  isolation: isolate;
  background: #efe7da;
}

.stage__pin {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: min(calc(100svh - var(--head-h)), 860px);
  padding-bottom: 34px;
  overflow: hidden;
}

@media (min-width: 1025px) {
  .stage__pin { min-height: calc(100svh - var(--head-h)); }
}

/* photo + ambient loop */

.stage .hero-media {
  position: absolute;
  inset: 0;
  z-index: -1;
  margin: 0;
  overflow: hidden;
  background: #efe7da;
}

.hero-media-inner {
  position: absolute;
  inset: 0;
  transform-origin: 72% 40%;
}

.hero-drift,
.hero-media picture,
.hero-media img {
  display: block;
  width: 100%;
  height: 100%;
}

.hero-drift { position: relative; }

.hero-media img {
  object-fit: cover;
  object-position: 42% 35%;
  filter: none;
}

/* The loop is a 16:9 crop of the same photo; JS sizes it to sit exactly on top. */
.hero-video {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  max-width: none;
  object-fit: fill;
  opacity: 0;
  transition: opacity 1.4s ease;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 10%);
  mask-image: linear-gradient(90deg, transparent 0, #000 10%);
  pointer-events: none;
}

.hero-video.is-playing { opacity: 1; }

/* A fixed warm highlight. Plain alpha, no blend mode and no animation: the loop video sits under it. */
.hero-media-inner::after {
  content: '';
  position: absolute;
  inset: -10%;
  background: radial-gradient(40% 50% at 78% 30%, rgba(255, 236, 200, .2), transparent 70%);
  pointer-events: none;
}

.hero-veil {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgba(246, 241, 232, .92) 0%, rgba(246, 241, 232, .74) 30%, rgba(246, 241, 232, .12) 56%, rgba(246, 241, 232, 0) 70%),
    linear-gradient(0deg, rgba(246, 241, 232, .55) 0%, rgba(246, 241, 232, 0) 26%);
  pointer-events: none;
}

/* copy column */

.stage__ui {
  position: relative;
  z-index: 3;
  flex: 1;
  display: flex;
  align-items: center;
  padding-block: clamp(56px, 9vh, 110px) 40px;
}

.stage__col {
  --indent: clamp(.5rem, 4.6vw, 4.8rem);
  min-width: 0;
  max-width: 100%;
}

.stage__kicker {
  display: flex;
  align-items: center;
  gap: .8rem;
  margin: 0 0 clamp(26px, 4vh, 40px);
  font-size: .64rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--forest);
}

.stage__kicker::after {
  content: '';
  flex: none;
  width: 2.2rem;
  height: 1px;
  background: rgba(31, 74, 58, .4);
}

.stage__pulse {
  position: relative;
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--forest);
}

.stage__pulse::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--forest);
  opacity: 0;
  animation: stage-pulse 2.8s var(--ease-soft) infinite;
}

@keyframes stage-pulse {
  0%        { transform: scale(1);   opacity: .38; }
  70%, 100% { transform: scale(3.4); opacity: 0; }
}

.stage__title {
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: normal;
  line-height: 1;
}

/* The mask for the line-by-line entrance must not cut glyphs: room below for descenders (g, j, ç) and the
   full stop, room right for the last letter's overhang; the negative margins give that room back. */
.stage__ln {
  display: block;
  overflow: hidden;
  padding: 0 .12em .24em 0;
  margin: 0 -.12em -.16em 0;
}

.stage__ln > .hero-reveal { display: block; }

.stage__ln--a {
  margin-bottom: -.06em;          /* with the mask's .24em padding: the same .18em gap as before */
  font-size: clamp(1.9rem, 3vw, 2.75rem);
  font-weight: 300;
  letter-spacing: -.035em;
  color: #3a4038;
}

.stage__ln--a > .hero-reveal {
  display: flex;
  align-items: baseline;
  gap: clamp(.7rem, 1.4vw, 1.1rem);
}

.stage__est {
  flex: none;
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--sage-deep);
  transform: translateY(-.6em);
}

/* The frame is measured in the line's own em, so it holds in every language: "Bright smile." is 4.6em and
   stays on one line; the longer translations (6.2 to 9.4em) break into two lines of at most 4.6em and never
   reach the face in the photograph. --hero-scale and --hero-vh come from i18n/site.json: for the two-line
   languages the line is a little smaller and also capped by the viewport height, so two lines fit short
   laptop screens. English has no cap, so its first frame is exactly the approved one. */
.stage__ln--b {
  width: max-content;
  max-width: min(calc(100% - var(--indent) + .12em + .8em), 6.1em);
  margin-left: var(--indent);
  padding-left: .8em;            /* hanging indent: a second line steps .8em to the right, */
  text-indent: -.8em;            /* a single line ("Bright smile.") stays exactly where it was */
  font-size: calc(clamp(3.6rem, min(7.4vw, var(--hero-vh, 100vh)), 7.8rem) * var(--hero-scale, 1));
  font-weight: 400;
  line-height: .92;
  letter-spacing: -.072em;
  color: var(--forest);
  text-wrap: balance;
}

.stage__copy { margin-left: var(--indent); }

.stage__lede {
  max-width: var(--hero-lede, 340px);
  margin: clamp(26px, 4vh, 38px) 0 30px;
  color: #3f463d;
  font-size: 1.02rem;
  line-height: 1.65;
}

.stage__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 26px;
}

.stage__actions .btn-primary { min-height: 52px; padding-inline: 24px; gap: 26px; }
.stage__actions .btn-ghost { padding-inline: 0; font-size: .85rem; border-radius: 0; color: var(--ink); }
.stage__actions .btn-ghost:hover .arrow,
.stage__actions .btn-ghost:focus-visible .arrow { transform: translateY(3px); }

/* the three steps; in the stage they double as its progress readout */

.stage__band { position: relative; z-index: 3; }

.process {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin: 0;
  padding: 20px 0 0;
  border-top: 1px solid rgba(31, 74, 58, .18);
  list-style: none;
}

.process-item {
  display: flex;
  align-items: center;
  gap: 15px;
  padding-right: 1rem;
}

.process-item + .process-item {
  padding-left: 32px;
  border-left: 1px solid var(--line);
}

.process-num {
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--sage-deep);
}

.process-label {
  font-size: .84rem;
  color: #525d51;
}

/* entrance: line by line (animation lives in CSS, one shot) */

.js .hero-reveal {
  opacity: 0;
  transform: translate3d(0, 105%, 0);
  animation: hero-in 1.1s var(--ease-out) forwards;
  animation-delay: calc(.25s + var(--d, 0) * .14s);
}

.js .stage__kicker.hero-reveal,
.js .stage__lede.hero-reveal,
.js .stage__actions.hero-reveal,
.js .process.hero-reveal {
  transform: translate3d(0, 16px, 0);
}

@keyframes hero-in {
  to { opacity: 1; transform: none; }
}

/* scene layers are not part of the static hero */
.stage__aside,
.stage__cap { display: none; }

/* ---------- tablet ---------- */

@media (min-width: 781px) and (max-width: 1050px) {
  .hero-veil {
    background:
      linear-gradient(90deg, rgba(246, 241, 232, .94) 0%, rgba(246, 241, 232, .8) 38%, rgba(246, 241, 232, .1) 66%, rgba(246, 241, 232, 0) 80%),
      linear-gradient(0deg, rgba(246, 241, 232, .6) 0%, rgba(246, 241, 232, 0) 26%);
  }
  .hero-media img { object-position: 70% 35%; }
  .stage__kicker { font-size: .55rem; letter-spacing: .1em; }
  .stage__actions { gap: 14px; }
  .stage__actions .btn-primary { padding-inline: 18px; gap: 16px; }
  .stage__actions .btn-ghost { font-size: .77rem; }
  .process-item + .process-item { padding-left: 20px; }
}

/* ---------- phone ---------- */

@media (max-width: 780px) {
  .stage { background: var(--ivory); }
  .stage__pin { min-height: 0; padding-bottom: 28px; }

  .stage .hero-media {
    position: relative;
    inset: auto;
    z-index: 0;
    height: min(92vw, 520px);
    order: -1;
  }
  .hero-media img { object-position: 50% 30%; }
  .hero-video { display: none; }
  .hero-veil { background: linear-gradient(0deg, var(--ivory) 0%, rgba(246, 241, 232, 0) 34%); }

  .stage__ui { margin-top: -64px; padding-block: 0 8px; }
  .stage__kicker { margin-bottom: 25px; font-size: .7rem; letter-spacing: .12em; }
  .stage__ln--a { font-size: clamp(1.6rem, 7vw, 2.2rem); }
  /* On phones the frame is the screen: the longest word of a two-line title (4.6em) plus the .5em step must
     fit 100vw minus the gutters, so the size follows --hero-scale here too (English stays 16.4vw). */
  .stage__ln--b {
    max-width: 100%;
    margin-left: 0;
    padding-left: .5em;
    text-indent: -.5em;
    font-size: calc(clamp(2.9rem, 16.4vw, 5.6rem) * var(--hero-scale, 1));
    letter-spacing: -.055em;
  }
  .stage__copy { margin-left: 0; }
  .stage__lede { max-width: 400px; margin: 22px 0 23px; font-size: .95rem; }
  .stage__actions { gap: 16px; }

  .process { margin-top: 26px; padding-top: 8px; grid-template-columns: 1fr; }
  .process-item,
  .process-item + .process-item { padding: 12px 0; gap: 16px; border-left: 0; }
  .process-label { font-size: .85rem; }
}

@media (max-width: 360px) {
  .stage__kicker { font-size: .6rem; }
  .stage__actions { gap: 12px; }
  .stage__actions .btn-primary { padding-inline: 18px; gap: 16px; }
  .stage__actions .btn-ghost { font-size: .78rem; }
}

/* ==========================================================================
   Stage mode. Variables (all 0..1, written on .stage by js/motion.js):
     --p        overall progress          --s-copy   hero copy visible
     --s-photo  photograph visible        --s-zoom   photograph push-in
     --s-enter  halo + object arrive      --s-open   parts separated
     --s-capa / --s-capb  captions        --s-exit   hand-off to the next section
   ========================================================================== */

@media (min-width: 1025px) {
  html.stage-on .stage { height: 320vh; }

  html.stage-on .stage__pin {
    position: sticky;
    top: var(--head-h);
    height: calc(100svh - var(--head-h));
    min-height: 0;
    background: var(--ivory);
  }

  /* 1 · the photograph recedes into ivory */
  html.stage-on .hero-media {
    opacity: var(--s-photo, 1);
    will-change: opacity;
  }
  html.stage-on .hero-media-inner {
    transform: scale(calc(1 + var(--s-zoom, 0) * .06));
    will-change: transform;
  }

  /* 2 · the copy clears */
  html.stage-on .stage__ui {
    opacity: var(--s-copy, 1);
    transform: translate3d(calc((1 - var(--s-copy, 1)) * -3.2vw), 0, 0);
    will-change: opacity, transform;
  }
  html.stage-on .stage__ui[data-spent="true"] { visibility: hidden; }

  /* 3 · the scene: halo + object in the right column, captions in the copy column */
  html.stage-on .stage__aside,
  html.stage-on .stage__cap {
    position: absolute;
    inset: 0 0 var(--band-h) 0;
    z-index: 2;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 42%);
    gap: clamp(2rem, 5vw, 4.5rem);
    align-items: center;
    pointer-events: none;
  }

  html.stage-on .stage__aside {
    opacity: calc(1 - var(--s-exit, 0));
    transform: translate3d(0, calc(var(--s-exit, 0) * -6vh), 0);
    will-change: opacity, transform;
  }

  .stage__visual {
    position: relative;
    grid-column: 2;
    min-height: min(68vh, 36rem);
  }

  .stage__halo {
    position: absolute;
    left: 50%;
    top: 50%;
    width: min(135%, 118vh);
    aspect-ratio: 1;
    translate: -50% -50%;
    opacity: var(--s-enter, 0);
    will-change: opacity;
  }

  .stage__orb {
    position: absolute;
    inset: 9%;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255, 255, 255, .94) 0%, rgba(255, 255, 255, .5) 30%, rgba(231, 238, 227, .38) 52%, rgba(231, 238, 227, 0) 72%);
  }

  .stage__rings {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    fill: none;
    stroke: var(--forest);
    transform: scale(calc(.82 + var(--s-enter, 0) * .18));
    will-change: transform;
  }

  .stage__rings circle {
    stroke-width: 1px;
    stroke-opacity: calc(.2 - var(--i) * .035);
    vector-effect: non-scaling-stroke;
  }

  .stage__object {
    position: absolute;
    left: 50%;
    top: 50%;
    height: min(56vh, 30rem);       /* seated; the open stack is ~21% taller */
    aspect-ratio: var(--aspect, .5);
    translate: -50% -50%;
    container-type: size;
    opacity: var(--s-enter, 0);
    transform: scale(calc(.94 + var(--s-enter, 0) * .06));
    will-change: opacity, transform;
  }

  /* --lift is a signed percentage of the object's own height (negative = up) */
  .stage__layer {
    position: absolute;
    left: var(--l);
    top: var(--t);
    width: var(--w);
    height: auto;
    max-width: none;
    opacity: 0;
    transform: translate3d(calc(var(--s-open, 0) * var(--drift, 0) * 1cqw), calc(var(--s-open, 0) * var(--lift, 0) * 1cqh), 0);
    transition: opacity .6s var(--ease-soft);
    will-change: transform;
  }

  .stage__layer.is-ready { opacity: 1; }

  /* B's explode runs along the tilted axis, so the parts also drift sideways (% of the object's width) */
  .stage__layer--crown { --drift: 3.3; }
  .stage__layer--abutment { --drift: .6; }
  .stage__layer--implant { --drift: -3.1; }

  .cap {
    grid-column: 1;
    grid-row: 1;
    max-width: 16ch;
    margin: 0;
    font-size: clamp(1.7rem, 3.6vw, 3rem);
    font-weight: 300;
    line-height: 1.12;
    letter-spacing: -.04em;
    color: var(--ink);
    will-change: opacity, transform;
  }

  .cap em {
    font-style: normal;
    font-weight: 400;
    color: var(--forest);
  }

  .cap--a {
    opacity: var(--s-capa, 0);
    transform: translate3d(0, calc((1 - var(--s-capa, 0)) * 18px), 0);
  }

  .cap--b {
    opacity: var(--s-capb, 0);
    transform: translate3d(0, calc((1 - var(--s-capb, 0)) * 18px), 0);
  }

  /* 4 · the strip: a fill line along its top rule, steps light up as the scene advances */
  html.stage-on .process::before {
    content: '';
    position: absolute;
    left: 0;
    top: -1px;
    width: 100%;
    height: 1px;
    background: var(--forest);
    transform: scaleX(var(--p, 0));
    transform-origin: left;
  }

  /* the first frame is untouched; later phases lift the step the scene is on */
  html.stage-on .process-num,
  html.stage-on .process-label { transition: color .45s var(--ease-soft); }

  html.stage-on .stage[data-phase="1"] .process-item:nth-child(2) .process-num,
  html.stage-on .stage[data-phase="2"] .process-item:nth-child(3) .process-num,
  html.stage-on .stage[data-phase="3"] .process-item:nth-child(3) .process-num { color: var(--forest); }

  html.stage-on .stage[data-phase="1"] .process-item:nth-child(2) .process-label,
  html.stage-on .stage[data-phase="2"] .process-item:nth-child(3) .process-label,
  html.stage-on .stage[data-phase="3"] .process-item:nth-child(3) .process-label { color: var(--ink); }
}

@media print {
  .stage { height: auto !important; }
  .stage__pin { position: static !important; height: auto !important; min-height: 0 !important; }
  .stage__aside, .stage__cap { display: none !important; }
  .stage__ui { opacity: 1 !important; transform: none !important; visibility: visible !important; }
}
