/* Beverlynn Upvan landing page. Light theme locked: the page must match the ad creative and
   the printed brochure, so it does not follow the OS colour scheme. One accent (Upvan teal). */

@font-face {
  font-family: "Montserrat";
  src: url("../fonts/montserrat/montserrat-variable-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  color-scheme: light;
  --paper: #f7f9fa;
  --paper-2: #ffffff;
  --band: #e6f3f7;
  --ink: #10202a;
  --muted: #55676f;
  --line: rgb(16 32 42 / 0.10);
  --line-soft: rgb(16 32 42 / 0.06);
  --teal: #0b7a92;        /* 4.9:1 on white: safe for button text */
  --teal-deep: #085f72;
  --teal-bright: #13a3c0; /* glow and gradient edges only, never text */
  --teal-soft: #d6ecf2;
  --r-surface: 16px;
  --r-input: 12px;
  --r-pill: 999px;
  --shadow-1: 0 1px 2px rgb(10 60 75 / 0.06), 0 10px 28px -14px rgb(10 60 75 / 0.28);
  --shadow-2: 0 2px 6px rgb(10 60 75 / 0.06), 0 28px 56px -28px rgb(10 60 75 / 0.38);
  --hl: inset 0 1px 0 rgb(255 255 255 / 0.75);
  --sec: clamp(72px, 10vw, 128px);
  --wrap: 1180px;
  --gutter: 24px;
  --hdr: 64px;
  --font: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --chrome: 0px; /* height of a phone browser's retracting toolbar: 100vh minus the small viewport */
  --bar: 0px;    /* height of the bottom contact bar where it shows (sections.css, phone.css) */
}
@supports (height: 100svh) { :root { --chrome: calc(100vh - 100svh); } }

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  margin: 0;
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
img, video, svg { display: block; max-width: 100%; }
[hidden] { display: none !important; }
img { height: auto; }
a { color: inherit; }
h1, h2, h3 { margin: 0; line-height: 1.1; letter-spacing: -0.02em; font-weight: 800; }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button, input { font: inherit; color: inherit; }
:focus-visible { outline: 3px solid var(--teal-bright); outline-offset: 3px; border-radius: 4px; }

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (prefers-reduced-motion: reduce) {
  /* transitions and keyframes jump straight to their end state */
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; }
}
.ic { width: 1.25em; height: 1.25em; fill: currentColor; flex: none; }
.skip {
  position: absolute; left: 16px; top: -60px; z-index: 100;
  padding: 10px 16px; background: var(--ink); color: #fff; border-radius: var(--r-pill);
}
.skip:focus { top: 12px; }

/* ---------- landscape gate ----------
   The page is built for a wide screen. A touch device held upright (phone or tablet) sees only
   this screen, and the page beneath cannot scroll, until it is turned. Desktop windows are never
   gated: the query needs a touch pointer with no hover. */
.turn {
  display: none; position: fixed; inset: 0; z-index: 70; background: var(--paper); color: var(--ink);
  place-items: center; padding: 24px var(--gutter); text-align: center;
}
.turn__in { display: grid; justify-items: center; gap: 12px; max-width: 30ch; }
.turn__logo { height: 64px; width: auto; margin-bottom: 14px; }
.turn__phone { color: var(--teal); margin: 8px 0 6px; animation: phone-turn 3s var(--ease) infinite; }
.turn__title { font-size: 1.5rem; }
.turn__copy { color: var(--muted); }
.turn .btn { margin-top: 10px; }
@keyframes phone-turn { 0%, 18% { transform: rotate(0); } 42%, 72% { transform: rotate(-90deg); } 90%, 100% { transform: rotate(0); } }
@media (orientation: portrait) and (hover: none) and (pointer: coarse) {
  .turn { display: grid; }
  html { overflow: hidden; }
}
@media (prefers-reduced-motion: reduce) { .turn__phone { animation: none; transform: rotate(-90deg); } }

