/* ============================================================
   HORN OK PLEASE — Vehicle Art as Design
   Rebuilt to match the user's real Illustrator layout. See the
   comment block at the top of index.html for what's real vs
   still placeholder.
   ============================================================ */

:root{
  --ink:#1a1a1a;
  --cream:#fff6e2;
  --font-display:'Anton', sans-serif;
  /* Poppins ships no Devanagari glyphs, so Noto Sans Devanagari is
     listed alongside it — Latin renders in Poppins, Hindi renders in
     Noto, and both respond to the same font-weight. Without this the
     Hindi silently fell back to the system UI face and ignored the
     600/700 weights the reference board uses. */
  --font-body:'Poppins','Noto Sans Devanagari', sans-serif;

  /* Core Visual Elements palette — sampled off your Illustrator board
     rather than reusing the brighter site theme vars, so the grid
     matches the reference exactly. */
  --c-yellow:#ffc401;
  --c-green:#fe2c5a;      /* pink — kept the var name so nothing else breaks */
  --c-blue:#1838ba;       /* the sunburst blue */
  --c-offwhite:#fff7e2;   /* the sunburst off-white */
  --c-orange:#ff9902;
}

/* ---------- CUSTOM FONT ----------
   Real file, pulled from your Downloads (TruckSans-Regular, exported
   via Calligraphr — has full A–Z, a–z, digits, basic punctuation).
   Lives at assets/fonts/ inside this project now. Every element using
   the .truck-font class picks this up automatically. */
@font-face{
  font-family:'Truck Sans';
  src:url('../assets/fonts/TruckSans-Regular.woff2') format('woff2'),
      url('../assets/fonts/TruckSans-Regular.ttf') format('truetype');
  font-weight:400;
  font-display:swap;
}
.truck-font{ font-family:'Truck Sans', var(--font-display); font-weight:400; }

/* ---------- THEME SYSTEM ----------
   --green is used as a teal throughout (toggle outlines, ticker,
   generator labels, half of the headline split) — tuned brighter/
   more teal to match the reference rather than a forest green. */
html[data-theme="india"]{
  --red:#fe2c5a; --blue:#293e9e; --yellow:#ffd317; --green:#02ad83; --orange:#ef9330;
}
html[data-theme="mexico"]{
  --red:#fe2c5a; --blue:#17b6b6; --yellow:#ffd317; --green:#02ad83; --orange:#ff6f3c;
}
html[data-theme="philippines"]{
  --red:#fe2c5a; --blue:#1e5fa8; --yellow:#ffd317; --green:#02ad83; --orange:#d4af37;
}

*{box-sizing:border-box; margin:0; padding:0;}
/* NO scroll-behavior:smooth here. The eased-scroll block in
   js/script.js drives the page with its own scrollTo calls every frame,
   and a native smooth behaviour would try to animate each one of those
   individually, fighting the easing. Jump links are eased in JS instead,
   and anyone with prefers-reduced-motion gets an instant jump. */
html{scroll-behavior:auto;}
/* The header is position:fixed, so an in-page jump would otherwise land
   with the section's first line tucked underneath it. scroll-margin-top
   offsets every anchor target by the header's height. */
#top,#originsSlideshow,#anatomy,#elements,#generator,#dipper{scroll-margin-top:90px;}
body{
  font-family:var(--font-body);
  background:var(--cream);
  color:var(--ink);
  overflow-x:hidden;
  transition:background .4s ease;
}
img,.ph{display:block; width:100%; height:100%; object-fit:cover;}
a{color:inherit; text-decoration:none;}
button{font-family:inherit; cursor:pointer;}
.wrap{max-width:1440px; margin:0 auto; padding:0 70px;}
@media(max-width:900px){.wrap{padding:0 24px;}}

.icon{width:100%; height:100%; display:block;}

.ph{
  background:repeating-linear-gradient(135deg, rgba(0,0,0,.06) 0 14px, rgba(0,0,0,.02) 14px 28px);
  border:2px dashed rgba(0,0,0,.25);
  display:flex; align-items:center; justify-content:center;
  text-align:center; font-family:var(--font-body); font-weight:600;
  font-size:13px; letter-spacing:.04em; text-transform:uppercase;
  color:rgba(0,0,0,.45); padding:12px;
}

.btn{
  display:inline-block; padding:14px 26px; border:2px solid var(--blue);
  background:transparent; color:var(--blue); font-weight:700; font-size:13px;
  letter-spacing:.06em; text-transform:uppercase; transition:.25s ease;
}
.btn:hover{background:var(--blue); color:var(--cream); transform:translateY(-2px);}
.btn.solid{background:var(--red); border-color:var(--red); color:var(--cream);}
.btn.solid:hover{background:var(--ink); border-color:var(--ink);}

.badge-dot{width:20px; height:20px; border-radius:50%; background:var(--blue); display:inline-block; transition:background .4s ease;}
.badge-dot.lg{width:44px; height:44px;}

.reveal{opacity:0; transform:translateY(28px); transition:opacity .7s ease, transform .7s ease;}
.reveal.in{opacity:1; transform:none;}

/* ---------- HERO BLOCK (header + hero share one sunburst) ----------
   Sunburst is now generated with a repeating-conic-gradient and slowly
   rotated, matching the holding page. No image file, so it stays crisp
   at any size and the rays are mathematically even. overflow:hidden is
   required here — the gradient element is far larger than the block so
   the rays stay parallel-looking near the centre rather than fanning. */
