/* ==========================================================================
   LE BENIC — opening film

   One pinned stage. Layers, back to front:
     rig > pan > dolly > world   S3 pool scene (+ bottle discovery), S2 landscape
     layer--moss                 S1 macro (pulls back into the world)
     burns                       text-safe tonal darkening behind the text
     fg                          foreground depth slots (hidden until real assets)
     captions                    slogan, scene captions
     label-macro                 S4–S5 product macro
     burn--ui, vignette, film UI, intro veil

   World geometry and every photo's framing live in the custom properties
   below, so choreography and imagery always line up. Replacing a photo
   later = replace the file, then retune only its focal-point variables.
   ========================================================================== */

.film {
  /* World width relative to the viewport (the camera pans across it) */
  --world-w: 125vw;
  /* Screen point where the macro texture "lives" inside the landscape:
     a foreground moss cushion in S2 */
  --match-x: 46%;
  --match-y: 66%;

  /* --- Asset framing (all 0–1). f = focal point inside the photo,
         t = where that focal point sits in its box. Frames never letterbox;
         when the box and photo ratios differ the focal point is honoured
         as far as the crop allows. --- */

  /* S1 · moss macro */
  --moss-ar: 1.7768;  --moss-fx: .5;  --moss-fy: .5;  --moss-tx: .5;  --moss-ty: .5;
  /* S2 · landscape with the pool (pool ≈ .60 / .51) */
  --land-ar: 1.7768;  --land-fx: .6;  --land-fy: .5;  --land-tx: .58; --land-ty: .5;
  /* S3 · woman at the pool — framed like object-position (f = t) */
  --pool-ar: 1.7768;  --pool-fx: .5;  --pool-fy: .35;
  /* S3 · the bottle label inside the pool photo: dolly target + focus crop */
  --product-x: .836;  --product-y: .6;
  /* S4–S5 · product macro (label ≈ .71 / .63) */
  --prod-ar: 1.7758;  --prod-fx: .5;  --prod-fy: .5;  --prod-tx: .5;  --prod-ty: .5;

  position: relative;
  height: 100vh;
  overflow: hidden;
  background: var(--ink);
}

@media (max-width: 760px), (max-aspect-ratio: 4/5) {
  .film {
    --world-w: 300vw;
    --match-x: 33%;
    --match-y: 78%;
    --moss-fx: .42; --moss-tx: .5;
    --land-fx: .58; --land-tx: .5;
    --pool-fx: .7;
    --prod-fx: .71; --prod-tx: .59;
  }
}

/* The film image area begins directly under the fixed header and its edge band */
.stage {
  position: absolute;
  inset: calc(var(--header-h) + var(--header-edge)) 0 0 0;
  overflow: hidden;
  contain: layout paint;
}

/* --------------------------------------------------------------------------
   Frames — a box with the photo's exact aspect ratio, covering its parent
   and positioned by focal point. Parents that hold a frame are size
   containers, so cq units refer to them.
   -------------------------------------------------------------------------- */
.frame {
  --ar: 1.7778;
  --fx: .5; --fy: .5;
  --tx: .5; --ty: .5;
  --fw: max(100cqw, 100cqh * var(--ar));
  --fh: max(100cqh, 100cqw / var(--ar));
  position: absolute;
  width: var(--fw);
  height: var(--fh);
  left: clamp(100cqw - var(--fw), 100cqw * var(--tx) - var(--fw) * var(--fx), 0px);
  top: clamp(100cqh - var(--fh), 100cqh * var(--ty) - var(--fh) * var(--fy), 0px);
}

/* --------------------------------------------------------------------------
   Plates — a slot for real media (painted placeholder only as a fallback)
   -------------------------------------------------------------------------- */
.plate { position: absolute; inset: 0; overflow: hidden; }
.plate__sharp { position: absolute; inset: 0; }

.plate canvas,
.plate__media {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   Camera rig & world
   GPU promotion (will-change) is switched on by film.js only while each
   layer moves, so layers rest at full raster sharpness.
   -------------------------------------------------------------------------- */
.rig {
  position: absolute;
  inset: 0;
  transform-origin: var(--match-x) var(--match-y);
}

.pan {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--world-w);
  height: 100%;
  container-type: size;
}

