/* ==========================================================================
   Nura, landing
   Design tokens follow the Nura Brand Book (Vol. One).
   Seven colours, no more. Two faces, no more.
   ========================================================================== */

:root {
  /* --- Palette (Brand Book IV) ------------------------------------------ */
  --cream:      #FBF4E9;   /* the page. everything sits on this            */
  --linen:      #F4E5D3;   /* the second surface. quiet division           */
  --sand:       #E7CEAE;   /* rules, edges, the underside of light         */
  --blush:      #E4A38F;   /* the skin note. used sparingly                */
  --amber:      #C97F35;   /* the signature. one per surface               */
  --terracotta: #8E3E22;   /* small caps, labels, the accent voice         */
  --carbon:     #221E1B;   /* the ink and the logo. never black            */

  /* Depth comes from opacity on the ink, not from more colours.
     The Brand Book sets secondary at 70% and tertiary at 45%. 45% measures
     2.8:1 on cream, which fails WCAG AA for body-size text, so the two steps
     are held apart at 76% / 64% instead. 7.2:1 and 4.8:1 on cream. Same
     principle, legible at 17px and below. */
  --ink:        var(--carbon);
  --ink-2:      color-mix(in srgb, var(--carbon) 76%, transparent);
  --ink-3:      color-mix(in srgb, var(--carbon) 64%, transparent);
  --cream-2:    color-mix(in srgb, var(--cream) 76%, transparent);
  --cream-3:    color-mix(in srgb, var(--cream) 55%, transparent);
  --hairline:   color-mix(in srgb, var(--carbon) 14%, transparent);
  --hairline-light: color-mix(in srgb, var(--cream) 26%, transparent);

  /* --- Type (Brand Book V) ---------------------------------------------- */
  --display: "Forum", "Cormorant Garamond", Georgia, serif;
  --text:    "Schibsted Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  --fs-display:  clamp(2.75rem, 1.1rem + 6.6vw, 4.75rem);   /* Forum 76 / 104% */
  --fs-headline: clamp(1.9rem,  1.1rem + 2.9vw, 2.5rem);    /* Forum 40 / 120% */
  --fs-title:    clamp(1.35rem, 1.05rem + 1.1vw, 1.65rem);
  --fs-lede:     clamp(1.075rem, 1rem + 0.35vw, 1.2rem);
  --fs-body:     1.0625rem;                                  /* 17 / 170%      */
  --fs-small:    0.9375rem;
  --fs-label:    0.6875rem;                                  /* 11 / 30% track */

  /* --- Space ------------------------------------------------------------- */
  --gutter:  clamp(1.5rem, 0.6rem + 3.6vw, 4.5rem);
  --section: clamp(5rem, 2.5rem + 9vw, 10.5rem);
  --measure: 34ch;
  --page:    1360px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ==========================================================================
   Reset
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--text);
  font-size: var(--fs-body);
  line-height: 1.7;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* clip, not hidden. `hidden` on one axis forces the other to compute to
     `auto`, which makes the body a scroll container: that is what breaks the
     sticky scenes on the about page in mobile browsers, and it moves the
     scroll events the scenes listen for. `clip` stops the same horizontal
     overflow without creating a scroller. */
  overflow-x: clip;
}

img, svg, video { display: block; max-width: 100%; }

/* WebKit paints its own circular start-playback badge over any video it has
   declined to autoplay, and it ignores the element having no `controls`.
   It is off-brand and it is not our affordance, the page supplies its own
   Play control when a clip genuinely needs one. */
video::-webkit-media-controls,
video::-webkit-media-controls-start-playback-button,
video::-webkit-media-controls-panel,
video::-webkit-media-controls-overlay-play-button {
  display: none !important;
  -webkit-appearance: none;
  opacity: 0;
}
button { font: inherit; color: inherit; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 400;           /* Forum: one weight, and that is the discipline */
  letter-spacing: 0.005em;    /* never tight */
  margin: 0;
  text-wrap: balance;
}

/* At display sizes a single long word can be wider than a small phone, which
   pushes the whole document sideways without any element box reporting it.
   Hyphenation is the graceful way out and only engages when a word truly
   cannot fit. */
h1, h2, h3, h4, .display, .headline, .title {
  overflow-wrap: break-word;
  hyphens: auto;
  -webkit-hyphens: auto;
}
p { margin: 0; }

::selection { background: var(--sand); color: var(--carbon); }

:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ==========================================================================
   Primitives
   ========================================================================== */

.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.label {
  font-family: var(--text);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--terracotta);
  margin: 0;
}
.label--quiet { color: var(--ink-3); }
.label--onDark { color: var(--cream-2); }

/* These carry the face as well as the size, so they work on any element and
   not just on h1..h4, which is where the family was previously coming from. */
