/* =====================================================================
   יאיר פז — Portfolio
   Cinematic dark RTL site. Logical properties throughout (RTL-first).
   ===================================================================== */

:root {
  --bg-void: #0A0A0A;
  --bg-true-black: #050505;
  --emerald-deep: #0B3D2E;
  --emerald-bright: #1FAE7A;
  --gold: #C9A227;
  --champagne: #E8D9B5;
  --ember: #D97706;
  --text-primary: #F5F3EE;
  --text-white: #FFFFFF;
  --text-muted: #8A8A8A;

  --font-display: 'Rubik', 'Heebo', sans-serif;
  --font-body: 'Heebo', 'Rubik', sans-serif;

  --ease-cine: cubic-bezier(0.16, 1, 0.3, 1); /* ~expo.out */
  --nav-h: 72px;
}

/* ------------------------------ reset ------------------------------ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  direction: rtl;
  background: var(--bg-void);
  scrollbar-color: var(--emerald-deep) var(--bg-true-black);
}

body {
  font-family: var(--font-body);
  font-weight: 300;
  color: var(--text-primary);
  background: var(--bg-void);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  line-height: 1.7;
}

img, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }
button, input, textarea { font: inherit; color: inherit; }

::selection { background: var(--emerald-deep); color: var(--champagne); }

/* =====================================================================
   FILM GRAIN — animated noise, ~5% opacity, cheap (background-position
   steps over an SVG turbulence tile; transform/none = no layout cost)
   ===================================================================== */
.grain {
  position: fixed;
  inset: -100px;
  z-index: 90;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: grain-shift 0.9s steps(4) infinite;
}
@keyframes grain-shift {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-40px, 30px); }
  50%  { transform: translate(30px, -50px); }
  75%  { transform: translate(-30px, -20px); }
  100% { transform: translate(0, 0); }
}
@media (max-width: 768px) {
  .grain { opacity: 0.03; animation-duration: 1.4s; } /* lighter on mobile */
}

/* =====================================================================
   CUSTOM CURSOR — desktop / fine pointers only (enabled via JS class)
   ===================================================================== */
.cursor-dot, .cursor-ring {
  display: none;
  position: fixed;
  top: 0; left: 0; /* physical on purpose: positioned via transform from (0,0) */
  z-index: 200;
  pointer-events: none;
  border-radius: 50%;
}
body.has-cursor .cursor-dot,
body.has-cursor .cursor-ring { display: block; }
body.has-cursor { cursor: none; }
body.has-cursor a, body.has-cursor button { cursor: none; }

/* Native fullscreen renders ONLY the fullscreen element and its descendants,
   so the custom cursor - which lives at body level - stops being painted and
   the pointer vanishes entirely. Hand the real cursor back while a document
   is fullscreen. */
body.cursor-native,
body.cursor-native a,
body.cursor-native button { cursor: auto; }
body.cursor-native button { cursor: pointer; }
body.cursor-native .cursor-dot,
body.cursor-native .cursor-ring { display: none; }
.cursor-dot {
  width: 6px; height: 6px;
  background: var(--emerald-bright);
  margin: -3px;
}
.cursor-ring {
  width: 34px; height: 34px;
  margin: -17px;
  border: 1px solid rgba(31, 174, 122, 0.55);
  transition: width 0.25s var(--ease-cine), height 0.25s var(--ease-cine),
              margin 0.25s var(--ease-cine), border-color 0.25s;
}
body.cursor-hover .cursor-ring {
  width: 56px; height: 56px; margin: -28px;
  border-color: var(--gold);
}

/* =====================================================================
   NAV
   ===================================================================== */
.site-nav {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-inline: clamp(20px, 4vw, 56px);
  background: linear-gradient(to bottom, rgba(5,5,5,0.75), transparent);
  transition: background 0.4s;
}
.site-nav.is-solid {
  background: rgba(5, 5, 5, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.nav-logo {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.25rem;
  color: var(--text-white);
  letter-spacing: 0.02em;
}
.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(18px, 3vw, 40px);
  font-weight: 400;
  font-size: 0.95rem;
}
.nav-links a {
  position: relative;
  color: var(--text-primary);
  transition: color 0.3s;
}
.nav-links a::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-end: -6px;
  inline-size: 0;
  block-size: 1px;
  background: var(--gold);
  transition: inline-size 0.35s var(--ease-cine);
}
.nav-links a:hover { color: var(--text-white); }
.nav-links a:hover::after { inline-size: 100%; }
.nav-cta {
  border: 1px solid rgba(31, 174, 122, 0.5);
  border-radius: 999px;
  padding: 8px 22px;
  transition: border-color 0.3s, box-shadow 0.3s, color 0.3s;
}
.nav-cta:hover {
  border-color: var(--emerald-bright);
  box-shadow: 0 0 24px rgba(31, 174, 122, 0.35);
}
.nav-cta::after { display: none; }
@media (max-width: 640px) {
  .nav-links { gap: 16px; font-size: 0.85rem; }
  .nav-links a:not(.nav-cta):nth-child(2) { display: none; } /* trim on tiny screens */
}

/* =====================================================================
   SHARED WORLD / STAGE LAYOUT (pinned scroll sequences)
   ===================================================================== */
/* The worlds are deliberately TRANSPARENT. Each one is pulled up by script.js
   so it starts pinning slightly before the previous one stops, and during
   that overlap the outgoing media has to remain visible *through* the
   incoming stage - that is what makes the handoff a crossfade rather than a
   swap. The page's own black sits behind them all. */