/* The push lands on the bottle label as it sits in the S3 frame */
.dolly {
  --fw: max(100cqw, 100cqh * var(--pool-ar));
  --fh: max(100cqh, 100cqw / var(--pool-ar));
  position: absolute;
  inset: 0;
  transform-origin:
    calc((100cqw - var(--fw)) * var(--pool-fx) + var(--fw) * var(--product-x))
    calc((100cqh - var(--fh)) * var(--pool-fy) + var(--fh) * var(--product-y));
}

.world { position: absolute; inset: 0; }

/* S3 · pool scene, spans the whole world */
.frame--pool {
  --ar: var(--pool-ar);
  --fx: var(--pool-fx); --tx: var(--pool-fx);
  --fy: var(--pool-fy); --ty: var(--pool-fy);
  transform-origin: 52% 75%;
}

/* Bottle discovery: s3-bottle-dim.webp is the exact source region
   x 1281, y 263, 234 × 508 px of the 1672 × 941 pool photo, darkened and
   feathered in the file itself (no CSS filter or mask). Regenerate it with
   the same box if the pool photo is replaced. */
.bottle {
  position: absolute;
  left: calc(1281 / 1672 * 100%);
  top: calc(263 / 941 * 100%);
  width: calc(234 / 1672 * 100%);
  height: calc(508 / 941 * 100%);
}
.plate--bottle .plate__media { object-fit: fill; }

/* S2 · landscape, one screen wide (plus pan travel), on top of the pool scene */
.view {
  position: absolute;
  top: 0;
  left: 0;
  width: 104vw;
  height: 100%;
  container-type: size;
}
.frame--landscape {
  --ar: var(--land-ar);
  --fx: var(--land-fx); --fy: var(--land-fy);
  --tx: var(--land-tx); --ty: var(--land-ty);
  transform-origin: calc(var(--land-fx) * 100%) 12%;
}

/* --------------------------------------------------------------------------
   Scene 1 macro layer
   Oversized so its feathered edge is off-screen until it pulls back.
   -------------------------------------------------------------------------- */