.display  { font-family: var(--display); font-weight: 400; font-size: var(--fs-display);  line-height: 1.04; }
.headline { font-family: var(--display); font-weight: 400; font-size: var(--fs-headline); line-height: 1.2; }
.title    { font-family: var(--display); font-weight: 400; font-size: var(--fs-title);    line-height: 1.3; }

.lede {
  font-size: var(--fs-lede);
  line-height: 1.68;
  color: var(--ink-2);
}
.note { font-size: var(--fs-small); color: var(--ink-3); line-height: 1.6; }

.accent {
  font-style: italic;
  color: var(--terracotta);
}

.rule {
  border: 0;
  border-top: 1px solid var(--hairline);
  margin: 0;
}

.section { padding-block: var(--section); }

/* Anchor targets sit clear of the fixed header. */
:where(#how, #reserve, #faq, #top) { scroll-margin-top: clamp(4.5rem, 3rem + 3vw, 6rem); }

/* Wordmark, drawn vector, never retyped, never below 48px. */
.wordmark { width: clamp(148px, 20vw, 232px); height: auto; }
.wordmark--sm { width: 104px; }

/* --- Buttons ------------------------------------------------------------ */

.btn {
  --btn-bg: var(--carbon);
  --btn-fg: var(--cream);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.7em;
  padding: 1.15em 2em;
  border: 1px solid var(--btn-bg);
  border-radius: 100px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: var(--fs-small);
  font-weight: 500;
  letter-spacing: 0.02em;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.4s var(--ease), background-color 0.4s var(--ease),
              color 0.4s var(--ease), border-color 0.4s var(--ease), opacity 0.3s;
}
.btn:hover  { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn[disabled] { opacity: 0.55; cursor: progress; transform: none; }

.btn--amber  { --btn-bg: var(--amber); --btn-fg: var(--carbon); }
.btn--amber:hover { --btn-bg: #d78f45; }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  border-color: var(--hairline);
}
.btn--ghost:hover { border-color: var(--carbon); }

.btn--onDark {
  --btn-bg: var(--cream);
  --btn-fg: var(--carbon);
}
.btn--ghostOnDark {
  --btn-bg: transparent;
  --btn-fg: var(--cream);
  border-color: var(--hairline-light);
}
.btn--ghostOnDark:hover { border-color: var(--cream); }

.btn--full { width: 100%; }

/* Text link with a hairline that draws in */
.link {
  color: inherit;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-repeat: no-repeat;
  background-position: 0 100%;
  transition: background-size 0.45s var(--ease);
  padding-bottom: 2px;
}
.link:hover { background-size: 100% 1px; }

/* ==========================================================================
   Reveal on scroll
   ========================================================================== */

/* Never put a video inside one of these. Safari treats a transparent element
   as not visible and will refuse to autoplay it, the clip then needs a
   scripted play(), which Safari can refuse in turn, and it ends up stranded
   behind a Play button. Reveal the copy around the media, not the media. */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 1s var(--ease), transform 1s var(--ease);
  transition-delay: var(--delay, 0ms);
}
.reveal.is-in { opacity: 1; transform: none; }

/* Belt and braces: if the script never runs, nothing stays hidden. */
.no-js .reveal { opacity: 1; transform: none; transition: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* ==========================================================================
   Header
   ========================================================================== */

.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  padding-block: clamp(1rem, 0.6rem + 1vw, 1.6rem);
  transition: background-color 0.5s var(--ease), backdrop-filter 0.5s var(--ease),
              box-shadow 0.5s var(--ease);
}
.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}
.header__mark { display: block; }
.header__mark svg, .header__mark img { width: 104px; height: auto; }

.header .btn { padding: 0.85em 1.5em; }

/* Navigation. One text link beside the reservation button, so the header
   stays restrained rather than becoming a menu. */
.header__nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.5vw, 2rem);
}
.header__link {
  font-size: var(--fs-small);
  letter-spacing: 0.02em;
  text-decoration: none;
  color: var(--cream);
  transition: opacity 0.3s var(--ease);
  opacity: 0.85;
  white-space: nowrap;
}
.header__link:hover { opacity: 1; }
.header.is-stuck .header__link { color: var(--carbon); }
.header__link[aria-current="page"] { opacity: 1; text-decoration: underline; text-underline-offset: 0.35em; }

/* Pages without a dark hero start inverted from the first paint. */
.header--solid {
  background: color-mix(in srgb, var(--cream) 88%, transparent);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  box-shadow: 0 1px 0 var(--hairline);
}
.header--solid .header__mark .m-ink { opacity: 1; }
.header--solid .header__link { color: var(--carbon); }
.header--solid .btn--headerCta { --btn-bg: var(--carbon); --btn-fg: var(--cream); }

@media (max-width: 560px) {
  .header__link { font-size: 0.875rem; }
  .header .btn { padding: 0.8em 1.15em; font-size: 0.875rem; }
}