.world { position: relative; background: transparent; }
.world-stage {
  position: relative;
  block-size: 100vh;
  block-size: 100svh;
  overflow: hidden;
}

.world-line {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.4rem, 3.4vw, 2.6rem);
  line-height: 1.35;
  color: var(--text-white);
  max-inline-size: 22ch;
  text-wrap: balance;
}

/* split-text spans (built by JS) */
.split-word, .split-char {
  display: inline-block;
  will-change: transform, opacity;
}
.split-ws { white-space: pre; }

/* media-missing fallback: intentional dark slate + filename tag */
.media-missing {
  background:
    radial-gradient(ellipse at 30% 20%, rgba(11, 61, 46, 0.5), transparent 60%),
    linear-gradient(160deg, #101010, #050505);
}
.media-missing > video, .media-missing > img { visibility: hidden; }
.media-missing::after {
  content: attr(data-label);
  position: absolute;
  inset-block-end: 18px;
  inset-inline-start: 18px;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  direction: ltr;
}

/* =====================================================================
   WORLD 1 — VIDEO
   ===================================================================== */
.w1-layer {
  position: absolute;
  inset: 0;
  opacity: 0;
}
.w1-layer.is-active { opacity: 1; }
.w1-video {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}
.w1-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 45%, rgba(5,5,5,0.55) 100%),
    linear-gradient(to top, rgba(5,5,5,0.75), transparent 35%),
    linear-gradient(to bottom, rgba(5,5,5,0.6), transparent 30%);
}

.w1-copy {
  position: absolute;
  z-index: 5;
}
/* Hero copy is the one block that sits centred - it must not cover Yair
   in the background plate the way the bottom-corner copy would. */
.w1-hero {
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  pointer-events: none;
}
.hero-name {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(3.4rem, 12vw, 10rem);
  line-height: 0.95;
  color: var(--text-white);
  text-shadow: 0 0 80px rgba(31, 174, 122, 0.25);
}
.hero-sub {
  margin-block-start: 18px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1rem, 2.4vw, 1.5rem);
  color: var(--champagne);
  letter-spacing: 0.04em;
}
.w1-line {
  inset-inline-start: clamp(20px, 6vw, 96px);
  inset-block-end: clamp(90px, 18vh, 180px);
  opacity: 0;
}
.w1-line-d .world-line { color: var(--champagne); }

.scroll-hint {
  position: absolute;
  z-index: 5;
  inset-inline-end: clamp(20px, 4vw, 56px);
  /* lifted clear of the logo strip below it, which it used to cut through */
  inset-block-end: clamp(74px, 10vh, 108px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  font-size: 0.72rem;
  letter-spacing: 0.3em;
  color: var(--text-muted);
}
.scroll-hint-bar {
  inline-size: 1px;
  block-size: 54px;
  background: linear-gradient(to bottom, var(--emerald-bright), transparent);
  animation: hint-drop 2.2s var(--ease-cine) infinite;
  transform-origin: top;
}
@keyframes hint-drop {
  0% { transform: scaleY(0); opacity: 0; }
  35% { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(1) translateY(18px); opacity: 0; }
}

/* =====================================================================
   WORLD 2 — STILLS
   Native aspect ratio preserved: object-fit contain in a bounding frame.
   ===================================================================== */
.world-stills .world-stage { background: transparent; }
.w2-frames { position: absolute; inset: 0; }
.w2-frame {
  position: absolute;
  /* symmetric, so the black above and below each photo is equal */
  inset-block: 10vh;
  inset-inline: 6vw;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
}
.w2-frame img {
  max-inline-size: 100%;
  max-block-size: 100%;
  inline-size: auto;
  block-size: auto;
  object-fit: contain; /* never force-crop the photography */
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.7);
}

.w2-copy {
  position: absolute;
  z-index: 6;
  inset-inline-start: clamp(20px, 5vw, 80px);
  inset-block-end: clamp(48px, 9vh, 96px);
  opacity: 0;
  max-inline-size: min(80vw, 640px);
}
.w2-copy .world-line {
  font-size: clamp(1.2rem, 2.6vw, 2rem);
  text-shadow: 0 2px 30px rgba(0, 0, 0, 0.8);
}

.w2-category {
  position: absolute;
  z-index: 6;
  inset-inline-end: clamp(20px, 5vw, 80px);
  inset-block-start: calc(var(--nav-h) + 18px);
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 0.8rem;
  letter-spacing: 0.22em;
  color: var(--champagne);
  /* Hidden until View1 has actually arrived. This stage is transparent and
     sits under World 1's pinned stage while it scrolls into range, so at
     opacity 1 the chip showed through over the last video clip. Its own
     tween in the World 2 timeline brings it in. */
  opacity: 0;
}
.w2-category::before {
  content: "";
  inline-size: 34px;
  block-size: 1px;
  background: var(--gold);
}
.w2-category-text { display: inline-block; }

/* =====================================================================
   WORLD 3 — AI + META MOMENT
   ===================================================================== */
.world-ai .world-stage {
  display: flex;
  align-items: center;
  justify-content: center;
}
.ai-copy {
  position: absolute;
  z-index: 6;
  inset-inline: 0;
  inset-block-end: clamp(40px, 8vh, 90px);
  display: grid;
  justify-items: center;
  text-align: center;
  gap: 14px;
  max-inline-size: min(90vw, 720px);
  margin-inline: auto;
}
.ai-line {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.05rem, 2.1vw, 1.55rem);
  line-height: 1.4;
  color: var(--text-white);
  opacity: 0;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.85);
}
.ai-line-3 { color: var(--emerald-bright); }

