/* ============================================================
   NEXA — Smart and Affordable
   Static one-pager. The exploded view video is the brand argument:
   every part on show, nothing hidden. So the page is dressed as a
   technical document rather than a lifestyle ad. Red behaves like an
   annotation colour on an engineering drawing, and mono appears only
   where the content is genuinely data.

   Two structural rules drive most of this file:
   1. Every static section is a .panel, sized to sit inside one laptop
      viewport so nothing gets cut off mid section.
   2. Type is centred throughout, including the pinned hero column.
   ============================================================ */

:root {
  --paper: #ffffff;
  --ink: #0a0a0b;
  --ink-2: #4a4f58;
  --ink-3: #7c828d;
  --signal: #e01e37;
  /* Deeper drench for the contact panel: the brand red is only 3.84:1
     against the tinted body copy that sits on it, this clears 4.5:1. */
  --signal-deep: #c4162c;
  /* Lifted red for small type on dark surfaces, where the brand red is
     3.75:1 and fails for 11px text. */
  --signal-lift: #f04257;
  --line: #e3e5e9;
  --line-dark: #26272b;
  /* Each video's own backdrop, sampled from the render, so the footage
     never reads as a panel sitting on a different surface. The desktop
     cut is a light studio, the mobile cut is near black. */
  --studio: #ededed;
  --studio-dark: #0f1112;

  --max: 1240px;
  --pad: clamp(20px, 5vw, 64px);

  --sans: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --ease: cubic-bezier(0.16, 1, 0.3, 1); /* ease-out-expo */

  --z-video: -1;
  --z-base: 1;
  --z-header: 50;
  --z-cue: 45;
  --z-progress: 60;
  --z-skip: 100;

  /* Scroll distance per scene. Every scene covers an equal share of the
     clip's total visual change (see script.js), so equal heights give a
     constant rate of movement. Raised from 175vh so the disassembly
     advances more slowly and reads more clearly. */
  --scene-h: 330vh;

  /* One size for every scene heading. The hero does not get to be larger
     than the beats that follow it: they are four steps of one argument,
     and a size jump would read as a hierarchy that is not there. */
  --scene-type: clamp(1.85rem, 2.9vw, 2.9rem);

  /* Header height, reserved so panels can subtract it and still fit
     inside a single viewport. */
  --header-h: 74px;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  text-align: center;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: var(--z-skip);
  background: var(--ink);
  color: #fff;
  padding: 12px 20px;
}
.skip-link:focus { left: 0; }

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

.container {
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--pad);
}

.display {
  margin: 0 0 14px;
  font-size: clamp(1.5rem, 2.35vw, 2.35rem);
  line-height: 1.06;
  letter-spacing: -0.035em;
  font-weight: 800;
}

/* ---------- Fixed scroll-scrubbed video layer ---------- */

/* Wide screens: the video takes the right 60% of the viewport and the
   copy is pinned in the left 40%, so the two never overlap. */
#video-container {
  position: fixed;
  top: 0;
  right: 0;
  width: 60vw;
  height: 100vh;
  height: 100dvh;
  z-index: var(--z-video);
  /* The footage's backdrop is neither flat nor symmetrical: the top runs
     #e0e0e0 at the edges to #eeeeee through the middle, while the floor
     below the product is lighter and cooler to the right. So the
     backdrop is two stacked gradients, each filling the half of the
     container that its matching letterbox bar lands in. */
  background-image:
    linear-gradient(to right, #e0e0e0 0%, #eeeeee 50%, #e0e0e0 100%),
    linear-gradient(to right, #f9f9f9 0%, #f9f9f9 50%, #fbfbfd 100%);
  background-size: 100% 50%, 100% 50%;
  background-position: top, bottom;
  background-repeat: no-repeat;
  pointer-events: none;
}

#video-container video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* `contain`, not `cover`. The disassembly spreads sideways, boards and
     speakers travelling to the far edges of the frame, and in a partial
     width column `cover` would crop exactly those parts away. `contain`
     keeps the whole frame; the container is painted in the footage's own
     backdrop, so the letterboxing reads as empty studio, not as bars. */
  object-fit: contain;
  object-position: center;
}

