/* ==========================================================================
   DIATONICA PREMIUM CASE-STUDY COMPONENT SYSTEM
   --------------------------------------------------------------------------
   A self-contained component library for scroll-storytelling case studies
   (Apple / Aman / Aesop style). Built once for Thermana Savna 2026, meant to
   be copy-pasted wholesale into the next case study — only tokens.css and
   the content inside each component need to change.

   Components in this file:
     1. Buttons        (.c-btn)
     2. Header          (.c-header)
     3. Hero            (.c-hero)
     4. Statement       (.c-statement)
     5. Showcase        (.c-showcase)        — single/large image storytelling
     6. Mockup Grid     (.c-mockup-grid)     — outdoor / digital ecosystem
     7. Video Section   (.c-video-section)
     8. Quote Block     (.c-quote)
     9. Gallery         (.c-gallery)         — detail closeups
     10. CTA            (.c-cta)             — closing section
     11. Footer         (.c-footer)
     12. Phone Mockup   (.c-phone)           — portrait video/image in a device frame
     13. Cursor         (.c-cursor)          — custom pointer
     14. Back to top    (.c-totop)
     15. Cinematic      (.c-cinematic)       — second scroll-scrubbed video chapter
     16. Horizontal Gallery (.c-hgallery)    — pinned sideways-scroll reel
     17. Timeline       (.c-timeline)        — vertical process/milestone list
     18. Signature      (.c-signature)       — closing credit block before the footer
     19. Void            (.c-void)           — cinematic black pause before the signature
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. BUTTON
   -------------------------------------------------------------------------- */
.c-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 1.1em 2.75em;
  font-family: var(--font-display);
  font-size: var(--size-label);
  font-weight: 500;
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--color-ink);
  border: 1px solid var(--color-line-strong);
  overflow: hidden;
  cursor: pointer;
  background: transparent;
  transition: color var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}

.c-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--color-accent);
  transform: translateX(-101%);
  transition: transform var(--dur-base) var(--ease-in-out);
  z-index: -1;
}

.c-btn:hover,
.c-btn:focus-visible {
  color: var(--color-bg);
  border-color: var(--color-accent);
}

.c-btn:hover::before,
.c-btn:focus-visible::before { transform: translateX(0); }

/* --------------------------------------------------------------------------
   2. HEADER
   -------------------------------------------------------------------------- */
.c-header {
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-xs) var(--container-pad);
  mix-blend-mode: normal;
  transition: background var(--dur-base) var(--ease-out), padding var(--dur-base) var(--ease-out);
}

.c-header.is-scrolled {
  padding-block: var(--space-3xs) calc(var(--space-3xs) + 0.5rem);
}

/* Wash sits on its own taller pseudo-element instead of the nav bar's own
   (much shorter) box, so the fade reads as ambient light falling off over
   the page rather than being clipped to the nav row's height. */
.c-header.is-scrolled::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 200px;
  background: linear-gradient(180deg, rgba(14, 17, 18, 0.55) 0%, rgba(14, 17, 18, 0.3) 45%, rgba(14, 17, 18, 0) 100%);
  backdrop-filter: blur(8px);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 55%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 55%, transparent 100%);
  z-index: -1;
  pointer-events: none;
}

.c-header__logo { display: flex; align-items: center; }
.c-header__logo img { height: clamp(34px, 3.6vw, 42px); width: auto; }

.c-header__nav {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.c-header__link {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  letter-spacing: var(--tracking-normal);
  color: var(--color-ink);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
  transition: color var(--dur-fast) var(--ease-out);
}

.c-header__link:hover { color: var(--color-accent); }

@media (max-width: 640px) {
  .c-header__nav { gap: var(--space-sm); }
  .c-header__nav .c-btn { display: none; }
}

/* --------------------------------------------------------------------------
   3. HERO — fullscreen media + headline + scroll cue
   -------------------------------------------------------------------------- */
.c-hero {
  position: relative;
  height: 100svh;
  min-height: 560px;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--color-bg);
}

/* Short viewports (phones in landscape) — 100svh isn't tall enough for
   title + lead + scroll cue at full size; they were clipping below the
   fold. Tighten everything to fit. */
@media (max-height: 500px) {
  .c-hero { min-height: 380px; align-items: center; }
  .c-hero__content { padding-bottom: var(--space-sm); }
  .c-hero__title { font-size: clamp(1.75rem, 4vw + 1rem, 3rem); }
  .c-hero__lead { display: none; }
  /* !important: the base .c-hero__scroll rule (display:flex) is declared
     later in this file at equal specificity and would otherwise win. */
  .c-hero__scroll { display: none !important; }
}

.c-hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.c-hero__media img,
.c-hero__media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Touch/tablet only (see main.js): the Hero video is swapped for its own
   poster frame plus a slow CSS-only zoom — video inside a GSAP-pinned
   (position:fixed) element was reported to simply not paint on real iOS
   Safari (a known WebKit quirk: video/poster failing to render inside a
   fixed + transform ancestor before playback starts), showing as "just
   text on a black background". A static image can't have that problem,
   and the animation needs no scroll/GSAP involvement at all. Plays once
   and holds at the zoomed-in frame (`forwards`) rather than looping back
   — the Hero is typically seen only briefly before scrolling on. */
.c-hero__media img.c-hero__kenburns {
  transform-origin: 54% 46%;
  animation: heroKenBurns 22s ease-out forwards;
}
@keyframes heroKenBurns {
  0% { transform: scale(1); }
  100% { transform: scale(1.12); }
}
@media (prefers-reduced-motion: reduce) {
  .c-hero__media img.c-hero__kenburns { animation: none; }
}

/* Stronger + faster Ken Burns for the small in-flow showcase images than
   the Hero's (which is deliberately gentle for a fullscreen section). On a
   small card a 1.12/22s zoom was near-imperceptible; these are 10s so the
   motion actually reads within a few seconds. Two intensities: --gentle
   (1.10) only for photo-sauna-candid, whose two figures sit right at the
   frame edges and get clipped past ~1.10; everything else zooms to 1.16. */
@keyframes kbShowcase {
  0% { transform: scale(1); }
  100% { transform: scale(1.16); }
}
@keyframes kbShowcaseGentle {
  0% { transform: scale(1); }
  100% { transform: scale(1.10); }
}