/* iPhone 15-style device around the ad - same material language as the
   original frame (near-black bezel, hairline edge, emerald glow), restyled
   into a phone: titanium rail, deep corner radius, Dynamic Island, buttons.
   The JS meta-moment timeline scales this open to fill the viewport. */
.ai-device {
  position: relative;
  z-index: 4;
  inline-size: min(76vw, 116vh, 960px);
  aspect-ratio: 19.5 / 9;            /* iPhone held landscape - the ad is 16:9 */
  border-radius: 6.2% / 13.5%;       /* iPhone 15 corner continuity */
  padding: 3px;                      /* titanium rail thickness */
  background: linear-gradient(150deg, #3a3a3c 0%, #1c1c1e 28%, #48484a 52%, #1c1c1e 76%, #38383a 100%);
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.9),
    0 0 90px rgba(31, 174, 122, 0.16),
    0 40px 120px rgba(0, 0, 0, 0.8);
  will-change: transform;
}
.ai-device-screen {
  position: relative;
  block-size: 100%;
  border: 6px solid #050505;         /* screen bezel */
  border-radius: 5.9% / 12.6%;
  background: #000;
  overflow: hidden;
}
.ai-device-screen video {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  /* The ad is 16:9 in a 19.5:9 screen - contain it so nothing is cropped,
     exactly as a real iPhone plays a landscape clip. */
  object-fit: contain;
}

/* Behind-the-scenes still: its own full-stage layer, above the device and
   below the meta line. Crossfaded in as the frame opens. */
#meta-still {
  position: absolute;
  inset: 0;
  z-index: 5;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  opacity: 0;
  pointer-events: none;
}

/* Dynamic Island - on the left edge, where it sits on a rotated iPhone.
   Physical left/right throughout this device: it is a picture of a real
   object and must not mirror with the RTL text flow. */
.ai-device-island {
  position: absolute;
  z-index: 3;
  left: 1.6%;
  top: 50%;
  transform: translateY(-50%);
  width: 3.4%;
  height: 29%;
  border-radius: 999px;
  background: #000;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}

/* Side buttons, rotated with the device: the power button lands on the top
   edge and the action/volume cluster on the bottom edge. */
.ai-device-btn {
  position: absolute;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, #4a4a4c, #2a2a2c);
}
.ai-device-btn-power   { top: -2px;    right: 26%;   width: 9%; }
.ai-device-btn-action  { bottom: -2px; right: 17%;   width: 4%; }
.ai-device-btn-vol-up  { bottom: -2px; right: 25%;   width: 6.5%; }
.ai-device-btn-vol-dn  { bottom: -2px; right: 33.5%; width: 6.5%; }

/* Desktop layout stays exactly as it is (copy pinned to the bottom of the
   stage). On mobile that leaves a big gap between the frame and the text,
   so there the two stack as one tight flex column instead. */
@media (max-width: 768px) {
  .ai-device { inline-size: 92vw; }
  .world-ai .world-stage {
    flex-direction: column;
    justify-content: center;
    gap: 18px;
  }
  .ai-copy {
    position: static;
    order: 2;                /* DOM order is copy-then-device; flip it back */
    inset: auto;
    max-inline-size: 92vw;
    padding-inline: 4vw;
  }
  .ai-device { order: 1; }
}

/* Soft blurred black pool behind the meta line, so the white type reads
   cleanly over the (dark but detailed) behind-the-scenes photograph. */
.meta-line::before {
  content: "";
  position: absolute;
  z-index: -1;              /* behind the type, above the photo */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  inline-size: min(112%, 1220px);
  block-size: min(46%, 360px);
  background: radial-gradient(ellipse at center,
    rgba(0, 0, 0, 0.68) 0%,
    rgba(0, 0, 0, 0.52) 40%,
    rgba(0, 0, 0, 0.26) 64%,
    transparent 82%);
  filter: blur(30px);
  pointer-events: none;
}

.meta-line {
  position: absolute;
  z-index: 8;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  isolation: isolate;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2rem, 7vw, 5.5rem);
  color: var(--text-white);
  /* Dark halo (not emerald): the text lands over a photograph and has to
     stay legible against it. */
  text-shadow:
    0 2px 12px rgba(0, 0, 0, 0.92),
    0 0 34px rgba(0, 0, 0, 0.72),
    0 0 80px rgba(0, 0, 0, 0.5);
  opacity: 0;
  pointer-events: none;
}

/* =====================================================================
   STATS STRIP
   ===================================================================== */
.stats {
  background: var(--bg-true-black);
  padding-block: clamp(90px, 16vh, 170px);
  border-block: 1px solid rgba(201, 162, 39, 0.12);
}
.stats-inner {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(32px, 5vw, 72px);
  max-inline-size: 1240px;
  margin-inline: auto;
  padding-inline: clamp(20px, 5vw, 64px);
  text-align: center;
}
/* Two-stat variant: narrower track so the pair stays visually balanced
   rather than drifting apart across the full width. */