.layer {
  position: absolute;
  pointer-events: none;
}
.layer--moss {
  inset: -25%;
  container-type: size;
  transform-origin: calc((var(--match-x) + 25%) / 1.5) calc((var(--match-y) + 25%) / 1.5);
  /* Feather reaches zero exactly at the layer's edges (so no border shows as it
     shrinks) while the on-screen area at scale 1–1.14 stays fully opaque */
  -webkit-mask-image:
    linear-gradient(to right, transparent, #000 17%, #000 83%, transparent),
    linear-gradient(to bottom, transparent, #000 17%, #000 83%, transparent);
  -webkit-mask-composite: source-in;
          mask-image:
    linear-gradient(to right, transparent, #000 17%, #000 83%, transparent),
    linear-gradient(to bottom, transparent, #000 17%, #000 83%, transparent);
          mask-composite: intersect;
}
.frame--moss {
  --ar: var(--moss-ar);
  --fx: var(--moss-fx); --fy: var(--moss-fy);
  --tx: var(--moss-tx); --ty: var(--moss-ty);
}

/* --------------------------------------------------------------------------
   Text-safe burns
   Feathered, edgeless tonal darkening in the imagery's own deepest
   moss/volcanic black, normal blending (no blend modes, no blur). Kept near
   black so shadows are never lifted into a veil. Each burn fades with its
   text on the same timeline tweens and is hidden when fully faded.
   -------------------------------------------------------------------------- */
.burns {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.burn {
  --burn: 9 11 8;
  --core: .56;
  position: absolute;
  pointer-events: none;
  background: radial-gradient(
    closest-side,
    rgb(var(--burn) / var(--core)) 0%,
    rgb(var(--burn) / calc(var(--core) * .82)) 38%,
    rgb(var(--burn) / calc(var(--core) * .38)) 70%,
    rgb(var(--burn) / 0) 100%
  );
}
.burn--slogan-a { left: -14vw; top: -4vh; width: 86vw; height: 76vh; --core: .52; will-change: opacity; }
.burn--slogan-b { right: -12vw; bottom: -8vh; width: 62vw; height: 62vh; --core: .46; will-change: opacity; }
.burn--cap1 { right: -14vw; top: -16vh; width: 64vw; height: 70vh; --core: .62; opacity: 0; visibility: hidden; will-change: opacity; }
.burn--cap2 { left: -18vw; bottom: -18vh; width: 70vw; height: 72vh; --core: .64; opacity: 0; visibility: hidden; will-change: opacity; }
.burn--cap3 { left: -18vw; bottom: -20vh; width: 74vw; height: 82vh; --core: .72; opacity: 0; visibility: hidden; will-change: opacity; }
.burn--ui {
  left: -10vw;
  right: -10vw;
  bottom: -16vh;
  height: 34vh;
  --core: .36;
}

/* --------------------------------------------------------------------------
   Captions
   -------------------------------------------------------------------------- */
.captions {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.captions a { pointer-events: auto; }

.slogan { margin: 0; font-weight: 400; }

.slogan__a {
  position: absolute;
  left: var(--gutter);
  top: clamp(104px, 20vh, 230px);
  display: block;
  font-family: var(--serif);
  font-size: clamp(3.3rem, 10.2vw, 11.5rem);
  line-height: 0.86;
  letter-spacing: -0.005em;
  text-transform: uppercase;
  will-change: transform, opacity, filter;
}
.slogan__row { display: block; white-space: nowrap; }
.slogan__row--indent { padding-left: 1.2em; }

/* Room above the letters for accents on capitals (Ý, Á, Ó, Ś …): the mask and the
   word both extend upward by the same amount, cancelled by negative margins, so
   nothing moves. The word's extra height also keeps accents hidden at the reveal's
   start position (yPercent 118). */
.mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-top: 0.24em;
  margin-top: -0.24em;
  padding-bottom: 0.06em;
  margin-bottom: -0.06em;
}
.mask > span {
  display: inline-block;
  padding-top: 0.24em;
  margin-top: -0.24em;
}

.slogan__b {
  position: absolute;
  right: var(--gutter);
  bottom: clamp(96px, 17vh, 210px);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.9rem;
  text-align: right;
  will-change: transform, opacity, filter;
}
.slogan__kicker {
  font-family: var(--sans);
  /* 11px → 14px → 20px → this (owner, 2026-09-17). A fixed pixel size stayed a tiny caption next to a
     statement that grows with the screen, so the kicker now grows with the screen too: about 0.3 of the
     statement on every desktop — 30px on a 1920 display, never below 20px. */
  font-size: clamp(20px, 1.57vw, 30px);
  font-weight: 400;
  letter-spacing: 0.42em;
  margin-right: -0.42em;
  text-transform: uppercase;
  color: var(--bone-72);
}
.slogan__soft {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(2.3rem, 5.4vw, 6.2rem);
  line-height: 0.95;
  letter-spacing: -0.01em;
}

/* --------------------------------------------------------------------------
   SHOP THE OIL — every appearance of the shared .cta (base.css) settles at ONE anchor:
   bottom-left, just above the chapter marker ("I — Rawness" … "III — Discovery"),
   clear of the left edge, the bottom edge and the small editorial text. Entrances and
   exits are on the film timeline; only this position is shared.
   -------------------------------------------------------------------------- */
.film {
  --cta-anchor-left: var(--gutter);
  --cta-anchor-bottom: calc(env(safe-area-inset-bottom, 0px) + clamp(20px, 3.4vh, 36px) + 16px + clamp(18px, 2.8vh, 30px));
}
.film-cta {
  position: absolute;
  z-index: 2; /* above the film's bottom shading and vignette, so the buttons are never dimmed */
  left: var(--cta-anchor-left);
  bottom: var(--cta-anchor-bottom);
}
.film-cta--rawness { will-change: transform, opacity, filter; }

/* The film's SHOP THE OIL buttons — one sizing system for all five: a touch larger than the shared
   .cta, luminous near-white type, a warm black lacquer body with the faintest dark-bronze depth and
   a very fine amber-bronze edge. Entrances, comet trail, timing and positions are unchanged. */
.film-cta .cta {
  --ground: linear-gradient(180deg, #16120d 0%, #0b0a08 58%, #0f0c09 100%);
  --edge: rgb(190 146 92 / 0.5);
  padding: 19px 40px 18px 41px;
  font-size: 12px;
  font-weight: 500; /* one step more body, so the near-white reads as bright at this size */
  color: #f8f6f1;
}
.film-cta .cta:hover { --ground: linear-gradient(180deg, #1d1711 0%, #100d0a 58%, #15110c 100%); --edge: rgb(208 166 108 / 0.72); }
@media (max-width: 760px) {
  .film-cta .cta { padding: 16px 29px 15px 30px; font-size: 11.5px; }
  /* phones: the opening scroll cue moves to the right edge so it never meets the larger button */
  .film .scroll-cue { left: auto; right: var(--gutter); translate: none; }
}

/* the (faded) landscape layer above the pool scene must not catch the lake button's clicks */
.view { pointer-events: none; }

.cap { position: absolute; }
.cap__index {
  margin-bottom: 1.1rem;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.4em;
  color: var(--bone-72);
}
.cap__text {
  font-family: var(--serif);
  font-size: clamp(1.6rem, 2.5vw, 2.6rem);
  line-height: 1.02;
}

/* Scene II line: a quiet tracked kicker over an italic serif phrase —
   the same pairing as "Made for the / deepest softness." */
.cap--2 .cap__index { margin-bottom: 1.6rem; }
.cap__text--within { line-height: 1; }
.cap__kicker {
  margin-bottom: 1.15rem;
  font-family: var(--sans);
  font-size: clamp(14px, 0.84vw, 16px);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--bone);
}
.cap__soft {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(2.2rem, 2.95vw, 3.05rem);
  line-height: 1.05;
  letter-spacing: -0.005em;
}

/* Landscape line: in the misty space above and right of the lake, right-aligned
   like "Made for the / deepest softness." */
.cap--1 {
  right: calc(var(--gutter) + 4vw);
  top: clamp(96px, 16vh, 200px);
  text-align: right;
}
.cap--1 .cap__kicker { margin-right: -0.34em; } /* optically align tracked caps to the right edge */

/* Portrait framings put this line in brighter sky: a deeper settle behind it */
@media (max-width: 760px), (max-aspect-ratio: 4/5) {
  .burn--cap1 { --core: .84; }
}


/* Both scene captions live in the dark lower-left foreground */
.cap--2 {
  left: var(--gutter);
  bottom: clamp(104px, 17vh, 190px);
}

.cap--3 {
  left: var(--gutter);
  bottom: clamp(96px, 14vh, 170px);
}
.cap__title {
  font-family: var(--serif);
  font-size: clamp(1.5rem, 2.1vw, 2.2rem);
  line-height: 1.05;
}
.cap__small {
  margin-top: 0.4rem;
  font-size: 13px;
  color: var(--bone-72);
}
.cap__link {
  display: inline-block;
  margin-top: 1.1rem;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--bone-48);
  padding-bottom: 3px;
}

/* --------------------------------------------------------------------------
   Foreground depth slots — reserved for real transparent foreground
   photography; hidden ([hidden] in index.html) until those assets exist.
   Geometry is kept so the timeline positions still apply when enabled.
   -------------------------------------------------------------------------- */
.fg { position: absolute; pointer-events: none; }
.fg--fronds { inset: -6%; }
.fg__intro { position: absolute; inset: 0; container-type: size; }
.fg--rock {
  left: 0;
  bottom: -8vh;
  width: 95vw;
  height: 58vh;
  container-type: size;
}

/* --------------------------------------------------------------------------
   Product macro — the camera arrives at the bottle and settles
   -------------------------------------------------------------------------- */
.label-macro {
  position: absolute;
  inset: 0;
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  background: var(--label);
  container-type: size;
}
.frame--product {
  --ar: var(--prod-ar);
  --fx: var(--prod-fx); --fy: var(--prod-fy);
  --tx: var(--prod-tx); --ty: var(--prod-ty);
}

/* --------------------------------------------------------------------------
   Vignette, film UI, intro veil
   -------------------------------------------------------------------------- */
.vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 80% 75% at 50% 46%, transparent 52%, rgba(0, 0, 0, 0.58) 100%);
}

.chapter {
  position: absolute;
  left: var(--gutter);
  bottom: calc(env(safe-area-inset-bottom, 0px) + clamp(20px, 3.4vh, 36px));
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 10px;
  font-weight: 400;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--bone-72);
}
.chapter__num { font-family: var(--serif); font-size: 15px; letter-spacing: 0.08em; min-width: 1.6em; }
.chapter__rule { position: relative; width: clamp(48px, 7vw, 110px); height: 1px; background: var(--bone-20); overflow: hidden; }
.chapter__rule i { position: absolute; inset: 0; background: var(--bone); transform: scaleX(0); transform-origin: left center; }
.chapter__name { display: inline-block; }

.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + clamp(20px, 3.4vh, 36px));
  translate: -50% 0;
}
.scroll-cue__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  font-size: 10px;
  letter-spacing: 0.34em;
  margin-right: -0.34em;
  text-transform: uppercase;
  color: var(--bone-72);
}
.scroll-cue i {
  display: block;
  width: 1px;
  height: 44px;
  background: linear-gradient(to bottom, var(--bone), transparent);
  transform-origin: top center;
  animation: cue 2.6s var(--ease-cine) infinite;
}
@keyframes cue {
  0%   { transform: scaleY(0); opacity: 1; }
  60%  { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(1); opacity: 0; }
}