/* PHONE-ONLY static showcase — stands in for a second scroll-scrub video
   moment (Statement→gallery, Motion→Quote) that would otherwise be empty
   pacing on a phone once the actual pinned video sections are swapped out
   (see .c-hero__kenburns above and main.js). Hidden by default; only the
   phone media query below switches it on, so tablet + desktop never see
   it — phone = "(pointer: coarse) and (max-width: 767px)", matching the
   isPhone check in main.js. (Unrelated to which devices keep Motion's own
   pinned scroll-scrub — see the isPhone/isTablet comment at the top of
   main.js for that split; this showcase strip is a separate, purely
   decorative addition that was never shown on tablet either way.)
   16:9 frame — these are wide architectural shots; a taller frame would
   crop their sides heavily. Verified (ffmpeg crop sim) that even at the
   Ken Burns peak zoom (1.12) nothing important leaves the 16:9 center
   frame, including the two figures at the edges of photo-sauna-candid.
   The zoom is paused until the frame scrolls into view (main.js adds
   .is-animating) — otherwise the 22s animation, starting at page load,
   would finish long before a visitor scrolls down this far and they'd
   only ever see the static end frame. */
.c-mobile-showcase { display: none; }
/* Phone-sized touch viewport, EITHER orientation: portrait (<=767px wide)
   OR landscape phone (<=500px tall). The height clause matches the isPhone
   definition in main.js so a sideways phone — which swaps out the pinned
   scroll-scrub moments just like portrait — also shows this decorative
   stand-in strip instead of leaving that pacing gap empty. Real tablets are
   >=768px tall in landscape, so they never match and never see it. */
@media (pointer: coarse) and (max-width: 767px),
       (pointer: coarse) and (max-height: 500px) {
  .c-mobile-showcase {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    padding-inline: var(--container-pad);
    margin-block: var(--space-lg);
  }
  .c-mobile-showcase__frame {
    position: relative;
    overflow: hidden;
    aspect-ratio: 16 / 9;
    background: var(--color-bg-raised);
  }
  .c-mobile-showcase__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    animation: kbShowcase 10s ease-out forwards;
    animation-play-state: paused;
  }
  .c-mobile-showcase__img--gentle { animation-name: kbShowcaseGentle; }
  .c-mobile-showcase__img.is-animating { animation-play-state: running; }
  @media (prefers-reduced-motion: reduce) {
    .c-mobile-showcase__img { animation: none; }
  }
}

.c-hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(14,17,18,0.15) 0%, rgba(14,17,18,0.25) 55%, rgba(14,17,18,0.92) 100%);
}

.c-hero__content {
  position: relative;
  z-index: 1;
  width: 100%;
  padding: 0 var(--container-pad) var(--space-xl);
}

/* Gold-on-warm-wood is illegible wherever the scrub lands on a light frame
   — unlike flat-background eyebrows elsewhere, this one sits over a moving
   video, so it needs its own guaranteed-contrast treatment. Bigger + lighter
   gold + heavier shadow than the base .u-eyebrow, which is tuned for flat
   backgrounds instead. */
.c-hero__eyebrow {
  margin-bottom: var(--space-sm);
  font-size: 1.0625rem;
  letter-spacing: var(--tracking-wide);
  color: var(--color-accent-soft);
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.95)) drop-shadow(0 3px 14px rgba(0, 0, 0, 0.7));
}

.c-hero__eyebrow::before { height: 2px; }

/* Brand wordmark line between the case-number eyebrow and the headline. */
.c-hero__brand {
  font-family: var(--font-display);
  font-size: var(--size-h3);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-accent-soft);
  margin-bottom: var(--space-2xs);
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.85));
}

.c-hero__title {
  font-family: var(--font-display);
  font-size: var(--size-hero);
  font-weight: 700;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  max-width: 34ch;
}

.c-hero__lead {
  margin-top: var(--space-sm);
  max-width: 42ch;
  font-size: var(--size-lead);
  color: var(--color-ink-dim);
}

/* Scroll cue — chevron that "draws" a line on hover + flip-up label,
   matching diatonica.si's .scroll-btn interaction exactly. */
.c-hero__scroll {
  position: absolute;
  left: 50%;
  bottom: var(--space-md);
  transform: translateX(-50%);
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2xs);
  height: 60px;
}

.c-hero__scroll-arrow {
  position: relative;
  width: 20px;
  height: 30px;
}

.c-hero__scroll-arrow::before {
  content: "";
  width: 14px;
  height: 14px;
  border-right: 2px solid var(--color-ink);
  border-bottom: 2px solid var(--color-ink);
  position: absolute;
  top: 0;
  left: 3px;
  transform: rotate(45deg);
  transition: border-color var(--dur-base) var(--ease-out);
}

.c-hero__scroll-arrow::after {
  content: "";
  width: 2px;
  height: 100%;
  background: var(--color-accent);
  position: absolute;
  bottom: 0;
  left: 9px;
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 1s var(--ease-out);
}

.c-hero__scroll:hover .c-hero__scroll-arrow::before { border-color: var(--color-accent); }
.c-hero__scroll:hover .c-hero__scroll-arrow::after { transform: scaleY(1); }

.c-hero__scroll-label {
  position: relative;
  display: block;
  overflow: hidden;
  height: 1.2em;
  /* Body sets line-height:1.75 — inherited into this label's ::before/
     ::after text, it made the glyph box taller than the 1.2em container
     with overflow:hidden, clipping the bottom of the letters. Match the
     line-height to the container height instead of inheriting it. */
  line-height: 1.2;
  color: transparent;
  font-family: var(--font-display);
  font-size: var(--size-label);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
}

.c-hero__scroll-label::before,
.c-hero__scroll-label::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  transition: transform var(--dur-base) var(--ease-in-out);
}
.c-hero__scroll-label::before { color: var(--color-ink-dim); transform: translateY(0); }
.c-hero__scroll-label::after { color: var(--color-accent); transform: translateY(-170%); }
.c-hero__scroll:hover .c-hero__scroll-label::before { transform: translateY(150%); }
.c-hero__scroll:hover .c-hero__scroll-label::after { transform: translateY(0); }

@keyframes scrollBounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(6px); }
}

.c-hero__scroll-arrow { animation: scrollBounce 2.2s var(--ease-in-out) infinite; }

@media (prefers-reduced-motion: reduce) {
  .c-hero__scroll-arrow { animation: none; }
}

/* --------------------------------------------------------------------------
   4. STATEMENT — single large-type moment
   -------------------------------------------------------------------------- */
.c-statement {
  padding-block: var(--space-section);
  display: flex;
  justify-content: center;
}

.c-statement__text {
  max-width: 18ch;
  text-align: center;
  font-family: var(--font-display);
  font-size: var(--size-h1);
  font-weight: 600;
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  color: var(--color-ink);
}

.c-statement__text em {
  font-style: normal;
  color: var(--color-accent);
}