.stats-inner--two {
  grid-template-columns: repeat(2, 1fr);
  max-inline-size: 880px;
  margin-inline: auto;
  padding-inline: clamp(20px, 5vw, 64px);
  text-align: center;
}
.stat { display: grid; gap: 14px; align-content: start; }
.stat-figure {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.6rem, 6.5vw, 5.5rem);
  line-height: 1;
  color: var(--text-white);
}
.stat-text { font-size: clamp(2rem, 4.6vw, 4rem); }
.stat-plus { color: var(--emerald-bright); }
.stat-count { font-variant-numeric: tabular-nums; }
.stat-label {
  font-size: clamp(0.85rem, 1.4vw, 1rem);
  color: var(--text-muted);
  max-inline-size: 30ch;
  margin-inline: auto;
}
@media (max-width: 768px) {
  .stats-inner { grid-template-columns: 1fr; gap: 48px; }
}

/* =====================================================================
   STORY
   ===================================================================== */
.story {
  background: var(--bg-void);
  padding-block: clamp(90px, 15vh, 180px);
}
.story-inner {
  display: grid;
  grid-template-columns: minmax(280px, 420px) 1fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
  max-inline-size: 1240px;
  margin-inline: auto;
  padding-inline: clamp(20px, 5vw, 64px);
}
.story-portrait { position: relative; }
.story-portrait img {
  inline-size: 100%;
  border-radius: 4px;
  filter: grayscale(18%) contrast(1.04);
  box-shadow:
    0 0 0 1px rgba(232, 217, 181, 0.08),
    0 30px 80px rgba(0, 0, 0, 0.6),
    0 0 120px rgba(11, 61, 46, 0.35);
}
.story-portrait figcaption {
  margin-block-start: 14px;
  font-size: 0.8rem;
  letter-spacing: 0.18em;
  color: var(--text-muted);
}
.story-copy { display: grid; gap: 22px; }
.story-copy p {
  font-size: clamp(1rem, 1.5vw, 1.15rem);
  color: var(--text-primary);
  max-inline-size: 58ch;
}
.section-title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.9rem, 4.4vw, 3.4rem);
  line-height: 1.15;
  color: var(--text-white);
  margin-block-end: 10px;
}
@media (max-width: 900px) {
  .story-inner { grid-template-columns: 1fr; }
  .story-portrait { max-inline-size: 420px; }
}

/* =====================================================================
   PILLARS
   ===================================================================== */
.pillars {
  background: var(--bg-true-black);
  padding-block: clamp(90px, 15vh, 180px);
  padding-inline: clamp(20px, 5vw, 64px);
}
.pillars .section-title {
  text-align: center;
  margin-block-end: clamp(44px, 7vh, 80px);
}
.pillars-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(18px, 2.5vw, 32px);
  max-inline-size: 1240px;
  margin-inline: auto;
}
.pillar {
  position: relative;
  padding: clamp(28px, 3vw, 44px);
  border: 1px solid rgba(245, 243, 238, 0.08);
  border-radius: 6px;
  background: linear-gradient(170deg, rgba(255,255,255,0.025), transparent 55%);
  transition: border-color 0.4s, box-shadow 0.4s, transform 0.4s var(--ease-cine);
  overflow: hidden;
}
.pillar::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 1px;
  background: linear-gradient(to left, transparent, var(--gold), transparent);
  opacity: 0;
  transition: opacity 0.4s;
}
.pillar:hover {
  border-color: rgba(31, 174, 122, 0.45);
  box-shadow: 0 0 60px rgba(31, 174, 122, 0.12), inset 0 0 60px rgba(11, 61, 46, 0.15);
  transform: translateY(-6px);
}
.pillar:hover::before { opacity: 1; }
.pillar-index {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.3em;
  color: var(--emerald-bright);
  direction: ltr;
  display: inline-block;
}
.pillar h3 {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.5rem, 2.4vw, 2rem);
  color: var(--text-white);
  margin-block: 14px 12px;
}
.pillar p { color: var(--text-muted); font-size: 0.98rem; }
@media (max-width: 900px) {
  .pillars-grid { grid-template-columns: 1fr; max-inline-size: 560px; }
}

/* =====================================================================
   SERVICES — typographic list + floating hover preview
   ===================================================================== */
.services {
  position: relative;
  background: var(--bg-void);
  padding-block: clamp(90px, 15vh, 180px);
  padding-inline: clamp(20px, 5vw, 64px);
}
.services .section-title { max-inline-size: 1100px; margin-inline: auto; }
.services-list {
  max-inline-size: 1100px;
  margin-inline: auto;
  margin-block-start: clamp(36px, 6vh, 64px);
  border-block-start: 1px solid rgba(245, 243, 238, 0.1);
}
.service-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: clamp(16px, 3vw, 40px);
  padding-block: clamp(22px, 3.4vh, 34px);
  border-block-end: 1px solid rgba(245, 243, 238, 0.1);
  transition: padding-inline-start 0.45s var(--ease-cine);
}
.service-row:hover { padding-inline-start: 18px; }
.service-num {
  font-family: var(--font-display);
  font-size: 0.78rem;
  letter-spacing: 0.25em;
  color: var(--text-muted);
  direction: ltr;
}
.service-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.35rem, 3.4vw, 2.4rem);
  color: var(--text-primary);
  transition: color 0.35s, text-shadow 0.35s;
}
.service-row:hover .service-name {
  color: var(--text-white);
  text-shadow: 0 0 40px rgba(31, 174, 122, 0.5);
}
.service-desc {
  font-size: 0.9rem;
  color: var(--text-muted);
  transition: color 0.35s;
}
.service-row:hover .service-desc { color: var(--champagne); }
@media (max-width: 640px) {
  .service-row { grid-template-columns: auto 1fr; }
  .service-desc { grid-column: 2; }
}