/* ---------- loading screen: logo, one large counter, a hairline of progress ----------
   seq.js adds .is-done once the first stretch of the walk is here. */
html:has(.loader:not(.is-done)) { overflow: hidden; }
.loader {
  position: fixed; inset: 0; z-index: 60; background: var(--paper); color: var(--ink);
  display: grid; place-items: center;
  padding: 24px var(--gutter) calc(28px + env(safe-area-inset-bottom));
  transition: opacity 0.6s var(--ease), visibility 0s linear 0.6s;
}
.loader.is-done { opacity: 0; visibility: hidden; pointer-events: none; }
.loader__in { display: grid; justify-items: center; gap: 14px; width: min(340px, 100%); text-align: center; }
.loader__logo { height: 72px; width: auto; margin-bottom: 18px; }
.loader__num { font-size: clamp(3rem, 2.2rem + 4vw, 4.5rem); font-weight: 800; letter-spacing: -0.04em; line-height: 1; font-variant-numeric: tabular-nums; }
.loader__bar { width: 100%; height: 2px; border-radius: 2px; background: var(--line); overflow: hidden; }
.loader__bar span { display: block; height: 100%; width: 100%; background: var(--teal); transform-origin: left; transform: scaleX(0); transition: transform 0.2s linear; }
.loader__label { font-size: 0.9375rem; color: var(--muted); }
@media (prefers-reduced-motion: reduce) { .loader { transition: none; } }

/* ---------- type ---------- */
.h1 { font-size: clamp(2rem, 1.2rem + 3.8vw, 3.6rem); line-height: 1.04; }
.h2 { font-size: clamp(1.75rem, 1.2rem + 2.2vw, 2.6rem); max-width: 22ch; text-wrap: balance; }
.h3 { font-size: 1.25rem; line-height: 1.25; }
.lead { color: var(--muted); font-size: clamp(1rem, 0.95rem + 0.3vw, 1.125rem); max-width: 60ch; margin-top: 14px; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 50px; padding: 0 24px;
  border-radius: var(--r-pill); border: 1px solid transparent;
  font-weight: 600; font-size: 1rem; text-decoration: none; white-space: nowrap;
  cursor: pointer; user-select: none;
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease), background-color 0.25s, border-color 0.25s, color 0.25s;
}
.btn:active { transform: scale(0.98); }
.btn--primary {
  color: #fff;
  background: linear-gradient(180deg, var(--teal-bright) -60%, var(--teal) 55%);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.28), 0 12px 26px -12px rgb(11 122 146 / 0.65);
}
.btn--primary:hover { background: linear-gradient(180deg, var(--teal) -40%, var(--teal-deep) 70%); transform: translateY(-2px); box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.22), 0 18px 34px -14px rgb(11 122 146 / 0.7); }
.btn--primary:active { transform: translateY(0) scale(0.98); }
.btn--ink {
  color: #fff; background: var(--ink);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.12), 0 12px 26px -14px rgb(16 32 42 / 0.6);
}
.btn--ink:hover { background: #1b3140; transform: translateY(-2px); }
.btn--ghost {
  color: var(--ink); background: var(--paper-2); border-color: var(--line);
  box-shadow: var(--hl), var(--shadow-1);
}
.btn--ghost:hover { border-color: rgb(16 32 42 / 0.22); transform: translateY(-2px); }
.btn--glass {
  color: #fff; background: rgb(255 255 255 / 0.14); border-color: rgb(255 255 255 / 0.32);
  -webkit-backdrop-filter: blur(14px) saturate(160%); backdrop-filter: blur(14px) saturate(160%);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.35);
}
.btn--glass:hover { background: rgb(255 255 255 / 0.22); transform: translateY(-2px); }
.btn--block { width: 100%; }
.btn--sm { min-height: 42px; padding: 0 16px; font-size: 0.9375rem; }

/* ---------- header: just the logo, straight on the picture, no bar.
   lp.js adds .is-hidden while the page scrolls down (full-screen walk) and removes it on the
   way back up; .is-solid once the walk has left the viewport, which puts a plain paper strip
   behind the logo so it never floats over body text. ---------- */