/* --------------------------------------------------------------------------
   5. SHOWCASE — large storytelling imagery, full or split layout
   -------------------------------------------------------------------------- */
.c-showcase { padding-block: var(--space-section); }

.c-showcase__head {
  padding-inline: var(--container-pad);
  max-width: var(--container-max);
  margin-inline: auto;
  margin-bottom: var(--space-lg);
}

.c-showcase__title {
  margin-top: var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--size-h2);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  max-width: 16ch;
}

.c-showcase__frame {
  position: relative;
  width: 100%;
  overflow: hidden;
  aspect-ratio: 16 / 9;
}

.c-showcase__frame--tall { aspect-ratio: 4 / 5; }
.c-showcase__frame--wide { aspect-ratio: 21 / 9; }

.c-showcase__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.08);
  will-change: transform;
}

/* Floating detail collage — a cutout PNG (real alpha transparency, no
   rectangular frame) that overlaps the seam between two neighbouring
   sections via negative margins, drop-shadowed like a physical object
   set on the page rather than boxed into its own panel. */
.c-floating-detail {
  position: relative;
  z-index: 3;
  max-width: min(900px, 46vw);
  margin: clamp(-100px, -14vw, -260px) auto clamp(-120px, -16vw, -300px);
  padding-inline: var(--container-pad);
  pointer-events: none;
  text-align: center;
}

.c-floating-detail__label {
  justify-content: center;
  margin-bottom: var(--space-sm);
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.7));
}

.c-floating-detail__img {
  width: 100%;
  height: auto;
  /* Explicit, not left to the width/height HTML attributes: this image
     has no `src` at all until lazy-loaded (data-src, see main.js
     lazyObserver) near scroll-in. Chromium derives a default aspect-ratio
     from the width/height attributes even with no src and reserves the
     correct ~400px box from first paint; WebKit does not — confirmed via
     Playwright WebKit that its computed height collapses to ~19px until
     the image actually loads, growing ~380px right under the Motion pin
     (#motion) below it, well after ScrollTrigger's page-load refresh
     passes have already cached that pin's start — main.js never
     re-measures afterward, leaving Motion's pin ~380px off through the
     rest of the page (measured: never self-corrects, confirmed idle 6s+).
     An authored aspect-ratio reserves the box immediately in every
     engine, independent of image load state entirely, so no JS refresh
     timing fix is needed. */
  aspect-ratio: 1447 / 1007;
  filter: drop-shadow(0 45px 70px rgba(0, 0, 0, 0.6)) drop-shadow(0 10px 22px rgba(0, 0, 0, 0.45));
}

/* Slower, longer travel than the base .r-slide-left (used elsewhere for
   the phone) — this piece is meant to drift in deliberately, not just
   slide the same amount everything else does. */
html.is-ready .c-floating-detail__img.r-slide-left {
  transform: translateX(-9rem);
  transition: opacity 1.6s var(--ease-out), transform 1.6s var(--ease-out);
}
html.is-ready .c-floating-detail__img.r-slide-left.in-view { transform: none; }

@media (max-width: 640px) {
  .c-floating-detail { max-width: 320px; margin: -90px auto -110px; }
}

.c-showcase__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-sm);
  padding-inline: var(--container-pad);
  max-width: var(--container-max);
  margin-inline: auto;
}

.c-showcase__grid + .c-showcase__grid { margin-top: var(--space-sm); }

.c-showcase__grid .c-showcase__frame:first-child { grid-column: span 7; }
.c-showcase__grid .c-showcase__frame:last-child { grid-column: span 5; }

@media (max-width: 860px) {
  .c-showcase__grid { grid-template-columns: 1fr; }
  .c-showcase__grid .c-showcase__frame { grid-column: auto !important; }
}

/* --------------------------------------------------------------------------
   6. MOCKUP GRID — outdoor / digital ecosystem presentation cards
   -------------------------------------------------------------------------- */
.c-mockup-grid { padding-block: var(--space-section); }

.c-mockup-grid__head {
  padding-inline: var(--container-pad);
  max-width: var(--container-max);
  margin-inline: auto;
  margin-bottom: var(--space-lg);
}

.c-mockup-grid__title {
  margin-top: var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--size-h2);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  max-width: 18ch;
}

.c-mockup-grid__list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-md);
  padding-inline: var(--container-pad);
  max-width: var(--container-max);
  margin-inline: auto;
  perspective: 1600px;
}