.service-preview {
  position: fixed;
  z-index: 80;
  inline-size: 240px;
  block-size: 160px;
  border-radius: 6px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.7), 0 0 50px rgba(11, 61, 46, 0.4);
  transform: scale(0.9);
}
.service-preview img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* =====================================================================
   CLIENT LOGO MARQUEE - overlaid on Video1 at the bottom of the hero.
   No scrim by design: the logos sit directly on the footage.
   ===================================================================== */
.hero-logos {
  position: absolute;
  z-index: 5;
  inset-inline: 0;
  inset-block-end: clamp(18px, 4vh, 40px);
  opacity: 0.001;            /* revealed by the hero intro timeline */
}

/* The container is forced LTR. In an RTL container an overflowing
   max-content track is right-aligned, so its duplicate set sits off-screen
   to the LEFT and translating left empties the row - which is exactly why
   the previous marquee ran once and died. LTR puts the overflow on the
   right, so translating -50% (one full set) loops seamlessly forever. */
.logo-marquee {
  direction: ltr;
  position: relative;
  overflow: hidden;
  inline-size: 100%;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
}
.logo-track {
  display: flex;
  align-items: center;
  inline-size: max-content;
  will-change: transform;
  animation: logo-marquee 52s linear infinite;
}
.logo-marquee:hover .logo-track { animation-play-state: paused; }
@keyframes logo-marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }   /* -50% = exactly one set */
}

/* The supplied logos range from near-black to white, so the dark ones would
   be invisible over the footage. script.js measures each one and tags the
   dark ones; inverting (rather than flattening to a silhouette) keeps their
   internal detail. */
.client-logo {
  block-size: clamp(26px, 3.2vw, 40px);
  inline-size: auto;
  flex: none;
  /* Spacing lives on the item, not as flex `gap`. With `gap`, one set spans
     half + 9 gaps while -50% of the track is only half + 8.5 gaps, so the
     loop jumped by half a gap each cycle. As a margin it divides evenly. */
  margin-inline-end: clamp(28px, 4vw, 56px);
  opacity: 0.72;
  filter: grayscale(1) drop-shadow(0 1px 6px rgba(0, 0, 0, 0.55));
  transition: opacity 0.4s, filter 0.4s;
}
.client-logo.is-dark-logo {
  filter: grayscale(1) invert(1) drop-shadow(0 1px 6px rgba(0, 0, 0, 0.55));
}
.client-logo:hover,
.client-logo.is-dark-logo:hover {
  opacity: 1;
  filter: drop-shadow(0 1px 6px rgba(0, 0, 0, 0.55));
}
@media (prefers-reduced-motion: reduce) {
  .logo-track { animation: none; }
  .logo-marquee { overflow-x: auto; }
}

/* =====================================================================
   PHOTO CAROUSEL - modest, roughly half-viewport height.
   Active slide centred; neighbours peek out under each arrow.
   ===================================================================== */
.carousel-section {
  background: var(--bg-void);
  padding-block: clamp(50px, 8vh, 90px);
  padding-inline: clamp(12px, 3vw, 40px);
}
.carousel {
  position: relative;
  display: flex;
  align-items: center;
  gap: clamp(6px, 1.5vw, 18px);
  max-inline-size: 1400px;
  margin-inline: auto;
}
.carousel-viewport {
  flex: 1;
  overflow: hidden;
  block-size: clamp(240px, 46vh, 460px);
}
/* Slides are positioned by signed distance from the active one, wrapped
   circularly, so both neighbours always peek - including at either end. */
.carousel-track {
  direction: ltr;
  position: relative;
  block-size: 100%;
}
.carousel-slide {
  position: absolute;
  inset-block: 0;
  left: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  block-size: 100%;
  padding-inline: clamp(6px, 1vw, 14px);
  will-change: transform;
}
.carousel-slide img {
  max-inline-size: 100%;
  max-block-size: 100%;
  inline-size: auto;
  block-size: auto;
  object-fit: contain;      /* native aspect ratio, same as the stills world */
  border-radius: 3px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
  opacity: 0.32;
  transform: scale(0.93);
  transition: opacity 0.6s var(--ease-cine), transform 0.6s var(--ease-cine);
}
.carousel-slide.is-active img {
  opacity: 1;
  transform: scale(1);
}
.carousel-arrow {
  flex: none;
  inline-size: 46px;
  block-size: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(245, 243, 238, 0.16);
  border-radius: 50%;
  background: rgba(10, 10, 10, 0.6);
  color: var(--text-primary);
  cursor: pointer;
  transition: border-color 0.3s, color 0.3s, box-shadow 0.3s, transform 0.3s var(--ease-cine);
}
.carousel-arrow:hover {
  border-color: var(--emerald-bright);
  color: var(--emerald-bright);
  box-shadow: 0 0 28px rgba(31, 174, 122, 0.3);
  transform: scale(1.06);
}
.carousel-arrow:focus-visible {
  outline: 2px solid var(--emerald-bright);
  outline-offset: 3px;
}
@media (max-width: 640px) {
  .carousel-arrow { inline-size: 44px; block-size: 44px; } /* min touch target */
  .carousel-viewport { block-size: clamp(200px, 38vh, 320px); }
}