/* Only needed where copy sits on top of the footage, which is the narrow
   layout. Nothing overlaps here. */
.video-scrim { display: none; }

/* Device split, decided once at load by script.js via matchMedia. This
   breakpoint must stay in sync with MOBILE_QUERY there. */
#video-container video[data-hero-video="mobile"] { display: none; }

/* ---------- Scroll progress ---------- */

.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 100%;
  background: var(--signal);
  transform: scaleX(0);
  transform-origin: 0 50%;
  z-index: var(--z-progress);
}

/* ---------- Header ---------- */

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 16px var(--pad);
  min-height: var(--header-h);
  /* Transparent over the video: a frosted bar would read as a band
     across the footage. It gains a surface only once the dark content
     scrolls up behind it (.is-stuck, set in script.js). */
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background .35s var(--ease), border-color .35s var(--ease);
}

.site-header.is-stuck {
  background: rgba(255, 255, 255, 0.88);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom-color: var(--line);
}

.brand img { width: 88px; }

.site-header nav {
  display: flex;
  align-items: center;
  gap: clamp(14px, 2.4vw, 28px);
  font-size: 14px;
  font-weight: 500;
}

.site-header nav a { color: var(--ink-2); transition: color .2s var(--ease); }
.site-header nav a:hover { color: var(--ink); }

.nav-cta {
  background: var(--ink);
  color: #fff !important;
  padding: 9px 18px;
  border-radius: 999px;
  font-weight: 600;
  transition: background .2s var(--ease);
}
.nav-cta:hover { background: var(--signal); }

/* ---------- Scrubbed scenes ----------
   Each .scene is a scroll-distance marker with no visible content of its
   own. The copy is pinned by .scene-inner so it holds still against the
   moving product. */

.scene { position: relative; height: var(--scene-h); }

/* The copy side's own surface. A shade lighter than the footage's
   backdrop, so the vertical join reads as a deliberate two panel
   composition rather than a mismatch. */
.hero-side {
  position: fixed;
  top: 0;
  left: 0;
  width: 40vw;
  height: 100vh;
  height: 100dvh;
  z-index: var(--z-video);
  background: #f7f7f7;
  pointer-events: none;
}

.scene-inner {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  width: 40%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  /* Left aligned here, unlike the rest of the page: in a tall narrow
     column a centred block has no fixed edge for the eye to return to,
     and every line starts in a different place. */
  text-align: left;
  padding: var(--header-h) clamp(28px, 3.4vw, 64px) 0;
  pointer-events: none;
}

.scene-inner a { pointer-events: auto; }

/* Wide enough to actually use the column. `balance` is switched off for
   these headings: it evens line lengths by shortening them all, which is
   what was leaving so much empty space to the right. */
.scene-top { max-width: 34ch; }
.scene h1, .scene h2 { text-wrap: normal; }


.scene h1 {
  margin: 0;
  font-size: var(--scene-type);
  line-height: 1.06;
  letter-spacing: -0.035em;
  font-weight: 900;
}

.scene h2 {
  margin: 0;
  font-size: var(--scene-type);
  line-height: 1.06;
  letter-spacing: -0.035em;
  font-weight: 900;
}

/* Same motif as the Features heading rule, aligned to its own context. */
.scene-rule {
  display: block;
  width: 46px;
  height: 2px;
  margin: clamp(18px, 2.6vh, 28px) 0;
  background: var(--ink);
}

.scene-top p {
  margin: 0;
  color: var(--ink-2);
  font-size: clamp(0.95rem, 1.15vw, 1.1rem);
  line-height: 1.65;
}

/* ---------- Scroll cue ----------
   Fixed to the viewport, centred on the screen rather than inside the
   hero's copy column. The beat is a slow pulse on scale and opacity so
   it reads as alive without becoming a distraction; the arrow travels on
   a longer cycle underneath it. */