@media (max-width: 960px) {
  .c-mockup-grid__list { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .c-mockup-grid__list { grid-template-columns: 1fr; }
}

/* Bento variant — Digital Ecosystem: asymmetric, aspect-ratio matched to
   each artifact so nothing gets cropped into an awkward shape. */
.c-mockup-grid__list--bento {
  grid-template-columns: repeat(12, 1fr);
}

.c-mockup-grid__list--bento .c-mockup-card:nth-child(1) { grid-column: span 7; }
.c-mockup-grid__list--bento .c-mockup-card:nth-child(1) .c-mockup-card__frame { aspect-ratio: 3 / 2; }

.c-mockup-grid__list--bento .c-mockup-card:nth-child(2) { grid-column: span 5; }
.c-mockup-grid__list--bento .c-mockup-card:nth-child(2) .c-mockup-card__frame { aspect-ratio: 4 / 3; }

.c-mockup-grid__list--bento .c-mockup-card:nth-child(3) { grid-column: span 7; }
.c-mockup-grid__list--bento .c-mockup-card:nth-child(3) .c-mockup-card__frame { aspect-ratio: 16 / 9; }

.c-mockup-grid__list--bento .c-mockup-card:nth-child(4) { grid-column: span 5; }
.c-mockup-grid__list--bento .c-mockup-card:nth-child(4) .c-mockup-card__frame { aspect-ratio: 3 / 4; }

/* Single-column (phones + portrait tablets): keep each card's aspect ratio
   matched to its source image instead of forcing a blanket 4/3, which
   cropped the wide/tall socials artifacts badly — the 16:9 key visual lost
   its "Ustvarjamo nove savne" wordmark + Thermana logo off the sides, and
   the 4:5 story-format image lost its top (2026) and bottom (thermana.si)
   to a landscape crop. Ratios: WEB 3:2, INSTAGRAM 4:3, KEY VISUAL 16:9,
   STORY 4:5 (the story image is 1100x1375 ≈ 4:5, a truer fit than the
   desktop bento's 3:4). Same selector specificity as the desktop per-card
   rules above, declared later, so these win below 860px without !important. */
@media (max-width: 860px) {
  .c-mockup-grid__list--bento { grid-template-columns: 1fr; }
  .c-mockup-grid__list--bento .c-mockup-card { grid-column: auto !important; }
  .c-mockup-grid__list--bento .c-mockup-card:nth-child(1) .c-mockup-card__frame { aspect-ratio: 3 / 2; }
  .c-mockup-grid__list--bento .c-mockup-card:nth-child(2) .c-mockup-card__frame { aspect-ratio: 4 / 3; }
  .c-mockup-grid__list--bento .c-mockup-card:nth-child(3) .c-mockup-card__frame { aspect-ratio: 16 / 9; }
  .c-mockup-grid__list--bento .c-mockup-card:nth-child(4) .c-mockup-card__frame { aspect-ratio: 4 / 5; }
}

/* Details variant — same tilt/zoom/caption card, aspect ratios matched to
   the two portrait + two landscape detail photos instead of the mockup
   set (draft alternative to the plain .c-gallery treatment above it). */
.c-mockup-grid__list--details {
  grid-template-columns: repeat(12, 1fr);
  row-gap: var(--space-lg);
}
.c-mockup-grid__list--details .c-mockup-card:nth-child(1) { grid-column: span 7; }
.c-mockup-grid__list--details .c-mockup-card:nth-child(1) .c-mockup-card__frame { aspect-ratio: 3 / 4; }

.c-mockup-grid__list--details .c-mockup-card:nth-child(2) { grid-column: span 5; align-self: end; }
.c-mockup-grid__list--details .c-mockup-card:nth-child(2) .c-mockup-card__frame { aspect-ratio: 1 / 1; }

.c-mockup-grid__list--details .c-mockup-card:nth-child(3) { grid-column: span 5; }
.c-mockup-grid__list--details .c-mockup-card:nth-child(3) .c-mockup-card__frame { aspect-ratio: 3 / 4; }

.c-mockup-grid__list--details .c-mockup-card:nth-child(4) { grid-column: span 7; align-self: end; }
.c-mockup-grid__list--details .c-mockup-card:nth-child(4) .c-mockup-card__frame { aspect-ratio: 5 / 3; }

@media (max-width: 860px) {
  .c-mockup-grid__list--details { grid-template-columns: 1fr 1fr; gap: var(--space-xs); }
  .c-mockup-grid__list--details .c-mockup-card { grid-column: span 1 !important; align-self: auto !important; }
  .c-mockup-grid__list--details .c-mockup-card__frame { aspect-ratio: 3 / 4 !important; }
  .c-mockup-grid__list--details .c-mockup-card:nth-child(4) { grid-column: span 2 !important; }
  .c-mockup-grid__list--details .c-mockup-card:nth-child(4) .c-mockup-card__frame { aspect-ratio: 5 / 3 !important; }
}

.c-mockup-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  transform-style: preserve-3d;
  transition: transform var(--dur-fast) var(--ease-out);
}

.c-mockup-card__frame {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  background: var(--color-bg-raised);
  box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0);
  transition: box-shadow var(--dur-base) var(--ease-out);
}

.c-mockup-card__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}

.c-mockup-card:hover .c-mockup-card__frame img { transform: scale(1.06); }
.c-mockup-card:hover .c-mockup-card__frame { box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.55); }

.c-mockup-card__caption {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-display);
  font-size: var(--size-small);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-ink-dim);
}

.c-mockup-card__caption span:last-child { color: var(--color-accent); }

@media (prefers-reduced-motion: reduce) {
  .c-mockup-card { transform: none !important; }
}

/* --------------------------------------------------------------------------
   7. VIDEO SECTION
   -------------------------------------------------------------------------- */
.c-video-section {
  padding-block: var(--space-section);
}

.c-video-section__head {
  padding-inline: var(--container-pad);
  max-width: var(--container-max);
  margin-inline: auto;
  margin-bottom: var(--space-lg);
}

.c-video-section__title {
  margin-top: var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--size-h2);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  max-width: 24ch;
}

.c-video-section__gallery { margin-top: var(--space-lg); }

.c-video {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #000;
  cursor: pointer;
}

.c-video video,
.c-video img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.c-video__poster { transition: opacity var(--dur-base) var(--ease-out); }
.c-video.is-playing .c-video__poster { opacity: 0; pointer-events: none; }

.c-video__play {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: clamp(64px, 8vw, 92px);
  height: clamp(64px, 8vw, 92px);
  border-radius: 50%;
  border: 1px solid rgba(245, 244, 242, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(14, 17, 18, 0.35);
  backdrop-filter: blur(4px);
  transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-base) var(--ease-out), background var(--dur-fast) var(--ease-out);
}

.c-video__play svg { width: 22px; height: 22px; fill: var(--color-ink); margin-left: 3px; }

.c-video:hover .c-video__play { background: var(--color-accent); transform: translate(-50%, -50%) scale(1.06); }
.c-video.is-playing .c-video__play { opacity: 0; pointer-events: none; }

/* --------------------------------------------------------------------------
   8. QUOTE BLOCK
   -------------------------------------------------------------------------- */
.c-quote {
  padding-block: var(--space-section);
  padding-inline: var(--container-pad);
  display: flex;
  justify-content: center;
}

.c-quote__inner { max-width: 52ch; text-align: center; }

.c-quote__mark {
  font-family: var(--font-display);
  font-size: 4rem;
  line-height: 1;
  color: var(--color-accent);
  margin-bottom: var(--space-xs);
}

.c-quote__text {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--size-h3);
  line-height: var(--leading-snug);
  color: var(--color-ink);
}

.c-quote__cite {
  display: block;
  margin-top: var(--space-md);
  font-family: var(--font-display);
  font-size: var(--size-label);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-ink-dim);
}

/* --------------------------------------------------------------------------
   9. GALLERY — detail closeups
   -------------------------------------------------------------------------- */
.c-gallery { padding-block: var(--space-section); }

.c-gallery__head {
  padding-inline: var(--container-pad);
  max-width: var(--container-max);
  margin-inline: auto;
  margin-bottom: var(--space-lg);
}

.c-gallery__title {
  margin-top: var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--size-h2);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  max-width: 18ch;
}

.c-gallery__list {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--space-sm);
  padding-inline: var(--container-pad);
  max-width: var(--container-max);
  margin-inline: auto;
}

.c-gallery__item { position: relative; overflow: hidden; aspect-ratio: 3 / 4; }
.c-gallery__item img { width: 100%; height: 100%; object-fit: cover; }