.hero-block{position:relative; overflow:hidden; background:#a72a4c; padding-top:var(--header-h);}
.page-sunburst{
  position:absolute; top:50%; left:50%; width:260vmax; height:260vmax;
  transform:translate(-50%,-50%); z-index:0; pointer-events:none;
  background:repeating-conic-gradient(from 0deg,
    #8c2d4b 0deg 6deg, transparent 6deg 12deg);
  animation:sunTurn 220s linear infinite;
}
@keyframes sunTurn{to{transform:translate(-50%,-50%) rotate(360deg);}}
@media(prefers-reduced-motion:reduce){.page-sunburst{animation:none;}}
/* Vignette: black at very low opacity pooling in from the corners and
   edges, dead-transparent through the middle so the sunburst hub stays
   clean. Sits above the rays (z:0) but below the icons (z:2), header
   (z:5) and hero copy (z:3), and never eats pointer events. */
.hero-block::after{
  content:''; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    radial-gradient(ellipse 78% 78% at 50% 50%,
      rgba(0,0,0,0) 40%, rgba(0,0,0,.10) 68%, rgba(0,0,0,.26) 88%, rgba(0,0,0,.40) 100%),
    linear-gradient(to right,  rgba(0,0,0,.16), rgba(0,0,0,0) 16%, rgba(0,0,0,0) 84%, rgba(0,0,0,.16)),
    linear-gradient(to bottom, rgba(0,0,0,.14), rgba(0,0,0,0) 18%, rgba(0,0,0,0) 82%, rgba(0,0,0,.18));
}

/* ---------- HEADER ---------- */
/* position:fixed (not sticky) so the logo + GENERATOR pill ride down
   the whole page as you scroll, past every section, instead of being
   clipped away by .hero-block's overflow:hidden. .hero-block gets a
   matching padding-top (--header-h) so the hero still starts at the
   very top of the page and the sunburst runs behind the header. */
:root{ --header-h:118px; }
.site-header{
  position:fixed; top:0; left:0; right:0; z-index:60;
  display:flex; justify-content:space-between; align-items:center;
  padding:30px 70px; background:transparent;
  transition:padding .3s ease, background .3s ease, box-shadow .3s ease;
}
/* Once you've scrolled off the hero the header is floating over cream
   page content, so it picks up a soft matching backdrop to stay legible
   without turning into a hard opaque bar. */
.site-header.shrink{
  padding:14px 70px;
  background:rgba(255,246,226,.92);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  box-shadow:0 2px 0 rgba(254,44,90,.9);
}
@media(max-width:900px){
  :root{ --header-h:72px; }   /* 14px padding x2 + 44px logo */
  .site-header{padding:14px 20px; gap:10px;}
  .site-header.shrink{padding:10px 20px;}
}
/* Logo is now the real OK mark (assets/img/OK logo.png), a square
   1595x1595 PNG — height-driven with width:auto so it never squashes. */
.logo-mark{display:inline-flex; align-items:center; line-height:0;}
.logo-mark img{
  height:58px; width:auto; display:block; object-fit:contain;
  transition:height .3s ease;
  filter:drop-shadow(0 2px 4px rgba(0,0,0,.18));
}
.site-header.shrink .logo-mark img{height:44px;}
@media(max-width:900px){
  .logo-mark img{height:44px;}
  .site-header.shrink .logo-mark img{height:36px;}
}
.header-cta{
  display:inline-flex; align-items:center; justify-content:center;
  padding:12px 26px; background:var(--red); color:var(--yellow); font-size:13px;
  font-weight:700; letter-spacing:.04em; border:1px solid var(--red);
}
/* keeps its pink at every state — the widen + spinning star-dots are the
   whole hover treatment, no colour flip to black */
.header-cta:hover, .header-cta:focus-visible, .header-cta:active{
  background:var(--red); border-color:var(--red); color:var(--yellow);
}
@media(max-width:900px){
  .header-cta{padding:8px 14px; font-size:9px;}
}

/* ---------- HERO ---------- */
/* z-index:3 here (not 1) — since .hero-icons moved up to be a sibling
   of .hero (for the shared-centre-point fix), stacking now compares
   THIS element's z-index against .hero-icons' z-index:2 directly. At
   z-index:1 the whole hero section (headline, paragraph, CTA boxes —
   everything) was sitting BEHIND the icon layer as one unit, regardless
   of any z-index set on things inside it. Bumping it to 3 puts all of
   the hero's real content back above the icons, so the icons render
   behind the text/buttons instead of over them. */
.hero{padding:90px 0 0; position:relative; z-index:3; min-height:88vh; display:flex; flex-direction:column;}
@media(max-width:900px){.hero{padding:50px 0 0; min-height:auto;}}
/* .hero also carries the .wrap class (max-width:1440px + margin:0 auto
   + padding:0 70px), which centres it as its own 1440px box — on any
   screen wider than 1440px that's a DIFFERENT box than the header's
   (full-width, just 70px padding), so PROMOTING.../the paragraph/the
   ICONOGRAPHY-PATTERNS-TYPOGRAPHY boxes in .hero-sub didn't line up
   with LOGO/GENERATOR above them. Fixing this by overriding just
   .hero's own box (not touching the shared .wrap rule other sections
   still rely on, and not touching the header) so it matches the
   header's exact model: full width, 70px padding, no extra centring. */
.hero.wrap{max-width:none; margin:0; padding-left:70px; padding-right:70px;}
@media(max-width:900px){.hero.wrap{padding-left:24px; padding-right:24px;}}

/* Every icon now originates from ONE single point — dead centre of
   the section (top:50%, left:50%, translate(-50%,-50%) at 0%) — then
   moves in a straight, constant-speed (linear) line purely horizontally
   until it's fully past the viewport edge, growing from a tiny speck to
   ~3x its box size along the way. Each icon is only actually visible
   for the first ~40% of its own cycle (the "ACTIVE" window below); for
   the remaining ~60% it's invisible and reset back at centre, waiting.
   All 5 share the exact same duration with evenly-spaced delays (1/5th
   of the duration apart) — with a 40%-active duty cycle that spacing
   mathematically keeps at most 2-3 icons visible at any moment, never
   the full set at once. */
.hero-icons{position:absolute; inset:0; z-index:2; pointer-events:none;}
.float-icon{
  position:absolute; top:50%; left:50%; width:64px; height:64px;
  /* animation-fill-mode:backwards fixes the "all icons sitting
     clustered at full size in the middle" glitch — without it, during
     animation-delay (before a cycle technically starts) the browser
     renders the element's plain un-animated CSS box: full opacity, no
     transform. "backwards" holds the first keyframe (scale 0,
     invisible) during that delay instead. ease-in (not linear) is the
     "extremely smooth, not abrupt" curve you asked for: slow growth
     right at the centre origin, continuously accelerating so most of
     the size increase happens in the second half of the journey —
     small in the middle, gradually bigger, properly large only right
     at the corner — and critically ease-in has NO deceleration at the
     end (opposite of ease-in-out), so it never re-introduces the
     "stopped at the edge" bug from before. */
  animation:driftOut var(--dur,23s) ease-in infinite backwards;
  animation-delay:var(--delay,0s);
}
.float-icon .floater{width:100%; height:100%; animation:spinSlow 11s linear infinite;}
.float-icon .icon-img{width:100%; height:100%; object-fit:contain; display:block;}
/* Single unbroken growth curve from 0%–62% (dead centre, scale 0) to
   (corner, scale 3.2) — only two transform stops, so ease-in applies
   as one continuous curve with no segment seams. Opacity stays fully
   at 1 for that entire stretch (no fading while visible) and only
   cuts at 63%, by which point it's already sitting at its fully-exited
   corner position, off-screen. */
@keyframes driftOut{
  0%{transform:translate(-50%,-50%) scale(0); opacity:1;}
  62%{transform:translate(calc(-50% + var(--tx)), calc(-50% + var(--ty))) scale(3.2); opacity:1;}
  63%{opacity:0;}
  100%{transform:translate(-50%,-50%) scale(0); opacity:0;}
}
@keyframes spinSlow{to{transform:rotate(360deg);}}
/* Each icon now heads toward its OWN corner (top-left / top-right /
   bottom-left / bottom-right), not just straight left/right — mixing
   --tx (horizontal) with --ty (vertical, in vh) sends it diagonally.
   Assigned so no two adjacent-delay icons share a direction. --tx/--ty
   magnitudes are generous (~70-88vw / ~50-78vh) so the fully-scaled
   icon clears the viewport corner before the opacity cut. Uniform 23s
   duration (slower, per your request) with a long 62%-active duty
   cycle.

   FREQUENCY: eight emitters now instead of five, and the delays are
   respaced from 23/5 (4.6s) to 23/8 (2.875s). The active window is
   unchanged at 62% x 23s = 14.3s, so the number in flight at any moment
   goes from 14.3/4.6 ~= 3 up to 14.3/2.875 ~= 5. The travel speed and
   the 23s cycle are untouched — only how densely they're released. Want
   even more? Add another .fi-N and re-divide 23s by the new count. */
.float-icon.fi-1{--tx:-88vw; --ty:78vh;  --dur:23s; --delay:0s;     width:240px; height:240px;} /* cow: bottom-left */
.float-icon.fi-2{--tx:85vw;  --ty:-72vh; --dur:23s; --delay:2.875s; width:210px; height:210px;} /* peacock: top-right */
.float-icon.fi-3{--tx:-80vw; --ty:-68vh; --dur:23s; --delay:5.75s;  width:150px; height:150px;} /* skull: top-left */
.float-icon.fi-4{--tx:82vw;  --ty:74vh;  --dur:23s; --delay:8.625s; width:190px; height:190px;} /* eagle: bottom-right */
.float-icon.fi-5{--tx:-70vw; --ty:50vh;  --dur:23s; --delay:11.5s;  width:130px; height:130px;} /* flower: bottom-left (shallow) */
.float-icon.fi-6{--tx:90vw;  --ty:-28vh; --dur:23s; --delay:14.375s; width:165px; height:165px;} /* peacock: right, shallow rise */
.float-icon.fi-7{--tx:-86vw; --ty:32vh;  --dur:23s; --delay:17.25s;  width:180px; height:180px;} /* cow: left, shallow fall */
.float-icon.fi-8{--tx:22vw;  --ty:86vh;  --dur:23s; --delay:20.125s; width:145px; height:145px;} /* eagle: straight down */

.hero-headline{
  position:relative; z-index:3; text-align:center; padding:0 0 24px; text-transform:uppercase;
  line-height:.82; letter-spacing:-.025em; display:flex; justify-content:center; align-items:center; flex-wrap:nowrap;
  gap:0 .12em;
}
.hero-headline span{display:inline-block; position:relative;}
/* --- HEAVY CREAM OUTLINE (replaces the patch image) ---
   The cream shape behind the words is no longer a PNG. Each span
   repeats its own text in a ::before that carries a very thick cream
   -webkit-text-stroke, so the shape is generated from the letterforms
   themselves and tracks them exactly at every size — no alignment to
   maintain, nothing to re-export if the wording changes.

   Layer order, back to front:
     ::before  cream stroke + cream fill   (the sticker shape)
     span      3px black stroke            (the thin outline, untouched)
     span      pink fill

   HOW IT STAYS BEHIND EVERY WORD: .hero-headline is the stacking
   context (position:relative + z-index:3) and the spans deliberately
   carry NO z-index, so they never make contexts of their own. Every
   ::before therefore lands in that one shared z-index:-1 layer and
   paints below ALL three words — otherwise PLEASE's cream would spill
   over OK's letters where the strokes overlap.

   -webkit-text-stroke centres on the glyph edge, so the outward reach
   is half of --hero-outline. 84px = ~42px of cream past the letters at
   1440px, matched to your reference. This is the ONE number to tune. */
.hero-headline{ --hero-outline:clamp(26px, 5.8vw, 84px); }
/* --- heartbeat + click to sound the horn ---
   --honk is written every frame by js/script.js. It carries a resting
   lub-dub heartbeat at all times, and while a horn is sounding the
   thump deepens and quickens with the live audio level.

   NO transition here on purpose: the value already changes every frame,
   so a transition would only smear one frame into the next and blunt
   the snap of the beat. It rests at exactly 1, so with JS off nothing
   moves. Depth and tempo are the four constants at the top of the
   "hero headline" block in js/script.js. */
.hero-headline{
  --honk:1;
  transform:scale(var(--honk));
  transform-origin:50% 50%;
  will-change:transform;
  cursor:pointer; user-select:none; -webkit-user-select:none;
}
.hero-headline:focus-visible{outline:3px solid var(--yellow); outline-offset:14px;}
.hero-headline span::before{
  content:attr(data-text);
  position:absolute; left:0; top:0; width:100%; height:100%;
  white-space:pre; pointer-events:none; z-index:-1;
  color:var(--cream);
  -webkit-text-stroke:var(--hero-outline) var(--cream);
  paint-order:stroke fill;
}
@media(max-width:900px){
  /* the lockup wraps onto multiple lines down here and the words sit
     much closer together, so the outline is scaled back to stop the
     three shapes merging into one unreadable slab */
  .hero-headline{ --hero-outline:22px; }
}

/* Solid pink/red fill with a black outline stroke — no duotone split. */
.hero-headline .w-horn, .hero-headline .w-please,
.hero-headline .w-ok{
  color:var(--red);
  -webkit-text-stroke:3px var(--ink); paint-order:stroke fill;
}
/* sizes matched to the holding page */
.hero-headline .w-horn{font-size:clamp(34px,7vw,104px);}
.hero-headline .w-please{font-size:clamp(34px,7vw,104px);}
.hero-headline .w-ok{font-size:clamp(64px,17vw,240px); margin:0; -webkit-text-stroke-width:4px;}
@media(max-width:900px){.hero-headline{flex-wrap:wrap;}}

.hero-sub{
  position:relative; z-index:2; display:grid; grid-template-columns:.9fr 1.3fr auto;
  gap:40px; padding:22px 0 60px; align-items:start;
  margin-top:auto;
}
/* Kerning/sizing matched to the reference: eyebrow reads as one tight
   compact block (line-height near 1, slightly negative tracking) like
   "À GOUROU, YOUR INDIAN RESTAURANT IN PARIS" — not loosely spaced. */
.eyebrow{font-family:var(--font-body); font-weight:700; color:var(--yellow); font-size:clamp(19px,2.15vw,27px); text-transform:uppercase; line-height:1.08; letter-spacing:-.01em; transition:color .4s ease;}
.hero-sub p{font-family:var(--font-body); font-weight:600; font-size:clamp(11.5px,1.05vw,13.5px); line-height:1.45; letter-spacing:0; max-width:40ch; color:var(--yellow); opacity:1;}
.swatch-preview{display:flex; align-items:flex-start; gap:14px;}
.mini-swatches{display:flex; gap:14px;}
/* Landscape ratio (not near-square) with tight uppercase tracking,
   matching the reference's "THE RESTAURANT / THE MENU / THE SHOP" boxes. */
.mini-swatch{
  min-width:172px; height:98px; border:1px solid var(--yellow); color:var(--yellow);
  display:flex; align-items:center; justify-content:center; text-align:center;
  font-size:13px; font-weight:700; letter-spacing:.03em; line-height:1.3; padding:8px 10px; word-break:break-word;
  cursor:pointer;
}
@media(max-width:900px){.hero-sub{grid-template-columns:1fr;} .swatch-preview{justify-content:flex-start; flex-wrap:wrap;} .mini-swatch{min-width:120px; height:74px; font-size:11px;}}

/* ---------- SCROLL-SCRUB COMMUNITY STRIP ----------
   One full-height band, two absolutely-stacked full-width layers,
   both cream with the rickshaw + hot-pink Poppins-extrabold text
   centred. .cb-community starts at translateX(-100%) (fully off the
   left edge) so at rest only FROM INDIA shows; the JS scrubs both
   layers' translateX with scroll (push transition + lerp traction). */
/* Stroke system: every rule in this run of sections is a SINGLE 4px
   pink line (the thickness the user marked). The strip deliberately
   has no border-bottom — the ticker's border-top IS the line between
   them, so they can't stack into a double-thick seam. */
.community-banner{
  position:relative; overflow:hidden; background:var(--cream);
  border-top:4px solid var(--red);
  height:clamp(104px,12.8vw,175px);
}
.cb-layer{
  position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  gap:30px; background:var(--cream); white-space:nowrap; will-change:transform;
}
.cb-community{transform:translateX(-100%);}
/* FROM INDIA fills the band edge-to-edge like the reference (band is
   15vw tall, type at ~11.5vw); TO THE COMMUNITY is deliberately set
   smaller so the two never collide while both are partially on screen
   mid-transition. */
.cb-text-lg{font-family:var(--font-body); font-weight:800; font-size:clamp(46px,9.8vw,160px); color:var(--red); text-transform:uppercase; line-height:1; letter-spacing:-.02em;}
/* Community text slightly smaller than FROM INDIA (anti-collision) but
   not tiny; rickshaw size intentionally NOT overridden here — it stays
   the same constant size in both strips. */
.cb-community .cb-text-lg{font-size:clamp(36px,6.7vw,110px);}
/* Real auto-rickshaw cutout (assets/img/auto-rickshaw.png — faces
   right, front at the right). Wheelie pivot = rear wheel (bottom-left
   origin) + negative JS rotation = the front/right end kicks upward.
   Rotation value is driven by JS from live scroll velocity, smoothed
   every frame — no CSS transition. */
/* .cb-auto carries the EXPLICIT width (same clamp the rick used) so
   it is unambiguously the sizing/positioning context for the smoke —
   previously the smoke's % width resolved against the whole
   transformed .cb-layer strip, which is why the clouds rendered
   gigantic. Now 44% genuinely means 44% of the auto. */
.cb-auto{position:relative; flex:none; display:block; width:clamp(74px,9.2vw,155px);}
.cb-rick{width:100%; height:auto; display:block; transform-origin:18% 90%;}
/* Two clouds per auto, proportioned to the reference: rear exhaust
   puff low behind the back wheel (~44% of auto width), smaller cloud
   drifting high off the front/top-right (~40%). On the wrapper — NOT
   the rotating .cb-rick — so they hold still while the auto wheelies. */
/* height:auto + object-fit:none override the global
   `img{width:100%; height:100%; object-fit:cover}` rule — THAT rule
   was what kept blowing the clouds up (100% height + cover = zoomed,
   cropped slab filling the auto's whole height, regardless of any
   width set here). With it neutralised the cloud keeps its own tiny
   natural aspect at the set width. */
.cb-smoke{position:absolute; pointer-events:none; height:auto; object-fit:initial;}
.cb-smoke.smoke-back{width:44%; left:-32%; bottom:-2%;}
/* floats just off the auto's top-front corner — its lower edge only
   slightly grazing the canopy, not overlapping the body. */
.cb-smoke.smoke-top{width:40%; right:-14%; top:-28%;}
@media(max-width:900px){.cb-layer{gap:14px;} .cb-text-lg{font-size:clamp(26px,7vw,48px);}}

/* ---------- MINI TICKER (cream band, red Poppins-bold text + dot
   separators, thin red rules — per the origins section design) ---------- */
.mini-ticker{background:var(--cream); overflow:hidden; padding:5px 0; border-top:4px solid var(--red); border-bottom:4px solid var(--red);}
/* Spacing lives on the items (margin-right), NOT on the container as
   flex gap — flex gap doesn't exist across the loop seam, which is
   what made the chain visibly "break" every cycle. With per-item
   margins the -50% marquee wraps with identical spacing throughout. */
/* 32s (was 16s) — the track is now twice as long, so doubling the
   duration keeps the visual speed identical. */
.mini-ticker-track{display:flex; width:max-content; animation:marquee 32s linear infinite; align-items:center;}
.mini-ticker-track span{font-size:clamp(14px,1.45vw,23px); font-weight:800; letter-spacing:.02em; color:var(--red); white-space:nowrap; text-transform:uppercase; margin-right:74px;}
.tick-dot{width:clamp(17px,1.55vw,28px); height:clamp(17px,1.55vw,28px); flex:none; margin-right:74px; animation:spin 5s linear infinite;}
/* Second instance of the ticker, sitting under the DIPPER teaser.
   Same construction, just given breathing room above and below so it
   reads as a divider between the case study and the footer. */
/* Flush against the DIPPER block below it: no bottom margin, and the
   generator section above closes its own trailing padding so the strip
   reads as the lid of the case-study block rather than floating in
   cream. */
.dipper-ticker{margin-top:0; margin-bottom:0;}

/* ---------- LOADING-BAR SLIDESHOW ----------
   Tall section per the design. Left column is a thick RED track; the
   GREEN fill rises from the bottom over the full 8s slide cycle,
   progressively covering the red, then — instead of fading — drops
   quickly back to the bottom in the last ~3% of the cycle and starts
   climbing again for the next slide. */
/* All strokes in this section are the site pink (var(--red)) at the
   uniform 4px weight — no black rules. */
.slideshow{position:relative; display:flex; height:clamp(500px,78vh,850px); border-bottom:4px solid var(--red); border-right:4px solid var(--red);}
/* No top/bottom border on the bar itself — the ticker's 4px rule above
   and the slideshow's 4px rule below already draw those lines, and the
   bar's own top border was what stopped the green fill 4px short of
   the video box's top edge (a child can't paint over its parent's
   border). Sides keep the 4px stroke. */
.loading-bar{width:clamp(40px,4.2vw,68px); flex:none; background:var(--red); position:relative; overflow:hidden; border-left:4px solid var(--red); border-right:4px solid var(--red);}
/* Fill: climbs from the bottom to the top over ~7s, then WIPES itself
   away from the bottom — the bottom edge sweeps up to the top (bottom
   0 -> 100% while height 100% -> 0, so the top edge stays pinned at
   the top) — and the cycle restarts. Like the reference video. */
.loading-bar-fill{position:absolute; bottom:0; left:0; width:100%; height:0%; background:var(--yellow); animation:fillBar 8s linear infinite;}
/* wipe compressed into the last 5% of the cycle (~0.4s) — much faster
   sweep than the climb. */
@keyframes fillBar{
  0%{bottom:0; height:0%;}
  95%{bottom:0; height:100%;}
  100%{bottom:100%; height:0%;}
}
.slideshow-frame{position:relative; flex:1; overflow:hidden;}
.slide{position:absolute; inset:0; opacity:0; transition:opacity 1s ease;}
.slide.active{opacity:1; position:relative;}
/* One photograph per slide, cropped to fill the frame whatever its own
   proportions are. Works for both the <img> and the placeholder div. */
.slide-media{width:100%; height:100%; display:block; object-fit:cover;}
.slide-media.ph{display:flex; align-items:center; justify-content:center;}
/* Caption band: full-bleed edge to edge, thicker red patch, big white
   uppercase Poppins-bold line at left + Hindi pairing at right. */
/* align-items:flex-start + reduced top padding = text sits toward the
   TOP of the red patch, not vertically centred in it. */
/* Height is LOCKED here too. The five slides carry captions of very
   different lengths, so this red band used to grow and shrink on every
   slide change and shove the whole page up and down. min-height clears
   the longest EN + HI pair; shorter captions just leave empty red. */
.caption-band{background:var(--red); color:#fff; display:flex; justify-content:space-between; align-items:flex-start; gap:24px; padding:30px 70px 56px; flex-wrap:wrap; min-height:300px; transition:background .4s ease;}
.caption-band p{font-family:var(--font-body); font-weight:700; text-transform:uppercase; font-size:clamp(18px,1.95vw,32px); line-height:1.4; max-width:52ch; transition:opacity .3s ease;}
/* JS adds .is-swapping for ~320ms so the words fade rather than snap
   while the picture behind them crossfades */
.caption-band.is-swapping p{opacity:0;}
.caption-band .native{font-size:clamp(13px,1.2vw,19px); font-weight:700; text-transform:none; opacity:.95; max-width:none;}
@media(max-width:900px){.caption-band{padding:26px 24px; min-height:230px;}}

/* ---------- SECTION TITLE (small eyebrow-style marker used above the
   truck-showcase and core-elements sections to actually name them) ---------- */
.section-head{padding:70px 70px 0;}
.section-title{
  display:block; margin:0;
  font-family:'Truck Sans', var(--font-display); font-weight:400;
  font-size:clamp(40px,5.6vw,88px); letter-spacing:-.055em; line-height:1;
  text-transform:uppercase; color:var(--green); transition:color .4s ease;
}
.section-sub{
  font-family:var(--font-body); font-weight:500;
  font-size:clamp(14px,1.35vw,19px); line-height:1.55; letter-spacing:0;
  max-width:62ch; margin-top:16px; color:#1e5691;
}
@media(max-width:900px){
  .section-head{padding:50px 24px 0;}
  .section-title{font-size:clamp(30px,8vw,44px);}
  .section-sub{margin-top:12px;}
}

/* ---------- TRUCK ANATOMY ----------
   Two-column: big illustration left, sticky detail panel right, view
   toggle beneath. Only one .tv is visible at a time; the toggle
   crossfades between them. Every .spot is a magnifier marker whose
   data-* attributes feed the panel — the panel image is the same PNG
   shown magnified via background-position, so no crop files exist to
   fall out of sync with the artwork. */
.anatomy{padding:30px 70px 90px;}
.anatomy-body{display:grid; grid-template-columns:1fr 340px; gap:46px; align-items:start;}

.anatomy-stage{position:relative; min-height:clamp(320px,38vw,540px);}
.tv{position:absolute; inset:0; opacity:0; visibility:hidden; transition:opacity .5s ease;
    display:flex; align-items:center; justify-content:center;}
.tv.is-active{opacity:1; visibility:visible; position:relative;}
.tv img{width:100%; height:auto; display:block; object-fit:contain;
        animation:truckPop .7s cubic-bezier(.34,1.56,.64,1);}
.tv[data-view="back"] img{max-width:62%; margin:0 auto;}   /* back view is near-square */
@keyframes truckPop{0%{transform:scale(.95);} 60%{transform:scale(1.02);} 100%{transform:scale(1);}}

/* --- MAGNIFYING-GLASS CURSOR ---
   A real loupe: the lens is a circle following the pointer, filled
   with the same truck PNG scaled up and offset so the magnified
   region matches exactly what sits under the glass. The default
   cursor is hidden over the stage so the lens IS the cursor. */
.anatomy-stage{cursor:none;}
.lens{
  position:absolute; width:clamp(150px,15vw,220px); height:clamp(150px,15vw,220px);
  border-radius:50%; transform:translate(-50%,-50%); pointer-events:none; z-index:20;
  opacity:0; transition:opacity .18s ease, border-color .2s ease, box-shadow .2s ease;
  border:7px solid var(--ink); background-repeat:no-repeat; background-color:var(--cream);
  box-shadow:0 10px 30px rgba(0,0,0,.28), inset 0 0 0 2px rgba(255,255,255,.55);
}
/* no handle anymore — just the circular lens, so the cursor reads as a
   loupe/lens rather than a hardware magnifying glass */
.lens.is-visible{opacity:1;}
/* over a motif the glass gives a small, calm confirmation pulse — the
   real "this is clickable" feedback now lives on the zone's own
   numbered badge below, sized exactly to the hit region instead of the
   free-floating cursor. */
.lens.is-hot{border-color:var(--red); box-shadow:0 12px 34px rgba(0,0,0,.34), inset 0 0 0 3px rgba(255,255,255,.7);
             animation:lensThrob .6s ease-in-out infinite; cursor:pointer;}
@keyframes lensThrob{
  0%  {transform:translate(-50%,-50%) scale(1);}
  50% {transform:translate(-50%,-50%) scale(1.05);}
  100%{transform:translate(-50%,-50%) scale(1);}
}
/* invisible hit regions — outlines only appear while a motif is live,
   so the user gets confirmation of what the glass has locked onto.
   Numbered badges (added in the markup) sit permanently at each zone's
   corner so every hotspot is discoverable without hovering first. */
.zones{position:absolute; inset:0; pointer-events:none;}
.zone{position:absolute; border:2px dashed transparent; border-radius:6px; transition:border-color .25s ease;}
.zone.is-lit{border-color:rgba(254,44,90,.85);}
/* THE BACK-VIEW ALIGNMENT FIX.
   The back truck is rendered at max-width:62% and centred, but .zones is
   inset:0 against the full-width .tv, so every % was being measured
   against a box ~1.6x wider than the artwork. That is why the back
   pointers sat outside the truck entirely. 62% centred leaves 19% either
   side, so pulling .zones in by 19% makes the two boxes line up. */
.tv[data-view="back"] .zones{left:19%; right:19%;}
@media(max-width:1000px){.tv[data-view="back"] .zones{left:11%; right:11%;}}

/* Blinking pointer, centred on its zone. Replaces the numbered badges:
   a small dot that pulses slowly, plus a ring that expands out of it. */
.zone-dot{
  position:absolute; top:50%; left:50%; width:15px; height:15px; border-radius:50%;
  background:var(--c-yellow); border:2px solid var(--ink); z-index:6;
  transform:translate(-50%,-50%);
  box-shadow:0 3px 9px rgba(0,0,0,.28);
  animation:dotBlink 2.6s ease-in-out infinite;
}
.zone-dot::after{
  content:''; position:absolute; top:50%; left:50%; width:100%; height:100%;
  margin:-50% 0 0 -50%; border-radius:50%; border:2px solid var(--c-yellow);
  animation:dotHalo 2.6s ease-out infinite;
}
@keyframes dotBlink{
  0%,100%{opacity:1;}
  50%    {opacity:.32;}
}
@keyframes dotHalo{
  0%  {transform:scale(.7); opacity:.85;}
  70% {transform:scale(2.6); opacity:0;}
  100%{transform:scale(2.6); opacity:0;}
}
/* locked on: stop the blink, go solid pink so it reads as "click me" */
.zone.is-lit .zone-dot{
  animation:none; opacity:1; background:var(--red);
  transform:translate(-50%,-50%) scale(1.35);
}
.zone.is-lit .zone-dot::after{animation:none; opacity:0;}
@media(prefers-reduced-motion:reduce){
  .zone-dot{animation:none;} .zone-dot::after{animation:none; opacity:0;}
}
@media(max-width:1000px){.zone-dot{width:13px; height:13px;}}

/* --- detail panel --- */
/* Height is LOCKED. Previously the panel resized on every hotspot
   because each motif's copy is a different length, so the pink box
   jumped taller/shorter as you moved the lens around. min-height is
   set to comfortably clear the longest copy in the set, and the copy
   is pinned to the top of the leftover space, so the box now stays
   exactly one size no matter which element is selected. */
.anatomy-panel{
  background:var(--red); padding:14px 14px 22px; position:sticky; top:110px;
  /* 520px = image (267) + title block (46) + padding (36) + room for the
     longest copy in the set (197 chars ≈ 6 lines ≈ 138px), plus a line
     of slack. Measured at 1440px, which is the worst case — the panel
     is a fixed 340px wide and the type only gets smaller below that. */
  min-height:520px; display:flex; flex-direction:column;
}
/* Now shows your real per-element crops from assets/img/truck side and
   truck back, so the chosen motif sits centred and in focus instead of a
   magnified slice of the whole truck with its neighbours crowding in.
   `contain` guarantees nothing is cropped off the edges of your export. */
.panel-img{
  width:100%; flex:none; aspect-ratio:998/854; background:var(--cream);
  background-repeat:no-repeat; background-size:contain; background-position:50% 50%;
  transition:opacity .25s ease;
}
.panel-title{font-family:var(--font-body); font-weight:800; text-transform:uppercase;
             font-size:clamp(13px,1.15vw,17px); letter-spacing:.05em; color:#fff; margin:18px 6px 8px;}
.panel-copy{font-family:var(--font-body); font-weight:500; font-size:clamp(12px,1vw,14.5px);
            line-height:1.6; color:#fff; opacity:.95; margin:0 6px;}
/* Air Horn play button. margin-top:auto drops it to the bottom of the
   panel's leftover space, so revealing it never changes the panel's
   locked height. Carries .nav-pill for the usual widen-and-spin. */
.panel-horn{
  margin:auto 6px 0; align-self:flex-start;
  display:inline-flex; align-items:center; justify-content:center;
  padding:12px 24px; background:var(--cream); border:1px solid var(--cream);
  color:var(--red); font-family:var(--font-body); font-weight:800;
  font-size:12px; letter-spacing:.06em; text-transform:uppercase;
}
.panel-horn[hidden]{display:none;}
.panel-horn:hover, .panel-horn:focus-visible{background:var(--cream); color:var(--red);}
.panel-horn .orb::before{filter:none;}   /* the star-dot's own pink reads on cream */
/* while a clip is actually sounding */
.panel-horn.is-sounding{animation:hornKick .34s ease-in-out infinite;}
@keyframes hornKick{0%,100%{transform:scale(1);} 50%{transform:scale(1.05);}}

/* --- view toggle --- */
.anatomy-toggle{display:flex; justify-content:center; gap:18px; margin-top:44px;
                padding-right:386px;}   /* optically centres under the truck, not the whole grid */
.view-btn{
  padding:15px 34px; border:2px solid var(--red); background:transparent; color:var(--red);
  font-family:var(--font-body); font-weight:700; font-size:clamp(12px,1.05vw,15px);
  letter-spacing:.08em; text-transform:uppercase; transition:.25s ease;
}
.view-btn:hover{background:rgba(254,44,90,.1);}
.view-btn.is-on{background:var(--red); color:#fff;}

@media(max-width:1000px){
  .anatomy{padding:20px 24px 60px;}
  .anatomy-body{grid-template-columns:1fr; gap:28px;}
  .anatomy-panel{position:static; min-height:0;}
  .anatomy-toggle{padding-right:0; margin-top:28px; gap:12px;}
  .view-btn{padding:12px 22px;}
  .tv[data-view="back"] img{max-width:78%;}
}

/* ---------- NAV PILL (shared hover/click orb effect) ----------
   Used on the header GENERATOR cta, the three hero mini-swatches
   (ORIGINS / TRUCK ANATOMY / VISUAL ELEMENTS) and the SIDE VIEW /
   BACK VIEW toggle. On hover (or while a toggle is the active state,
   via .is-on) the pill widens from both sides and a small star-dot
   shape — masked to solid yellow so it reads the same regardless of
   the source PNG's own colour, same shape as the mini-ticker's
   spinning dot — spins in from the left and right edges and keeps
   spinning continuously while the pill stays expanded. Declared here,
   after .header-cta / .mini-swatch / .view-btn, so its `transition`
   and hover rules win the cascade on elements carrying both classes. */
.nav-pill{
  position:relative; overflow:hidden;
  transition:padding .35s cubic-bezier(.34,1.2,.4,1), background-color .25s ease,
             color .25s ease, border-color .25s ease, letter-spacing .35s ease;
}
/* Orb = an outer span that handles the slide-in (transition) wrapping an
   inner ::before that handles the endless spin (animation). They must be
   separate elements: an animation on `transform` completely overrides any
   transitioned `transform` on the same element, which is what stopped the
   previous version from ever sliding in. */
.nav-pill .orb{
  position:absolute; top:50%; width:17px; height:17px; margin-top:-8.5px;
  opacity:0; pointer-events:none; z-index:1;
  transition:opacity .28s ease, transform .38s cubic-bezier(.34,1.5,.5,1);
}
/* star-dot.png as a background-image (NOT as a mask — a PNG mask renders
   nothing here, which is what made these invisible the first time). The
   file is pink, so it gets inverted to white/cream wherever it sits on a
   dark or coloured button, and left alone on cream. */
.nav-pill .orb::before{
  content:''; position:absolute; inset:0;
  background:url('../assets/img/star-dot.png') center/contain no-repeat;
  animation:spin 1.5s linear infinite;
}
.header-cta .orb::before{filter:brightness(0) invert(1);}
.nav-pill .orb-l{left:14px; transform:translateX(-14px) scale(.4);}
.nav-pill .orb-r{right:14px; transform:translateX(14px) scale(.4);}
.nav-pill:hover, .nav-pill:focus-visible, .nav-pill.is-on{
  padding-left:3em; padding-right:3em; letter-spacing:.08em;
}
.nav-pill:hover .orb, .nav-pill:focus-visible .orb, .nav-pill.is-on .orb{
  opacity:1; transform:translateX(0) scale(1);
}
/* the view toggle sits on cream — star-dot's own pink reads correctly on
   the unfilled button, and inverts to white once the button turns solid */
.view-btn.is-on .orb::before{filter:brightness(0) invert(1);}

/* ---------- SWATCH BURST (ORIGINS / TRUCK ANATOMY / VISUAL ELEMENTS) ----------
   Different treatment from .nav-pill on purpose — these are the bigger
   landscape boxes, matching "LE RESTAURANT / LE MENU / LA BOUTIQUE" in
   the reference: on hover the whole box fills edge-to-edge with a
   rotating sunburst (thin bright spokes over blue, same conic-gradient
   technique as the hero) and a small star-dot icon springs in at the
   centre, instead of small orbs at the sides. */
.swatch-burst{position:relative; overflow:hidden; transition:border-color .3s ease;}
/* The burst spins CONTINUOUSLY — `spin` is a pure rotate keyframe, unlike
   `sunTurn` which also carries the hero's translate(-50%,-50%) and was
   dragging the whole gradient off to one corner. Hover only fades it in;
   the rotation never stops, so it reads exactly like the hero background. */
/* MUST be a SQUARE, and big enough that its own corners never enter the
   box while it turns. A 230%x230% box is a rectangle — rotating it swept
   a visible diagonal edge across the button, which is the "edges moving
   here and there" you saw. A fixed 760px square is larger than any of
   these buttons' diagonals at every breakpoint, so only the middle of
   the gradient is ever on screen and the spin looks perfectly fixed.
   Centred with margin, not translate, so nothing competes with the
   rotate animation on `transform`. */
.swatch-burst-bg{
  position:absolute; top:50%; left:50%; width:760px; height:760px;
  margin:-380px 0 0 -380px; z-index:0; pointer-events:none;
  background:repeating-conic-gradient(from 0deg,
    var(--c-blue) 0deg 2.6deg, var(--c-offwhite) 2.6deg 4deg);
  opacity:0; transition:opacity .38s ease;
  animation:spin 40s linear infinite;
}
.swatch-burst:hover .swatch-burst-bg, .swatch-burst:focus-visible .swatch-burst-bg{opacity:1;}
@media(prefers-reduced-motion:reduce){.swatch-burst-bg{animation:none;}}
/* Solid blue pool behind the label so the text stays readable against the
   stripes — replaces the yellow star that used to sit here. */
.swatch-burst-glow{
  position:absolute; top:50%; left:50%; width:170%; height:210%;
  margin:-105% 0 0 -85%; z-index:1; pointer-events:none;
  background:radial-gradient(ellipse at center,
    var(--c-blue) 0%, var(--c-blue) 34%, rgba(24,56,186,0) 70%);
  opacity:0; transition:opacity .35s ease;
}
.swatch-burst:hover .swatch-burst-glow, .swatch-burst:focus-visible .swatch-burst-glow{opacity:1;}
.swatch-burst-label{position:relative; z-index:2; transition:color .3s ease;}
.swatch-burst:hover .swatch-burst-label, .swatch-burst:focus-visible .swatch-burst-label{color:#fff;}
.swatch-burst:hover, .swatch-burst:focus-visible{border-color:var(--blue);}

/* ---------- CORE VISUAL ELEMENTS GRID ----------
   Rebuilt to match your Illustrator board: 3x3, thin cream gutters
   between cards, portrait-ish cards. Three plain white cards carry a
   heading + description; the six coloured cards carry Hindi + English
   headings top-left, a star top-right, a full-width colour patch
   holding the artwork, and a caption pinned to the bottom.
   Icon cards are yellow with a blue patch, pattern cards are green
   with an orange patch. */
.card-grid{
  display:grid; grid-template-columns:repeat(3,1fr);
  gap:10px; background:var(--cream); padding:0;
  margin-top:56px;   /* breathing room under the section subhead */
}
@media(max-width:900px){.card-grid{margin-top:34px;}}
/* outer card keeps its original proportion — it was the inner colour
   patch that needed shortening, not the container */
.cve-card{
  position:relative; aspect-ratio:1/1.18; min-height:330px;
  display:flex; flex-direction:column;
}

/* --- plain description cards (ICONOGRAPHY / PATTERNS / TYPOGRAPHY) --- */
.cve-text{
  background:#fff; padding:30px 28px;
  justify-content:flex-start; gap:14px;
}
.cve-text h6{
  font-family:var(--font-body); font-weight:700; color:var(--ink);
  font-size:clamp(24px,2.45vw,36px); text-transform:uppercase;
  letter-spacing:-.015em; line-height:1.08;
}
.cve-text p{
  font-family:var(--font-body); font-weight:400; color:var(--ink);
  font-size:clamp(13px,1.12vw,16px); line-height:1.45;
}

/* --- coloured media cards --- */
.cve-media{perspective:1500px; outline:none;}
.cve-inner{
  position:relative; width:100%; height:100%;
  transition:transform .7s cubic-bezier(.4,.15,.2,1); transform-style:preserve-3d;
}
.cve-media:hover .cve-inner, .cve-media:focus-visible .cve-inner{transform:rotateY(180deg);}

.cve-front, .cve-back{
  position:absolute; inset:0;
  backface-visibility:hidden; -webkit-backface-visibility:hidden;
  display:flex; flex-direction:column;
}
.cve-front{padding:22px 20px 24px; gap:0;}
.is-icon    .cve-front{background:var(--c-yellow);}
.is-pattern .cve-front{background:var(--c-green);}

/* min-height locks the title block to the same depth on every card, so a
   one-line title (A MOTHERLY COW) and a two-line one (THE DAZZLING
   PEACOCK) still start their colour patch at exactly the same Y. That
   misalignment is what made the inner boxes look staggered. */
.cve-head{
  display:flex; align-items:flex-start; justify-content:space-between; gap:12px;
  flex:none; min-height:clamp(92px,9.2vw,126px);
}
.cve-titles{display:flex; flex-direction:column; gap:7px;}
/* Poppins SemiBold for the Devanagari line, Bold for the English —
   Poppins ships no Devanagari glyphs, so the Hindi falls back to the
   system Indic face at weight 600. See the note in the handover. */
.cve-titles .native{
  font-family:var(--font-body); font-weight:600; color:#fff;
  font-size:clamp(20px,2vw,29px); line-height:1.2;
}
.cve-titles h5{
  font-family:var(--font-body); font-weight:700; color:#fff;
  font-size:clamp(24px,2.45vw,36px); text-transform:uppercase;
  line-height:1.08; letter-spacing:-.012em;
}
/* star-dot.png, inverted to white to sit on the coloured cards, turning
   slowly — same asset as the ticker dots and the CTA button orbs */
.star{
  width:26px; height:26px; flex:none;
  background:url('../assets/img/star-dot.png') center/contain no-repeat;
  filter:brightness(0) invert(1);
  animation:spin 7s linear infinite;
}
@media(prefers-reduced-motion:reduce){.star{animation:none;}}

/* the colour patch sitting behind the artwork */
/* SHORTER than before (was flex:1, filling all leftover space). Fixed
   proportional height so the blue/orange box is a wide rectangle rather
   than a tall one — width is untouched. */
.patch{
  flex:none; height:48%; margin:22px 0 0;
  display:flex; align-items:center; justify-content:center;
  font-family:var(--font-body); font-weight:600; font-size:12px;
  letter-spacing:.04em; text-transform:uppercase; color:rgba(255,255,255,.85);
  text-align:center; padding:10px;
}
.is-icon    .patch{background:var(--c-blue);}
.is-pattern .patch{background:var(--c-orange);}
/* Your real Illustrator artwork. object-fit:contain + explicit box is
   needed because the global `img` rule is width:100%/height:100%/cover,
   which would crop these square PNGs to fill the patch. */
.patch .motif{width:82%; height:82%; object-fit:contain;}
.patch .icon{width:46%; height:auto; aspect-ratio:1/1; max-height:76%;}
/* The two PATTERN artworks are long horizontal strips, not squares —
   meenakari.png is 4913x789 (6.2:1) and nazar battu.png is 2520x860
   (2.9:1). Fitting those into the square 82% box the icons use would
   shrink them to a hairline, so they run nearly the full width instead
   and take their height from their own ratio, which is how a painted
   border band reads on the truck anyway. */
.patch.is-strip{padding:10px 6px;}
.patch.is-strip .motif{width:96%; height:auto; max-height:88%; object-fit:contain;}

/* max-width lets a long caption wrap onto a second line instead of
   running the full width and sitting hard against the card's edge */
.cap{
  margin-top:auto; padding-top:14px; max-width:88%;
  font-family:var(--font-body); font-weight:700; color:#fff;
  font-size:clamp(10.5px,.94vw,13px); line-height:1.4;
  text-transform:uppercase; letter-spacing:.02em;
}

/* --- flipped face: rotating sunburst + orange info panel (img 7) --- */
.cve-back{transform:rotateY(180deg); overflow:hidden; background:var(--c-blue);}
/* `spin` is a pure rotate. The hero's `sunTurn` also carries
   translate(-50%,-50%), which is what was dragging this burst off to
   the top-left corner instead of radiating from the centre. */
/* square + oversized for the same reason as .swatch-burst-bg — a
   rectangle would sweep its own corners across the card as it turns */
.back-sun{
  position:absolute; top:50%; left:50%; width:1100px; height:1100px;
  margin:-550px 0 0 -550px; pointer-events:none;
  background:repeating-conic-gradient(from 0deg,
    var(--c-offwhite) 0deg 1.4deg, var(--c-blue) 1.4deg 4deg);
  animation:spin 46s linear infinite;
}
@media(prefers-reduced-motion:reduce){.back-sun{animation:none;}}
.back-panel{
  position:absolute; inset:34px 30px; z-index:1;
  background:var(--c-orange); color:#fff;
  padding:26px 24px 30px; display:flex; flex-direction:column; gap:4px;
}
.back-panel .native{
  font-family:var(--font-body); font-weight:600; color:#fff;
  font-size:clamp(16px,1.6vw,23px); line-height:1.3;
}
.back-panel h6{
  font-family:var(--font-body); font-weight:700; color:#fff;
  font-size:clamp(19px,1.92vw,28px); text-transform:uppercase;
  line-height:1.1; margin-bottom:8px;
}
.back-panel p{
  font-family:var(--font-body); font-weight:500; color:#fff;
  font-size:clamp(11px,.96vw,13.5px); line-height:1.45;
}
.back-panel .star{position:absolute; right:16px; top:16px; width:22px; height:22px;}

/* footer of the flipped card: artwork patch on the LEFT, download button
   on the RIGHT, sitting on a shared baseline (per the reference) */
.back-foot{
  margin-top:auto; padding-top:16px;
  display:flex; align-items:flex-end; justify-content:space-between; gap:14px;
}
.back-thumb{
  flex:none; width:46%; aspect-ratio:4/3; background:var(--c-blue);
  display:flex; align-items:center; justify-content:center; padding:8px;
}
.back-thumb img{width:100%; height:100%; object-fit:contain;}
.back-thumb.is-empty{
  font-family:var(--font-body); font-size:9.5px; font-weight:700;
  letter-spacing:.04em; text-transform:uppercase; color:rgba(255,255,255,.75);
  background:rgba(0,0,0,.16);
}
/* .dl-btn also carries .nav-pill, so it inherits the widen + spinning
   star-dot behaviour of the hero GENERATOR button. It keeps its pink at
   every state — no black on hover or click. */
.dl-btn{
  flex:none;
  display:inline-flex; align-items:center; justify-content:center;
  padding:11px 15px; background:var(--red); color:#fff; border:1px solid var(--red);
  font-family:var(--font-body); font-weight:700; font-size:9.5px;
  letter-spacing:.06em; text-transform:uppercase; white-space:nowrap;
}
.dl-btn:hover, .dl-btn:focus-visible, .dl-btn:active{background:var(--red); border-color:var(--red); color:#fff;}
/* smaller expansion + smaller, further-inset orbs than the default
   .nav-pill, so the stars never ride over the label on this small button */
.dl-btn:hover, .dl-btn:focus-visible{padding-left:2.9em; padding-right:2.9em;}
.dl-btn .orb{width:12px; height:12px; margin-top:-6px;}
.dl-btn .orb-l{left:8px;} .dl-btn .orb-r{right:8px;}
.dl-btn .orb::before{filter:brightness(0) invert(1);}
.dl-btn.is-disabled{
  background:rgba(0,0,0,.2); border-color:transparent; color:rgba(255,255,255,.7);
  cursor:default; pointer-events:none; font-size:9.5px;
}

@media(max-width:900px){
  .card-grid{grid-template-columns:1fr;}
  .cve-card{aspect-ratio:auto; min-height:360px;}
  .back-panel{inset:24px 20px; padding:20px 18px 24px;}
  .back-thumb{width:52px; height:52px;}
}

/* ---------- TYPE SPECIMEN BAND ----------
   Reference layout: heading top-left, a short note top-right, the
   wordmark set enormous across the full width beneath them, and the
   download button pinned bottom-right. */
/* margin-top separates the pink band from the Core Visual Elements grid
   above it — they were butting straight up against each other */
.specimen-band{background:var(--red); margin-top:90px; padding:58px 0 46px; transition:background .4s ease;}
.specimen-inner{display:flex; flex-direction:column; gap:6px;}
@media(max-width:900px){.specimen-band{margin-top:54px;}}
.specimen-top{
  display:flex; justify-content:space-between; align-items:flex-start;
  gap:40px; flex-wrap:wrap;
}
.specimen-copy{
  font-family:var(--font-body); font-weight:700; color:var(--cream);
  font-size:clamp(15px,1.35vw,20px); text-transform:uppercase;
  line-height:1.25; letter-spacing:.01em;
}
.specimen-note{
  font-family:var(--font-body); font-weight:700; color:var(--cream);
  font-size:clamp(9.5px,.82vw,11.5px); line-height:1.5;
  text-transform:uppercase; letter-spacing:.03em;
  max-width:44ch; text-align:left; opacity:.92;
}
.specimen-text{
  display:block; width:100%; text-align:center;
  font-size:clamp(48px,11.4vw,168px); color:#f3d9a5;
  text-transform:uppercase; line-height:.94; letter-spacing:-.01em;
  margin:42px 0 4px;   /* clears the note block sitting top-right */
}
.tag-btn{display:inline-block; padding:11px 18px; background:var(--yellow); color:var(--ink); font-size:11px; font-weight:700; letter-spacing:.06em; transition:background .4s ease;}
/* same pill + spinning star-dot as the hero GENERATOR button, sized to
   match it (13px type, 12px/26px padding) */
/* yellow on the pink band so the button actually separates from its
   background; label and star-dot both pink. star-dot.png is natively
   #fe2c5a, so it needs no filter here — just cancel the white invert
   inherited from .dl-btn. */
.download-btn{
  /* centred in the band rather than pushed to the right edge. The parent
     .specimen-inner is a flex column, so align-self is what positions it
     across the section, and margin-top opens a gap under the specimen. */
  align-self:center; margin-top:26px;
  font-size:13px; padding:12px 26px; letter-spacing:.04em;
  background:var(--c-yellow); border:1px solid var(--c-yellow); color:var(--red);
}
.download-btn:hover, .download-btn:focus-visible, .download-btn:active{
  background:var(--c-yellow); border-color:var(--c-yellow); color:var(--red);
  padding-left:3em; padding-right:3em;
}
.download-btn .orb{width:16px; height:16px; margin-top:-8px;}
.download-btn .orb-l{left:12px;} .download-btn .orb-r{right:12px;}
.download-btn .orb::before{filter:none;}
@media(max-width:900px){
  .specimen-top{flex-direction:column; gap:14px;}
  .specimen-note{max-width:none;}
  .download-btn{align-self:center; margin-top:18px;}
}

/* ---------- TYPE TESTER + TYPE PREVIEW (continue the red band) ---------- */
.type-lab, .type-preview{background:var(--red); transition:background .4s ease;}
.type-lab{padding:20px 0 46px;}
.lab-inner{
  display:grid; grid-template-columns:270px 1fr; gap:48px; align-items:start;
  border-top:2px solid rgba(255,246,226,.28); padding-top:38px;
}
.lab-controls{display:flex; flex-direction:column; gap:24px;}
.lab-field{display:flex; flex-direction:column; gap:10px;}
.lab-field label{
  font-family:var(--font-body); font-weight:700; color:var(--cream);
  font-size:12px; letter-spacing:.05em; text-transform:uppercase;
  display:flex; justify-content:space-between; align-items:center; gap:10px;
}
.lab-val{font-weight:600; opacity:.8; letter-spacing:.02em;}
/* range styled on both engines so the track reads on the pink */
.lab-field input[type=range], .prev-size input[type=range]{
  -webkit-appearance:none; appearance:none; width:100%; height:4px;
  background:rgba(255,246,226,.35); border-radius:99px; outline:none; cursor:pointer;
}
.lab-field input[type=range]::-webkit-slider-thumb,
.prev-size input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none; appearance:none; width:18px; height:18px; border-radius:50%;
  background:var(--cream); border:3px solid var(--c-blue); cursor:grab;
}
.lab-field input[type=range]::-moz-range-thumb,
.prev-size input[type=range]::-moz-range-thumb{
  width:18px; height:18px; border-radius:50%; background:var(--cream);
  border:3px solid var(--c-blue); cursor:grab;
}
.lab-swatches{display:flex; align-items:center; gap:9px; flex-wrap:wrap;}
.lab-sw{
  width:28px; height:28px; border-radius:50%; background:var(--sw);
  border:2px solid rgba(255,246,226,.6); padding:0; transition:transform .18s ease, border-color .18s ease;
}
.lab-sw:hover{transform:scale(1.12);}
.lab-sw.is-on{border-color:var(--ink); transform:scale(1.12);}
.lab-swatches input[type=color]{
  width:32px; height:28px; padding:0; border:2px solid rgba(255,246,226,.6);
  background:none; cursor:pointer;
}
.lab-hint{
  font-family:var(--font-body); font-size:11.5px; color:var(--cream);
  letter-spacing:.04em; text-transform:uppercase; opacity:.85;
}
.lab-hint strong{font-weight:800;}

.lab-preview{display:flex; flex-direction:column; gap:26px; min-width:0;}
.lab-target{
  color:var(--cream); outline:none; cursor:text; word-wrap:break-word;
  border-left:4px solid transparent; padding-left:18px;
  transition:border-color .25s ease, background .25s ease;
}
.lab-target:hover{background:rgba(255,246,226,.07);}
.lab-target.is-selected{border-left-color:var(--cream); background:rgba(255,246,226,.09);}
h3.lab-target{font-size:48px; line-height:1.15; font-weight:400;}
p.lab-target{font-size:19px; line-height:1.5; font-weight:500; font-family:var(--font-body);}

.type-preview{padding:0 0 70px;}
.prev-inner{border-top:2px solid rgba(255,246,226,.28); padding-top:34px;}
.prev-bar{display:flex; align-items:center; gap:24px; flex-wrap:wrap;}
.prev-input{
  flex:1; min-width:240px; padding:16px 22px; border-radius:99px;
  border:2px solid rgba(255,246,226,.55); background:transparent; color:var(--cream);
  font-family:var(--font-body); font-size:14px; font-weight:600; outline:none;
}
.prev-input::placeholder{color:rgba(255,246,226,.6);}
.prev-input:focus{border-color:var(--cream);}
.prev-size{display:flex; align-items:center; gap:14px; min-width:280px;}
.prev-size-val{
  flex:none; padding:9px 14px; background:rgba(0,0,0,.22); color:var(--cream);
  font-family:var(--font-body); font-size:12px; font-weight:700; letter-spacing:.04em;
}
.prev-display{
  margin-top:34px; color:var(--cream); font-size:96px; line-height:1.05;
  word-wrap:break-word; overflow-wrap:anywhere;
}
@media(max-width:900px){
  .lab-inner{grid-template-columns:1fr; gap:30px;}
  h3.lab-target{font-size:34px;}
  .prev-size{min-width:0; width:100%;}
  .prev-display{font-size:56px; margin-top:24px;}
}

/* ---------- WORDMARK + BADGE ---------- */
.wordmark-section{padding:70px 0; display:flex; align-items:center; justify-content:center; gap:40px; flex-wrap:wrap; text-align:center;}
.wordmark-section .word{font-family:var(--font-display); color:var(--red); font-size:clamp(46px,9vw,110px); text-transform:uppercase; line-height:.95; transition:color .4s ease;}
/* The badge is now two stacked images, not a drawn ring: the square
   radial burst spins underneath (same `spin` keyframe the ticker stars
   and CTA orbs use, so the whole site turns at one visual language) and
   the OK logo is pinned dead centre on top, completely still. No border,
   no ::after ring — the artwork carries its own edge. */
.badge{width:230px; height:230px; position:relative; flex:none; display:grid; place-items:center;}
@keyframes spin{to{transform:rotate(360deg);}}
.badge-radial{
  position:absolute; inset:0; width:100%; height:100%; object-fit:contain;
  animation:spin 26s linear infinite;
}
/* OK logo 2 is 1362x795 (landscape), so it's width-driven with height
   auto — sized to ~46% of the burst so it sits inside the star's solid
   core rather than running over the points. */
.badge-logo{
  position:relative; z-index:2; width:46%; height:auto; object-fit:contain;
  filter:drop-shadow(0 2px 6px rgba(0,0,0,.22));
}
@media(prefers-reduced-motion:reduce){.badge-radial{animation:none;}}
@media(max-width:900px){.badge{width:170px; height:170px;}}

/* ---------- POLAROID MAKER ---------- */
.pg-section{padding-top:10px;}
/* 40px of trailing padding, not 90px — the BRAND / IDENTITY / PRINT
   strip now closes this section off, so the old deep gutter just left a
   dead cream band above it. */
.pg-layout{display:grid; grid-template-columns:370px 1fr; gap:48px; align-items:start; padding:20px 0 40px;}
.pg-controls{display:flex; flex-direction:column;}
.pg-stage{position:sticky; top:100px; display:flex; flex-direction:column; align-items:center; gap:14px;}
#polaroidCanvas{
  width:100%; max-width:520px; height:auto; background:#fbf3e0;
  box-shadow:0 26px 60px rgba(0,0,0,.22); cursor:pointer; touch-action:none;
}
#polaroidCanvas.is-dragging{cursor:grabbing;}
.pg-selected{
  font-family:var(--font-body); font-size:11.5px; letter-spacing:.03em;
  text-transform:uppercase; color:var(--blue); opacity:.8; text-align:center;
}
.pg-selected b{font-weight:800;}

/* stacked accordion body — the shared .swatch-row is a flex row, this
   turns it into a column for the taller polaroid control groups */
.pg-stack{flex-direction:column; align-items:stretch; gap:14px;}
.pg-row{display:flex; gap:8px; flex-wrap:wrap; align-items:center;}
.pg-motif-row .swatch{flex:1 1 auto;}
.pg-seg{display:flex; gap:6px; flex-wrap:wrap;}
.pg-seg .swatch.is-on{background:var(--ink); color:var(--cream);}
.pg-label{
  font-family:var(--font-body); font-size:10.5px; font-weight:700;
  letter-spacing:.07em; text-transform:uppercase; color:var(--green);
}
.pg-field{display:flex; flex-direction:column; gap:7px;}
.pg-field span{
  font-family:var(--font-body); font-size:10.5px; font-weight:700;
  letter-spacing:.06em; text-transform:uppercase; color:var(--ink); opacity:.75;
  display:flex; justify-content:space-between; gap:10px;
}
.pg-field b{font-weight:800; opacity:1; color:var(--blue);}
.pg-field input[type=range]{
  -webkit-appearance:none; appearance:none; width:100%; height:4px;
  background:rgba(26,26,26,.2); border-radius:99px; outline:none; cursor:pointer;
}
.pg-field input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none; appearance:none; width:17px; height:17px; border-radius:50%;
  background:var(--cream); border:3px solid var(--c-blue); cursor:grab;
}
.pg-field input[type=range]::-moz-range-thumb{
  width:17px; height:17px; border-radius:50%; background:var(--cream);
  border:3px solid var(--c-blue); cursor:grab;
}
.pg-chips{display:flex; flex-wrap:wrap; gap:7px;}
.pg-chip{
  width:26px; height:26px; border-radius:50%; background:var(--chip);
  border:2px solid rgba(26,26,26,.25); padding:0; cursor:pointer;
  transition:transform .16s ease, border-color .16s ease;
}
.pg-chip:hover{transform:scale(1.14);}
.pg-chip.is-on{border-color:var(--ink); transform:scale(1.16);}
.pg-check{
  display:flex; align-items:center; gap:9px;
  font-family:var(--font-body); font-size:11px; font-weight:700;
  letter-spacing:.04em; text-transform:uppercase; cursor:pointer;
}
.pg-check input{width:16px; height:16px; accent-color:var(--c-blue); cursor:pointer;}
.pg-hint{font-size:10.5px; line-height:1.5; opacity:.6;}
.pg-note{
  font-size:11px; line-height:1.55; color:var(--blue); font-weight:600;
  border-left:3px solid var(--red); padding-left:11px;
}
/* the "as drawn" chip keeps the artwork's own colours */
.pg-chip[data-colour="original"]{
  width:auto; min-width:46px; height:26px; border-radius:13px;
  background:repeating-linear-gradient(45deg,#fff 0 5px,#e6ddc8 5px 10px);
  display:flex; align-items:center; justify-content:center;
}
.pg-chip[data-colour="original"] span{
  font-family:var(--font-body); font-size:6.5px; font-weight:800;
  line-height:1.05; letter-spacing:.02em; color:var(--ink); text-align:center;
}
.pg-mail{padding-top:22px; display:flex; flex-direction:column; gap:9px;}
.pg-mail .text-input{flex:1; min-width:0;}
@media(max-width:1000px){
  .pg-layout{grid-template-columns:1fr; gap:32px;}
  .pg-stage{position:static;}
}

/* ---------- legacy generator layout (kept for the shared control CSS) ---------- */
.generator-layout{display:grid; grid-template-columns:340px 1fr; gap:40px; align-items:start; padding:20px 0 90px;}
.generator-controls{display:flex; flex-direction:column;}
.control-group{border-bottom:1px solid rgba(0,0,0,.15); padding:14px 0;}
.control-label.acc-toggle{
  display:flex; width:100%; justify-content:space-between; align-items:center;
  background:none; border:none; font-size:11.5px; font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; color:var(--green); padding:0 0 6px; transition:color .4s ease;
}
.control-label.acc-toggle::after{content:'+'; font-size:14px;}
.accordion.open .control-label.acc-toggle::after{content:'–';}
.accordion .swatch-row{display:none;}
.accordion.open .swatch-row{display:flex;}
.swatch-row{gap:8px; flex-wrap:wrap; padding-top:6px;}
.swatch{padding:9px 14px; border:2px solid var(--ink); background:var(--cream); font-size:11px; font-weight:700; letter-spacing:.03em; transition:.2s ease;}
.swatch:hover{background:rgba(0,0,0,.06);}
.swatch.active{background:var(--ink); color:var(--cream);}
.text-input{width:100%; padding:10px 12px; border:2px solid var(--ink); background:var(--cream); font-family:var(--font-body); font-size:13px;}
.upload-label{display:inline-block;}
.control-note{font-size:10px; opacity:.55; margin-top:8px; line-height:1.5;}
.generator-actions{display:flex; gap:10px; padding-top:16px;}
/* RANDOMISE + EXPORT PNG get the same widen + spinning star-dot as the hero
   GENERATOR button. .btn is inline-block, so it needs inline-flex here for the
   label to stay centred while the padding animates. Both buttons are filled at
   the moment the orbs appear (RANDOMISE is solid red, EXPORT turns blue on
   hover), so the star-dot is inverted to white in both cases. */
.generator-actions .btn.nav-pill{display:inline-flex; align-items:center; justify-content:center;}
.generator-actions .orb::before{filter:brightness(0) invert(1);}
.generator-preview{display:flex; align-items:center; justify-content:center; background:rgba(0,0,0,.03); border:2px solid var(--ink); padding:24px;}
#posterCanvas{width:100%; max-width:460px; height:auto; box-shadow:0 18px 40px rgba(0,0,0,.18);}
@media(max-width:900px){.generator-layout{grid-template-columns:1fr;}}

/* ---------- MARQUEE KEYFRAME ----------
   The PRODUCT/OUTPUT ROW, the EXPLORE INDIA marquee and the closing
   FOOTER PHOTO band were all removed from the page, so their rules are
   gone with them. This keyframe stays because .mini-ticker-track (the
   HISTORY AND ORIGINS strip and the new BRAND / IDENTITY / PRINT strip
   under DIPPER) still drives its scroll from it. */
@keyframes marquee{from{transform:translateX(0);} to{transform:translateX(-50%);}}

/* ---------- FOOTER ---------- */
.site-footer{padding:50px 0 30px; font-size:12px;}
.footer-info{text-align:center; line-height:1.8; font-size:13px; padding-bottom:22px;}
.footer-info strong{font-weight:700;}
/* LinkedIn + Portfolio. Both carry .nav-pill, so they inherit exactly
   the same widen-and-spin hover as the GENERATOR button in the header —
   .footer-cta only supplies the colours and the resting size. */
.footer-links{display:flex; justify-content:center; align-items:center; gap:18px; flex-wrap:wrap; padding-bottom:10px;}
.footer-cta{
  display:inline-flex; align-items:center; justify-content:center;
  padding:12px 26px; background:var(--red); color:var(--yellow); font-size:13px;
  font-weight:700; letter-spacing:.04em; border:1px solid var(--red);
  text-transform:uppercase;
}
.footer-cta:hover, .footer-cta:focus-visible, .footer-cta:active{
  background:var(--red); border-color:var(--red); color:var(--yellow);
}
.footer-cta .orb::before{filter:brightness(0) invert(1);}
@media(max-width:900px){.footer-cta{padding:10px 20px; font-size:11px;}}
/* .footer-nav and .footer-credit were removed from the markup — the
   fixed header already carries navigation, and the reference credit is
   gone. Their rules are deleted with them. */

section{scroll-margin-top:80px;}
/* ============================================================
   DIPPER — teaser strip
   Video is a true 2:1 file, so the media column is locked to that
   ratio and the blue panel simply matches its height.
   ============================================================ */
/* margin-top is 0 so the BRAND / IDENTITY / PRINT ticker directly above
   sits flush on top of this section, its bottom rule doubling as the
   dark block's top edge — no cream gap between the two. */
.dipper-teaser{
  display:grid; grid-template-columns:1fr 400px; align-items:stretch;
  margin-top:0; background:var(--ink);
}
.dt-media{position:relative; overflow:hidden;}
.dt-media video{width:100%; height:100%; object-fit:cover; display:block;}
.dt-panel{
  background:#2a3ec0; color:#fff; padding:44px 40px;
  display:flex; flex-direction:column; justify-content:center; gap:14px;
}
.dt-title{
  font-family:var(--font-body); font-weight:800; color:var(--c-yellow);
  font-size:clamp(34px,3.4vw,52px); line-height:1; letter-spacing:-.02em;
}
.dt-sub{
  font-family:var(--font-body); font-weight:700; color:var(--c-yellow);
  font-size:clamp(15px,1.5vw,22px); text-transform:uppercase; letter-spacing:.01em;
}
.dt-copy{
  font-family:var(--font-body); font-weight:500; color:#fff;
  font-size:clamp(12.5px,1.08vw,15.5px); line-height:1.6;
}
.dt-cta{
  align-self:flex-start; margin-top:10px;
  display:inline-flex; align-items:center; justify-content:center;
  padding:14px 30px; background:var(--c-yellow); border:1px solid var(--c-yellow);
  color:#2a3ec0; font-family:var(--font-body); font-weight:800; font-size:13px;
  letter-spacing:.06em; text-transform:uppercase;
}
.dt-cta:hover, .dt-cta:focus-visible, .dt-cta:active{
  background:var(--c-yellow); border-color:var(--c-yellow); color:#2a3ec0;
}
/* The star-dots on VIEW WORK now match the button's own text colour
   (#2a3ec0) instead of staying pink. star-dot-blue.png is the same
   artwork flooded with that blue — a real recoloured file rather than a
   CSS filter or mask, so it renders identically in every browser. */
.dt-cta .orb::before{
  filter:none;
  background-image:url('../assets/img/star-dot-blue.png');
}
@media(max-width:1000px){
  .dipper-teaser{grid-template-columns:1fr; margin-top:0;}
  .dt-panel{padding:32px 24px;}
}

/* ============================================================
   DIPPER — case study overlay (dark)
   Column width is shared by the copy blocks and the slides, so every
   left and right edge on the page lines up on one pair of margins.
   ============================================================ */
.dipper-case{
  --dc-bg:#0d0d0d; --dc-ink:#f2ede2; --dc-mute:#a5a096;
  --dc-accent:#f4c542; --dc-card:#171717; --dc-line:rgba(255,255,255,.12);
  --dc-col:1040px;
  position:fixed; inset:0; z-index:120; background:var(--dc-bg); color:var(--dc-ink);
  opacity:0; visibility:hidden; transition:opacity .4s ease, visibility .4s ease;
}
.dipper-case.is-open{opacity:1; visibility:visible;}
.dc-scroll{position:absolute; inset:44px 0 0; overflow-y:auto; -webkit-overflow-scrolling:touch;}

/* top bar, in the spirit of a file window */
.dc-bar{
  position:absolute; top:0; left:0; right:0; height:44px; z-index:3;
  display:flex; align-items:center; gap:12px; padding:0 16px;
  background:#000; border-bottom:1px solid var(--dc-line);
  font-family:var(--font-body); font-size:12px; letter-spacing:.02em;
}
.dc-dot{width:9px; height:9px; border-radius:50%; background:var(--dc-accent); flex:none;}
.dc-file{font-weight:700; color:var(--dc-ink);}
.dc-bar-meta{color:var(--dc-mute);}
.dc-close{
  margin-left:auto; background:transparent; border:1px solid var(--dc-line);
  color:var(--dc-ink); font-family:var(--font-body); font-size:12px; font-weight:600;
  padding:7px 14px; cursor:pointer; transition:background .2s ease, border-color .2s ease;
}
.dc-close:hover{background:var(--dc-accent); border-color:var(--dc-accent); color:#000;}

.dc-wrap{width:min(var(--dc-col), calc(100% - 44px)); margin:0 auto;}

/* ---------- header ---------- */
.dc-head{padding:76px 0 10px;}
.dc-project{
  font-family:var(--font-body); font-weight:700; color:var(--dc-accent);
  font-size:12px; letter-spacing:.22em; margin-bottom:16px;
}
.dc-head h1{
  font-family:var(--font-body); font-weight:800; color:var(--dc-ink);
  font-size:clamp(46px,6.6vw,96px); line-height:1; letter-spacing:-.03em;
}
.dc-kicker{
  font-family:var(--font-body); font-weight:700; color:var(--dc-ink);
  font-size:clamp(18px,2.1vw,30px); margin-top:14px;
}
.dc-tag{
  font-family:var(--font-body); font-style:italic; color:var(--dc-mute);
  font-size:clamp(13px,1.25vw,17px); margin-top:12px;
}
.dc-rule{border:0; border-top:1px solid var(--dc-line); margin:34px 0 26px;}
.dc-meta{display:grid; grid-template-columns:repeat(3,1fr); gap:26px;}
.dc-meta span{
  display:block; font-family:var(--font-body); font-weight:600; color:var(--dc-mute);
  font-size:11px; letter-spacing:.16em; margin-bottom:8px;
}
.dc-meta p{font-family:var(--font-body); font-size:clamp(13px,1.15vw,16px); color:var(--dc-ink);}
.dc-tools{display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-top:30px;}
.dc-tools-label{
  font-family:var(--font-body); font-weight:600; color:var(--dc-mute);
  font-size:11px; letter-spacing:.16em; margin-right:6px;
}
.dc-chip{
  font-family:var(--font-body); font-size:13px; font-weight:500; color:var(--dc-ink);
  border:1px solid var(--dc-line); border-radius:99px; padding:8px 16px; background:#131313;
}

/* ---------- section blocks ---------- */
.dc-h3{
  font-family:var(--font-body); font-weight:700; color:var(--dc-ink);
  font-size:clamp(20px,2.1vw,28px); margin-bottom:14px; letter-spacing:-.01em;
}
.dc-block{padding:54px 0 26px;}
.dc-block p{
  font-family:var(--font-body); font-weight:400; color:var(--dc-ink);
  font-size:clamp(13.5px,1.2vw,17px); line-height:1.62; max-width:88ch; margin-bottom:14px;
}
.dc-source{font-size:12.5px !important; color:var(--dc-mute) !important;}
.dc-source a{color:var(--dc-accent); text-decoration:underline;}

/* ---------- about cards ---------- */
.dc-about{padding:56px 0 12px;}
.dc-cards{display:grid; grid-template-columns:repeat(3,1fr); gap:18px;}
.dc-card{
  background:var(--dc-card); border-left:3px solid var(--dc-accent);
  padding:22px 20px 24px; position:relative;
}
.dc-card-tag{
  font-family:var(--font-body); font-weight:700; color:var(--dc-accent);
  font-size:10px; letter-spacing:.16em; margin-bottom:10px;
}
.dc-card h4{
  font-family:var(--font-body); font-weight:700; color:var(--dc-ink);
  font-size:clamp(15px,1.4vw,19px); margin-bottom:10px;
}
.dc-card p{
  font-family:var(--font-body); font-weight:400; color:var(--dc-mute);
  font-size:clamp(12.5px,1.05vw,14.5px); line-height:1.6;
}

/* ---------- slides ---------- */
/* ---------- MOODBOARD GRID (Process / Final Output) ----------
   A real CSS masonry-ish layout: a fixed 12px row rhythm with tiles
   spanning a number of rows, so images of different proportions pack
   together without gaps and without any JS. .wide doubles the column
   span, .tall doubles the row span. Tiles are square-ish by default. */
.dc-moodboard{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(210px, 1fr));
  grid-auto-rows:150px;
  gap:14px;
  padding:6px 0 40px;
}
/* PROCESS — six equal squares, three across on desktop. aspect-ratio
   drives the height so every tile matches regardless of what the source
   image's own proportions are; object-fit:cover crops to fill. */
.dc-moodboard.is-square{grid-template-columns:repeat(3, 1fr); grid-auto-rows:auto;}
.dc-moodboard.is-square .dc-tile{grid-row:auto; aspect-ratio:1/1;}
/* FINAL OUTPUT — four tall portraits in one row, matching the shots. */
.dc-moodboard.is-final{grid-template-columns:repeat(4, 1fr); grid-auto-rows:auto;}
.dc-moodboard.is-final .dc-tile{grid-row:auto; aspect-ratio:127/169;}
.dc-tile{
  grid-row:span 2; overflow:hidden; position:relative; background:#131313;
  border:1px solid var(--dc-line);
  transition:transform .32s cubic-bezier(.34,1.1,.4,1), border-color .32s ease;
}
.dc-tile.wide{grid-column:span 2;}
.dc-tile.tall{grid-row:span 3;}
.dc-tile img{width:100%; height:100%; object-fit:cover; display:block;}
.dc-tile:hover{transform:translateY(-4px) scale(1.012); border-color:var(--dc-accent); z-index:2;}
/* placeholder styling inside the dark overlay — the site-wide .ph is
   tuned for cream backgrounds and would glare here */
.dc-tile .ph{
  background:repeating-linear-gradient(135deg, rgba(255,255,255,.05) 0 14px, rgba(255,255,255,.015) 14px 28px);
  border:1px dashed rgba(255,255,255,.22); color:rgba(255,255,255,.42);
  height:100%; font-size:11px;
}
@media(max-width:900px){
  .dc-moodboard.is-square{grid-template-columns:repeat(2, 1fr);}
  .dc-moodboard.is-final{grid-template-columns:repeat(2, 1fr);}
}
@media(max-width:700px){
  .dc-moodboard{grid-template-columns:repeat(auto-fill, minmax(150px, 1fr)); grid-auto-rows:110px; gap:10px;}
  .dc-moodboard.is-square, .dc-moodboard.is-final{grid-auto-rows:auto; gap:10px;}
  .dc-tile.wide{grid-column:span 2;}
}

.dc-slide{width:min(var(--dc-col), calc(100% - 44px)); margin:0 auto 4px; position:relative;}
.dc-slide img, .dc-slide video{width:100%; height:auto; display:block;}
.dc-end{height:110px;}

/* Designed copy laid over the artboard's own empty space rather than
   sitting underneath it. Lighter weight and a wide measure so each of
   these runs to three lines. */
/* Poppins Regular, and a wide enough measure that each of these runs to
   three lines rather than five. 78ch was the constraint before, not the
   82% — at ~13px that capped the line at roughly 60 characters. */
.dc-cap{
  font-family:var(--font-body); font-weight:400; text-align:center;
  font-size:clamp(11px,1.02vw,15px); line-height:1.55;
  max-width:min(104ch, 92%); margin:0 auto;
}
.cap-over .dc-cap{position:absolute; left:50%; transform:translateX(-50%);}
.dc-slide.dark.cap-over .dc-cap{bottom:11%;}      /* clears the photos above it */
.dc-slide.cap-low.cap-over .dc-cap{bottom:6%;}    /* dieline: sits below the artwork */
.dc-slide.cap-light.cap-over .dc-cap{bottom:9%;}  /* cream artboard  */
.dc-cap-yellow{color:#f0bd3c;}
.dc-cap-red{color:#d9483d;}

@media(max-width:1000px){
  .dc-meta{grid-template-columns:1fr; gap:18px;}
  .dc-cards{grid-template-columns:1fr;}
  .dc-head{padding:54px 0 6px;}
  .dc-block{padding:38px 0 20px;}
  .dc-cap{font-size:10px; max-width:88%;}
  .dc-slide.dark.cap-over .dc-cap{bottom:9%;}
  .dc-slide.cap-low.cap-over .dc-cap{bottom:4%;}
  .dc-slide.cap-light.cap-over .dc-cap{bottom:6%;}
}

/* ============================================================
   CUSTOM CURSOR
   Two fixed layers drawn by js/script.js: a slowly spinning star-dot
   (the mark already used on every button orb and in the tickers) and a
   small solid dot pinned to the exact pointer position so precision is
   never lost.

   Everything hangs off .cur-on, which the script only adds when a fine
   pointer is present — no mouse, no class, and the system cursor stays.
   Text fields keep the I-beam, because losing it while typing is worse
   than any styling gain.
   ============================================================ */
html.cur-on, html.cur-on *{cursor:none !important;}
html.cur-on input[type="text"], html.cur-on input[type="email"],
html.cur-on input[type="number"], html.cur-on textarea,
html.cur-on [contenteditable="true"]{cursor:text !important;}

.cur-star, .cur-dot{
  position:fixed; left:0; top:0; z-index:9999; pointer-events:none;
  will-change:transform;
}
/* The star artwork lives ONLY on the ::before. It has to: JS writes the
   follow position to .cur-star's own transform every frame, and an
   `animation` on transform always beats a scripted one on the same
   element — so the spin has to sit on a separate inner layer. If the
   image were on both, you would see one spinning copy and one static
   copy stacked on top of each other. */
.cur-star{
  width:30px; height:30px; background:none;
  transition:width .2s ease, height .2s ease, opacity .2s ease;
}
.cur-star::before{
  content:''; position:absolute; inset:0;
  background:url('../assets/img/star-dot.png') center/contain no-repeat;
  animation:spin 3.6s linear infinite;
}
.cur-dot{
  width:7px; height:7px; border-radius:50%;
  background:var(--cream); box-shadow:0 0 0 1.5px rgba(26,26,26,.55);
  transition:width .2s ease, height .2s ease, opacity .2s ease, background .2s ease;
}
/* over anything clickable: the star opens up, the dot tightens */
.cur-star.is-over{width:46px; height:46px;}
.cur-dot.is-over{width:5px; height:5px; background:var(--yellow);}
/* pressed */
.cur-star.is-down{width:22px; height:22px;}
.cur-dot.is-down{width:11px; height:11px;}
/* over the anatomy stage, which draws its own magnifying lens; and
   .is-gone for when the pointer leaves the window entirely */
.cur-star.is-hidden, .cur-dot.is-hidden,
.cur-star.is-gone,   .cur-dot.is-gone{opacity:0;}

@media(hover:none), (pointer:coarse){
  .cur-star, .cur-dot{display:none;}
}

/* ============================================================
   LIGHTBOX — click any content image to see it full screen
   Built by js/script.js on first use. z-index 9500 puts it over the
   Dipper case study (120) but under the custom cursor (9999), so the
   star still tracks while the viewer is open.
   ============================================================ */
html.lb-locked{overflow:hidden;}          /* freeze the page behind it */
.lb{
  position:fixed; inset:0; z-index:9500;
  display:none; align-items:center; justify-content:center;
  padding:clamp(20px, 4vw, 64px);
  background:rgba(12,10,11,.94);
  -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
  opacity:0; transition:opacity .22s ease;
}
.lb.is-open{display:flex; opacity:1;}
.lb-img{
  max-width:100%; max-height:100%; width:auto; height:auto;
  object-fit:contain; display:block;
  box-shadow:0 30px 90px rgba(0,0,0,.6);
  transform:scale(1); transition:transform .28s cubic-bezier(.34,1.06,.4,1);
  cursor:zoom-in;
}
/* second click magnifies; transform-origin is written by the script
   from the pointer position, so moving the mouse pans the image */
.lb-img.is-big{transform:scale(2.4); cursor:zoom-out;}
.lb-close{
  position:absolute; top:18px; right:22px; z-index:2;
  width:44px; height:44px; line-height:1;
  background:transparent; border:1px solid rgba(255,246,226,.4);
  color:var(--cream); font-size:26px; font-family:var(--font-body);
  transition:background .2s ease, border-color .2s ease, transform .2s ease;
}
.lb-close:hover, .lb-close:focus-visible{
  background:var(--red); border-color:var(--red); transform:rotate(90deg);
}
/* the affordance on the page itself */
.dc-tile img, .dc-slide img, #originsSlideshow .slide-media{cursor:zoom-in;}