/* Over the hero the header is cream; once past it, it inverts to ink.
   Both wordmarks stack in one grid cell and cross-fade, so the vector is
   never recoloured and never retyped. */
.header__mark { display: grid; }
.header__mark img {
  grid-area: 1 / 1;
  transition: opacity 0.45s var(--ease);
}
.header__mark img { opacity: 0; }
.header.is-stuck .header__mark .m-ink { opacity: 1; }

.header .btn--headerCta { --btn-bg: var(--cream); --btn-fg: var(--carbon); }

.header.is-stuck {
  background: color-mix(in srgb, var(--cream) 88%, transparent);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  box-shadow: 0 1px 0 var(--hairline);
}
.header.is-stuck .btn--headerCta { --btn-bg: var(--carbon); --btn-fg: var(--cream); }

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--carbon);
  color: var(--cream);
  padding: 0.9rem 1.4rem;
  z-index: 100;
  border-radius: 0 0 8px 0;
  font-size: var(--fs-small);
}
.skip:focus { left: 0; }

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--carbon);
  isolation: isolate;
}

/* Positive stacking rather than negative. Painting the plate behind the
   stacking context is a grey area for Safari's autoplay visibility test, and
   the layering reads identically either way. */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero__media video, .hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Showing more of the frame's left edge carries the device to the right,
     clear of the wordmark and headline. */
  object-position: 32% 45%;
}

@media (max-width: 760px) {
  .hero__media video, .hero__media img { object-position: 40% 38%; }
}

/* Photograph bleeds full page. The wordmark sits low and left, never centred. */
.hero__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* The device is centre-frame in this clip and the type is left-aligned over
     it, so the veil carries the lower two thirds where the copy sits and
     releases towards the top, where the light and the device face stay clear. */
  background:
    /* A soft scrim anchored to the copy corner. It protects the headline where
       it runs past the device into open gold, without flattening the plate. */
    radial-gradient(150% 115% at 0% 100%,
      color-mix(in srgb, var(--carbon) 50%, transparent) 0%,
      color-mix(in srgb, var(--carbon) 34%, transparent) 42%,
      color-mix(in srgb, var(--carbon) 14%, transparent) 66%,
      transparent 84%),
    linear-gradient(to right,
      color-mix(in srgb, var(--carbon) 46%, transparent) 0%,
      color-mix(in srgb, var(--carbon) 22%, transparent) 38%,
      color-mix(in srgb, var(--carbon) 6%,  transparent) 62%,
      color-mix(in srgb, var(--carbon) 26%, transparent) 100%),
    linear-gradient(to top,
      color-mix(in srgb, var(--carbon) 66%, transparent) 0%,
      color-mix(in srgb, var(--carbon) 46%, transparent) 26%,
      color-mix(in srgb, var(--carbon) 22%, transparent) 52%,
      color-mix(in srgb, var(--carbon) 4%,  transparent) 80%,
      color-mix(in srgb, var(--carbon) 32%, transparent) 100%);
}

.hero__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-block: clamp(3rem, 1rem + 7vw, 6rem);
}
/* Masthead rule sits between the wordmark and the headline, clear of the
   fixed header so the two never overlap on scroll. */
.hero__top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.5rem;
  padding-bottom: 1.15rem;
  border-bottom: 1px solid var(--hairline-light);
  margin-bottom: clamp(1.75rem, 1rem + 2.5vw, 2.75rem);
}

.hero__mark { margin-bottom: clamp(1.1rem, 0.7rem + 1.6vw, 1.9rem); }

/* One label now, so it simply sits left against the rule. */
.hero__top { justify-content: flex-start; }
.hero__mark svg, .hero__mark img { width: clamp(210px, 34vw, 420px); height: auto; }

.hero h1 {
  color: var(--cream);
  max-width: 16ch;
  margin-bottom: 1.5rem;
}
.hero__lede {
  color: var(--cream-2);
  max-width: 46ch;
  font-size: var(--fs-lede);
  line-height: 1.65;
  /* Full gap restored now that the lede is the last thing before the CTA. */
  margin-bottom: clamp(2rem, 1.2rem + 2.5vw, 2.75rem);
}

.hero__cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem 1.1rem;
}
.hero__ctaNote {
  /* Sits over the brightest part of the plate, so it takes the secondary
     cream rather than the tertiary one. */
  color: var(--cream-2);
  font-size: var(--fs-small);
  flex-basis: 100%;
  margin-top: 0.25rem;
}

.hero__scroll {
  position: absolute;
  z-index: 2;
  right: var(--gutter);
  bottom: clamp(3rem, 1rem + 7vw, 6rem);
  writing-mode: vertical-rl;
  color: var(--cream-2);
  font-size: var(--fs-label);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  gap: 1rem;
}
.hero__scroll::after {
  content: "";
  width: 1px;
  height: 54px;
  background: linear-gradient(to bottom, var(--cream-3), transparent);
}
@media (max-width: 900px) { .hero__scroll { display: none; } }