.c-gallery__item:nth-child(1) { grid-column: span 7; }
.c-gallery__item:nth-child(2) { grid-column: span 5; aspect-ratio: 1/1; align-self: end; }
.c-gallery__item:nth-child(3) { grid-column: span 5; }
.c-gallery__item:nth-child(4) { grid-column: span 7; aspect-ratio: 5 / 3; align-self: end; }

@media (max-width: 860px) {
  .c-gallery__list { grid-template-columns: 1fr 1fr; gap: var(--space-xs); }
  .c-gallery__item { grid-column: span 1 !important; aspect-ratio: 3/4 !important; align-self: auto !important; }
  .c-gallery__item:nth-child(4) { grid-column: span 2 !important; aspect-ratio: 5/3 !important; }
}

/* --------------------------------------------------------------------------
   10. CTA — closing section
   -------------------------------------------------------------------------- */
.c-cta {
  position: relative;
  min-height: 90svh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  overflow: hidden;
}

.c-cta__media { position: absolute; inset: 0; z-index: 0; }
.c-cta__media img { width: 100%; height: 100%; object-fit: cover; }
.c-cta__media::after { content: ""; position: absolute; inset: 0; background: var(--color-overlay-strong); }

.c-cta__content { position: relative; z-index: 1; padding: var(--space-xl) var(--container-pad); }

.c-cta__title {
  font-family: var(--font-display);
  font-size: var(--size-h1);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  max-width: 18ch;
  margin-inline: auto;
}

.c-cta__lead {
  margin: var(--space-sm) auto var(--space-lg);
  max-width: 40ch;
  color: var(--color-ink-dim);
  font-size: var(--size-lead);
}

/* --------------------------------------------------------------------------
   11. FOOTER — mirrors diatonica.si's real footer (logo / nav / contact /
   social / copyright) so a case-study page reads as part of the same site.
   -------------------------------------------------------------------------- */
.c-footer {
  padding: var(--space-xl) var(--container-pad) var(--space-lg);
  border-top: 1px solid var(--color-line);
  font-family: var(--font-display);
  font-size: 0.8625rem; /* --size-label +15% */
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-ink-dim);
}

.c-footer__grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1.3fr 1fr;
  gap: var(--space-lg);
  max-width: var(--container-max);
  margin-inline: auto;
  padding-bottom: var(--space-lg);
}

.c-footer__logo img { height: 42px; width: auto; }

.c-footer__nav { display: flex; flex-direction: column; gap: var(--space-2xs); }
.c-footer__nav a { color: var(--color-ink-dim); transition: color var(--dur-fast) var(--ease-out); }
.c-footer__nav a:hover,
.c-footer__nav a[aria-current="page"] { color: var(--color-accent); }

.c-footer__contact { display: flex; flex-direction: column; gap: var(--space-2xs); list-style: none; margin: 0; padding: 0; }
.c-footer__contact a { color: var(--color-ink-dim); text-transform: none; letter-spacing: var(--tracking-normal); font-family: var(--font-body); font-size: 0.935rem; transition: color var(--dur-fast) var(--ease-out); }
.c-footer__contact a:hover { color: var(--color-accent); }

.c-footer__social { display: flex; flex-direction: column; gap: var(--space-2xs); align-items: flex-start; }

.c-footer__flip {
  position: relative;
  display: inline-block;
  overflow: hidden;
  height: 1.4em;
  line-height: 1.4em;
  transition: transform var(--dur-base) var(--ease-in-out);
}

.c-footer__flip::after {
  content: attr(data-text);
  position: absolute;
  left: 0;
  top: 100%;
  color: var(--color-accent);
}

.c-footer__flip:hover { transform: translateY(-100%); }

.c-footer__bottom {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-top: var(--space-lg);
  border-top: 1px solid var(--color-line);
  color: var(--color-ink-faint);
  text-align: center; /* matches diatonica.si's .footer-copyright */
}

@media (max-width: 860px) {
  .c-footer__grid { grid-template-columns: 1fr 1fr; row-gap: var(--space-lg); }
}
@media (max-width: 480px) {
  .c-footer__grid { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   12. PHONE MOCKUP — portrait video/image presented as if viewed on a phone
   -------------------------------------------------------------------------- */
.c-phone-stage {
  display: flex;
  justify-content: center;
  padding-block: var(--space-md);
}

/* Split variant: phone on one side, editorial copy on the other. Used in
   Details so the bigger phone still has room to breathe next to text. */
.c-phone-stage--split {
  display: grid;
  grid-template-columns: 1fr 1.1fr;
  align-items: center;
  gap: var(--space-xl);
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-pad);
  text-align: left;
}

.c-phone-stage--split .c-phone { margin-inline: auto; }

.c-phone-stage__body .u-eyebrow { margin-bottom: var(--space-sm); }

.c-phone-stage__title {
  font-family: var(--font-display);
  font-size: var(--size-h2);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  margin-bottom: var(--space-sm);
}

.c-phone-stage__text { color: var(--color-ink-dim); font-size: var(--size-lead); max-width: 42ch; }

@media (max-width: 860px) {
  .c-phone-stage--split { grid-template-columns: 1fr; text-align: center; gap: var(--space-lg); }
  .c-phone-stage__text { margin-inline: auto; }
}

/* iPhone 16 Pro Max proportions — screen ratio 1290:2796 (~9:19.5), very
   thin uniform bezel, big continuous corner radius, floating Dynamic
   Island instead of a bezel-attached notch, small side buttons for
   silhouette recognition. */
.c-phone {
  position: relative;
  width: clamp(260px, 26vw, 380px);
  aspect-ratio: 1290 / 2796;
  background: #0b0c0d;
  border-radius: clamp(46px, 4.6vw, 68px);
  padding: 5px;
  box-shadow: 0 50px 90px -30px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(245, 244, 242, 0.08);
  cursor: pointer;
}

.c-phone::before,
.c-phone::after {
  content: "";
  position: absolute;
  background: #1c1d1e;
}

/* Right-edge power button */
.c-phone::before {
  right: -2px;
  top: 21%;
  width: 3px;
  height: 9%;
  border-radius: 2px 0 0 2px;
}

/* Left-edge action + volume button */
.c-phone::after {
  left: -2px;
  top: 16%;
  width: 3px;
  height: 6%;
  border-radius: 0 2px 2px 0;
  box-shadow: 0 8.5vw 0 -1px #1c1d1e, 0 12.5vw 0 -1px #1c1d1e;
}

.c-phone__screen {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: clamp(42px, 4.2vw, 62px);
  overflow: hidden;
  background: #000;
}

.c-phone__screen video,
.c-phone__screen img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.c-phone__notch {
  position: absolute;
  top: 3.4%;
  left: 50%;
  transform: translateX(-50%);
  width: 28%;
  height: 3.6%;
  min-height: 20px;
  background: #050607;
  border-radius: 999px;
  z-index: 2;
}

.c-phone__poster { transition: opacity var(--dur-base) var(--ease-out); }
.c-phone.is-playing .c-phone__poster { opacity: 0; }

/* --------------------------------------------------------------------------
   13. CURSOR — custom pointer, replaces the system cursor on desktop.
   Base dot in accent gold; grows on .pointer-large / .pointer-small targets.
   -------------------------------------------------------------------------- */
html.has-custom-cursor,
html.has-custom-cursor a,
html.has-custom-cursor button {
  cursor: none;
}

.c-cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-accent);
  pointer-events: none;
  z-index: 9999;
  transform: translate(-50%, -50%);
  transition: width 0.5s cubic-bezier(0.2, 0.96, 0.34, 1), height 0.5s cubic-bezier(0.2, 0.96, 0.34, 1),
    background 0.5s cubic-bezier(0.2, 0.96, 0.34, 1), opacity 0.3s var(--ease-out);
}