.scroll-cue {
  position: fixed;
  left: 50%;
  bottom: clamp(20px, 3.4vh, 40px);
  transform: translateX(-50%);
  z-index: var(--z-cue);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  pointer-events: none;
  color: var(--ink);
}

.scroll-cue-text {
  font-family: var(--mono);
  font-size: clamp(11px, 1vw, 13px);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
  animation: cue-beat 1.8s ease-in-out infinite;
}

.scroll-cue-arrow {
  width: 15px;
  height: 20px;
  animation: cue-drop 1.8s ease-in-out infinite;
}

@keyframes cue-beat {
  0%, 100% { transform: scale(1);    opacity: 0.72; }
  45%      { transform: scale(1.07); opacity: 1; }
}

@keyframes cue-drop {
  0%, 100% { transform: translateY(0);   opacity: 0.5; }
  45%      { transform: translateY(5px); opacity: 1; }
}

/* ---------- Static content ----------
   Every panel is a single viewport tall and vertically centres its own
   content, so no section is ever cut in half by the fold. min-height
   rather than height: if a viewport is genuinely too short for the
   content, the panel grows instead of clipping it. */

.page-content {
  position: relative;
  z-index: var(--z-base);
  background: var(--paper);
}

/* Sections scroll normally, with one exception: the closing card slides
   up over the specs panel as the page's last move. Only the specs panel
   pins, so this is a single deliberate transition rather than every
   section stacking.

   Gated on BOTH dimensions, because a sticky element taller than the
   viewport pins its top and leaves its lower half permanently
   unreachable. Short windows and narrow screens scroll normally. */
@media (min-width: 901px) and (min-height: 660px) {
  .page-content > .specs {
    position: sticky;
    top: 0;
  }

  /* A soft edge on the incoming card so it reads as a sheet moving over
     the panel beneath rather than a hard cut. */
  .page-content > .closing {
    position: relative;
  }

  .page-content > .closing::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 40px;
    transform: translateY(-100%);
    pointer-events: none;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.16), rgba(0, 0, 0, 0));
  }
}

.panel {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  padding: calc(var(--header-h) + 3vh) 0 5vh;
}

.panel > .container { width: 100%; }

.panel-head { margin-bottom: clamp(20px, 3.4vh, 42px); }

.panel-head .display { margin-bottom: 10px; }

.panel-head p {
  margin: 0 auto;
  max-width: 52ch;
  color: var(--ink-2);
  font-size: clamp(0.9rem, 1vw, 0.98rem);
}

.panel-note {
  margin: clamp(18px, 2.6vh, 32px) 0 0;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
}

/* ---------- Models (near-black drench) ---------- */