/* =====================================================================
   MOTION GRAPHICS - Video6 in the original laptop-style frame.
   Modest scale; 16:9 contained, never cropped.
   ===================================================================== */
.mg-section {
  background: var(--bg-void);
  padding-block: clamp(20px, 4vh, 50px) clamp(60px, 10vh, 120px);
  padding-inline: clamp(20px, 5vw, 64px);
  display: flex;
  justify-content: center;
}
.mg-device {
  inline-size: min(62vw, 720px);
}
.mg-device-screen {
  position: relative;
  border: 10px solid #161616;
  border-radius: 18px;
  background: #000;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  box-shadow:
    0 0 0 1px #262626,
    0 0 90px rgba(31, 174, 122, 0.16),
    0 40px 120px rgba(0, 0, 0, 0.8);
}
.mg-video {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;      /* 16:9 in a 16:9 frame - fits exactly, no crop */
}
.mg-device-base {
  margin-inline: auto;
  inline-size: 34%;
  block-size: 10px;
  border-radius: 0 0 12px 12px;
  background: linear-gradient(#1c1c1c, #0c0c0c);
}
@media (max-width: 768px) {
  .mg-device { inline-size: 92vw; }
}

/* =====================================================================
   CONTACT / FINAL CTA
   ===================================================================== */
.contact {
  position: relative;
  background: var(--bg-true-black);
  /* Top padding trimmed right down, with the slack moved to .resume's bottom
     margin instead. That balances the space above and below the résumé link
     so it sits centred in the gap rather than hanging near the headline. */
  padding-block: clamp(14px, 2.6vh, 34px) clamp(80px, 12vh, 140px);
  padding-inline: clamp(20px, 5vw, 64px);
}
/* Two overlapping layers blend this section into the void above it instead
   of cutting to it. ::before ramps the base colour from transparent to solid
   across the tail of the previous section. */
.contact::before {
  content: "";
  position: absolute;
  z-index: 0;
  inset-inline: 0;
  inset-block-start: clamp(-340px, -36vh, -220px);
  block-size: clamp(220px, 36vh, 340px);
  pointer-events: none;
  background: linear-gradient(to bottom,
    rgba(5, 5, 5, 0) 0%,
    rgba(5, 5, 5, 0.3) 42%,
    rgba(5, 5, 5, 0.72) 72%,
    rgba(5, 5, 5, 1) 100%);
}
/* ::after carries the emerald glow. It straddles the section boundary and
   falls off to nothing in every direction, so the tint has no edge of its
   own - previously the radial peaked exactly on the boundary, which is
   what made the seam visible. */
.contact::after {
  content: "";
  position: absolute;
  z-index: 0;
  inset-inline: 0;
  inset-block-start: clamp(-220px, -22vh, -140px);
  block-size: clamp(420px, 62vh, 620px);
  pointer-events: none;
  background: radial-gradient(ellipse 68% 52% at 50% 50%,
    rgba(11, 61, 46, 0.42) 0%,
    rgba(11, 61, 46, 0.22) 42%,
    transparent 74%);
}
/* keep the content above both blend layers */
.contact-headline,
.contact-grid,
.resume { position: relative; z-index: 1; }

/* =====================================================================
   RÉSUMÉ - inline expanding panel
   The toggle occupies the gap that already sat above the CTA headline
   (.contact's top padding was reduced to match), so the page is no taller
   until the panel is actually opened.
   ===================================================================== */
.resume {
  text-align: center;
  /* matches (mg-section's bottom padding + .contact's top padding) above it,
     so the link lands mid-gap */
  margin-block-end: clamp(74px, 13vh, 154px);
}
.resume-toggle {
  border: 0;
  background: none;
  font-family: var(--font-body);
  font-weight: 300;                 /* deliberately quiet next to the headline */
  font-size: clamp(0.9rem, 1.2vw, 1rem);
  letter-spacing: 0.14em;
  color: var(--text-muted);
  cursor: pointer;
  padding: 6px 2px;
  position: relative;
  transition: color 0.3s;
}
.resume-toggle::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: 1px;
  background: var(--gold);
  transform: scaleX(0.35);
  transform-origin: center;
  opacity: 0.5;
  transition: transform 0.4s var(--ease-cine), opacity 0.4s;
}
.resume-toggle:hover { color: var(--champagne); }
.resume-toggle:hover::after { transform: scaleX(1); opacity: 1; }
.resume-toggle:focus-visible { outline: 2px solid var(--emerald-bright); outline-offset: 4px; }

/* The panel's height is animated from 0, so the page grows in place rather
   than a dialog appearing over it. */
.resume-panel {
  overflow: hidden;
  block-size: 0;
}
.resume-panel[hidden] { display: none; }

.resume-viewer {
  position: relative;
  max-inline-size: min(880px, 92vw);
  margin-inline: auto;
  margin-block-start: clamp(22px, 3vh, 36px);
  border: 1px solid rgba(245, 243, 238, 0.12);
  border-radius: 6px;
  background: #0f0f0f;
  overflow: hidden;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.6);
}
.resume-scroll {
  overflow: auto;
  max-block-size: min(78vh, 900px);
  display: flex;
  justify-content: center;
  align-items: flex-start;
  overscroll-behavior: contain;
}
.resume-doc {
  display: block;
  inline-size: 100%;
  block-size: auto;
  flex: none;
  aspect-ratio: 1166 / 1648;   /* reserve the box before the file decodes */
  background: #fff;
}