.c-cursor.is-out { opacity: 0; }

.c-cursor.is-large {
  width: 64px;
  height: 64px;
  background: rgba(177, 146, 111, 0.12);
  box-shadow: 0 0 30px rgba(177, 146, 111, 0.55);
}

.c-cursor.is-small {
  width: 26px;
  height: 26px;
  background: rgba(177, 146, 111, 0);
  box-shadow: 0 0 24px rgba(177, 146, 111, 0.9);
}

/* --------------------------------------------------------------------------
   14. BACK TO TOP — mirrors diatonica.si's .to-top-btn: chevron that
   "draws" itself on hover, fades in once the reader has scrolled down.
   -------------------------------------------------------------------------- */
.c-totop {
  position: fixed;
  bottom: 40px;
  right: 40px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--color-line);
  background: rgba(14, 17, 18, 0.6);
  backdrop-filter: blur(6px);
  z-index: var(--z-overlay);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.c-totop.is-visible { opacity: 1; visibility: visible; transform: translateY(0); }
.c-totop:hover { border-color: var(--color-accent); }

.c-totop__arrow {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 10px;
  height: 20px;
  transform: translate(-50%, -40%);
}

.c-totop__arrow::before {
  content: "";
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--color-ink-dim);
  border-top: 2px solid var(--color-ink-dim);
  position: absolute;
  top: 2px;
  left: 50%;
  transform: translateX(-50%) rotate(-45deg);
  transition: border-color var(--dur-base) var(--ease-out);
}

.c-totop__arrow::after {
  content: "";
  position: absolute;
  height: 100%;
  width: 2px;
  top: 0;
  left: 50%;
  transform: scaleY(0) translateX(-50%);
  transform-origin: top;
  background: var(--color-accent);
  transition: transform var(--dur-base) var(--ease-out);
}

.c-totop:hover .c-totop__arrow::before { border-color: var(--color-accent); }

.c-totop:hover .c-totop__arrow::after { transform: scaleY(1) translateX(-50%); }

@media (max-width: 640px) {
  .c-totop { bottom: 20px; right: 20px; width: 38px; height: 38px; }
}

/* --------------------------------------------------------------------------
   15. CINEMATIC — second scroll-scrubbed video chapter, mid-page. Shares
   the hero's pin/scrub JS (main.js wireCinematicScrub) but reads as its
   own moment: centered copy instead of hero's bottom-left composition.
   -------------------------------------------------------------------------- */
.c-cinematic {
  position: relative;
  height: 100svh;
  min-height: 560px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  overflow: hidden;
  background: var(--color-bg);
  text-align: center;
  /* Forces its own GPU compositing layer for the GSAP pin (see
     wireCinematicScrub's pinType: "transform" in main.js) — without it,
     Safari was seen repainting this section on every scrub tick instead of
     just re-compositing a layer, which is what read as skip/jank there
     while Chrome (which layer-promotes more aggressively on its own)
     stayed smooth for the identical scroll input. */
  will-change: transform;
}

.c-cinematic__media { position: absolute; inset: 0; z-index: 0; }
.c-cinematic__media video,
.c-cinematic__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Own compositing layer for the video/poster itself — same Safari
     rationale as .c-cinematic above; the currentTime-driven video decode
     is the actual per-frame work, so it benefits most directly. */
  transform: translateZ(0);
}

/* Touch/tablet only (see main.js) — same swap and same reasoning as
   .c-hero__kenburns: video inside a GSAP-pinned element risked never
   painting on real iOS Safari. */
.c-cinematic__media img.c-cinematic__kenburns {
  animation: heroKenBurns 22s ease-out forwards;
}
@media (prefers-reduced-motion: reduce) {
  .c-cinematic__media img.c-cinematic__kenburns { animation: none; }
}
/* Copy sits bottom-center now (see .c-cinematic__content) — a soft, low
   gradient just keeps the very bottom edge from ever going pure white,
   not a hard black wash (a flat dark panel there read as the section
   "ending in black" once the scrub reached the tail of the clip). */
.c-cinematic__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(14,17,18,0.05) 0%, rgba(14,17,18,0.08) 45%, rgba(14,17,18,0.35) 100%);
}

/* Frosted scrim behind just the copy, instead of darkening the whole
   frame — legible over any busy footage without ever reading as "the
   video went black". */
.c-cinematic__scrim {
  position: absolute;
  inset: auto 0 0 0;
  height: 46%;
  backdrop-filter: blur(10px) saturate(1.1);
  -webkit-backdrop-filter: blur(10px) saturate(1.1);
  will-change: backdrop-filter;
  background: linear-gradient(180deg, rgba(14, 17, 18, 0) 0%, rgba(14, 17, 18, 0.4) 100%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 35%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 35%);
}

.c-cinematic__content { position: relative; z-index: 1; width: 100%; padding: 0 var(--container-pad) var(--space-xl); }
.c-cinematic__content .u-eyebrow { justify-content: center; margin-bottom: var(--space-sm); }

.c-cinematic__title {
  font-family: var(--font-display);
  font-size: var(--size-h1);
  font-weight: 700;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  max-width: 18ch;
  margin-inline: auto;
}

.c-cinematic__lead {
  margin: var(--space-sm) auto 0;
  max-width: 42ch;
  font-size: var(--size-lead);
  color: var(--color-ink);
}

/* --------------------------------------------------------------------------
   16. HORIZONTAL GALLERY — pinned section, cards translate sideways as
   the reader scrolls down. Falls back to a native horizontal scroll strip
   when JS/pointer:fine isn't available (see page.css touch fallback).
   -------------------------------------------------------------------------- */