/* ==========================================================================
   Shared layout helpers
   ========================================================================== */

/* Media with no frame. No border, no radius, no card. */
.film {
  position: relative;
  overflow: hidden;
  background: var(--carbon);
}
.film video, .film img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Shown only when the browser refused to autoplay, so a clip is never a dead
   poster with no way in. */
.mediaPlay {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  border: 0;
  padding: 0;
  background: color-mix(in srgb, var(--carbon) 22%, transparent);
  color: var(--cream);
  cursor: pointer;
}
.mediaPlay[hidden] { display: none; }
.mediaPlay span {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.85em 1.5em 0.85em 1.2em;
  border: 1px solid var(--hairline-light);
  border-radius: 100px;
  background: color-mix(in srgb, var(--carbon) 62%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  transition: background-color 0.35s var(--ease), border-color 0.35s var(--ease);
}
.mediaPlay:hover span {
  background: color-mix(in srgb, var(--carbon) 78%, transparent);
  border-color: var(--cream);
}
.mediaPlay svg { width: 0.85rem; height: 0.85rem; fill: currentColor; }

/* WebKit paints its own badge over any video it declined to autoplay. */
video::-webkit-media-controls,
video::-webkit-media-controls-start-playback-button,
video::-webkit-media-controls-panel,
video::-webkit-media-controls-overlay-play-button {
  display: none !important;
  -webkit-appearance: none;
  opacity: 0;
}

.spec {
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-top: 1.6rem;
}

/* ==========================================================================
   What Nura does
   ========================================================================== */

/* The section closes on a full width film, so its own bottom padding would
   just stack on top of the next section's. */
.how { padding-bottom: 0; }

.how__head {
  margin-bottom: clamp(3.5rem, 2rem + 6vw, 7rem);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, clamp(24rem, 36vw, 32rem));
  align-items: center;
  gap: clamp(2.5rem, 1rem + 5vw, 6rem);
}
.how__intro { max-width: 62ch; }
.how__head h2 { max-width: 16ch; }
.how__lede { margin-top: 1.75rem; max-width: 52ch; }

/* --------------------------------------------------------------------------
   The shifting words. Six inline buttons inside the lede, so the interaction
   is found by reading rather than by hunting for a control.
   -------------------------------------------------------------------------- */

.shift__w {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  /* Grows the tap target to roughly 44px without moving the line. */
  padding: 0.42em 0.14em;
  margin: -0.42em -0.14em;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: var(--sand);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.24em;
  transition: color 0.5s var(--ease), text-decoration-color 0.5s var(--ease);
}
.shift__w:hover,
.shift__w:focus-visible,
.shift__w.is-on {
  color: var(--terracotta);
  text-decoration-color: var(--terracotta);
}
/* Hover is a maybe; is-on is the word the figure is actually showing, so it
   carries a heavier rule and a warm wash to separate the two. */
.shift__w.is-on {
  text-decoration-thickness: 2px;
  background: color-mix(in srgb, var(--terracotta) 10%, transparent);
  border-radius: 3px;
  transition: color 0.5s var(--ease), text-decoration-color 0.5s var(--ease),
              background 0.5s var(--ease);
}
.shift__w:focus-visible { outline: 2px solid var(--terracotta); outline-offset: 2px; }

.shift__hint {
  margin-top: 1.4rem;
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
}
/* Without the script the words do nothing, so they should not invite a
   click. The paragraph still reads exactly the same. */
.no-js .shift__hint { display: none; }
.no-js .shift__w { text-decoration: none; cursor: text; }

/* --------------------------------------------------------------------------
   The blend. Four components drawn as overlapping washes, multiplied onto
   the cream so the overlaps mix the way the formula does. Nothing here is
   photographed and nothing here is data: it is the copy, shown.
   -------------------------------------------------------------------------- */

.blend { margin: 0; }

.blend__stage {
  position: relative;
  aspect-ratio: 1;
  width: 100%;
}

/* An absolutely positioned <svg> is a replaced element, and engines disagree
   about whether insets size it or merely offset it. Safari kept it at full
   size and only moved it, which drew the ring half again too big and pushed
   it down and right, so the labels ended up sitting on the circles. Explicit
   width and height resolve the same way everywhere. */
.blend__svg {
  position: absolute;
  left: var(--M);
  top: var(--M);
  width: calc(100% - 2 * var(--M));
  height: calc(100% - 2 * var(--M));
  overflow: visible;
}

.blend__ring {
  fill: none;
  stroke: var(--hairline);
  stroke-width: 1;
}