/* centred fullscreen control, panel view only */
.resume-expand {
  position: absolute;
  /* physical left/top on purpose: inset-inline-start resolves to `right` in
     RTL, which offset this by half its own width instead of centring it */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  inline-size: 62px;
  block-size: 62px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--text-primary);
  background: rgba(10, 10, 10, 0.72);
  border: 1px solid rgba(245, 243, 238, 0.22);
  border-radius: 50%;
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: border-color 0.3s, color 0.3s, box-shadow 0.3s, transform 0.3s var(--ease-cine);
}
.resume-expand:hover {
  border-color: var(--emerald-bright);
  color: var(--emerald-bright);
  box-shadow: 0 0 34px rgba(31, 174, 122, 0.35);
  transform: translate(-50%, -50%) scale(1.06);
}
.resume-expand:focus-visible { outline: 2px solid var(--emerald-bright); outline-offset: 3px; }

/* bottom control bar - fullscreen only */
/* The page is centred now, so the controls sit over white. A tall scrim
   keeps them legible without a hard-edged bar across the document. */
.resume-bar {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  display: none;
  align-items: flex-end;
  justify-content: center;
  gap: 16px;
  padding-block: 40px 16px;
  background: linear-gradient(to top,
    rgba(4, 4, 4, 0.94) 0%,
    rgba(4, 4, 4, 0.82) 34%,
    rgba(4, 4, 4, 0.42) 66%,
    transparent 100%);
}
.resume-shrink {
  inline-size: 46px;
  block-size: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.15rem;
  line-height: 1;
  color: var(--text-primary);
  background: rgba(10, 10, 10, 0.8);
  border: 1px solid rgba(245, 243, 238, 0.22);
  border-radius: 50%;
  cursor: pointer;
  transition: border-color 0.3s, color 0.3s;
}
.resume-shrink:hover { border-color: var(--emerald-bright); color: var(--emerald-bright); }
.resume-hint { font-size: 0.75rem; letter-spacing: 0.12em; color: var(--text-muted); }

/* fullscreen state */
.resume-viewer:fullscreen {
  max-inline-size: none;
  inline-size: 100vw;
  block-size: 100vh;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: #0b0b0b;
}
.resume-viewer:fullscreen .resume-scroll {
  max-block-size: 100vh;
  block-size: 100vh;
  align-items: flex-start;         /* margin:auto below does the centring */
}
.resume-viewer:fullscreen .resume-doc {
  inline-size: auto;               /* JS drives the zoom width */
  max-inline-size: none;
  /* auto margins centre it both ways AND keep every edge reachable once it
     overflows, which `align-items: center` alone would clip away */
  margin: auto;
}
.resume-viewer:fullscreen .resume-expand { display: none; }
.resume-viewer:fullscreen .resume-bar { display: flex; }

/* Fallback for when the Fullscreen API is unavailable or refused (some
   embedded/managed browsers reject it): a fixed full-viewport overlay that
   behaves identically. Kept as its own rule block so an unsupported
   :fullscreen selector can never invalidate it. */
/* .resume carries z-index:1, which creates a stacking context and would trap
   the overlay below the nav and the WhatsApp button. Raise the host while the
   overlay is up so it genuinely covers everything. */
.resume.is-fs-host { z-index: 400; }
.resume-viewer.is-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 300;
  max-inline-size: none;
  inline-size: 100vw;
  block-size: 100vh;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: #0b0b0b;
}
.resume-viewer.is-fullscreen .resume-scroll {
  max-block-size: 100vh;
  block-size: 100vh;
  align-items: flex-start;
}
.resume-viewer.is-fullscreen .resume-doc {
  inline-size: auto;
  max-inline-size: none;
  margin: auto;
}
.resume-viewer.is-fullscreen .resume-expand { display: none; }
.resume-viewer.is-fullscreen .resume-bar { display: flex; }

@media (max-width: 640px) {
  .resume-expand { inline-size: 52px; block-size: 52px; font-size: 1.25rem; }
  .resume-hint { display: none; }
}
.contact-headline {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.2rem, 7vw, 5.8rem);
  line-height: 1.08;
  color: var(--text-white);
  text-align: center;
  max-inline-size: 16ch;
  margin-inline: auto;
  margin-block-end: clamp(56px, 9vh, 100px);
  text-wrap: balance;
}
.contact-grid {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) minmax(300px, 1.4fr);
  gap: clamp(40px, 6vw, 96px);
  max-inline-size: 1000px;
  margin-inline: auto;
}
.contact-details {
  display: grid;
  gap: 20px;
  align-content: start;
  justify-items: start;
}
.contact-item {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.05rem, 1.8vw, 1.3rem);
  color: var(--text-primary);
  position: relative;
  transition: color 0.3s;
}
.contact-item::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-end: -4px;
  inline-size: 0;
  block-size: 1px;
  background: var(--gold);
  transition: inline-size 0.35s var(--ease-cine);
}
.contact-item:hover { color: var(--emerald-bright); }
.contact-item:hover::after { inline-size: 100%; }