.hdr {
  position: fixed; inset: 0 0 auto 0; z-index: 40; height: var(--hdr);
  pointer-events: none; /* the bar is empty air; only the logo takes taps */
  border-bottom: 1px solid transparent;
  transition: transform 0.45s var(--ease), background-color 0.35s, border-color 0.35s;
}
.hdr.is-hidden { transform: translateY(-110%); }
.hdr.is-hidden:focus-within { transform: none; } /* keyboard focus brings it back */
.hdr__in { height: 100%; display: flex; align-items: center; }
.hdr__logo { display: block; pointer-events: auto; }
.hdr__logo img { height: 46px; width: auto; }
.hdr.is-solid { background-color: var(--paper); border-color: var(--line-soft); }
@media (min-width: 900px) { .hdr__logo img { height: 52px; } }
@media (prefers-reduced-motion: reduce) { .hdr { transition: none; } }

/* ---------- stats ---------- */
.stats { padding-block: 28px; background: var(--paper-2); border-bottom: 1px solid var(--line-soft); }
.stats__row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 0; }
.stats__row li {
  padding: 4px 16px; border-left: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 2px;
}
.stats__num { font-size: clamp(1.9rem, 1.4rem + 2vw, 2.75rem); font-weight: 800; letter-spacing: -0.03em; line-height: 1; font-variant-numeric: tabular-nums; }
.stats__num small { font-size: 0.55em; font-weight: 700; color: var(--teal); margin-left: 2px; }
.stats__label { color: var(--muted); font-size: 0.9375rem; }
@media (min-width: 900px) {
  .stats { padding-block: 34px; }
  .stats__row { grid-template-columns: repeat(4, 1fr); gap: 0; }
  .stats__row li { padding: 10px 22px; }
}

/* ---------- sections ---------- */
.sec { padding-block: var(--sec); }
.sec--band {
  background:
    radial-gradient(900px 420px at 8% 0%, rgb(255 255 255 / 0.85), transparent 60%),
    var(--band);
}
.odo { display: inline-block; height: 1em; overflow: hidden; vertical-align: top; } /* one odometer digit (motion.js) */
.odo > span { display: block; }
.odo > span > span { display: block; height: 1em; line-height: 1; }

/* ---------- the walk-in: the hero (scroll-driven frame sequence, seq.js) ----------
   Default (no JS, reduced motion, data saver, failed load): six stills stacked with their
   captions, starting under the fixed header. seq.js adds .walk--live to pin a canvas and scrub
   the frames instead, and .walk--painted once the first frame is on the canvas (until then
   the preloaded poster of that same frame shows, so the hero never paints blank).
   The captions are plain text over the picture, no panel: a soft dark gradient at the foot of
   the frame and a text shadow carry the legibility, so the render stays in view. */