.blend__drop {
  transform-box: fill-box;
  transform-origin: center;
  mix-blend-mode: multiply;
  transform: translate(var(--dx, 0px), var(--dy, 0px)) scale(var(--s, 0.9));
  opacity: var(--o, 0.45);
  transition: transform 0.56s var(--ease), opacity 0.56s var(--ease);
}
/* Graded warm family: palest for water, deepest for repair. Sebum is the one
   tone not already in the palette, so it is mixed from two that are rather
   than introduced as a colour of its own. Declared once here and used by both
   the circle and its label swatch, so the two can never drift apart. */
.blend {
  --c-hydration:   var(--sand);
  --c-barrier:     var(--amber);
  --c-sebum:       color-mix(in srgb, var(--amber) 45%, var(--sand));
  --c-sensitivity: var(--blush);
  --c-renewal:     var(--terracotta);
}
.blend__drop[data-part="hydration"]   { fill: var(--c-hydration); }
.blend__drop[data-part="barrier"]     { fill: var(--c-barrier); }
.blend__drop[data-part="sebum"]       { fill: var(--c-sebum); }
.blend__drop[data-part="sensitivity"] { fill: var(--c-sensitivity); }
.blend__drop[data-part="renewal"]     { fill: var(--c-renewal); }

.blend__name {
  position: absolute;
  margin: 0;
  /* Swatch sits on the inward side, so it reads as pointing at its circle.
     Colour here is a second cue on top of position, never the only one: two
     of the five fills are far too pale on cream to carry meaning alone, so
     each swatch takes a faint rim to stay locatable. */
  display: inline-flex;
  align-items: center;
  line-height: 1;
  gap: 0.5em;
  /* On a narrow stage the side labels reach the ring. A cream halo, costing no
     layout, lets the label break the hairline cleanly instead of sitting on
     it. Invisible everywhere else, since the page is this colour. */
  background: var(--cream);
  box-shadow: 0 0 0 0.3em var(--cream);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* Held at a legible weight in every state. Fading these down to match the
     drops would have dropped small tracked type under 3:1 on cream, so the
     lead is signalled by colour instead. */
  color: var(--ink-3);
  transition: color 0.9s var(--ease);
}
/* All five swatches sit on one circle concentric with the ring, so their gap
   to it is equal by construction rather than by hand. Each label is anchored
   by its swatch, not by its box, which is what made the gaps uneven before:
   a long word like HYDRATION pushed its swatch up against the ring while a
   short one like SEBUM left its swatch stranded far outside.

   --Rd is the swatch circle's radius: the ring, plus the gap, plus the swatch's
   own radius. The per-label numbers are the unit vector from the centre to that
   label's circle, so each swatch sits on its own circle's bearing. The longest
   word sets how large the ring can be, which is why both step down together. */
.blend__stage {
  /* --M is the margin the figure leaves for its labels. It is a length, not a
     percentage, because what has to fit there is a fixed number of pixels of
     type. Holding it constant means every pixel the column gains goes to the
     drawing. --Rd is the swatch circle's radius: the ring, the gap, and the
     swatch's own radius, all measured out from the same centre. */
  --M: 84px;
  --gapPx: 10px;
  --Rd: calc(0.4294 * (100% - 2 * var(--M)) + var(--gapPx));
}
/* --Rd stops at the gap because a custom property substitutes where it is
   declared, not where it is used: folding the swatch radius in on the stage,
   where --dotR does not exist, makes the whole declaration invalid. Both are
   in scope here on the label itself, so the two are added here instead. */
.blend__name { --dotR: 0.31em; --Rc: calc(var(--Rd) + var(--dotR)); }

.blend__name--barrier     { --dx: calc(50% + var(--Rc) * 0.0995); --dy: calc(50% - var(--Rc) * 0.9950); }
.blend__name--hydration   { --dx: calc(50% - var(--Rc)); --dy: 50%; }
.blend__name--sebum       { --dx: calc(50% + var(--Rc) * 0.9983); --dy: calc(50% + var(--Rc) * 0.0587); }
.blend__name--sensitivity { --dx: calc(50% - var(--Rc) * 0.4789); --dy: calc(50% + var(--Rc) * 0.8779); }
.blend__name--renewal     { --dx: calc(50% + var(--Rc) * 0.5735); --dy: calc(50% + var(--Rc) * 0.8192); }

/* Swatch leads, word runs outward. */
.blend__name {
  left: calc(var(--dx) - var(--dotR));
  top: var(--dy);
  transform: translateY(-50%);
}
/* Left of the figure: the word runs the other way, so the swatch stays inward.
   Anchored by the same left edge and then pulled back by its own width, rather
   than by `right`, which would leave both offsets set and over-constrain it. */
.blend__name--hydration,
.blend__name--sensitivity {
  flex-direction: row-reverse;
  left: calc(var(--dx) + var(--dotR));
  transform: translate(-100%, -50%);
}