.contact-form { display: grid; gap: 20px; }
.form-field { display: grid; gap: 8px; }
.form-field label {
  font-size: 0.82rem;
  letter-spacing: 0.14em;
  color: var(--text-muted);
}
.form-field input,
.form-field textarea {
  background: rgba(245, 243, 238, 0.04);
  border: 1px solid rgba(245, 243, 238, 0.14);
  border-radius: 4px;
  padding: 13px 16px;
  color: var(--text-primary);
  transition: border-color 0.3s, box-shadow 0.3s, background 0.3s;
  resize: vertical;
}
.form-field input:focus,
.form-field textarea:focus {
  outline: none;
  border-color: var(--emerald-bright);
  box-shadow: 0 0 0 3px rgba(31, 174, 122, 0.15);
  background: rgba(245, 243, 238, 0.06);
}
.form-submit {
  justify-self: start;
  border: 1px solid var(--emerald-bright);
  border-radius: 999px;
  background: transparent;
  color: var(--text-white);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  padding: 13px 46px;
  cursor: pointer;
  transition: background 0.35s, box-shadow 0.35s, transform 0.35s var(--ease-cine);
}
.form-submit:hover {
  background: var(--emerald-deep);
  box-shadow: 0 0 44px rgba(31, 174, 122, 0.4);
  transform: translateY(-2px);
}
@media (max-width: 820px) {
  .contact-grid { grid-template-columns: 1fr; }
}

/* =====================================================================
   FOOTER
   ===================================================================== */
.site-footer {
  background: var(--bg-true-black);
  border-block-start: 1px solid rgba(245, 243, 238, 0.07);
  padding-block: clamp(48px, 7vh, 80px);
  padding-inline: clamp(20px, 5vw, 64px);
  text-align: center;
  display: grid;
  gap: 26px;
}
.footer-nav, .footer-contact {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(18px, 4vw, 44px);
  font-size: 0.92rem;
}
.footer-nav a, .footer-contact a {
  color: var(--text-muted);
  transition: color 0.3s;
}
.footer-nav a:hover, .footer-contact a:hover { color: var(--champagne); }
.footer-note {
  font-size: 0.88rem;
  color: var(--gold);
  opacity: 0.75;
}
.footer-copy { font-size: 0.78rem; color: var(--text-muted); }

/* =====================================================================
   WHATSAPP BUTTON — fixed bottom-left (physical, per spec), idle pulse
   ===================================================================== */
.whatsapp-btn {
  position: fixed;
  left: 24px;   /* intentionally physical: bottom-LEFT in every direction */
  bottom: 24px;
  z-index: 120;
  inline-size: 54px;
  block-size: 54px;
  min-inline-size: 48px;
  min-block-size: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #128C4A;
  color: #fff;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.5s var(--ease-cine), transform 0.5s var(--ease-cine), background 0.3s;
  pointer-events: none;
}
.whatsapp-btn.is-visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.whatsapp-btn:hover { background: #16A85A; }
.whatsapp-btn::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 1px solid rgba(31, 174, 122, 0.6);
  animation: wa-pulse 2.6s var(--ease-cine) infinite;
}
@keyframes wa-pulse {
  0% { transform: scale(1); opacity: 0.7; }
  70% { transform: scale(1.45); opacity: 0; }
  100% { transform: scale(1.45); opacity: 0; }
}

/* =====================================================================
   REVEAL-ON-SCROLL (calm sections after the meta moment)
   ===================================================================== */
.reveal { opacity: 0; transform: translateY(36px); }
html.no-motion .reveal { opacity: 1; transform: none; }

/* =====================================================================
   REDUCED MOTION — pinned choreography collapses into a simple,
   fully readable stacked layout with plain fades.
   ===================================================================== */
html.no-motion .grain { animation: none; }
html.no-motion .scroll-hint-bar { animation: none; }
html.no-motion .whatsapp-btn::before { animation: none; }
html.no-motion .whatsapp-btn { opacity: 1; transform: none; pointer-events: auto; }

html.no-motion .world-stage { block-size: auto; overflow: visible; }
html.no-motion .w1-layer,
html.no-motion .w2-frame {
  position: relative;
  inset: auto;
  opacity: 1;
  margin-block: 24px;
}
html.no-motion .w1-layer { block-size: 60vh; }
html.no-motion .w2-frame { block-size: 70vh; }
html.no-motion .w1-copy, html.no-motion .w2-copy {
  position: relative;
  inset: auto;
  opacity: 1;
  padding: 40px clamp(20px, 6vw, 96px) 0;
}
html.no-motion .hero-logos { position: relative; inset: auto; opacity: 1; padding-block: 28px; }
html.no-motion .w1-vignette, html.no-motion .scroll-hint,
html.no-motion .w2-category, html.no-motion .meta-line { display: none; }
html.no-motion .world-ai .world-stage {
  flex-direction: column;
  gap: 32px;
  padding-block: 60px;
}
html.no-motion .ai-copy { position: relative; inset: auto; }
html.no-motion .ai-line { opacity: 1; }
html.no-motion .split-word, html.no-motion .split-char { opacity: 1 !important; transform: none !important; }

/* Carousel with no JS choreography: a plain scrollable strip.
   The slides are absolutely positioned by JS, so put them back in flow. */
html.no-motion .carousel-arrow { display: none; }
html.no-motion .carousel-viewport { overflow-x: auto; }
html.no-motion .carousel-track {
  display: flex;
  align-items: center;
  inline-size: max-content;
}
html.no-motion .carousel-slide {
  position: relative;
  left: auto;
  flex: none;
  inline-size: min(70vw, 460px);
  transform: none !important;
}
html.no-motion .carousel-slide img { opacity: 1; transform: none; }
/* No meta moment without motion, so the crossfade still stays out. */
html.no-motion #meta-still { display: none; }