.models { background: var(--ink); color: #fff; }
.models .display { font-size: clamp(1.35rem, 2vw, 2rem); }
.models .display { color: #fff; }
.models .panel-head p { color: #a2a7b0; }

.models-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(10px, 1.15vw, 18px);
  align-items: stretch;
}

.model {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(12px, 1.6vh, 18px) clamp(11px, 1.2vw, 18px);
  border: 1px solid var(--line-dark);
  border-radius: 4px;
  background: #121216;
  transition: border-color .3s var(--ease), transform .3s var(--ease);
}

.model:hover { border-color: #3a3c42; transform: translateY(-4px); }

/* The featured model is a different object, not the same card scaled:
   it carries the signal colour and sits proud of the row. */
.model--featured {
  background: #17171c;
  border-color: var(--signal);
  transform: translateY(-12px);
}
.model--featured:hover { border-color: var(--signal); transform: translateY(-16px); }

/* Flag with a rule running out to either side. The rules are pseudo
   elements so the label stays a single centred text node. */
.model-flag {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  margin: 0 0 clamp(8px, 1.2vh, 14px);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--signal-lift);
}
.model-flag::before,
.model-flag::after {
  content: "";
  height: 1px;
  width: clamp(16px, 3vw, 34px);
  background: var(--signal-lift);
  opacity: 0.55;
}

/* Keeps the three cards' headings on the same baseline even though only
   the middle one carries a flag above it. */
.model:not(.model--featured) h3 {
  margin-top: calc(10px + clamp(8px, 1.2vh, 14px));
}

.model h3 {
  margin: 0 0 6px;
  font-size: clamp(0.86rem, 0.96vw, 0.96rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.model-size {
  margin: 0 0 clamp(8px, 1.3vh, 14px);
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
}
.model-size span {
  display: block;
  font-size: clamp(1.2rem, 1.75vw, 1.65rem);
  font-weight: 700;
  color: #fff;
  line-height: 1;
  margin-bottom: 2px;
}

.model-price {
  width: 100%;
  margin: 0 0 clamp(12px, 1.8vh, 20px);
  padding-bottom: clamp(12px, 1.8vh, 20px);
  border-bottom: 1px solid var(--line-dark);
  font-family: var(--mono);
  font-size: clamp(0.85rem, 0.98vw, 0.98rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}
.model-price .cur {
  display: block;
  font-size: 0.62rem;
  font-weight: 500;
  color: var(--ink-3);
  letter-spacing: 0.08em;
  margin-bottom: 2px;
}

/* Icon plus stacked label and value, left aligned inside the card. This
   is the one place type is not centred: the icons form a vertical line
   the eye can follow down the list, which centring would break. */
.model-specs {
  width: 100%;
  margin: 0 0 clamp(11px, 1.7vh, 18px);
  padding: 0;
  list-style: none;
  flex: 1;
  text-align: left;
}

.model-specs li {
  display: flex;
  align-items: center;
  gap: clamp(9px, 1vw, 14px);
  padding: clamp(5px, 0.8vh, 7px) 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.model-specs li:last-child { border-bottom: 0; }

.spec-ico {
  flex: 0 0 auto;
  width: clamp(16px, 1.3vw, 20px);
  height: clamp(16px, 1.3vw, 20px);
  color: var(--ink-3);
}
.spec-ico svg { width: 100%; height: 100%; display: block; }

.spec-txt {
  display: block;
  color: #eceef1;
  font-size: clamp(0.76rem, 0.86vw, 0.84rem);
  line-height: 1.3;
}
.spec-txt em {
  display: block;
  font-style: normal;
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  margin-bottom: 2px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: clamp(8px, 1.1vh, 11px) 16px;
  border-radius: 4px;
  font-size: clamp(0.8rem, 0.88vw, 0.87rem);
  font-weight: 600;
  cursor: pointer;
  transition: background .2s var(--ease), color .2s var(--ease), border-color .2s var(--ease);
}

.btn-solid { background: var(--signal); color: #fff; }
.btn-solid:hover { background: #f0304a; }

/* Outlined in the signal colour rather than grey: the two non featured
   cards are still a buy action, just not the recommended one. */
.btn-line { border: 1px solid var(--signal); color: var(--signal-lift); }
.btn-line:hover { background: var(--signal); color: #fff; }

.btn-invert { width: auto; background: #fff; color: var(--ink); padding: 14px 32px; }
.btn-invert:hover { background: var(--ink); color: #fff; }

/* Secondary action, demoted to a quiet link so the card keeps one clear
   primary button without losing the enquiry route. */
.model-more {
  display: block;
  margin-top: clamp(8px, 1.2vh, 12px);
  font-size: 12px;
  color: var(--ink-3);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color .2s var(--ease);
}
.model-more:hover { color: #fff; }

/* ---------- Inside ----------
   Four points arranged around a cut out product shot, so the section has
   a subject at its centre rather than being four text blocks in a row. */

.inside { background: #fbfbfb; }

.inside-head { margin-bottom: clamp(26px, 4vh, 52px); }

/* Weight contrast inside one line, rather than a second font: the
   emphasis lands on the word that carries the argument. */
.inside-title {
  margin: 0;
  font-size: clamp(1.6rem, 2.85vw, 2.65rem);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.03em;
}
.inside-title strong { font-weight: 800; }

.title-rule {
  display: block;
  width: 42px;
  height: 2px;
  margin: clamp(14px, 2vh, 22px) auto 0;
  background: var(--ink);
}

.inside-layout {
  display: grid;
  grid-template-columns: 1fr 1.25fr 1fr;
  gap: clamp(20px, 3.5vw, 64px);
  align-items: center;
}

.inside-col {
  display: flex;
  flex-direction: column;
  gap: clamp(18px, 3vh, 38px);
}

/* Hairline between the two points in a column, matching the reference
   layout. Only between them, never above the first or below the last. */
.inside-item + .inside-item {
  padding-top: clamp(18px, 3vh, 38px);
  border-top: 1px solid var(--line);
}

.inside-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(42px, 3.5vw, 52px);
  height: clamp(42px, 3.5vw, 52px);
  margin: 0 auto clamp(12px, 1.8vh, 18px);
  border-radius: 50%;
  background: #efefef;
  color: var(--ink);
}

.inside-icon svg {
  width: 45%;
  height: 45%;
  display: block;
}

.inside-item h3 {
  margin: 0 0 8px;
  font-size: clamp(0.9rem, 1vw, 1rem);
  font-weight: 700;
  letter-spacing: -0.015em;
}

.inside-item p {
  margin: 0 auto;
  max-width: 30ch;
  color: var(--ink-2);
  font-size: clamp(0.82rem, 0.9vw, 0.88rem);
  line-height: 1.55;
}

.inside-figure { margin: 0; }

/* Cut out to transparent PNG, so it floats on the section rather than
   sitting on a visible plate. Its own contact shadow survived the cut as
   soft alpha, which is what keeps it grounded. */
.inside-figure img { width: 100%; }

/* ---------- Specs ----------
   A real comparison, not a flat table. The middle column carries the
   same emphasis it has in the models grid so the two sections agree. */

.specs {
  background: var(--ink);
  color: #fff;
  /* Top padding clears the fixed header as well as giving the section
     its own breathing room, so the heading can never tuck under it. */
  padding: calc(var(--header-h) + clamp(46px, 7vh, 92px)) 0 clamp(64px, 10vh, 120px);
}
.specs .display { color: #fff; }
.specs .panel-head p { color: #a2a7b0; }

.spec-table {
  font-family: var(--mono);
  font-size: clamp(0.68rem, 0.8vw, 0.78rem);
  border-top: 1px solid rgba(255, 255, 255, 0.85);
}

.spec-row {
  display: grid;
  grid-template-columns: 1.3fr repeat(3, 1fr);
  gap: clamp(8px, 1.2vw, 20px);
  align-items: center;
  padding: clamp(7px, 1.1vh, 12px) 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.spec-row > span { display: block; }

.spec-label {
  font-family: var(--sans);
  font-weight: 500;
  color: #a2a7b0;
  text-align: left;
}

.spec-row--head {
  border-bottom: 1px solid rgba(255, 255, 255, 0.85);
  padding-bottom: clamp(10px, 1.6vh, 18px);
}

.spec-col {
  font-family: var(--sans);
  font-weight: 700;
  font-size: clamp(0.78rem, 0.92vw, 0.9rem);
  letter-spacing: -0.01em;
}

.spec-col em {
  display: block;
  font-style: normal;
  font-family: var(--mono);
  font-size: clamp(1.05rem, 1.65vw, 1.55rem);
  font-weight: 700;
  line-height: 1.1;
  margin-top: 2px;
}

/* The Edge column, tinted down the full height of the table. */
.spec-col--hi {
  background: rgba(224, 30, 55, 0.16);
  box-shadow: 0 0 0 1px rgba(240, 66, 87, 0.35);
  border-radius: 3px;
  padding: 4px 6px;
}
.spec-row--head .spec-col--hi { color: var(--signal-lift); }

.spec-row--price {
  border-bottom: 0;
  font-weight: 700;
  font-size: clamp(0.8rem, 1vw, 0.95rem);
}

/* ---------- Closing (contact + footer share one viewport) ----------
   The wrapper is what measures a viewport. The contact panel then takes
   whatever height is left once the footer has claimed its own, so the
   two always land in the same frame instead of the footer being pushed
   onto a screen of its own. */

.closing {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.contact {
  flex: 1;
  display: flex;
  align-items: center;
  background: var(--signal-deep);
  color: #fff;
  padding: clamp(48px, 8vh, 96px) 0;
}

/* Everything in the card is centred as one optical block: the container
   is capped and auto centred so the heading, paragraph and button all
   share a single centre line rather than each finding their own. */
.contact > .container {
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.contact .display { color: #fff; }

.contact > .container > p {
  margin: 0 0 clamp(22px, 3.2vh, 34px);
  max-width: 46ch;
  /* A tint of the surface's own hue, not grey: grey on colour reads
     washed out. */
  color: #ffdfe4;
}


/* ---------- Footer ---------- */

.site-footer {
  flex: 0 0 auto;
  background: var(--ink);
  color: #fff;
  padding: clamp(26px, 4vh, 44px) 0;
}

/* Wider and less inset than the page container: the footer is a bar, so
   its two ends should sit near the edges of the screen rather than lining
   up with the body copy above it. */
.site-footer .container {
  max-width: 1600px;
  padding: 0 clamp(18px, 2.4vw, 40px);
}

.footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  text-align: left;
}

.footer-brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.footer-logo { width: clamp(120px, 13vw, 168px); opacity: 0.92; }

/* Sans, not mono: it is a sentence, not a data point, and the mono was
   making a plain copyright line read like a terminal string. */
.footer-line {
  margin: 0;
  font-size: 13px;
  color: var(--ink-3);
  letter-spacing: 0;
}

.footer-credit {
  margin: 0;
  font-size: 13px;
  color: var(--ink-3);
  text-align: right;
}

.footer-credit a {
  color: #fff;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--signal-lift);
  transition: color .2s var(--ease);
}
.footer-credit a:hover { color: var(--signal-lift); }

/* ---------- Reveals ----------
   Hidden only once JS confirms it can bring them back, so a script
   failure leaves the copy visible rather than stranding it invisible. */

.js-ready [data-fade] { opacity: 0; }

/* ============================================================
   Narrow screens
   ============================================================ */

@media (max-width: 900px) {
  /* Full bleed, matching the Mohyuddin build: `cover` fills the viewport
     edge to edge and `object-position: top` takes any crop off the
     bottom of the frame rather than the top. `contain` was tried here
     and produced exactly the boxed, bordered look that build had already
     rejected, so the copy goes back over the footage instead of beside
     it. The portrait cut is near black, so white copy over it reads
     fine with the scrim below doing the rest. */
  #video-container {
    inset: 0;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    background: var(--studio-dark);
  }

  #video-container video {
    inset: 0;
    top: 0;
    bottom: auto;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top;
  }

  #video-container video[data-hero-video="desktop"] { display: none; }
  #video-container video[data-hero-video="mobile"]  { display: block; }

  /* Copy sits over the footage, so the scrim both darkens the whole
     frame and weights that darkening toward the top where the copy
     lands. It never reaches full opacity lower down, so the product
     stays visible through it. */
  .video-scrim {
    display: block;
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
      linear-gradient(to bottom,
        rgba(15, 17, 18, 0.94) 0%,
        rgba(15, 17, 18, 0.78) 26%,
        rgba(15, 17, 18, 0.52) 52%,
        rgba(15, 17, 18, 0.48) 100%);
  }

  /* No split to sit beside, so the copy panel goes away entirely. */
  .hero-side { display: none; }

  /* Centred in the viewport rather than pinned under the header. */
  .scene-inner {
    width: 100%;
    height: 100vh;
    height: 100dvh;
    justify-content: center;
    align-items: center;
    text-align: center;
    padding: var(--header-h) var(--pad) 0;
  }

  /* Was 22ch, which cut the column short and left the sides empty. The
     line length is governed by the padding now, so the copy uses the
     screen it has. */
  .scene-top { max-width: 100%; }

  /* Scaled off viewport WIDTH here, not the desktop clamp. At 1.85rem
     the headline was a hair too wide for a phone and broke into stubs
     ("Premium is / a price tag. / Not a / product."); sized this way
     each deliberate line fits on one row. */
  .scene h1,
  .scene h2 {
    font-size: clamp(1.35rem, 6.4vw, 2.1rem);
  }

  .scene-top p { font-size: clamp(0.88rem, 3.7vw, 1.02rem); }
  .scene-rule { margin-left: auto; margin-right: auto; background: #fff; }

  /* Footage is near black here, so the hero copy inverts. */
  .scene h1, .scene h2 { color: #fff; }
  .scene-top p { color: #c9ccd2; }
  .scroll-cue { color: #fff; }

  /* The header sits over near black footage up top, so its logo has to
     invert too until the light content scrolls under it. */
  .site-header:not(.is-stuck) .brand img { filter: invert(1); }
  .site-header:not(.is-stuck) nav a { color: #c9ccd2; }
  .site-header:not(.is-stuck) .nav-cta { background: #fff; color: var(--ink) !important; }

  .models-grid { grid-template-columns: 1fr; gap: 14px; }
  .model:not(.model--featured) h3 { margin-top: 0; }
  .model--featured, .model--featured:hover { transform: none; }
  .model-size span { display: inline; font-size: 1.6rem; margin-right: 6px; }
  .model-price .cur { display: inline; margin-right: 6px; }

  /* Product shot leads, then the four points in a two column grid under
     it. The column hairline would read as an arbitrary rule once the
     layout reflows, so it becomes a top border on every item instead. */
  .inside-layout { grid-template-columns: 1fr; gap: clamp(24px, 4vh, 40px); }
  .inside-figure { order: -1; max-width: 460px; margin: 0 auto; }

  .inside-col {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(18px, 3vh, 30px);
  }
  .inside-item + .inside-item { padding-top: 0; border-top: 0; }
  .inside-item p { max-width: 26ch; }

  .spec-row { grid-template-columns: 1fr repeat(3, 1fr); gap: 6px; }

  /* Shorter viewports cover fewer real pixels per vh, so scenes get
     more distance to keep the scrub from feeling stepped. */
  :root { --scene-h: 300vh; --header-h: 64px; }

  /* Panels stop being locked to one viewport: on a phone the models
     grid genuinely needs to scroll. */
  .panel { min-height: 0; padding: clamp(64px, 10vh, 96px) 0; }

  /* The closing card's slide over is opted into by the
     min-width/min-height query above, so nothing to switch off here. */

  .footer-inner { flex-direction: column; text-align: center; gap: 18px; }
  .footer-brand { align-items: center; }
  .footer-credit { text-align: center; }
}

@media (max-width: 560px) {
  body { font-size: 16px; }
  .brand img { width: 74px; }
  .site-header { padding: 12px var(--pad); }
  .site-header nav a:not(.nav-cta) { display: none; }
  /* The pill was reading as an oversized button on a phone. It is a nav
     item, not the page's primary action. */
  .nav-cta { padding: 7px 15px; font-size: 12.5px; }
  .spec-table { font-size: 0.66rem; }
  .spec-label { font-size: 0.72rem; }
  /* Two columns of feature copy get too narrow to read on a phone. */
  .inside-col { grid-template-columns: 1fr; }
  .inside-item p { max-width: 34ch; }
}

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .js-ready [data-fade] { opacity: 1; }
  .scroll-progress { display: none; }
  .scroll-cue-text,
  .scroll-cue-arrow { animation: none; opacity: .9; }
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
  .model:hover,
  .model--featured,
  .model--featured:hover { transform: none; }
}