.blend__name--hydration   { --swatch: var(--c-hydration); }
.blend__name--barrier     { --swatch: var(--c-barrier); }
.blend__name--sebum       { --swatch: var(--c-sebum); }
.blend__name--sensitivity { --swatch: var(--c-sensitivity); }
.blend__name--renewal     { --swatch: var(--c-renewal); }

/* The figure and the type step down together: HYDRATION has to fit between the
   stage edge and its swatch, and that margin is what limits the ring. */
@media (max-width: 900px) {
  .blend__stage { --M: 74px; --gapPx: 8px; }
  .blend__name { font-size: 0.625rem; letter-spacing: 0.08em; }
}
@media (max-width: 460px) {
  .blend__stage { --M: 70px; --gapPx: 8px; }
  .blend__name { font-size: 0.5625rem; letter-spacing: 0.08em; }
}

/* The component carrying the most weight says so. */
.blend__name.is-lead { color: var(--terracotta); }

.blend__scenario {
  display: block;
  margin-bottom: 0.75rem;
}
.blend__caption {
  margin: clamp(2.75rem, 2rem + 2.5vw, 4.5rem) 0 0;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 32ch;
  /* Held open to the tallest line so hovering never reflows the row. */
  min-height: 7em;
  opacity: 1;
  /* Out fast, in slow, so the new line finishes arriving at roughly the moment
     the drops settle. Matching both durations left the caption reading a state
     the picture had not reached yet. */
  transition: opacity 0.38s var(--ease);
}
.blend__caption.is-swapping { opacity: 0; transition-duration: 0.14s; }

@media (max-width: 900px) {
  .how__head { grid-template-columns: minmax(0, 1fr); }
  .blend { max-width: 24rem; margin-inline: auto; }
  .blend__caption { max-width: none; text-align: center; margin-inline: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .blend__drop,
  .blend__name,
  .blend__caption { transition: none; }
}

/* Each chapter sits on a full width band the height of its film, so the film
   has no cut edge of its own: it ends where its own shadow tone continues.
   The four colours are sampled from the darkest third of each clip and then
   levelled to one luminance, so they read as a family and every text tier
   holds the same contrast across all four. */
.chapter {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(2rem, 1rem + 4vw, 5rem);
  margin-bottom: clamp(5rem, 3rem + 8vw, 11rem);
  background: var(--band, var(--carbon));
}

.chapter__film { aspect-ratio: 5 / 4; }

/* The film keeps the wider track on both sides. Reordering alone handed the
   wide track to the copy on flipped chapters, which left a 36ch column sitting
   against the page edge with all the slack stranded behind it. */
.chapter--flip { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); }
.chapter--flip .chapter__film { order: 2; }
.chapter--flip .chapter__body { order: 1; }

.chapter__body { padding-inline: clamp(1.5rem, 5vw, 5.5rem); }
.chapter__copy { max-width: 36ch; }
/* Copy sits against the film in both directions, so the two layouts mirror. */
.chapter--flip .chapter__copy { margin-left: auto; }
.chapter__copy h3 { margin-block: 1rem 1.1rem; color: var(--cream); }
.chapter__copy p  { color: var(--cream-2); }
/* Terracotta disappears into the band, so the label takes the sand voice. */
.chapter__copy .label { color: var(--sand); }
.chapter__copy .spec  { color: var(--cream-2); }

@media (max-width: 900px) {
  .chapter,
  .chapter--flip {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.5rem, 4vw, 2.5rem);
  }
  .chapter__film { aspect-ratio: 4 / 3; }
  .chapter--flip .chapter__film { order: 0; }
  .chapter--flip .chapter__body { order: 0; }
  .chapter--flip .chapter__copy { margin-left: 0; }
  .chapter__body { padding-inline: var(--gutter); padding-bottom: clamp(2.5rem, 6vw, 3.5rem); }
  .chapter__copy { max-width: 44ch; }
}

/* The statement that closes the explanation, carried on a full width film.
   No frame, no caption, the line sits in the picture. */
.pull {
  position: relative;
  margin-top: clamp(3rem, 2rem + 4vw, 6rem);
  min-height: clamp(28rem, 62svh, 44rem);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  isolation: isolate;
  background: var(--carbon);
}
.pull__media { position: absolute; inset: 0; z-index: 0; }
.pull__media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Favouring the left of frame carries the device right, clear of the line. */
  object-position: 30% 50%;
}
.pull__veil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(150% 130% at 0% 100%,
      color-mix(in srgb, var(--carbon) 72%, transparent) 0%,
      color-mix(in srgb, var(--carbon) 50%, transparent) 44%,
      color-mix(in srgb, var(--carbon) 18%, transparent) 72%,
      transparent 90%),
    linear-gradient(to top,
      color-mix(in srgb, var(--carbon) 80%, transparent) 0%,
      color-mix(in srgb, var(--carbon) 62%, transparent) 26%,
      color-mix(in srgb, var(--carbon) 34%, transparent) 52%,
      color-mix(in srgb, var(--carbon) 10%, transparent) 78%,
      color-mix(in srgb, var(--carbon) 30%, transparent) 100%);
}
.pull__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-block: clamp(2.5rem, 2rem + 3vw, 4.5rem);
}
.pull__line {
  font-family: var(--display);
  font-size: var(--fs-display);
  line-height: 1.1;
  color: var(--cream);
}
.pull__sub {
  margin-top: clamp(1.1rem, 0.9rem + 0.6vw, 1.6rem);
  font-size: var(--fs-lede);
  line-height: 1.6;
  /* Brighter than the usual secondary cream: this is body-size text over a
     moving plate, so it carries the stricter 4.5:1 requirement. */
  color: color-mix(in srgb, var(--cream) 90%, var(--carbon));
  max-width: 40ch;
}