.c-hgallery {
  position: relative;
  /* x stays hidden — required so the horizontally-sliding track (cards
     translated via transform: translateX() in main.js) doesn't show cards
     queued off to the right. y is NOT hidden: the July 12 fix (see git
     history — vertical centering via height:100svh + flex) assumes
     content always fits within one viewport, and on a real 14" Windows
     laptop it apparently doesn't (captions/numbers reported cut off at
     the bottom — the regression this guards against). Investigated with
     real Playwright runs (Chromium/Firefox/WebKit) at 1512x982 and
     several nearby widths: could not reproduce the clip (margin held at
     ~43-47px in every case, and the isTablet flag — the suspected cause —
     doesn't gate anything in this section, confirmed by reading main.js).
     Most likely a Windows-specific font-metric difference this macOS
     sandbox can't reproduce. Leaving height/flex-centering exactly as the
     July 12 fix left them (unaffected here, and specifically flagged in
     CLAUDE.md as risky to touch) and only changing the failure mode: if
     content ever again exceeds 100svh, it now spills visibly below the
     section instead of being silently hard-clipped mid-caption. */
  overflow-x: hidden;
  overflow-y: visible;
  height: 100svh;
  min-height: 560px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.c-hgallery__head {
  padding-inline: var(--container-pad);
  max-width: var(--container-max);
  margin-inline: auto;
  margin-bottom: var(--space-lg);
}

/* Wider than the shared .u-section-lead 52ch cap: at 52ch, two of this
   lead's explicit <br />-separated lines (each ~85-87 characters) wrap
   onto a second line apiece, adding ~74px of otherwise-avoidable height
   to a section that's already fighting to fit its content within
   height:100svh (see the vertical-centering fix). 82ch is wide enough for
   both long lines to render on one line each (verified: content height
   stops shrinking past 80ch, so 82ch is already at the floor set by the
   explicit line breaks, not still constrained by wrapping). */
.c-hgallery__head .u-section-lead {
  max-width: 82ch;
}

.c-hgallery__title {
  margin-top: var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--size-h2);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  max-width: 18ch;
}

.c-hgallery__track {
  display: flex;
  gap: var(--space-md);
  padding-inline: var(--container-pad);
  will-change: transform;
}

.c-hgallery__card { flex: 0 0 auto; width: min(72vw, 560px); }

.c-hgallery__frame {
  position: relative;
  overflow: hidden;
  aspect-ratio: 3 / 2;
  background: var(--color-bg-raised);
}

.c-hgallery__frame img,
.c-hgallery__frame video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}

.c-hgallery__card:hover .c-hgallery__frame img,
.c-hgallery__card:hover .c-hgallery__frame video { transform: scale(1.05); }

.c-hgallery__caption {
  display: flex;
  justify-content: space-between;
  margin-top: var(--space-2xs);
  font-family: var(--font-display);
  font-size: var(--size-small);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-ink-dim);
}

.c-hgallery__caption span:last-child { color: var(--color-accent); }

/* Finale — the last card (Brošura video) grows into this fullscreen layer
   once the horizontal glide finishes, scroll-scrubs through to the end of
   its own clip, then releases to the next section. Scale/opacity driven
   from JS (main.js), not this transition — scrub needs to track the
   scrollbar exactly, a CSS transition would lag behind it. */
/* position:fixed (not absolute) so this always sizes to the true viewport
   regardless of the section's own (content-driven, likely shorter than
   100vh) height — needed for the FLIP grow-to-fullscreen math in main.js,
   which computes the transform from the real last-card rect to exactly
   {0,0,innerWidth,innerHeight}. */
.c-hgallery__finale {
  position: fixed;
  inset: 0;
  z-index: 40;
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transform-origin: 0 0;
  will-change: opacity, transform;
}

.c-hgallery__finale video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* PHONE-ONLY fallback: plain horizontal scroll-snap strip (with a JS
   auto-glide, see main.js), no pin/translate involved. Scoped to phone-
   sized touch viewports in EITHER orientation — portrait (<=767px wide) OR
   landscape phone (<=500px tall) — matching the isPhone definition in
   main.js (which skips the pin + FLIP finale on those SAME viewports).
   Tablet keeps the pinned scroll-scrub + FLIP finale like desktop (a real
   tablet is >=768px tall in landscape, so it never matches here). Both
   clauses MUST stay in lock-step with isPhone: the `transform:none
   !important` below overrides the JS pin's inline transform, so it may only
   apply where main.js has actually dropped the pin — otherwise it would
   freeze a still-pinned track. Finale layer never activates without the
   pinned-scroll JS, so on phone it stays hidden and the last card is a
   plain static image (swapped in main.js). */
@media (pointer: coarse) and (max-width: 767px),
       (pointer: coarse) and (max-height: 500px) {
  .c-hgallery__track {
    overflow-x: auto;
    scroll-snap-type: x proximity;
    padding-bottom: var(--space-sm);
    transform: none !important;
  }
  .c-hgallery__card { scroll-snap-align: start; width: 78vw; }
  .c-hgallery__finale { display: none; }
}

/* --------------------------------------------------------------------------
   17. TIMELINE — vertical process/milestone list ("It Started With Three
   Images"). Centered, minimal, reuses existing type tokens only.
   -------------------------------------------------------------------------- */
.c-timeline {
  padding-block: var(--space-section);
  text-align: center;
}

.c-timeline__head {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-pad);
  margin-bottom: var(--space-lg);
}

.c-timeline__title {
  font-family: var(--font-display);
  font-size: var(--size-h1);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  max-width: 20ch;
  margin-inline: auto;
}

.c-timeline__title em { font-style: normal; color: var(--color-accent); }