.intro-veil {
  position: absolute;
  inset: 0;
  z-index: 3; /* stays above everything, buttons included */
  background: var(--ink);
  pointer-events: none;
}

/* Placeholder HUD — visible only while painted placeholders are in use */
.asset-hud {
  position: fixed;
  right: var(--gutter);
  bottom: calc(env(safe-area-inset-bottom, 0px) + clamp(20px, 3.4vh, 36px));
  z-index: 150;
  display: none;
  align-items: center;
  gap: 12px;
  max-width: min(520px, 60vw);
  font-family: ui-monospace, "SFMono-Regular", Consolas, monospace;
  font-size: 10px;
  letter-spacing: 0.04em;
  color: rgba(233, 225, 213, 0.55);
}
.has-placeholders .asset-hud { display: flex; }
.hud-hidden .asset-hud { display: none; }
.asset-hud__tag { padding: 3px 6px; border: 1px dashed rgba(233, 225, 213, 0.35); text-transform: uppercase; letter-spacing: 0.14em; }
.asset-hud__hint { opacity: 0.6; white-space: nowrap; }

/* --------------------------------------------------------------------------
   Small screens
   -------------------------------------------------------------------------- */
@media (max-width: 760px) {
  .slogan__a { font-size: clamp(3rem, 15.5vw, 5.4rem); top: clamp(96px, 17vh, 150px); }
  .slogan__row--indent { padding-left: 0.9em; }
  /* always clear of SHOP THE OIL and the scroll cue below it, also on short phones (640px and less) */
  .slogan__b { bottom: max(clamp(88px, 15vh, 140px), calc(var(--cta-anchor-bottom) + 64px)); gap: 0.6rem; }
  .slogan__kicker { font-size: min(19px, 5.6vw); } /* 10px → 13px → 19px, the same step as on desktop; eases down below 340px so the longest translation still fits a 280px phone */
  .slogan__soft { font-size: clamp(2.2rem, 11vw, 3.4rem); }

  .cap--1 { right: calc(var(--gutter) + 3vw); top: 11vh; }
  .cap--2 { bottom: 20vh; }
  .cap--3 { bottom: 14vh; }
  .burn--cap1 { right: -40vw; top: -18vh; width: 150vw; height: 58vh; }

  .burn--slogan-a { left: -40vw; width: 150vw; height: 60vh; }
  .burn--slogan-b { right: -40vw; width: 130vw; height: 52vh; }
  .burn--cap2,
  .burn--cap3 { left: -40vw; width: 150vw; height: 64vh; }

  .fg--rock { width: 160vw; height: 46vh; }

  .asset-hud { left: auto; max-width: 52vw; bottom: calc(env(safe-area-inset-bottom, 0px) + 18px); }
  .asset-hud__hint { display: none; }
  .asset-hud [data-hud-note] { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}

@media (max-width: 760px) and (max-height: 700px) {
  .chapter__name { display: none; }
}