.walk__track { position: relative; }
.walk__stage { position: relative; width: 100%; }
.walk__poster, .walk__canvas { display: none; }
.walk__cards { display: grid; gap: 20px; padding: calc(var(--hdr) + 20px) var(--gutter) var(--sec); max-width: var(--wrap); margin: 0 auto; box-sizing: content-box; }
.walk__card { position: relative; color: #fff; border-radius: var(--r-surface); overflow: hidden; background: #0d1a22; box-shadow: var(--shadow-2); }
.walk__card::after {
  content: ""; position: absolute; inset: 40% 0 0 0; pointer-events: none;
  background: linear-gradient(180deg, rgb(13 26 34 / 0) 0%, rgb(13 26 34 / 0.62) 100%);
}
.walk__still { display: block; aspect-ratio: 4 / 3; } /* the frames' own shape; phones are landscape-only */
.walk__still img { width: 100%; height: 100%; display: block; object-fit: cover; }
.walk__rail, .walk__bar { display: none; }
.walk__text {
  position: absolute; left: 20px; right: 20px; bottom: 20px; z-index: 1;
  text-shadow: 0 1px 2px rgb(0 0 0 / 0.45), 0 2px 18px rgb(0 0 0 / 0.4);
}
.walk__h { font-size: clamp(1.4rem, 1.1rem + 1.4vw, 2rem); line-height: 1.1; letter-spacing: -0.02em; }
.walk__h--hero { font-size: clamp(1.75rem, 1.15rem + 2.2vw, 2.6rem); line-height: 1.05; letter-spacing: -0.025em; }
.walk__text p { margin-top: 6px; color: rgb(255 255 255 / 0.92); font-size: 1rem; line-height: 1.45; }
.walk__text .btn { margin-top: 16px; } /* the last stop's Enquire now */
@media (min-width: 640px) {
  .walk__cards { grid-template-columns: 1fr 1fr; gap: 24px; padding-top: calc(var(--hdr) + 32px); }
  .walk__card--hero { grid-column: 1 / -1; }
  .walk__text { left: 28px; right: auto; bottom: 28px; max-width: 440px; }
  .walk__card--hero .walk__text { max-width: 600px; }
  .walk__card--hero .walk__text p { font-size: 1.125rem; }
}

/* live: pinned canvas */
.walk--live .walk__track { background: #0d1a22; height: calc(100vh + var(--walk-len, 3600px)); }
/* The stage is 100vh (the large viewport), not 100dvh, on purpose: with dvh the stage grew each
   time a phone's toolbar retracted mid-scroll, the canvas had to re-fit, and the frame jumped.
   At 100vh nothing changes size while scrolling; while the toolbar is showing, the bottom strip
   of the stage sits under the screen edge, so bottom-anchored parts add --chrome to stay clear. */
.walk--live .walk__stage { position: sticky; top: 0; height: 100vh; overflow: hidden; }
.walk--live .walk__stage::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgb(13 26 34 / 0.24) 0%, rgb(13 26 34 / 0) 26%, rgb(13 26 34 / 0) 52%, rgb(13 26 34 / 0.6) 100%);
}
.walk--live .walk__card::after { display: none; } /* the stage gradient above does this job */
.walk--live .walk__poster { display: block; position: absolute; inset: 0; }
.walk--live .walk__poster img { width: 100%; height: 100%; object-fit: cover; object-position: center; }
.walk--live .walk__canvas { display: block; position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; }
.walk--painted .walk__canvas { opacity: 1; } /* the poster stays underneath: it is the page's LCP image */
.walk--live .walk__still { display: none; }
.walk--live .walk__cards { display: contents; }
.walk--live .walk__card {
  position: absolute; left: var(--gutter); right: var(--gutter); bottom: calc(var(--chrome) + 28px + env(safe-area-inset-bottom)); z-index: 1;
  border-radius: 0; overflow: visible; background: none; box-shadow: none;
  visibility: hidden; opacity: 0; will-change: transform, opacity;
}
.walk--live .walk__text { position: relative; left: auto; right: auto; bottom: auto; max-width: 440px; }
.walk--live .walk__card--hero .walk__text { max-width: 600px; opacity: 0; }
.walk--ready.walk--live .walk__card--hero .walk__text { animation: text-rise 0.55s var(--ease) both; } /* once the loading screen has gone */
@keyframes text-rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.walk--live .walk__bar {
  display: block; position: absolute; left: 0; right: 0; bottom: var(--chrome); height: 3px; z-index: 1;
  background: rgb(255 255 255 / 0.14);
}
.walk__bar span { position: absolute; inset: 0; transform-origin: left; transform: scaleX(0); }
.walk__bar-load { background: rgb(255 255 255 / 0.3); }
.walk__bar-pos { background: var(--teal-bright); box-shadow: 0 0 12px rgb(19 163 192 / 0.8); }
@media (min-width: 900px) {
  .walk--live .walk__card { left: max(var(--gutter), calc((100vw - var(--wrap)) / 2 + var(--gutter))); right: auto; bottom: calc(var(--chrome) + 72px); width: min(440px, calc(100vw - 2 * var(--gutter))); }
  .walk--live .walk__card--hero { width: min(560px, calc(100vw - 2 * var(--gutter))); }
  .walk--live .walk__rail {
    display: grid; gap: 10px; position: absolute; right: 40px; top: 50%; transform: translateY(-50%); z-index: 1;
    margin: 0; padding: 0; list-style: none;
  }
  .walk__rail button {
    display: flex; align-items: center; justify-content: flex-end; gap: 10px; padding: 6px 0; border: 0; background: none; cursor: pointer;
    color: rgb(255 255 255 / 0.72); font-weight: 600; font-size: 0.8125rem; letter-spacing: 0.01em;
    text-shadow: 0 1px 2px rgb(0 0 0 / 0.6), 0 2px 14px rgb(0 0 0 / 0.5);
    transition: color 0.25s;
  }
  .walk__rail button::after { content: ""; width: 18px; height: 2px; border-radius: 2px; background: currentColor; transition: width 0.3s var(--ease), background-color 0.3s; }
  .walk__rail button:hover { color: #fff; }
  .walk__rail button[aria-current="true"] { color: #fff; }
  .walk__rail button[aria-current="true"]::after { width: 36px; background: var(--teal-bright); box-shadow: 0 0 10px rgb(19 163 192 / 0.8); }
}

/* ---------- motion hooks (motion.js adds .motion to <html> only when animation is allowed) ----------
   Hidden start states live behind .motion so a page without it (reduced motion, no GSAP, a script
   error) renders fully static and visible. */
.motion [data-reveal] { opacity: 0; transform: translateY(26px); will-change: transform, opacity; }
.motion [data-split] { visibility: hidden; } /* until motion.js has wrapped the words */
.motion [data-split].is-split { visibility: visible; }
.w { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: 0.14em; margin-bottom: -0.14em; }
.w > span { display: inline-block; }

/* ---------- shared: section frame and chips ----------
   A frame is a heading column beside the section's material. It stacks on narrow windows, sits
   side by side from 900 px, and phone.css turns it into the landscape-phone frame. */
.frame { display: grid; gap: 28px; }
@media (min-width: 900px) {
  .frame { grid-template-columns: minmax(250px, 0.78fr) minmax(0, 1.62fr); column-gap: clamp(40px, 5vw, 72px); align-items: start; }
  /* --head-h comes from lp.js: a head taller than the room left pins by its foot instead */
  .frame > .sec__head {
    position: sticky; top: calc(var(--hdr) + 28px);
    top: min(calc(var(--hdr) + 28px), calc(100svh - var(--bar) - var(--head-h, 0px) - 16px));
  }
}
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }
.chip {
  display: inline-flex; align-items: center; min-height: 40px; padding: 0 16px; cursor: pointer;
  border-radius: var(--r-pill); border: 1px solid rgb(16 32 42 / 0.16); background: var(--paper-2);
  font-weight: 600; font-size: 0.9375rem; line-height: 1.2; color: var(--ink);
  box-shadow: var(--hl), 0 4px 12px -8px rgb(10 60 75 / 0.35);
  transition: background-color 0.25s, border-color 0.25s, color 0.25s, transform 0.35s var(--ease), box-shadow 0.35s var(--ease);
}
.chip:hover { border-color: rgb(16 32 42 / 0.3); transform: translateY(-1px); }
.chip:active { transform: scale(0.97); }
.chip[aria-pressed="true"] { background: var(--teal); border-color: var(--teal); color: #fff; box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.25), 0 10px 22px -12px rgb(11 122 146 / 0.7); }

/* addData.js toast, restyled to the page */
.custom-alert { top: auto !important; left: 50% !important; bottom: 96px !important; transform: translateX(-50%); font-family: var(--font) !important; border-radius: 14px !important; }
@media (min-width: 900px) and (min-height: 600px) { .custom-alert { bottom: 28px !important; } } /* sits above the sticky bar otherwise */