.c-timeline__list {
  list-style: none;
  margin: 0 auto;
  padding: 0 var(--container-pad);
  max-width: 440px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.c-timeline__item {
  font-family: var(--font-display);
  font-size: var(--size-h3);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  color: var(--color-ink);
  padding-block: var(--space-2xs);
}

.c-timeline__item:not(:last-child)::after {
  content: "↓";
  display: block;
  margin-top: var(--space-2xs);
  color: var(--color-accent);
  font-size: 1.1rem;
}

.c-timeline__closing {
  margin: var(--space-lg) auto 0;
  padding-inline: var(--container-pad);
  max-width: 46ch;
  font-family: var(--font-display);
  font-size: var(--size-h3);
  font-weight: 500;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  color: var(--color-ink-dim);
}

/* --------------------------------------------------------------------------
   18. SIGNATURE — closing credit block before the footer. Generous
   whitespace, centered, no interactive elements — reads as the last page
   of a printed book, not another CTA.
   -------------------------------------------------------------------------- */
.c-signature {
  position: relative;
  padding-block: calc(var(--space-section) * 1.1) calc(var(--space-section) * 1.5);
  text-align: center;
  background: var(--color-bg);
}

/* Bridges the Void section's pure #000 into this section's own (slightly
   lighter) background — without this the cut from Void's black hold felt
   like a hard jump instead of settling into place. */
/* Slower than the base .r-fade (1.1s) — this is the "fade from black"
   payoff moment right after the Void section, deserves a more deliberate
   pace than a routine content reveal elsewhere on the page. */
html.is-ready .c-signature.r-fade { transition: opacity 2.2s var(--ease-out); }

.c-signature__brand {
  font-family: var(--font-display);
  font-size: var(--size-h2);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-ink);
  margin-bottom: var(--space-2xs);
}

.c-signature__tagline {
  font-family: var(--font-display);
  font-size: var(--size-lead);
  font-weight: 500;
  color: var(--color-accent-soft);
  margin-bottom: var(--space-lg);
}

.c-signature__roles {
  font-family: var(--font-body);
  font-size: var(--size-small);
  color: var(--color-ink-faint);
  line-height: var(--leading-body);
}

.c-signature__divider {
  display: block;
  width: 28px;
  height: 1px;
  background: var(--color-line);
  margin: var(--space-lg) auto;
}

.c-signature__line {
  font-family: var(--font-display);
  font-size: var(--size-lead);
  font-weight: 500;
  letter-spacing: var(--tracking-normal);
  color: var(--color-ink-dim);
}

.c-signature__meta {
  font-family: var(--font-display);
  font-size: var(--size-label);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--color-ink-faint);
}

@media (prefers-reduced-motion: reduce) {
  .c-timeline__item, .c-signature__brand, .c-signature__line { transition: none; }
}

/* --------------------------------------------------------------------------
   19. VOID — cinematic pause between the closing CTA and the signature.
   Pure black, sequential text reveal driven entirely by scroll position
   (see main.js) so it stays in sync with actual scroll speed, not a timer.
   -------------------------------------------------------------------------- */
.c-void {
  position: relative;
  height: 100svh;
  min-height: 420px;
  background: #000;
  overflow: hidden;
}

.c-void__stage {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.c-void__line {
  position: absolute;
  margin: 0;
  padding-inline: var(--container-pad);
  font-family: var(--font-display);
  font-size: clamp(2rem, 2vw + 1.5rem, 4.5rem);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  color: var(--color-ink);
  opacity: 0;
  will-change: opacity;
}

/* Final line ("Endless possibilities.") in the page's gold accent — same
   token as the eyebrows / logo — for a warm payoff after the two white
   lines, instead of a third identical white line. */
.c-void__line[data-line="2"] { color: var(--color-accent); }

/* No JS / reduced-motion fallback — stack all three lines statically so
   the content is still readable instead of a permanently black, empty
   section (main.js only wires the scroll-scrub inside the same
   !reduceMotion guard everything else on the page uses). */
@media (prefers-reduced-motion: reduce) {
  .c-void { height: auto; padding-block: var(--space-section); }
  .c-void__stage { position: static; display: block; }
  .c-void__line { position: static; opacity: 1; margin-block: var(--space-sm); }
  /* main.js's scroll-scrub (and the .is-visible toggle it drives) never
     runs under reduced-motion, so the cue must default to visible here —
     otherwise it would stay permanently hidden instead of just static. */
  .c-void__scroll { position: static; opacity: 1; pointer-events: auto; margin-top: var(--space-md); }
}

/* Scroll cue for the end of the Void's pinned black hold — the last ~6-7%
   of its scroll range fades every line to opacity:0 (see updateVoidLines /
   voidPhases in main.js), leaving pure black with nothing on screen to
   signal the page is still alive and scrolling continues into the
   signature. Exact visual duplicate of .c-hero__scroll (same font,
   spacing, arrow-draw + bounce animation, bottom-center placement) —
   copied under its own .c-void__scroll classes so the Hero original stays
   untouched. Hidden until the visitor reaches "Endless possibilities." —
   see .is-visible below and updateVoidLines() in main.js — instead of
   Hero's own cue's always-visible behaviour: Void opens on a black screen
   with nothing to scroll toward yet, so an immediately-visible "Scroll"
   cue there read as pointing at nothing. */
.c-void__scroll {
  position: absolute;
  left: 50%;
  bottom: var(--space-md);
  transform: translateX(-50%);
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2xs);
  height: 60px;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-slow) var(--ease-out);
}

.c-void__scroll.is-visible {
  opacity: 1;
  pointer-events: auto;
}

.c-void__scroll-arrow {
  position: relative;
  width: 20px;
  height: 30px;
}

.c-void__scroll-arrow::before {
  content: "";
  width: 14px;
  height: 14px;
  border-right: 2px solid var(--color-ink);
  border-bottom: 2px solid var(--color-ink);
  position: absolute;
  top: 0;
  left: 3px;
  transform: rotate(45deg);
  transition: border-color var(--dur-base) var(--ease-out);
}

.c-void__scroll-arrow::after {
  content: "";
  width: 2px;
  height: 100%;
  background: var(--color-accent);
  position: absolute;
  bottom: 0;
  left: 9px;
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 1s var(--ease-out);
}

.c-void__scroll:hover .c-void__scroll-arrow::before { border-color: var(--color-accent); }
.c-void__scroll:hover .c-void__scroll-arrow::after { transform: scaleY(1); }

.c-void__scroll-label {
  position: relative;
  display: block;
  overflow: hidden;
  height: 1.2em;
  line-height: 1.2;
  color: transparent;
  font-family: var(--font-display);
  font-size: var(--size-label);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
}

.c-void__scroll-label::before,
.c-void__scroll-label::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  transition: transform var(--dur-base) var(--ease-in-out);
}
.c-void__scroll-label::before { color: var(--color-ink-dim); transform: translateY(0); }
.c-void__scroll-label::after { color: var(--color-accent); transform: translateY(-170%); }
.c-void__scroll:hover .c-void__scroll-label::before { transform: translateY(150%); }
.c-void__scroll:hover .c-void__scroll-label::after { transform: translateY(0); }

.c-void__scroll-arrow { animation: scrollBounce 2.2s var(--ease-in-out) infinite; }

@media (prefers-reduced-motion: reduce) {
  .c-void__scroll-arrow { animation: none; }
}