@media (max-width: 760px) {
  .pull { min-height: clamp(24rem, 58svh, 34rem); }
  .pull__media video { object-position: 42% 50%; }
}

/* ==========================================================================
   Questions
   ========================================================================== */

.faq__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(1.5rem, 1rem + 3vw, 4rem);
}
.faq__head { grid-column: 1 / span 4; }
.faq__head h2 { margin-top: 1rem; }
.faq__list { grid-column: 6 / span 7; border-top: 1px solid var(--hairline); }
@media (max-width: 900px) {
  .faq__grid { grid-template-columns: minmax(0, 1fr); }
  .faq__head, .faq__list { grid-column: auto; }
}

details { border-bottom: 1px solid var(--hairline); }
details summary {
  cursor: pointer;
  list-style: none;
  padding: 1.5rem 2.5rem 1.5rem 0;
  position: relative;
  font-family: var(--display);
  font-size: var(--fs-title);
  line-height: 1.35;
  transition: color 0.3s var(--ease);
}
details summary::-webkit-details-marker { display: none; }
details summary:hover { color: var(--terracotta); }
details summary::after {
  content: "";
  position: absolute;
  right: 0.35rem;
  top: 50%;
  width: 11px; height: 11px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: translateY(-70%) rotate(45deg);
  transition: transform 0.35s var(--ease);
  opacity: 0.55;
}
details[open] summary::after { transform: translateY(-30%) rotate(225deg); }
details .answer {
  padding: 0 clamp(0rem, 6vw, 3rem) 1.75rem 0;
  color: var(--ink-2);
  max-width: 62ch;
}
details .answer p + p { margin-top: 0.85rem; }
/* Only 400 and 500 of the text face are loaded, so a default bold would be
   synthesised. Emphasis takes the real medium weight and the full ink. */
details .answer strong { font-weight: 500; color: var(--ink); }

/* ==========================================================================
   Reserve. The closing cinematic moment and the form in one section.
   ========================================================================== */

.reserve {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: var(--carbon);
  color: var(--cream);
  padding-block: clamp(5rem, 3rem + 8vw, 9rem);
}
.reserve__media { position: absolute; inset: 0; z-index: 0; }
.reserve__media img { width: 100%; height: 100%; object-fit: cover; }
.reserve__veil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(to right,
      color-mix(in srgb, var(--carbon) 86%, transparent) 0%,
      color-mix(in srgb, var(--carbon) 66%, transparent) 55%,
      color-mix(in srgb, var(--carbon) 40%, transparent) 100%),
    linear-gradient(to top,
      color-mix(in srgb, var(--carbon) 58%, transparent) 0%,
      color-mix(in srgb, var(--carbon) 26%, transparent) 50%,
      color-mix(in srgb, var(--carbon) 48%, transparent) 100%);
}

.reserve__grid {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(2.5rem, 1rem + 5vw, 6rem);
  align-items: center;
}
.reserve__copy  { grid-column: 1 / span 6; }
.reserve__panel { grid-column: 8 / span 5; }
@media (max-width: 980px) {
  .reserve__grid { grid-template-columns: minmax(0, 1fr); }
  .reserve__copy, .reserve__panel { grid-column: auto; }
}

.reserve h2 { color: var(--cream); }
.reserve__lede {
  color: var(--cream-2);
  font-size: var(--fs-lede);
  line-height: 1.7;
  max-width: 42ch;
  margin-top: clamp(1.75rem, 1rem + 2vw, 2.5rem);
}

.terms {
  list-style: none;
  margin: clamp(1.75rem, 1rem + 2vw, 2.5rem) 0 0;
  padding: 0;
  display: grid;
  gap: 0.9rem;
  max-width: 44ch;
}
.terms li {
  position: relative;
  padding-left: 1.5rem;
  font-size: var(--fs-small);
  color: var(--cream-2);
  line-height: 1.6;
}
.terms li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 0.5rem;
  height: 1px;
  background: var(--cream-3);
}

.reserve__panel {
  background: var(--cream);
  color: var(--ink);
  padding: clamp(1.75rem, 1rem + 2.5vw, 3rem);
}
.panel__price {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-block: 1rem 0.4rem;
}
.panel__amount {
  font-family: var(--display);
  font-size: clamp(3rem, 1.5rem + 5vw, 4.25rem);
  line-height: 1;
}
.panel__unit { color: var(--ink-3); font-size: var(--fs-small); }
.panel__sub  { color: var(--ink-2); font-size: var(--fs-small); margin-bottom: 1.9rem; }

.field { display: grid; gap: 0.5rem; margin-bottom: 1rem; }
.field label {
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.field input {
  font: inherit;
  font-size: var(--fs-body);
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--carbon) 24%, transparent);
  border-radius: 0;
  padding: 0.85rem 0.1rem;
  width: 100%;
  transition: border-color 0.3s var(--ease);
}
.field input::placeholder { color: var(--ink-3); }
.field input:hover  { border-bottom-color: color-mix(in srgb, var(--carbon) 45%, transparent); }
.field input:focus  { border-bottom-color: var(--amber); outline: none; }
.field input[aria-invalid="true"] { border-bottom-color: var(--terracotta); }

.field__error { font-size: var(--fs-small); color: var(--terracotta); min-height: 1.25rem; }

.consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.7rem;
  align-items: start;
  margin-block: 0.35rem 1.6rem;
  font-size: var(--fs-small);
  color: var(--ink-2);
  line-height: 1.55;
  cursor: pointer;
}
.consent input {
  appearance: none;
  -webkit-appearance: none;
  width: 1.05rem; height: 1.05rem;
  margin-top: 0.32rem;
  border: 1px solid color-mix(in srgb, var(--carbon) 32%, transparent);
  background: transparent;
  cursor: pointer;
  transition: background-color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.consent input:checked {
  background: var(--carbon) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.2 4.8 8.5 9.5 3.8' fill='none' stroke='%23FBF4E9' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/72% no-repeat;
  border-color: var(--carbon);
}
.consent a { color: var(--ink); }

.panel__foot {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1.2rem;
  font-size: 0.8125rem;
  color: var(--ink-3);
  text-align: center;
}
.panel__foot svg { width: 0.9rem; height: 0.9rem; flex: none; margin-top: 0.22em; }

.formStatus {
  margin-top: 1rem;
  font-size: var(--fs-small);
  color: var(--terracotta);
  line-height: 1.55;
}
.formStatus:empty { margin: 0; }

/* ==========================================================================
   Footer
   ========================================================================== */

.footer { background: var(--carbon); color: var(--cream-2); padding-block: clamp(3rem, 2rem + 3vw, 5rem) 2.5rem; }
.footer__top {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(2rem, 1rem + 3vw, 3.5rem);
  padding-bottom: clamp(2.5rem, 1.5rem + 3vw, 4rem);
  border-bottom: 1px solid var(--hairline-light);
}
.footer__brand { grid-column: 1 / span 4; }
.footer__brand p { color: var(--cream-3); font-size: var(--fs-small); margin-top: 1.5rem; max-width: 30ch; }
.footer__nav { grid-column: 7 / span 3; }
.footer__nav + .footer__nav { grid-column: 10 / span 3; }
@media (max-width: 900px) {
  .footer__top { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__brand { grid-column: 1 / -1; }
  .footer__nav, .footer__nav + .footer__nav { grid-column: auto; }
}
.footer__nav ul { list-style: none; margin: 1.25rem 0 0; padding: 0; display: grid; gap: 0.8rem; }
.footer__nav a { color: var(--cream-2); text-decoration: none; font-size: var(--fs-small); }
.footer__nav a:hover { color: var(--cream); }

.footer__base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 2rem;
  font-size: 0.8125rem;
  color: var(--cream-3);
}
.footer__mono { width: 34px; height: 34px; opacity: 0.85; }

/* ==========================================================================
   Mobile reservation dock. Restrained, and only after the hero.
   ========================================================================== */

.dock {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 55;
  padding: 0.7rem var(--gutter) calc(0.7rem + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--cream) 94%, transparent);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  box-shadow: 0 -1px 0 var(--hairline);

  /* Kept out of the tab order while it is off screen. */
  transform: translateY(110%);
  visibility: hidden;
  transition: transform 0.5s var(--ease), visibility 0s linear 0.5s;
}
.dock.is-up {
  transform: none;
  visibility: visible;
  transition: transform 0.5s var(--ease), visibility 0s;
}
.dock .btn { padding-block: 0.95em; font-size: 0.9375rem; }

@media (min-width: 901px) { .dock { display: none; } }
@media (prefers-reduced-motion: reduce) { .dock { transition: none; } }

/* ==========================================================================
   Utility
   ========================================================================== */

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