/* ============ THEME TOKENS ============ */
:root{
  --flame:#E4572E; --flame-2:#D0491F; --mint:#1F9E6E;
  /* Playfair carries the headings , high-contrast and editorial, which is the
     register a fashion product wants. Geist keeps the body and the technical
     labels quiet and modern underneath it, so the serif is the only voice
     raised on the page. */
  /* One size for every section heading. Each section used to carry its own,
     which had drifted from 2.5rem to 4rem across the page and left the
     sections looking unrelated to each other. */
  /* Section headings: 25px on a phone, 33px on a desktop. `2.6vw` is what makes
     both ends land exactly , it reaches 25px at a 960px viewport and 33px at
     1270px, so the clamp holds the floor below one and the ceiling above the
     other. Set on the token rather than per heading, because eight rules read
     it and only one of them was `.sec-h2`. */
  --h2:clamp(25px,2.6vw,33px);

  --serif:"Playfair Display",Georgia,serif;
  --sans:"Geist","Geist Fallback",system-ui,-apple-system,sans-serif;
  --mono:"Geist Mono","Geist Mono Fallback",ui-monospace,monospace;

  /* light (default) */
  --bg:#e5e5e5; --bg2:#e5e5e5; --card:#fff;
  --text:#17150F; --dim:#5B5344; --muted:#8A8172;
  --line:rgba(23,21,15,.16); --line-soft:rgba(23,21,15,.08);
  --sheet-bg:#171511; --sheet-line:rgba(255,255,255,.1);
  --bar-other:linear-gradient(180deg,#C9C0AD,#AAA08A);
  --shadow:0 30px 70px -35px rgba(23,21,15,.5);
  --grain-blend:multiply; --grain-op:.05;
  --veil:radial-gradient(ellipse 72% 62% at 50% 45%, rgba(241,236,225,.62), rgba(241,236,225,.97) 78%);
  /* The bar is dark in both states , see the note by `header.nav.solid`. */
  --nav-bg:rgba(10,9,8,.86);
  --glow:radial-gradient(circle, rgba(228,87,46,.12), transparent 62%);
}
[data-theme="dark"]{
  --flame-2:#F0774E; --mint:#5FD3A3;
  --bg:#0A0908; --bg2:#12100D; --card:#14120F;
  --text:#EDE7DA; --dim:#B9B1A0; --muted:#7d7565;
  --line:rgba(237,231,218,.16); --line-soft:rgba(237,231,218,.08);
  --sheet-bg:#141210; --sheet-line:rgba(237,231,218,.1);
  --bar-other:linear-gradient(180deg,#3a352c,#232019);
  --shadow:0 40px 90px -40px rgba(0,0,0,.95);
  --grain-blend:screen; --grain-op:.06;
  --veil:radial-gradient(ellipse 72% 62% at 50% 45%, rgba(10,9,8,.3), rgba(10,9,8,.94) 78%);
  --nav-bg:rgba(10,9,8,.82);
  --glow:radial-gradient(circle, rgba(228,87,46,.14), transparent 62%);
}

*{box-sizing:border-box}
/* No overflow on the root at all: `clip` here is what silently killed every
   `position:sticky` pin on the page , Chrome treats a clip container as the
   sticky's scrollport, and a box that never scrolls never unsticks. The
   horizontal overflow is still held by `body{overflow-x:hidden}` below, which
   propagates to the viewport now that the root is visible again. */
html{scroll-behavior:auto}

/* ── in-page anchors ──────────────────────────────────────────────────
   The header is fixed at 74px, so an anchor jump lands with the section's
   heading tucked underneath it. `scroll-margin-top` offsets where the scroll
   STOPS, which costs the layout nothing.

   By id rather than on every section: these are the ones the nav, the footer
   and the hero actually link to. */
#pricing,#features,#demo,#why,#faq,#casting,#ensemble,#reels,#cats,#how,#contact{scroll-margin-top:96px}
body{margin:0;background:var(--bg);color:var(--text);font-family:var(--sans);line-height:1.55;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;transition:background .5s,color .5s}
body::before{content:"";position:fixed;inset:0;pointer-events:none;z-index:9998;opacity:var(--grain-op);mix-blend-mode:var(--grain-blend);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
a{color:inherit;text-decoration:none}
img{display:block}
h1,h2,h3{margin:0;font-family:var(--serif);font-weight:500;letter-spacing:-.014em;line-height:1.28}
/* Section headings. The per-section rules below all point at the same token,
   so the size is set in exactly one place. */
.sec-h2{font-size:var(--h2);margin:6px 0; font-weight: bold;}
.wrap{max-width:1280px;margin:0 auto;padding:0 17px}
.wrap-1{max-width: 1000px;margin:0 auto;padding:0 17px}
.eyebrow{font-family:var(--mono);font-size:.7rem;letter-spacing:.26em;text-transform:uppercase;color:var(--flame);font-weight:700}
.k-label{font-family:var(--mono);font-size:.66rem;letter-spacing:.22em;text-transform:uppercase;color:var(--muted)}

/* ============ shared card hover: gradient rim + coloured bloom ============
   Opt in by adding `card-glow` alongside a card's own class. Two independent parts:

   The RIM is one gradient masked down to its own padding box , the standard
   two-layer mask/exclude trick , so it rides over whatever border the card
   already carries without a second element and without touching the card's
   background. It lives on ::after because `.stat` already spends ::before on
   its top accent.

   The BLOOM is a box-shadow, not a blurred pseudo-element: a shadow is not
   clipped by the card's own `overflow:hidden`, needs no z-index juggling
   against the card's content, and costs no extra paint layer.

   Both ends of the gradient are the page's own accents rather than imported
   colours, so this reads as the same design system, not a borrowed effect. */
.card-glow{position:relative;
  transition:transform .35s cubic-bezier(.2,.8,.2,1),box-shadow .4s,border-color .35s}
.card-glow::after{content:"";position:absolute;inset:0;border-radius:inherit;padding:1.5px;
  background:linear-gradient(135deg,var(--flame),#E0559B 52%,var(--genie));
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
          mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;
  opacity:0;transition:opacity .35s;pointer-events:none}
.card-glow:hover{transform:translateY(-5px);
  box-shadow:0 16px 34px -24px rgba(23,21,15,.42),
             0 26px 52px -18px color-mix(in srgb,var(--genie) 40%,transparent)}
.card-glow:hover::after{opacity:1}
/* Keyboard gets the same affordance the pointer does. */
.card-glow:focus-within{transform:translateY(-5px)}
.card-glow:focus-within::after{opacity:1}

/* custom cursor */
.cur{position:fixed;z-index:10000;top:0;left:0;width:10px;height:10px;border-radius:50%;background:var(--flame);pointer-events:none;
  transform:translate(-50%,-50%);transition:width .25s,height .25s,background .25s;mix-blend-mode:difference}
.cur.big{width:56px;height:56px;background:#fff}
@media(hover:none){.cur{display:none}}
.progress{position:fixed;top:0;left:0;height:2px;background:var(--flame);z-index:9999;width:0%}

/* ---------- nav ---------- */
header.nav{position:fixed;top:0;left:0;right:0;z-index:900;border-bottom:1px solid transparent;
  transition:transform .35s cubic-bezier(.2,.8,.2,1),background .4s,border-color .4s}
/* Set by landing.js on the way down and cleared on the way up. `translateY`
   rather than `top`, so it is a compositor transform and does not lay the page
   out again on every frame of the slide. */
header.nav.nav-away{transform:translateY(-100%)}
/* Dark once it solidifies, not light. It starts transparent over the dark hero
   and used to flip to the page's cream on scroll, which meant the logo, links
   and burger all had to swap colour mid-scroll. Keeping it dark throughout
   makes the bar one object that fades in rather than two that trade places ,
   and the hairline goes light with it, since a dark-on-light rule is invisible
   against this. */
header.nav.solid{background:var(--nav-bg);backdrop-filter:blur(12px);
  border-color:rgba(237,231,218,.12)}
/* Solid from the first pixel, for pages with no dark hero under the bar.
   `.solid` only arrives once landing.js sees 40px of scroll, which is right on
   the home page , the bar is transparent over a dark hero until then. On a page
   that opens on the cream background it meant light-on-dark contents floating on
   cream: a white logo and pale links on pale paper. A separate class rather than
   presetting `.solid`, because the frame loop owns that one and would clear it
   the moment you scrolled back to the top. */
header.nav.nav-onlight{background:var(--nav-bg);backdrop-filter:blur(12px);
  border-color:rgba(237,231,218,.12)}
.nav-in{display:flex;align-items:center;justify-content:space-between;height:74px;gap:18px}
.logo{display:inline-flex;align-items:center}
.logo-img{height:116px;width:auto;display:block}
.logo-dark{display:none}
[data-theme="dark"] .logo-light{display:none}
[data-theme="dark"] .logo-dark{display:block}
footer .logo-img{height:46px}
.nav-links{display:flex;gap:34px}
.nav-links a{font-size:.9rem;color:var(--dim);font-weight:500;position:relative;padding:4px 0;transition:color .25s}
.nav-links a::after{content:"";position:absolute;left:0;bottom:-2px;width:0;height:1px;background:var(--flame);transition:width .3s}
.nav-links a:hover{color:var(--text)}
.nav-links a:hover::after{width:100%}
.nav-right{display:flex;align-items:center;gap:12px}

.btn{display:inline-flex;align-items:center;gap:.55em;font-weight:600;font-size:.95rem;padding:.85em 1.5em;border-radius:2px;cursor:pointer;border:1px solid transparent;transition:transform .3s cubic-bezier(.2,.7,.2,1),background .3s,border-color .3s,color .3s}
.btn .arw{transition:transform .3s}
.btn:hover .arw{transform:translateX(5px)}

/* ── the running-gradient sweep, shared by the CTAs and the how-it-works card ──
   `@property` is what makes the angle animatable: a plain custom property is
   an untyped token, so it would jump 0deg → 360deg with nothing in between.
   Declaring it an <angle> is what lets the engine interpolate it. Where
   @property is unsupported the gradient simply holds at 0deg , a static rim,
   not a broken one. */
@property --sweep-angle{syntax:"<angle>";initial-value:0deg;inherits:false}
@keyframes sweep{to{--sweep-angle:360deg}}

/* The primary call to action. White rather than a filled flame: against this
   page's grey a white plane with a lit edge carries further than another block
   of orange, and it keeps the accent for the one thing that is moving. */
.btn-cta{background:var(--card);color:var(--text);border-color:var(--line-soft);
  border-radius:10px;position:relative;isolation:isolate;
  box-shadow:0 10px 26px -18px rgba(23,21,15,.5); padding: 0.8em;}
/* Same masked ring as .hiw-card , one gradient clipped to its own padding box,
   so only the rim paints and the button's white face is untouched. */
.btn-cta::before{content:"";position:absolute;inset:0;border-radius:inherit;
  padding:1.6px;pointer-events:none;
  background:conic-gradient(from var(--sweep-angle),
    transparent 0deg,#7c5cff 42deg,var(--flame) 84deg,transparent 136deg,transparent 360deg);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
          mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;
  animation:sweep 6s linear infinite}
.btn-cta:hover{transform:translateY(-2px);
  box-shadow:0 16px 34px -18px rgba(23,21,15,.5),
             0 18px 40px -20px color-mix(in srgb,#7c5cff 40%,transparent)}
/* Twice round while the pointer is on it , the button answers the hover
   without changing colour or size enough to shift anything around it. */
.btn-cta:hover::before{animation-duration:3s}
.btn-line{border-color:var(--line);color:var(--text)}
.btn-line:hover{border-color:var(--text);transform:translateY(-2px)}

/* ---------- hero ---------- */
/* ---------- hero: editorial split ---------- */
/* Text left, a collage of real frames right. The product IS photographs, so the
   hero shows them at a size worth looking at instead of blurred behind a veil. */
.hero{min-height:100svh;display:flex;align-items:center;padding:130px 0 60px;position:relative;overflow:hidden}
.hero-grid{display:grid;grid-template-columns:1.05fr 1fr;gap:60px;align-items:center}
.hero h1{font-size:clamp(2.9rem,6.4vw,5.6rem);letter-spacing:-.02em}
.hero h1 .ln{display:block;overflow:hidden}
.hero h1 .ln span{display:inline-block;transform:translateY(115%);animation:rise 1.1s cubic-bezier(.16,.84,.24,1) forwards}
.hero h1 .ln:nth-child(2) span{animation-delay:.14s}
.hero h1 em{font-style:italic;color:var(--flame)}
@keyframes rise{to{transform:none}}
.hero .eyebrow{display:inline-block;opacity:0;animation:fadeup .8s .1s forwards}
.hero .sub{color:var(--dim);font-size:clamp(1rem,1.4vw,1.15rem);max-width:52ch;margin:26px 0 0;opacity:0;animation:fadeup 1s .5s cubic-bezier(.2,.7,.2,1) forwards}
.hero .sub b{color:var(--text)}
.hero-cta{display:flex;gap:16px;margin-top:34px;opacity:0;animation:fadeup 1s .7s cubic-bezier(.2,.7,.2,1) forwards;flex-wrap:wrap}
.hero-note{font-family:var(--mono);font-size:.66rem;color:var(--muted);margin-top:22px;letter-spacing:.12em;text-transform:uppercase;opacity:0;animation:fadeup 1s .9s forwards}
@keyframes fadeup{from{opacity:0;transform:translateY(22px)}to{opacity:1;transform:none}}

/* the collage , three overlapping frames, each easing up in turn */
.collage{position:relative;height:min(76svh,680px)}
.pl{position:absolute;border-radius:6px;overflow:hidden;box-shadow:var(--shadow);opacity:0;animation:plin 1s cubic-bezier(.16,.84,.24,1) forwards}
/* Top-anchored, not centred.
   `cover` on a portrait photograph in a plate that is wider than it is tall
   scales to the width and overflows vertically , and the default `50% 50%`
   spends that overflow equally at both ends, which takes the crown off every
   model. `0%` keeps the top of the source, so whatever headroom the photograph
   was framed with is the headroom the plate shows; the trim all comes off the
   hem, where there is nothing to lose. */
.pl img,.pl svg{width:100%;height:100%;object-fit:cover;object-position:50% 0%}
/* --r keeps each frame's tilt through the animation; without it the rotation
   would be reset to 0 by the transform on the final keyframe. */
@keyframes plin{from{opacity:0;transform:translateY(26px) rotate(var(--r,0deg))}to{opacity:1;transform:rotate(var(--r,0deg))}}
/* Four plates, laid so the hero frame keeps the left and the three smaller ones
   stack down the right and across the bottom. Each is nudged off-square by a
   degree or two , a perfectly aligned collage reads as a grid, not a pinboard.
   The right column stops at 78% so the SHOT ON stamp has its corner. */
.pl.main{left:4%;top:2%;width:52%;height:74%;--r:0deg;animation-delay:.25s;z-index:2}
.pl.b{right:0;top:0;width:40%;height:40%;--r:1.6deg;animation-delay:.4s;z-index:3}
.pl.d{right:5%;top:42%;width:35%;height:36%;--r:-1.4deg;animation-delay:.55s;z-index:3}
.pl.c{left:8%;bottom:4%;width:37%;height:34%;--r:-2deg;animation-delay:.7s;z-index:4}
.pl .cap{position:absolute;bottom:0;left:0;right:0;padding:14px 12px 8px;background:linear-gradient(transparent,rgba(0,0,0,.6));
  font-family:var(--mono);font-size:.54rem;letter-spacing:.14em;color:#fff;text-transform:uppercase;z-index:3}

/* Each frame swaps its own media layer, so the caption and the shutter above it
   stay put while the photograph underneath cross-fades. */
.pl .pl-media{position:absolute;inset:0;z-index:1;transition:opacity .45s,transform .45s}
.pl .pl-media.out{opacity:0;transform:scale(1.03)}
.pl .pl-media img,.pl .pl-media svg{width:100%;height:100%;object-fit:cover;object-position:50% 0%;display:block}
/* A camera flash on the lead frame , it is what makes the swap read as a shot
   being taken rather than a slideshow advancing. */
.shutter{position:absolute;inset:0;background:#fff;opacity:0;z-index:2;pointer-events:none}
.shutter.snap{animation:snap .32s ease-out}
@keyframes snap{0%{opacity:.55}100%{opacity:0}}
.stamp .rec{color:var(--flame);animation:recpulse 1.4s steps(1) infinite}
@keyframes recpulse{50%{opacity:.45}}
/* min-width stops the sentence reflowing as the word changes length. */
.rotw{display:inline-block;color:var(--flame);font-weight:600;min-width:7.5ch;transition:opacity .3s,transform .3s}
.rotw.sw{opacity:0;transform:translateY(8px)}
.stamp{position:absolute;right:6%;bottom:6%;z-index:4;background:var(--card);border:1px solid var(--line);border-radius:100px;
  padding:10px 18px;font-family:var(--mono);font-size:.6rem;letter-spacing:.14em;color:var(--text);text-transform:uppercase;
  box-shadow:var(--shadow);opacity:0;animation:fadeup .8s 1s forwards}
.stamp b{color:var(--flame)}

/* ---------- pinned narrative ---------- */
.pin-wrap{position:relative}
.pin-wrap .pin{position:sticky;top:0;min-height:480px;display:flex;align-items:center;justify-content:center;overflow:hidden}
.narr .pin-wrap{height:320svh}
.scene{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:0 26px;will-change:opacity,transform}
.scene .tag{font-family:var(--mono);font-size:.72rem;letter-spacing:.3em;color:var(--muted);text-transform:uppercase;margin-bottom:30px}
.scene h2{font-size:clamp(2.2rem,5.6vw,4.6rem);max-width:20ch;font-weight:500}
.scene h2 b{color:var(--flame);font-weight:500;font-style:italic}
.scene.sol .tag{color:var(--flame)}

/* ---------- big counter ---------- */
.counter-sec .pin-wrap{height:340svh}
.counter-sec .pin{flex-direction:column;gap:8px}
.cnt-cap{font-family:var(--mono);font-size:.72rem;letter-spacing:.26em;text-transform:uppercase;color:var(--muted);text-align:center;max-width:40ch;line-height:2}
.cnt-cap b{color:var(--text)}
.big-num{font-family:var(--serif);font-weight:600;font-size:clamp(5rem,17vw,15rem);line-height:1;letter-spacing:-.03em;color:var(--text);
  font-variant-numeric:tabular-nums;display:flex;align-items:baseline;gap:.06em}
.big-num .rup{font-size:.42em;color:var(--muted)}
.big-num .unit{font-family:var(--mono);font-size:.13em;color:var(--muted);letter-spacing:.2em;margin-left:.6em}
.cost-bars{display:flex;gap:60px;margin-top:56px;align-items:flex-end}
.cbar{display:flex;flex-direction:column;align-items:center;gap:14px}
.cbar .bar{width:66px;border-radius:3px 3px 0 0;background:var(--bar-other);transform-origin:bottom;height:220px}
.cbar.us .bar{background:linear-gradient(180deg,#F0774E,var(--flame))}
.cbar .k-label{color:var(--dim)}
.cnt-x{font-family:var(--mono);color:var(--mint);font-size:.86rem;letter-spacing:.14em;margin-top:34px;opacity:0;transform:translateY(10px);transition:opacity .5s,transform .5s}
.cnt-x.on{opacity:1;transform:none}

/* ---------- horizontal rail ---------- */
/* Ported from the platform-panel reference. A dark band with image-led cards:
   a frame carrying a numbered pill, then a tight block of type. Written with
   literals where it must be dark by design rather than by theme, the same way
   the hero band is. */
.rail-sec{position:relative;background:var(--bg2);transition:background .5s}
.rail-head{max-width:1180px;margin:0 auto;padding:clamp(44px,5vw,68px) 24px 0;text-align:center}
.rail-head h2{font-size:var(--h2);margin-top:16px}
.rail-head h2 em{font-style:italic;color:var(--flame)}
.rv h2 em{font-style:italic;color:var(--flame)}

.head h2 em{font-style:italic;color:var(--flame)}

.rail-head .eyebrow{color:var(--flame)}
.rail-head .sec-p{color:var(--dim);font-size:1.02rem;line-height:1.6;max-width:56ch;margin:18px auto 0}

.rail-pinzone{position:relative}
/* `pan-y` hands vertical swipes to the browser and keeps horizontal ones for
   the drag handler in landing.js , without it a sideways swipe on a phone does
   nothing at all, because the browser has no horizontal scroll to give it. */
/* Capped, not proportional. At `80svh` the pin grew with the window while the
   cards stayed ~405px tall, so a 1150px screen centred them inside 920px and
   left 258px of empty band above AND below. The clamp keeps the band at ~68px
   on any tall screen.
   The 480px floor is not a taste decision: `.rail-progress` sits at bottom:34px
   inside this box, so anything under ~473px puts that hairline through the
   bottom of a centred card. */
.rail-pin{position:sticky;top:0;height:clamp(480px,64svh,540px);display:flex;align-items:center;
  overflow:hidden;touch-action:pan-y;cursor:grab}
.rail-pin:active{cursor:grabbing}
/* Text selection turns a drag into a highlight the moment the pointer crosses a
   heading, which is the one thing a drag must never do. */
.rail-track.dragging{user-select:none}
.rail-track.dragging *{pointer-events:none}
.rail-track{display:flex;gap:18px;padding:0 24px;width:max-content;will-change:transform;align-items:stretch}

/* Light, on the page's own surface. The dark version leaned on its border
   alone to separate card from band; on light that reads as a flat outline, so
   the card carries a soft shadow instead and the border goes back to being a
   hairline. */
.rcard{position:relative;width:296px;flex:0 0 auto;background:var(--card);
  border:1px solid var(--line-soft);border-radius:10px;overflow:hidden;
  box-shadow:0 10px 26px -20px rgba(23,21,15,.5);
  /* `translate` is left free for the reveal below, so the two compose instead
     of overwriting each other , the lift is the only thing on `transform`. */
  transition:transform .35s cubic-bezier(.2,.7,.2,1),border-color .35s,box-shadow .35s}
.rcard:hover{transform:translateY(-8px);border-color:rgba(228,87,46,.55);
  box-shadow:0 26px 46px -28px rgba(23,21,15,.55)}

/* Still dark behind the picture , it is a photographic frame, and a light
   ground would flash white before the image paints. */
.rcard .pimg{position:relative;aspect-ratio:4/3.1;background:#1b1915;overflow:hidden}
.rcard .pimg img,.rcard .pimg svg{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .6s cubic-bezier(.2,.7,.2,1)}
.rcard:hover .pimg img{transform:scale(1.05)}
/* Scrim, so the pill stays legible over any artwork. */
.rcard .pimg::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(transparent 55%,rgba(14,12,9,.72))}

.rcard .num{position:absolute;top:10px;left:11px;z-index:2;
  font-family:var(--mono);font-size:.6rem;letter-spacing:.12em;color:#fff;
  background:rgba(14,12,9,.6);border:1px solid rgba(240,74,23,.5);
  border-radius:100px;padding:4px 10px}

.rcard .pt{padding:16px 18px 20px}
.rcard h3{margin:0;font-family:var(--sans);font-weight:600;font-size:1.04rem;
  line-height:1.3;letter-spacing:0;color:var(--text)}
/* The reference highlights one phrase per heading rather than the whole line. */
.rcard h3 b{color:var(--flame);font-weight:600}
.rcard p{margin:9px 0 0;color:var(--dim);font-size:.88rem;line-height:1.55}

/* The foot labels, under the rail. */
.pl-foot{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;
  padding-bottom:clamp(30px,4vw,48px)}
.pl-lbl{font-family:var(--mono);font-size:.56rem;letter-spacing:.16em;
  color:var(--muted);text-transform:uppercase}

/* Each card rises as the track carries it in. Gated behind `.reveal`, which
   landing.js adds , without JS nothing is ever hidden in the first place. */
.rail-track.reveal .rcard{opacity:0;translate:0 26px}
.rail-track.reveal .rcard.in{opacity:1;translate:none;
  transition:opacity .55s cubic-bezier(.2,.7,.2,1),translate .55s cubic-bezier(.2,.8,.2,1)}

.rail-progress{position:absolute;bottom:34px;left:32px;right:32px;height:1px;background:var(--line-soft)}
.rail-progress .fill{height:100%;width:0%;background:var(--flame)}
.drag-hint{position:absolute;top:34px;right:32px;font-family:var(--mono);font-size:.64rem;letter-spacing:.22em;color:var(--muted);text-transform:uppercase}
/* prompt visuals */
.pv{height:100%;display:flex;flex-direction:column;justify-content:center;gap:10px;padding:16px}
.pline{display:flex;align-items:center;gap:8px;background:var(--bg2);border:1px solid var(--line);border-radius:5px;padding:10px 12px;font-family:var(--mono);font-size:.62rem;letter-spacing:.03em;color:var(--dim);overflow:hidden;white-space:nowrap}
.pline .pc{width:7px;height:14px;background:var(--flame);flex:0 0 auto;animation:blink 1s steps(1) infinite}
@keyframes blink{50%{opacity:0}}
.pline.genie{border-color:rgba(228,87,46,.5)}
.ptags{display:flex;flex-wrap:wrap;gap:6px}
.ptag{font-family:var(--mono);font-size:.56rem;letter-spacing:.06em;border:1px solid var(--line);border-radius:100px;padding:4px 9px;color:var(--muted);text-transform:uppercase}
.ptag.hot{border-color:rgba(228,87,46,.6);color:var(--flame)}
.parrow{font-family:var(--mono);font-size:.62rem;color:var(--mint);letter-spacing:.14em}
.wallet{height:100%;display:flex;align-items:center;justify-content:center}
.wchip{background:var(--bg2);border:1px solid var(--line);border-radius:8px;padding:18px 22px;min-width:200px;box-shadow:var(--shadow)}
.wchip .amt{font-family:var(--serif);font-size:1.9rem;margin-top:6px}
.wchip .cr{font-family:var(--mono);font-size:.66rem;color:var(--mint);margin-top:8px;letter-spacing:.08em}

/* ---------- stats ---------- */
/* Four proof points. Cards on the page's grey rather than cells divided by
   hairlines: each number is a separate claim, and its own white plane is what
   makes it read as one instead of as a row in a table. */
.stats{padding:50px 0 0 0}
.stats-in{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(12px,1.4vw,18px)}
.stat{position:relative;overflow:hidden;background:var(--card);
  border:1px solid var(--line-soft);border-radius:18px;
  padding:clamp(26px,2.6vw,34px) clamp(20px,2vw,28px);
  transition:transform .35s cubic-bezier(.2,.8,.2,1),box-shadow .35s,border-color .35s}
/* The accent draws itself across the top edge when the number starts counting,
   so the card arrives as one gesture rather than two. `.lit` is set by the
   same observer that runs the count , see landing.js. */
.stat::before{content:"";position:absolute;left:0;top:0;height:3px;width:100%;
  background:linear-gradient(90deg,var(--flame),transparent);
  transform:scaleX(0);transform-origin:0 50%;
  transition:transform .8s cubic-bezier(.2,.8,.2,1)}
.stat.lit::before{transform:none}

/* Baseline-aligned so the unit sits on the number's feet, not its middle. */
.stat .num{font-family:var(--serif);font-size:clamp(2.3rem,4vw,3.4rem);line-height:1;
  font-variant-numeric:tabular-nums;letter-spacing:-.015em;
  display:flex;align-items:baseline;gap:.1em}
/* The currency mark comes out of the serif on purpose: Playfair has no rupee
   of its own, and the Georgia fallback it reaches for sets one with the wrong
   advance width, which is what made ₹ collide with the 25 beside it. */
.stat .num .pre{font-family:var(--sans);font-size:.6em;font-weight:500;letter-spacing:0}
.stat .num small{font-size:.4em;font-family:var(--mono);color:var(--flame);font-weight:500}
.stat .cap{margin-top:16px;display:block}


/* ---------- assurances ---------- */
/* These are the reassurances, so they are set as eight affirmative cards
   rather than ruled rows , underlined grey text reads as the small print the
   heading is promising it is not. */
.assure{padding:clamp(30px,4vw,50px) 0 clamp(60px,8vw,100px)}
.agrid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.aitem{display:flex;gap:13px;align-items:center;padding:17px 20px;
  background:var(--card);border:1px solid var(--line-soft);border-radius:14px;
  font-size:1rem;line-height:1.45;color:var(--text);
  opacity:0;translate:0 14px;
  transition:transform .35s cubic-bezier(.2,.8,.2,1),box-shadow .4s,border-color .35s}
/* Each card rises on the parent's reveal, one after the next along the grid,
   so the block lands as a sweep rather than eight things at once.

   Deliberately an animation on `translate`, not a transition on `transform`:
   a staggered transition-delay would also delay the hover lift , the eighth
   card would hang for 385ms before moving , and an animation that filled
   `transform` would outrank the hover rule in the cascade and pin the card
   down. `translate` is its own property, so the reveal and the lift compose
   instead of fighting. */
.agrid.in .aitem{animation:aitemIn .5s cubic-bezier(.2,.7,.2,1) both;
  animation-delay:calc(var(--i,0) * 55ms)}
@keyframes aitemIn{from{opacity:0;translate:0 14px}to{opacity:1;translate:none}}
/* A card this small would be swamped by the full bloom, so it gets a shorter
   throw , the rim and the lift are shared, only the shadow is scaled. */
.aitem.card-glow:hover{transform:translateY(-3px);
  box-shadow:0 10px 22px -18px rgba(23,21,15,.4),
             0 16px 32px -14px color-mix(in srgb,var(--genie) 32%,transparent)}
/* A filled disc, not a bare glyph: at this size a loose ✓ sits at a different
   height in every fallback font and the column of them goes ragged. */
.aitem .tick{flex:0 0 auto;width:23px;height:23px;border-radius:50%;
  background:color-mix(in srgb,var(--mint) 16%,transparent);color:var(--mint);
  display:grid;place-items:center;font-size:.7rem;font-weight:800;line-height:1}
@media(max-width:720px){
  .agrid{grid-template-columns:1fr}
  /* Two 1-column-wide stat cards at phone width leave the numbers stranded in
     a lot of white; stacked, each claim gets the full measure. */
  .stats-in{grid-template-columns:1fr}
  .stat{padding:22px 20px}
  .aitem{padding:15px 16px;font-size:.96rem}
}

/* ---------- contact sheet demo (dark in both themes , it's a light table) ---------- */
/* Was `0` on top at every width, so "AI fashion shoot studio" began the instant
   the reel strip ended. Matches the reels band above it so the two read as
   evenly spaced sections rather than one running into the next. */
.demo{padding:clamp(52px,7vw,86px) 0 30px}
/* `auto` on the sheet track, not a fraction: sized as a fraction the sheet
   grew with the viewport, and its frames are 3:4 , so every extra pixel of
   width cost a third again in height. The sheet now sets its own width and the
   copy takes what is left. */
.demo-grid{display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:clamp(26px,3.6vw,52px);align-items:center}
/* Sized for a column, not for the full measure: at the old clamp the headline
   ran to four lines beside the sheet. */
.demo h2{margin-top:14px}
.demo .sec-p{color:var(--dim);font-size:1rem;max-width:42ch;margin:14px 0 0;line-height:1.55}
.demo .sec-p b{color:var(--text)}

/* ── one block, two lengths ───────────────────────────────────────────
   Write the long version for a desktop column and a short one for a phone,
   mark them `desktop` and `mobile`, and they swap at the breakpoint.

   Not tied to `sec-p`: the third place that needed this was a bare <p> inside
   .genie-copy, and qualifying the rule would have meant either duplicating it
   or bolting an unrelated class onto that paragraph purely as a hook.

   `revert` rather than `block`, so the pair works on whatever element it is
   put on , a <div> or a <ul> gets its own natural display back, not a <p>'s.

   Declared before the breakpoint that reverses them: these have equal
   specificity, so whichever came last would otherwise win outright. */
.mobile{display:none}
@media(max-width:720px){
  .desktop{display:none}
  .mobile{display:revert}
}
.demo-cta{margin-top:24px}
.demo p.d{color:var(--dim);font-size:1.06rem;max-width:46ch;margin:20px 0 30px}
.sheet{position:relative;background:var(--sheet-bg);border:1px solid var(--line-soft);
  border-radius:12px;padding:clamp(12px,1.2vw,16px);box-shadow:var(--shadow);
  width:clamp(300px,33vw,452px)}
.sheet-top{display:flex;justify-content:space-between;margin-bottom:10px}
.sheet-top .lbl,.sheet-foot .lbl{font-family:var(--mono);font-size:.64rem;letter-spacing:.18em;color:#8f8676;text-transform:uppercase}
.sheet-top .roll{font-family:var(--mono);font-size:.64rem;color:#F0774E;letter-spacing:.1em}
.frames{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.frame{position:relative;aspect-ratio:3/4;border-radius:3px;overflow:hidden;background:#1b1915;opacity:0;transform:scale(.9) translateY(10px)}
.frame.pop{animation:pop .6s cubic-bezier(.2,.8,.2,1) forwards}
@keyframes pop{to{opacity:1;transform:none}}
/* Top-anchored for the poses, centred for the packshot.
   `cover` in this 3/4 cell overflows vertically for any source taller than 4:3
   , the 9:16 frames overflow by 26% , and the default `50% 50%` spends half of
   that on the top, which is where the head is.
   Frame 00 is excluded on purpose: it is the garment on its own, so the whole
   piece matters and there is no head to protect. Anchoring it to the top would
   trade a safe crop for a cut hem. */
.frame img,.frame svg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.frame:not(.garment) img{object-position:50% 0%}
.frame .fnum{position:absolute;top:6px;left:7px;font-family:var(--mono);font-size:.58rem;color:#fff;z-index:3;text-shadow:0 1px 3px rgba(0,0,0,.7)}
.frame .fpose{position:absolute;bottom:6px;left:7px;font-family:var(--mono);font-size:.54rem;letter-spacing:.08em;color:#fff;text-transform:uppercase;z-index:3;text-shadow:0 1px 3px rgba(0,0,0,.7)}
.frame.garment{outline:1.5px solid var(--flame);outline-offset:-1.5px}
.frame .tag{position:absolute;top:6px;right:7px;z-index:3;font-family:var(--mono);font-size:.48rem;letter-spacing:.1em;background:var(--flame);color:#fff;padding:2px 5px;border-radius:2px;text-transform:uppercase}
.frame .idc{position:absolute;top:6px;right:7px;z-index:3;width:8px;height:8px;border-radius:50%;background:#5FD3A3;box-shadow:0 0 0 3px rgba(95,211,163,.25)}
/* A set whose frame is missing still holds its slot , the gap is the point,
   it shows which angles this shoot does not have. */
.frame.missing{opacity:.28!important;transform:none!important}

/* footer: garment thumbnails navigate between shoots */
.sheet-foot{display:flex;justify-content:center;align-items:center;margin-top:10px;padding-top:10px;border-top:1px solid var(--sheet-line);gap:10px;flex-wrap:wrap}
.sheet .nav{display:flex;align-items:center;gap:14px}
.nbtn{position:relative;background:none;border:1px solid rgba(237,231,218,.28);color:#EDE7DA;
  width:38px;height:38px;border-radius:50%;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
  transition:background .25s,border-color .25s,transform .15s}
.nbtn svg{width:14px;height:14px;transition:transform .25s}
.nbtn:hover{background:var(--flame);border-color:var(--flame)}
.nbtn:hover svg{transform:translateX(2px)}
.nbtn.prev:hover svg{transform:translateX(-2px)}
.nbtn:active{transform:scale(.9)}
.thumbs{display:flex;gap:9px;align-items:center}
.thumb{position:relative;width:24px;height:28px;border-radius:5px;border:0;padding:0;cursor:pointer;background:#1b1915;
  transition:transform .25s cubic-bezier(.2,.8,.2,1),opacity .25s;opacity:.55}
/* the conic ring doubles as the dwell timer for the current set */
.thumb::before{content:"";position:absolute;inset:-3px;border-radius:7px;z-index:0;
  background:conic-gradient(#F0774E calc(var(--p,0)*1%),rgba(237,231,218,.14) 0)}
.thumb .tin{position:absolute;inset:0;border-radius:5px;overflow:hidden;z-index:1;background:#221f19}
.thumb .tin img,.thumb .tin svg{width:100%;height:100%;object-fit:cover;display:block}
.thumb .tlbl{position:absolute;bottom:2px;left:0;right:0;z-index:2;text-align:center;
  font-family:var(--mono);font-size:.46rem;letter-spacing:.08em;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.9)}
.thumb:hover{opacity:.95;transform:translateY(-3px)}
.thumb.on{opacity:1;transform:scale(1.14)}
.thumb.on:hover{transform:scale(1.14)}
/* Only offered where there is no pointer to press the arrows with. */
.swipe-hint{font-family:var(--mono);font-size:.5rem;letter-spacing:.12em;color:#8f8676;text-transform:uppercase;display:none}
@media(hover:none){.swipe-hint{display:inline}}
.scan{position:absolute;left:20px;right:20px;top:52px;height:2px;background:linear-gradient(90deg,transparent,var(--flame),transparent);opacity:0;z-index:5;pointer-events:none}
.scan.run{animation:scan 1.4s ease-in-out}
@keyframes scan{0%{opacity:0;transform:translateY(0)}12%{opacity:1}88%{opacity:1}100%{opacity:0;transform:translateY(330px)}}
.imgcredit{font-family:var(--mono);font-size:.6rem;color:var(--muted);letter-spacing:.06em;margin-top:14px}

/* ---------- pricing ---------- */
.pricing{padding:50px 0 0 0;background:var(--bg2);border-top:1px solid var(--line-soft);transition:background .5s}
.pricing .head{text-align:center;max-width:760px;margin:0 auto clamp(30px,4vw,48px)}
.pricing h2{font-size:var(--h2);margin-top:16px}
.pricing .head p{color:var(--dim);margin-top:20px}
/* The packs ride the same scroll-scrubbed rail as "Inside the studio": the zone
   is as tall as the row is wide, the pin holds the row still while you scroll
   through it, and landing.js maps one onto the other. `pan-y` is what lets a
   thumb drag sideways , see the note on .rail-pin. */
.price-pinzone{position:relative}
/* Capped, not a plain fraction. At `70svh` the pin grew with the window while
   the card stayed ~376px, so a 1080px screen centred it inside 756px and left
   190px of empty band above and below. The floor is not taste: `.rail-progress`
   sits at bottom:34px inside this box, so anything under ~444px would draw that
   hairline through the bottom of a centred card. */
.price-pin{position:sticky;top:0;height:clamp(470px,52svh,540px);display:flex;align-items:center;
  overflow:hidden;touch-action:pan-y;cursor:grab}
.price-pin:active{cursor:grabbing}
.plans{display:flex;gap:16px;padding:0 24px;width:max-content;will-change:transform;align-items:stretch}
.plans.dragging{user-select:none}
.plans.dragging *{pointer-events:none}
/* Wide enough that every card fits , or so nearly that scrubbing it would mean
   a screen and a half of pinned scroll for fifty pixels of movement. Either way
   there is nothing worth scrubbing, so the zone stops being tall, the pin has
   no range to hold in, and the packs go back to being a plain grid. The class
   is set by landing.js, which is the only thing that can measure it. */
.no-travel .rail-pin,.no-travel .price-pin{position:relative;height:auto;min-height:0}
.no-travel .rail-track{width:auto;justify-content:center;flex-wrap:wrap}
.no-travel .plans{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  width:min(100%,1180px);margin:0 auto;padding:0 24px}
.no-travel .plan{flex:none}
.no-travel .rail-progress{display:none}
/* The dots exist only where the plans grid becomes a rail. Declared here, not
   after the breakpoint that turns them on , same specificity, so whichever
   came last would win, and that has to be the media query. landing.js also
   sets `hidden`; this is the belt to that pair of braces. */
.plan-dots{display:none}
.plan{flex:0 0 clamp(320px,27vw,400px);border:1px solid var(--line-soft);border-radius:8px;padding:32px 26px;background:var(--card);display:flex;flex-direction:column;position:relative;transition:transform .35s cubic-bezier(.2,.7,.2,1),border-color .35s,box-shadow .35s,background .5s}
/* Outranks `.rv`, whose .9s reveal transition would otherwise time the lift
   as well and make it feel like it is dragging. */
.plan.card-glow{transition:transform .35s cubic-bezier(.2,.8,.2,1),box-shadow .4s,
  border-color .35s,opacity .9s}
.plan.card-glow:hover{transform:translateY(-8px)}
.plan.feat{border-color:rgba(228,87,46,.6);background:linear-gradient(180deg,rgba(228,87,46,.1),rgba(228,87,46,.02) 40%),var(--card)}
.badge{position:absolute;top:-11px;left:26px;background:var(--flame);color:#fff;font-family:var(--mono);font-size:.58rem;letter-spacing:.16em;text-transform:uppercase;padding:5px 11px;border-radius:2px}
.p-name{font-family:var(--mono);font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;color:var(--flame);font-weight:700}
.p-price{font-family:var(--serif);font-size:2.6rem;margin:18px 0 4px}
.p-per{font-family:var(--mono);font-size:.74rem;color:var(--muted)}
.p-cap{font-size:.9rem;color:var(--dim);margin:16px 0 20px}
.plan ul{list-style:none;padding:0;margin:0 0 28px;flex:1;display:grid;gap:10px}
.plan li{font-size:.9rem;color:var(--dim);display:flex;gap:9px;line-height:1.45}
.plan li::before{content:",";color:var(--flame)}
.plan .btn{width:100%;justify-content:center;margin-top:auto}
.pnote{text-align:center;font-family:var(--mono);font-size:.66rem;letter-spacing:.14em;color:var(--muted);text-transform:uppercase;margin-top:36px}

/* ---------- faq ---------- */
.faq{padding:50px 0 0px}
.qa{border-bottom:1px solid var(--line-soft)}
.qa summary{cursor:pointer;list-style:none;display:flex;justify-content:space-between;align-items:center;gap:20px;
  padding:22px 4px;font-weight:600;font-size:1.05rem;color:var(--text);transition:color .25s}
.qa summary::-webkit-details-marker{display:none}
.qa summary::after{content:"+";font-family:var(--mono);color:var(--flame);font-size:1.2rem;transition:transform .3s}
.qa[open] summary::after{transform:rotate(45deg)}
.qa summary:hover{color:var(--flame)}
.qa p{margin:0 0 22px;padding:0 4px;color:var(--dim);max-width:64ch}
.qa p b{color:var(--text)}

/* ---------- final ---------- */

/* ── contact / lead capture ───────────────────────────────────────────
   Sits between the closing CTA and the footer. Two columns: the case for
   writing in on the left, the form on the right , so the form is what the eye
   lands on, and the reasons are there for the people who need them. */
/* Also the page's closing section now , the full-height `.final` band that used
   to sit above it has folded into the left column, which is why the padding is
   a little more generous than a mid-page section would want. */
.contact{position:relative;overflow:hidden;border-top:1px solid var(--line-soft);
  background:var(--bg2);padding:96px 0 100px;transition:background .5s}
/* The glow the closing band carried, kept but re-aimed: it sat centred on a
   full-width band, and here it pools behind the left column instead. */
.contact::before{content:"";position:absolute;left:-10%;top:50%;width:60vw;height:60vw;
  max-width:820px;max-height:820px;transform:translateY(-50%);border-radius:50%;
  background:var(--glow);pointer-events:none;z-index:0}
/* Above the glow , without a stacking context of its own the grid would sit
   under a decorative pseudo-element. */
.contact .wrap{position:relative;z-index:1}
.ct-grid{display:grid;grid-template-columns:1fr 1.05fr;gap:64px;align-items:start}
.ct-say h2{font-size:clamp(2rem,3.8vw,3.2rem);margin-top:16px;max-width:13ch;line-height:1.1}
.ct-say h2 em{font-style:italic;color:var(--flame)}
.ct-say .sec-p{color:var(--dim);font-size:1rem;line-height:1.65;max-width:46ch;margin:20px 0 0}
.ct-start{margin-top:30px}
.ct-form{background:var(--card);border:1px solid var(--line-soft);border-radius:10px;
  padding:32px;box-shadow:var(--shadow);display:grid;gap:16px}
.ct-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
/* Floating labels.
   The label starts inside the field, where a placeholder would be, and rises
   onto the border when the field is focused or has something in it. One piece
   of text doing both jobs: nothing is asked twice, and the question stays
   readable while you answer it , which a placeholder does not, because it
   disappears the moment you type. */
.ct-field{position:relative;display:block}
.ct-field>span{
  position:absolute;left:8px;top:13px;z-index:1;pointer-events:none;
  font-family:var(--sans);font-size:.94rem;font-weight:400;letter-spacing:0;
  text-transform:none;color:var(--muted);
  /* The pad + background is what notches the outline: floated, the label sits
     ON the border line and masks the part it covers. So this has to match the
     card behind it, which is why the fields are transparent below. */
  padding:0 5px;background:var(--card);
  transform-origin:left center;
  transition:transform .18s cubic-bezier(.2,.8,.2,1),color .18s}
.ct-field input,.ct-field select,.ct-field textarea{
  font:inherit;font-size:.94rem;color:var(--text);background:transparent;
  border:1px solid var(--line);border-radius:6px;padding:11px 13px;width:100%;
  transition:border-color .2s,box-shadow .2s}
/* Up onto the border. `:has()` because the label is written before the field it
   belongs to, so no sibling combinator can reach it from the input. */
.ct-field:has(input:focus)>span,
.ct-field:has(textarea:focus)>span,
.ct-field:has(input:not(:placeholder-shown))>span,
.ct-field:has(textarea:not(:placeholder-shown))>span,
/* A select always displays something, so its label has nowhere to rest. */
.ct-field:has(select)>span{transform:translateY(-21px) scale(.84)}
.ct-field:has(:focus)>span{color:var(--flame)}
/* The example text belongs to the field you are filling in, not to the one you
   are looking at , shown once the label has moved out of its way. */
.ct-field textarea::placeholder{opacity:0;transition:opacity .18s}
.ct-field textarea:focus::placeholder{opacity:.7}
/* Without `:has()` the label has no way to know whether its field is filled, so
   a floating label would sit on top of whatever you typed. In that case it goes
   back to the stacked micro-label it was before , plainer, but never wrong. */
@supports not selector(:has(*)){
  .ct-field{display:grid;gap:7px}
  .ct-field>span{position:static;transform:none;background:none;padding:0;
    font-family:var(--mono);font-size:.6rem;letter-spacing:.14em;text-transform:uppercase}
  .ct-field textarea::placeholder{opacity:.7}
}
.ct-field textarea{resize:vertical;min-height:104px;line-height:1.55}
/* The ring is the focus indicator, so it must not be removed with the outline ,
   keyboard users have nothing else to go on. */
.ct-field :focus-visible{outline:none;border-color:var(--flame);box-shadow:0 0 0 3px rgba(228,87,46,.16)}
.ct-field select{appearance:none;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 18px) 52%,calc(100% - 13px) 52%;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:38px}
.ct-form.sending{opacity:.6;pointer-events:none}

/* Off-screen rather than display:none , a bot that skips hidden inputs would
   walk straight past a honeypot it cannot see. */
.ct-hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

.ct-send{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:4px}
.ct-msg{font-size:.88rem;line-height:1.4;margin:0;color:var(--dim)}
.ct-msg.err{color:var(--flame)}
.ct-msg.ok{color:var(--mint)}
.ct-fine{font-size:.78rem;color:var(--muted);margin:0;line-height:1.5}

/* Replaces the form on success. Same box, so the page does not jump. */
.ct-done{text-align:center;padding:26px 6px}
.ct-tick{width:46px;height:46px;margin:0 auto 18px;border-radius:50%;
  display:grid;place-items:center;font-size:1.3rem;color:#fff;background:var(--mint)}
.ct-done h3{font-family:var(--serif);font-size:1.5rem;margin:0 0 10px}
.ct-done p{color:var(--dim);font-size:.92rem;line-height:1.6;margin:0 auto;max-width:38ch}

@media(max-width:900px){
  .contact{padding:72px 0 78px}
  .ct-grid{grid-template-columns:1fr;gap:38px}
  .ct-say h2{max-width:none}
  /* The global `.rv.in{text-align:center}` further down catches everything that
     reveals, this form included. A label has to stay left of its field and a
     rule marker left of its line, so both opt back out , the form by
     out-specifying it, the list by being targeted directly, which beats an
     inherited value whatever its specificity. */
  .ct-form.rv.in{text-align:left}
}
@media(max-width:620px){
  .ct-form{padding:22px;border-radius:8px}
  /* Two 50% columns on a phone leave each field too narrow to read its own
     label, so they stack. */
  .ct-row{grid-template-columns:1fr}
  .ct-send{gap:12px}
  .ct-send .btn{width:100%;justify-content:center}
}

/* ── legal pages (/privacy, /terms) ───────────────────────────────────
   The authored documents ship their own stylesheet; this is deliberately NOT
   that one. Those files use their own variable names over a different palette,
   and loading two systems that both define --bg would corrupt whichever landed
   second , the same reason the marketing layout links landing.css rather than
   importing it. So the body copy comes across and the styling is rebuilt on
   this page's tokens. */
.legal{padding-top:74px}          /* clears the fixed header */

.lg-head{padding:56px 0 40px;border-bottom:1px solid var(--line-soft);text-align:center}
.lg-head h1{font-size:clamp(2.1rem,5vw,3.4rem);margin:14px 0 0;line-height:1.1}
.lg-tag{color:var(--dim);font-size:1.02rem;line-height:1.6;max-width:60ch;margin:18px auto 0}
.lg-dates{display:flex;justify-content:center;gap:38px;flex-wrap:wrap;margin-top:26px}
.lg-dates div{display:grid;gap:4px}
.lg-dates span{font-family:var(--mono);font-size:.58rem;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.lg-dates b{font-size:.92rem;color:var(--text);font-weight:600}

.lg-shell{display:grid;grid-template-columns:250px 1fr;gap:56px;align-items:start;padding:46px 0 70px}

/* Sticky at desktop width, a real <details> below it , see the note in
   LegalShell for why the collapse is markup and not script. */
.lg-toc{position:sticky;top:96px}
.lg-toc details{border:1px solid var(--line-soft);border-radius:8px;background:var(--card);padding:14px 16px}
.lg-toc summary{font-family:var(--mono);font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);cursor:pointer;list-style:none}
.lg-toc summary::-webkit-details-marker{display:none}
.lg-toc ol{list-style:none;padding:0;margin:14px 0 0;display:grid;gap:9px;counter-reset:none}
.lg-toc a{font-size:.85rem;line-height:1.4;color:var(--dim);transition:color .2s}
.lg-toc a:hover{color:var(--flame)}

.lg-body{min-width:0;max-width:74ch}
.lg-body h2{font-size:clamp(1.3rem,2.2vw,1.7rem);line-height:1.25;margin:46px 0 14px;
  display:flex;align-items:baseline;gap:12px;scroll-margin-top:96px}
.lg-body h2:first-child{margin-top:0}
/* The numeral is decoration , the heading text already reads "1. Who We Are" in
   the contents , so it is sized down and set in mono rather than competing with
   the heading it sits beside. */
.lg-body .secnum{flex:0 0 auto;font-family:var(--mono);font-size:.72rem;color:var(--flame);
  border:1px solid var(--line);border-radius:5px;padding:3px 7px;line-height:1}
.lg-body h3{font-size:1.02rem;margin:28px 0 10px;scroll-margin-top:96px}
.lg-body p{color:var(--dim);line-height:1.75;margin:0 0 15px}
.lg-body ul,.lg-body ol{color:var(--dim);line-height:1.75;margin:0 0 15px;padding-left:0;list-style:none;display:grid;gap:9px}
.lg-body li{position:relative;padding-left:22px}
.lg-body ul li::before{content:"";position:absolute;left:0;top:.72em;width:11px;height:1px;background:var(--flame)}
.lg-body ol{counter-reset:lgo}
.lg-body ol li{counter-increment:lgo}
.lg-body ol li::before{content:counter(lgo) ".";position:absolute;left:0;top:0;
  font-family:var(--mono);font-size:.76rem;color:var(--flame)}
.lg-body strong{color:var(--text);font-weight:600}
.lg-body a{color:var(--flame);text-decoration:underline;text-underline-offset:2px}

@media(max-width:900px){
  .lg-shell{grid-template-columns:1fr;gap:26px;padding:30px 0 56px}
  .lg-toc{position:static}
  .lg-head{padding:40px 0 32px}
  .lg-dates{gap:26px}
  /* The global `.rv.in{text-align:center}` does not reach here , nothing on
     these pages carries .rv , but the head is centred by design and the body
     must not follow it. */
  .lg-body{text-align:left}
}
@media(max-width:620px){
  .lg-body h2{gap:9px}
}

footer{border-top:1px solid var(--line-soft);padding:56px 0 40px;color:var(--dim)}
footer .fin{display:flex;justify-content:space-between;gap:30px;flex-wrap:wrap;align-items:flex-start}
footer .k-label{display:block;margin-bottom:12px}
footer a{display:block;font-size:.9rem;margin-bottom:9px;transition:color .2s}
footer a:hover{color:var(--text)}
footer .fbot{margin-top:44px;padding-top:24px;border-top:1px solid var(--line-soft);display:flex;justify-content:space-between;flex-wrap:wrap;gap:10px;font-family:var(--mono);font-size:.64rem;letter-spacing:.08em;color:var(--muted)}

.rv{opacity:0;transform:translateY(30px);transition:opacity .9s cubic-bezier(.2,.7,.2,1),transform .9s cubic-bezier(.2,.7,.2,1)}
.rv.in{opacity:1;transform:none}

@media(max-width:960px){
  .rv.in{text-align: center;}
  .nav-links{display:none}
  /* The collage stacks under the copy rather than beside it, and loses height ,
     a 76svh photo block below the fold is all a phone would show. */
  .hero{padding:75px 0 50px}
  .hero-grid{grid-template-columns:1fr;gap:44px}
  .collage{height:60svh}
  .stats-in{grid-template-columns:1fr 1fr}
  .demo-grid{grid-template-columns:1fr;gap:24px}
  /* Stacked, the sheet has the column to itself , the desktop cap would leave
     it stranded left of a full-width block of copy. */
  .sheet{width:100%;max-width:452px;justify-self:center}
  .cost-bars{gap:30px}
}
@media(max-width:620px){
  /* The clamp's 2.9rem floor never kicks in on a phone , 46px of display type
     ate the fold, so the h1 is pinned flat here instead. */
  .hero h1{font-size:26px !important}
  /* Centre the credits block without flattening it.
     `display:flex` here overrode the inline `display:grid` on that span, and a
     flex row puts all four children , label, value, label, value , on one line.
     Only the alignment needed changing; the grid's two columns are what put
     "Base Credit" and "Bonus Credit" on rows of their own. */
  .p-cap span{justify-content:center !important}
  /* A snap rail, not four stacked cards. Stacked, comparing the packs means
     scrolling nearly four screens and holding the last price in your head;
     side by side you can swipe them against each other, which is the decision
     this section exists for. Full-bleed with a 8vw gutter so a card sits dead
     centre with its neighbours peeking in , the peek is the affordance, so it
     needs no "swipe me" label. */
  /* Still pinned , the drag works by scrolling the page, so it needs the zone's
     height to push into. Just shorter, and the gutter narrows so a card sits
     centred with its neighbours peeking in. */
  /* The hairline is hidden at this width (below), so nothing has to clear the
     card and the pin can sit tighter to it than the desktop one. */
  .price-pin{min-height:0;height:clamp(430px,60svh,500px)}
  .plans{gap:12px;padding:0 8vw}
  .plan{flex:0 0 84vw}
  /* Dots here, the hairline on the desktop. Two readouts of the same position
     is one too many, and the dots are the one that reads on a phone. */
  .price-pin .rail-progress{display:none}
  /* Built by landing.js. The active dot stretches into a bar rather than just
     changing colour , a size change reads at a glance where a shade change on
     a 7px circle does not. */
  .plan-dots{display:flex;justify-content:center;align-items:center;gap:7px;margin-top:2px}
  .pdot{width:7px;height:7px;padding:0;border:0;border-radius:100px;cursor:pointer;
    background:var(--line);transition:width .3s cubic-bezier(.2,.8,.2,1),background .3s}
  .pdot.on{width:22px;background:var(--flame)}
  .pdot:hover{background:var(--dim)}
  .pdot.on:hover{background:var(--flame)}
  .hero-cta{flex-direction:row;align-items:flex-start}
  .rcard{flex-basis:82vw}
}
@media(prefers-reduced-motion:reduce){
  *{animation-duration:.001ms!important;animation-delay:0ms!important;transition-duration:.001ms!important}
  .rv,.hero .eyebrow,.hero .sub,.hero-cta,.hero-note,.pl,.stamp{opacity:1;transform:none}
  .hero h1 .ln span{transform:none}
  .frame{opacity:1;transform:none}
}
:focus-visible{outline:2px solid var(--flame);outline-offset:3px}

/* ---------- darkroom filmstrip ---------- */
/* A reel of frames that develop from raw negative to finished photograph as
   they cross a central beam , the transformation the product performs, shown
   rather than described. Drag to scrub; page scroll drives the reel's speed. */
.darkroom{padding:90px 0 0}
.dark-strip{position:relative;background:#100E0B;border-top:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft);
  padding:30px 0 26px;overflow:hidden;cursor:grab;user-select:none;margin-top:44px}
.dark-strip.dragging{cursor:grabbing}
/* film sprocket holes, top and bottom */
.sprockets{position:absolute;left:0;right:0;height:10px;pointer-events:none;
  background-image:radial-gradient(circle 3px, rgba(237,231,218,.22) 98%, transparent), radial-gradient(circle 3px, rgba(237,231,218,.22) 98%, transparent);
  background-size:26px 10px;background-repeat:repeat-x}
.sprockets.top{top:10px}
.sprockets.bot{bottom:8px}
.track{display:flex;gap:16px;width:max-content;will-change:transform;padding:0 8px}
.cell{position:relative;height:250px;aspect-ratio:3/4;border-radius:4px;overflow:hidden;flex:0 0 auto;background:#1b1915}
.cell img,.cell svg{width:100%;height:100%;object-fit:cover;display:block;pointer-events:none}
/* The filter rides on .inner, not .cell , filtering the cell would take the
   caption and frame number down with the image. */
.cell .inner{position:absolute;inset:0;will-change:filter,transform}
.cell .cap{position:absolute;bottom:0;left:0;right:0;padding:12px 8px 6px;background:linear-gradient(transparent,rgba(0,0,0,.62));
  font-family:var(--mono);font-size:.5rem;letter-spacing:.12em;color:#fff;text-transform:uppercase;z-index:3;opacity:.4;transition:opacity .3s}
.cell.lit .cap{opacity:1}
.cell .neg{position:absolute;top:6px;left:7px;z-index:3;font-family:var(--mono);font-size:.5rem;letter-spacing:.1em;color:rgba(237,231,218,.5)}

/* the developer beam */
.beam{position:absolute;top:0;bottom:0;left:50%;width:2px;transform:translateX(-50%);z-index:5;pointer-events:none;
  background:linear-gradient(180deg,transparent,var(--flame) 22%,#F0774E 50%,var(--flame) 78%,transparent)}
.beam::before{content:"";position:absolute;top:0;bottom:0;left:-34px;width:70px;
  background:radial-gradient(ellipse 46% 52% at 50% 50%, rgba(228,87,46,.18), transparent 72%)}
.beam-lbl{position:absolute;top:8px;left:50%;transform:translateX(-50%);z-index:6;pointer-events:none;
  font-family:var(--mono);font-size:.52rem;letter-spacing:.24em;color:#F0774E;text-transform:uppercase;
  background:rgba(16,14,11,.72);padding:3px 10px;border-radius:100px;border:1px solid rgba(228,87,46,.4)}
.strip-foot{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;margin-top:14px;padding:0 8px}
.slbl{font-family:var(--mono);font-size:.54rem;letter-spacing:.16em;color:var(--muted);text-transform:uppercase}

@media(max-width:640px){.cell{height:190px}}
@media(prefers-reduced-motion:reduce){
  /* Every frame simply arrives developed, and the captions stay readable. */
  .cell .inner{filter:none!important;transform:none!important}
  .cell .cap{opacity:1}
}

/* ---------- casting panel: one garment, every model ---------- */
/* A 5×6 matrix , five models, six setups , flipping past at shutter speed.
   The claim being made is range WITH identity held, so the minimap matters as
   much as the loupe: every frame in a row is visibly the same face. */
.castworld{padding:20px 0 0}
/* The head centres as one block on a shared measure , the same `-head` pattern
   the reels, create and cats sections use. */
.castworld-head{text-align:center;max-width:760px;margin:0 auto}
.castworld-head h2{margin-top:16px}
.castworld-head .sec-p{color:var(--dim);font-size:1.02rem;line-height:1.6;
  margin:18px auto 0;max-width:62ch}
.castworld-head .sec-p b{color:var(--text)}
.lr-box{background:#2a2a2a;border:1px solid var(--line-soft);border-radius:10px;padding:22px;box-shadow:var(--shadow);margin-top:46px}
.lr-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:18px;gap:12px;flex-wrap:wrap}
.lr-box .lbl{font-family:var(--mono);font-size:.64rem;letter-spacing:.18em;color:#8f8676;text-transform:uppercase}
.lr-box .roll{font-family:var(--mono);font-size:.64rem;color:#F0774E;letter-spacing:.1em}
.lr-main{display:grid;grid-template-columns:1.05fr 1fr;gap:24px;align-items:stretch}

/* the loupe , the frame currently being looked at */
.loupe{position:relative;border-radius:6px;overflow:hidden;background:#1b1915;aspect-ratio:3/4;max-height:560px; width: 78%;}
.loupe .media{position:absolute;inset:0;animation:settle .3s cubic-bezier(.2,.8,.2,1)}
.loupe .media img,.loupe .media svg{width:100%;height:100%;object-fit:cover;display:block}
@keyframes settle{from{transform:scale(1.035);opacity:.55}to{transform:none;opacity:1}}
/* The overlays that used to sit here , .veil, .who, .idchip, .fno , are gone
   with the markup they styled. .veil went too: its only job was darkening the
   bottom of every frame so the caption could be read, and with no caption it
   was dimming the photograph for nothing. */
.loupe .bar{position:absolute;left:0;bottom:0;height:3px;background:var(--flame);z-index:3;width:0%}

/* the matrix , rows are models, columns are setups */
/* Capped, and pushed to the right of its column.
   The label track used to take 86px of this width; with the names gone that
   went straight into the six thumbnails, which is why they grew. This puts a
   ceiling on the matrix instead of letting it spread , five rows of 3:4 cells
   is also what sets the panel's height, so capping the width caps both. */
.mapside{display:flex;flex-direction:column;gap:14px;min-width:0;
  width:100%;max-width:486px;justify-self:end;}
/* Six even columns, no label track , the header row and the per-row model names
   are gone (see landing.js), so the grid is the photographs and nothing else. */
.mm-row{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:6px;margin-top:6px}
.mm-row:first-child{margin-top:0}
.mm-cell{aspect-ratio:3/4;border-radius:3px;overflow:hidden;position:relative;background:#1b1915;cursor:pointer;
  outline:2px solid transparent;outline-offset:-2px;transition:outline-color .2s,opacity .2s;opacity:.6}
.mm-cell img,.mm-cell svg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.mm-cell:hover{opacity:.95}
.mm-cell.on{outline-color:var(--flame);opacity:1}
.mm-cell.seen{opacity:.85}
.mm-legend{margin-top:auto;display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap}
.mm-legend .same{font-family:var(--mono);font-size:.52rem;letter-spacing:.1em;color:#5FD3A3;text-transform:uppercase}
.lr-foot{display:flex;justify-content:space-between;align-items:center;margin-top:16px;padding-top:14px;border-top:1px solid var(--sheet-line);gap:10px;flex-wrap:wrap}

@media(max-width:860px){
  .reel-cap{
    margin-top: 8px !important;
  }
  .lr-main{grid-template-columns:1fr}
  .loupe{max-height:none; width: 100%;}
  /* No .mapside rule here on purpose , the matrix is hidden outright below this
     width further down the file, so anything set on it would never apply. */
}
@media(prefers-reduced-motion:reduce){
  .loupe .media{animation:none}
}

/* ---------- how it works: the shot setup ---------- */
/* An interactive version of the pitch , pick a model, a background and a pose
   and watch the frame change. Every other panel on this page shows finished
   work; this one lets the visitor drive it, which is the closest thing to a
   trial before signing up. */
.hiw{padding:50px 0 0}
.hiw-head{text-align:center;max-width:640px;margin:0 auto}
.hiw-head .sec-p{margin-left:auto;margin-right:auto}
/* Womenswear / Menswear , a segmented control rather than another pill row,
   because it does not set one property of the shot, it swaps the whole panel
   underneath it. */
.hiw-tabs{margin:30px auto 0}
/* Icon buttons, not a labelled tab strip. Two words of chrome at the head of
   a card whose other four groups are already labelled read as a heavier
   control than the choice deserves; a silhouette says the same thing in a
   third of the width. The name lives on as the button's aria-label + title. */
.hiw-tab{border:0;background:transparent;color:var(--dim);border-radius:100px;cursor:pointer;
  width:38px;height:34px;padding:0;display:grid;place-items:center;
  font-family:inherit;transition:background .25s,color .25s}
.hiw-tab svg{width:21px;height:21px;display:block}
.hiw-tab:hover{color:var(--text)}
.hiw-tab.on{background:var(--card);color:var(--text);box-shadow:0 2px 10px -4px rgba(23,21,15,.45)}
/* Inside the card the pill track is one control among the others rather than a
   centred header, so it drops the auto margins and aligns with the labels. */
.hiw-card .hiw-tabs,.hiw-card .hiw-garments{margin:0;justify-content:flex-start}

.hiw-card{margin-top:26px;background:#2a2a2a;border:1px solid var(--line-soft);border-radius:20px;
  box-shadow:var(--shadow);padding:30px;display:grid;grid-template-columns:1fr .82fr;gap:34px;align-items:center;
  position:relative;overflow:hidden}

/* ── the light that runs round the card ──────────────────────────────
   The colours are the requested sweep , transparent → violet → flame →
   transparent , but laid out as a conic gradient rather than a linear one,
   because only a conic can be spun about the card's centre and read as one
   light travelling the perimeter. A linear gradient can be slid, and that
   reads as a bar crossing the card, not a border in motion.

   `@property` is what makes the spin possible at all: a plain custom property
   is an untyped token, so it would flip from 0deg to 360deg with nothing in
   between. Declaring it an <angle> is what lets the engine interpolate it.
   Where @property is unsupported the ring simply holds still at 0deg, which
   is a static gradient rim rather than a broken one.

   Masked to its own padding box by the same exclude trick `.card-glow` uses,
   so only the 1.5px rim paints and the card's interior is untouched. */
.hiw-card::before{content:"";position:absolute;inset:0;border-radius:inherit;
  padding:1.5px;pointer-events:none;z-index:1;
  background:conic-gradient(from var(--sweep-angle),
    transparent 0deg,#7c5cff 42deg,var(--flame) 84deg,transparent 136deg,transparent 360deg);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
          mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;
  animation:sweep 6s linear infinite}
/* the garments being worked on , a card, not a pill: this is the one choice
   the visitor should be able to see rather than read */
/* A left-aligned wrap row, not a full-width two-column grid. Garment was the
   only group in this card that spanned the whole column, which made a choice
   between two items look heavier than the model, backdrop and pose rows under
   it. Now every group in the card is a row of small controls that start at the
   same left edge. */
/* The same track as `.hiw-tabs` , grey capsule, hairline, 5px of padding , so
   the two rows read as one kind of control. Listed alongside it rather than
   duplicated, so a change to the track reaches both. */
.hiw-tabs,.hiw-garments{display:flex;justify-content:center;gap:6px;width:max-content;max-width:100%;
  background:var(--bg2);border:1px solid var(--line-soft);border-radius:100px;padding:5px}
.hiw-garments{flex-wrap:wrap}
/* A garment button IS a `.hiw-tab`; `.gtab` only swaps the drawn silhouette for
   a chip of the garment, at the same 21px the category icons use. */
.hiw-tab.gtab .gt{width:21px;height:21px;border-radius:5px;overflow:hidden;display:block;
  /* A hairline, so a pale flat-lay still reads as a chip against the track and
     against the white pill it sits on when selected. */
  box-shadow:inset 0 0 0 1px rgba(23,21,15,.2)}
.hiw-tab.gtab .gt img,.hiw-tab.gtab .gt svg{width:100%;height:100%;object-fit:cover;display:block}

.hiw-group{margin-top:24px}
.hiw-group:first-child{margin-top:0}
.hiw-group:nth-child(2) {
  margin-top: 0;
}
.hiw-group .k-label{display:block;margin-bottom:10px}
.hiw-opts{display:flex;gap:10px;flex-wrap:wrap}
.opt{border:1px solid var(--line);background:var(--card);color:var(--text);border-radius:100px;
  padding:.62em 1.15em;font-size:.92rem;font-weight:500;cursor:pointer;
  transition:background .25s,border-color .25s,color .25s,transform .2s}
.opt:hover{border-color:var(--text);transform:translateY(-1px)}
/* The gradient marks every made choice , model, backdrop and pose alike. It was
   on the model pill alone, on the reasoning that the model is the only choice
   that changes WHO is in the photo; in practice that made two of the three rows
   look like settings rather than choices. One rule now, not one per row, so
   `.opt` cannot drift between them.
   `background-image` has no interpolation, so the fill lands at once while the
   border and text still ease , the model pill has always behaved this way. */
.opt.on{background:linear-gradient(90deg,var(--flame),#7c5cff);border-color:transparent;color:#fff}
.hiw-cta{margin-top:30px}

/* the resulting frame */
.hiw-view{position:relative;border-radius:16px;overflow:hidden;background:#1b1915;aspect-ratio:1/1}
.hiw-view .media{position:absolute;inset:0;animation:settle .32s cubic-bezier(.2,.8,.2,1)}
/* The desktop box is square while the photography is 4:5, so `cover` overflows
   vertically and a centred crop takes ~10% off the top , the head, on a panel
   whose entire job is showing a model. Top-anchored for the photograph only;
   the drawn croquis is authored to fit the box and must not be shifted. */
.hiw-view .media img,.hiw-view .media svg{width:100%;height:100%;object-fit:cover;display:block}
.hiw-view .media img{object-position:50% 0%}
.hiw-cap{position:absolute;left:14px;bottom:14px;z-index:2;background:rgba(23,21,15,.72);color:#fff;
  border-radius:100px;padding:8px 15px;font-size:.82rem;backdrop-filter:blur(6px)}
.hiw-center{display: flex; flex-direction: column; align-items: center; text-align: center;}  
.hiw-flex{ display: flex; flex-direction: column; gap: 25px; align-items: center;}

@media(max-width:860px){
.hiw-flex{ display: flex; flex-direction: row; gap: 25px;}
  /* Stacked, the whole widget has to fit one phone screen. It is a thing you
     drive, and a control whose result is 400px below it is a control you
     cannot tell is working , so every part is trimmed to keep the frame in
     view while you tap. No `order` override on purpose: the card still reads
     in the order it is used, category through pose, then the frame those
     choices produce. */
  .hiw-center{display: flex; flex-direction: column; align-items: center; text-align: center;}  
  .hiw-card{grid-template-columns:1fr;gap:12px;padding:16px}
  .hiw-group{margin-top:13px}
  .hiw-group .k-label{margin-bottom:6px}
  .hiw-opts{gap:7px}
  .opt{padding:.42em .9em;font-size:.82rem}
  .hiw-tab{width:34px;height:31px}
  .hiw-tab svg{width:19px;height:19px}
  .hiw-garments{gap:7px}
  /* Shrinks with `.hiw-tab` above; only the chip needs saying. */
  .hiw-tab.gtab .gt{width:19px;height:19px;border-radius:4px}
  .hiw-cta{margin-top:14px}
  .hiw-cta .btn{width:100%;justify-content:center;padding:.7em 1.2em;font-size:.9rem}
  /* Height is the set dimension here and the ratio derives the width, so the
     frame scales with the phone instead of taking the full column width and
     pushing itself off the bottom of the screen. */
  .hiw-view{width:auto;height:50vh;aspect-ratio:3/4;justify-self:center}
  /* Anchored both sides and truncated: the frame is ~200px wide here and the
     caption is a four-part line, so left-anchored it would run off the edge. */
  .hiw-cap{left:8px;right:8px;bottom:8px;padding:6px 10px;font-size:.66rem;text-align:center;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
}
@media(prefers-reduced-motion:reduce){
  .hiw-view .media{animation:none}
}

/* ---------- dark hero band ---------- */
/* The hero runs dark in BOTH themes , photographs read better against it, and
   it gives the page a clear opening beat before the light sections below.
   Written with literals rather than the theme tokens on purpose: this band is
   dark by design, not by preference. */
.hero{background:#0A0908;color:#EDE7DA}
.hero h1{color:#FBF7EF; font-size: 49px; margin-top: 18px;}
.hero .sub{color:#B9B1A0}
.hero .sub b{color:#EDE7DA}
.hero-note{color:#8a8172}
/* the outline CTA needs a light edge to exist against the dark */
.hero .btn-line{border-color:rgba(237,231,218,.34);color:#EDE7DA; padding: 0.8em;}
.hero .btn-line:hover{border-color:#EDE7DA;background:rgba(237,231,218,.06)}

/* The bar is dark whether it is transparent over the hero or solid over the
   page, so its contents are light-on-dark throughout. These were once gated on
   `:not(.solid)`; with the solid state dark too there is nothing left to gate. */
header.nav .logo-light{display:none}
header.nav .logo-dark{display:block}
header.nav .nav-links a{color:rgba(237,231,218,.72)}
header.nav .nav-links a:hover{color:#EDE7DA}
header.nav .btn-line{border-color:rgba(237,231,218,.35);color:#EDE7DA}
header.nav .btn-line:hover{border-color:#EDE7DA;background:rgba(237,231,218,.06)}

/* ---------- mobile navigation ---------- */
/* Below 960px the inline links and CTAs are hidden, so the burger IS the
   navigation , it is never hidden, and it takes the nav's light-on-dark
   treatment at every scroll position. */
.burger{display:none;position:relative;width:42px;height:42px;border:1px solid var(--line);border-radius:100px;
  background:transparent;cursor:pointer;flex-direction:column;align-items:center;justify-content:center;gap:5px;
  transition:border-color .25s,background .25s}
.burger span{display:block;width:17px;height:1.5px;background:var(--text);border-radius:2px;
  transition:transform .3s cubic-bezier(.2,.8,.2,1),opacity .2s}
.burger:hover{border-color:var(--text)}
header.nav .burger{border-color:rgba(237,231,218,.32)}
header.nav .burger span{background:#EDE7DA}
/* the bars become the X while the sheet is open */
body.mnav-open .burger span:nth-child(1){transform:translateY(6.5px) rotate(45deg)}
body.mnav-open .burger span:nth-child(2){opacity:0}
body.mnav-open .burger span:nth-child(3){transform:translateY(-6.5px) rotate(-45deg)}

.mnav{position:fixed;inset:0;z-index:890}          /* under the bar (900) so the burger stays clickable */
.mnav-scrim{position:absolute;inset:0;border:0;padding:0;background:rgba(10,9,8,.55);
  backdrop-filter:blur(3px);cursor:pointer;opacity:0;transition:opacity .3s}
.mnav-sheet{position:absolute;top:0;left:0;right:0;background:var(--bg);border-bottom:1px solid var(--line-soft);
  padding:96px 28px 34px;box-shadow:var(--shadow);
  transform:translateY(-100%);transition:transform .38s cubic-bezier(.22,.9,.3,1)}
body.mnav-open .mnav-scrim{opacity:1}
body.mnav-open .mnav-sheet{transform:none}

.mnav-links{display:flex;flex-direction:column}
.mnav-links a{font-family:var(--serif);font-size:1.7rem;line-height:1.5;color:var(--text);
  border-bottom:1px solid var(--line-soft);padding:12px 0;transition:color .2s}
.mnav-links a:last-child{border-bottom:0}
.mnav-links a:hover{color:var(--flame)}
.mnav-cta{display:flex;flex-direction:column;gap:12px;margin-top:26px}
.mnav-cta .btn{justify-content:center}

/* The sheet is scrollable in its own right on a short screen, so a long menu
   in landscape never puts the last link past the bottom edge. */
@media(max-height:520px){
  .mnav-sheet{max-height:100svh;overflow-y:auto}
  .mnav-links a{font-size:1.25rem;padding:9px 0}
}
@media(max-width:960px){
  .burger{display:flex}
  .nav-cta{display:none}                            /* Log in / Register move into the sheet */
}
@media(min-width:961px){
  .mnav{display:none}                               /* nothing to open above the breakpoint */
}
@media(prefers-reduced-motion:reduce){
  .mnav-sheet,.mnav-scrim,.burger span{transition:none}
}

/* ---------- "what do you want to create" accordion ---------- */
/* Four entry points that expand on hover. The panels animate `flex-grow`
   rather than width , grow is a single transitionable number and the row stays
   exactly full whatever the viewport, where animating widths would need them
   to sum correctly at every frame. */
.create{padding:50px 0 0}
.create-head{text-align:center;max-width:720px;margin:0 auto}
.create-head .sec-p{margin-left:auto;margin-right:auto}
/* `relative` so the round advance control can be pinned to the row's edge. */
.create-row{position:relative;display:flex;gap:14px;margin-top:24px;height:min(45svh,600px)}
.cnext{position:absolute;right:-19px;top:50%;transform:translateY(-50%);z-index:4;
  width:44px;height:44px;border-radius:50%;border:0;cursor:pointer;
  background:var(--flame);color:#fff;display:flex;align-items:center;justify-content:center;
  box-shadow:0 10px 26px -8px rgba(228,87,46,.9);transition:transform .25s,background .25s}
.cnext:hover{background:var(--flame-2);transform:translateY(-50%) scale(1.08)}
.cnext:active{transform:translateY(-50%) scale(.94)}
.cnext svg{width:17px;height:17px}
.cpanel{position:relative;flex:1 1 0;min-width:0;border-radius:16px;overflow:hidden;background:#1b1915;
  cursor:pointer;border:0;padding:0;text-align:left;color:#fff;display:block;
  will-change:flex-grow;transition:flex-grow .55s cubic-bezier(.22,.9,.3,1)}
/* Only the width moves. The others keep flex-grow:1 and simply lose their share
   as the open one claims more , 1 : 1 : 1 : 5.8 puts the open card at ~66% of
   the row and each closed one at ~11%, which is the proportion in the design. */
.cpanel.on{flex-grow:5.8}
/* The card is a fixed window; the image behind it is what moves. Scaling the
   picture instead of the box means the frame's corners and its neighbours stay
   put, and the type layered over it is never resampled. */
.cpanel img,.cpanel svg,.cpanel video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 30%;
  /* Both anchors point at the top, because two separate things crop the head.

     `transform-origin` handles the scale(1.08): about the centre it grows the
     picture in every direction at once, and the half growing upward is the
     half with the face in it.

     `object-position` handles the bigger one. Closed, the panel is narrow and
     tall, so `cover` fits by height and nothing is cropped vertically. Open,
     it is ~6x wider, so `cover` switches to fitting by width and the image
     overflows the box vertically by a lot , and 50% 30% then holds the crop
     30% down, which on a full-length shot lands below the chin. Panning to
     the top edge as it opens keeps the head in frame at every width. */
  transform-origin:50% 0;
  transition:transform .7s cubic-bezier(.22,.9,.3,1),
             object-position .7s cubic-bezier(.22,.9,.3,1)}
.cpanel.on img,.cpanel.on svg,.cpanel.on video{transform:scale(1.08);object-position:50% 6%}
/* keeps the type legible whatever the photograph is doing underneath it */
.cpanel::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(transparent 42%,rgba(10,9,8,.82))}

.cpanel .cname{position:absolute;left:20px;bottom:22px;z-index:2;font-size:1.18rem;font-weight:600;
  white-space:nowrap;transition:opacity .3s,transform .45s cubic-bezier(.22,.9,.3,1)}
.cpanel .cdetail{position:absolute;left:28px;right:28px;bottom:26px;z-index:2;
  opacity:0;transform:translateY(14px);pointer-events:none;
  transition:opacity .4s .12s,transform .5s .12s cubic-bezier(.22,.9,.3,1)}
.cpanel .cdetail h3{font-size:clamp(1.5rem,2.4vw,2.1rem);color:#fff;line-height:1.1}
.cpanel .cdetail p{color:rgba(255,255,255,.82);font-size:1rem;margin:10px 0 0;max-width:46ch}
.cpanel .center{display:inline-flex;align-items:center;gap:.5em;margin-top:16px;
  color:var(--flame);font-weight:600;font-size:1rem}
.cpanel .center .arw{transition:transform .3s}
.cpanel.on .cname{opacity:0;transform:translateY(10px)}
.cpanel.on .cdetail{opacity:1;transform:none;pointer-events:auto}
.cpanel.on:hover .center .arw{transform:translateX(5px)}

@media(max-width:860px){
  /* The row turns on its side: four full-width banners stacked, each showing
     only its name until it is opened. Sideways the panels either had to be
     slivers or a rail that hides three of the four doors off-screen , stacked,
     all four are visible at once and the open one has the width to be read.
     Height is the animated property here rather than flex-grow: the column has
     no fixed extent to share out, so each panel owns its own size. */
  /* The zone's height is written by landing.js from the viewport, and the pin
     inside it is what actually sticks. Above this breakpoint both are plain
     wrappers with no height and no stickiness. */
  .create-pin{position:sticky;top:0;display:flex;align-items:center}
  .create-row{flex-direction:column;height:auto;gap:12px;margin-top:14px;width:100%}
  .mapside{display: none;}
  .lr-box{margin-top: 10px;}
  .sheet-foot{justify-content: center;}
  
  /* Sized so the whole stack , one open card plus three closed , fits inside
     the pinned viewport. A row taller than the pin would have its last card
     cut off with no way to scroll to it, since scrolling is what advances the
     accordion rather than moving the section. */
  .create-row .cpanel{flex:0 0 auto;height:72px;
    transition:height .5s cubic-bezier(.22,.9,.3,1)}
  /* `.on` is set by landing.js, not :hover , on a touch screen the first tap
     opens the panel and only the second follows the link. */
  .create-row .cpanel.on{height:min(48svh,360px)}
  .cnext{display:none}              /* nothing to advance to , all four show */
}
@media(prefers-reduced-motion:reduce){
  .cpanel,.cpanel img,.cpanel svg,.cpanel video,.cpanel .cname,.cpanel .cdetail{transition:none}
}

/* ---------- "built for brands at every stage" category carousel ---------- */
/* Pills pick a category; the deck fans three cards with the chosen one upright
   in the middle. The tilt on the outer two is what stops this reading as three
   equal cards in a row , they are clearly waiting their turn. */
.cats{overflow:hidden}
.cats-head{text-align:center;max-width:680px;margin:0 auto}
.cats-head .sec-p{margin:14px auto 0}
.cats-pills{display:flex;flex-wrap:wrap;justify-content:center;gap:10px;margin-top:30px}
.cpill{border:1px solid var(--line);background:var(--card);color:var(--text);border-radius:100px;
  padding:0.4em 0.5em;font-size:.92rem;font-weight:500;cursor:pointer;white-space:nowrap;
  transition:background .25s,border-color .25s,color .25s,transform .2s}
.cpill:hover{border-color:var(--text);transform:translateY(-1px)}
.cpill.on{background:var(--text);border-color:var(--text);color:var(--bg)}

/* the deck */
.cats-stage{position:relative;height:min(78svh,660px);margin-top:40px;cursor:grab;
  /* Horizontal gestures belong to the deck, vertical ones to the page , without
     this the browser claims the drag as a scroll and the deck never moves. */
  touch-action:pan-y;user-select:none;-webkit-user-select:none}
.cats-stage.dragging{cursor:grabbing}
/* While dragging the transform IS the finger position, so a transition would
   make it lag behind by its own duration. */
.cats-stage.dragging .ccard{transition:none}
/* Native image/link dragging would otherwise hijack the gesture with a ghost. */
.ccard img{-webkit-user-drag:none;user-select:none;pointer-events:none}
.ccard{position:absolute;top:0;left:50%;width:clamp(240px,26vw,352px);height:100%;
  border-radius:20px;overflow:hidden;background:#1b1915;color:#fff;text-align:center;
  border:0;padding:0;cursor:pointer;text-decoration:none;display:block;
  /* Transforms are written from JS so one formula covers every offset and the
     wrap-around; the transition here is what makes them glide. */
  transition:transform .62s cubic-bezier(.22,.9,.3,1),opacity .5s;
  box-shadow:0 30px 60px -30px rgba(10,9,8,.55)}
.ccard img,.ccard svg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
/* enough scrim to carry white type over any photograph */
.ccard::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(rgba(10,9,8,.1) 20%,rgba(10,9,8,.62))}
.ccard-in{position:absolute;left:22px;right:22px;top:44%;z-index:2;transform:translateY(-30%)}
.ccard-in h3{font-size:clamp(1.8rem,3vw,2.6rem);color:#fff;line-height:1.02;text-shadow:0 2px 18px rgba(0,0,0,.5)}
.ccard-in p{font-size:.95rem;line-height:1.5;color:rgba(255,255,255,.9);margin:14px 0 0;
  text-shadow:0 1px 10px rgba(0,0,0,.6)}
.ccard .clearn{display:inline-flex;align-items:center;gap:.45em;margin-top:20px;background:var(--card);
  color:var(--text);border-radius:100px;padding:.62em 1.2em;font-size:.9rem;font-weight:600;
  box-shadow:0 8px 20px -8px rgba(10,9,8,.5)}
.ccard .clearn .arw{transition:transform .3s}
.ccard:hover .clearn .arw{transform:translateX(4px)}
/* Only the middle card is a live target , the others are there to be brought
   forward first, and their copy is half-turned and unreadable anyway. */
.ccard:not(.mid){pointer-events:auto}
.ccard:not(.mid) .clearn{display:none}

@media(max-width:860px){
  /* One card at a time: a fanned deck at phone width is three slivers, and the
     side cards' rotated copy is unreadable. The pills still drive it. */
  .cats-stage{height:min(72svh,560px)}
  /* One card, near full-bleed , at this width the deck is a single card, so it
     should use the room rather than sit in the middle of two empty margins. */
  .ccard{width:min(88vw,420px)}
  .ccard-in{left:26px;right:26px}

  /* A wrapped pill row leaves a ragged 4+3 that clips the moment one label is
     a little long. A single scrolling strip cannot clip whatever the labels
     say, and the active pill is scrolled into view when it changes.
     Negative margins let it run to the screen edges while the first and last
     pills keep the text column's padding. */
  .cats-pills{flex-wrap:wrap;justify-content:center;overflow-x:auto;
    margin-left:-35px;margin-right:-35px;padding:2px 32px;
    scrollbar-width:none;-ms-overflow-style:none;scroll-snap-type:x proximity}
  .cats-pills::-webkit-scrollbar{display:none}
  .cpill{flex:0 0 auto;scroll-snap-align:center}
}
@media(prefers-reduced-motion:reduce){
  .ccard{transition:none}
}

/* ---------- prompt genie: summoned by the scroll ---------- */
/* Violet and gold are the Genie's colours inside the app, and carrying them
   here is what makes this read as the same feature rather than another flame
   panel. Declared beside the section instead of at the top of the file
   because nothing else on the page uses them. */
:root{--genie:#6E44D6;--genie-2:#A87B26}
[data-theme="dark"]{--genie:#B08CFF;--genie-2:#D8B45E}

.genie-sec{position:relative;background:var(--bg2);transition:background .5s}
.genie-sec .pin-wrap{height:340svh}
.genie-sec .pin{flex-direction:column;justify-content:flex-start;gap:clamp(16px,3vh,30px);
  height:100svh;min-height:600px;padding:clamp(90px,12vh,130px) 24px 46px}

/* Darkens the section as the panel forms, so it reads as a dialog over the
   page rather than one more card sitting in the flow. Opacity is scrubbed
   from scroll, which is why there is no transition on it. */
.genie-veil{position:absolute;inset:0;opacity:0;pointer-events:none;z-index:2;
  background:radial-gradient(ellipse 74% 62% at 50% 58%,color-mix(in srgb,var(--genie) 16%,transparent),transparent 70%),
             rgba(8,7,6,.66)}

.genie-copy{position:relative;z-index:1;text-align:center;will-change:opacity,transform}
.genie-copy .eyebrow{color:var(--genie)}
.genie-copy h2{font-size:var(--h2);margin-top:14px}
.genie-copy h2 em{font-style:italic;color:var(--genie)}
.genie-copy p{color:var(--dim);font-size:1.02rem;margin:16px auto 0;max-width:76ch}
.genie-hint{display:inline-block;margin-top:20px;font-family:var(--mono);font-size:.64rem;
  letter-spacing:.22em;text-transform:uppercase;color:var(--muted)}
.genie-hint .arw{color:var(--genie)}

/* A centring layer over the whole pin rather than a block in the column: the
   tile and the panel it becomes must share one centre, or the smoke would
   leave from one point and the panel form at another. Transparent to the
   pointer so the copy underneath stays selectable. */
/* The padding pushes the centre , and so the tile, the burst and the panel
   that forms out of it , clear of the copy above. This value is only the
   starting point: landing.js measures the copy and overwrites it, because a
   fixed number cannot know how many lines the paragraph wrapped to. */
.genie-stage{position:absolute;inset:0;z-index:3;pointer-events:none;padding-top:min(120px,14vh);
  display:flex;align-items:center;justify-content:center}

/* ---- the tile ---- */
@keyframes gbob{0%,100%{transform:translateY(0) rotate(-1.2deg)}50%{transform:translateY(-9px) rotate(1.2deg)}}
@keyframes ghalo{0%,100%{opacity:.4;transform:scale(1)}50%{opacity:.85;transform:scale(1.16)}}

/* The bob lives on .gt-in, not the tile: the scroll writes the tile's own
   transform every frame, and two transforms on one box cannot both win. */
.genie-tile{position:absolute;width:214px;padding:20px 16px 18px;border-radius:18px;cursor:pointer;
  text-align:center;color:var(--text);font-family:inherit;
  border:1px solid color-mix(in srgb,var(--genie) 28%,transparent);
  background:linear-gradient(160deg,var(--card),color-mix(in srgb,var(--genie) 9%,var(--card)));
  box-shadow:0 20px 46px -20px color-mix(in srgb,var(--genie) 60%,transparent),var(--shadow);
  will-change:transform,opacity,filter}
/* A masked pseudo-element is the only way to stroke a gradient border. */
.genie-tile::after{content:"";position:absolute;inset:-2px;border-radius:20px;padding:2px;
  background:linear-gradient(140deg,var(--genie),#b98bff,var(--genie-2));
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;opacity:.6;pointer-events:none}
.gt-in{display:block;animation:gbob 3.4s ease-in-out infinite;transform-origin:50% 60%}
.gt-orb{position:relative;display:flex;width:76px;height:76px;margin:0 auto 12px;
  align-items:center;justify-content:center;transition:transform .3s;
  filter:drop-shadow(0 6px 16px color-mix(in srgb,var(--genie) 45%,transparent))}
.gt-orb::before{content:"";position:absolute;inset:-8px;border-radius:50%;
  background:radial-gradient(circle,color-mix(in srgb,var(--genie) 35%,transparent),transparent 70%);
  animation:ghalo 2.6s ease-in-out infinite}
.gt-orb img{position:relative;width:100%;height:100%;object-fit:contain}
.genie-tile:hover .gt-orb{transform:scale(1.06)}
.gt-name{display:block;font-size:1.04rem;font-weight:700;letter-spacing:-.01em}
.gt-sub{display:block;margin-top:3px;font-size:.76rem;color:var(--muted)}

/* ---- the panel the smoke turns into ---- */
/* Dark in both themes, like the contact sheet , it is a player, not a card. */
/* The third cap is the height one: a 16/9 player plus its bar and caption is
   taller than a short viewport, and .pin clips whatever runs past it , so the
   panel is narrowed until it fits rather than cropped. */
.genie-modal{position:absolute;width:min(780px,calc(100vw - 40px),calc((100svh - 320px) * 16 / 9));
  border-radius:14px;overflow:hidden;opacity:0;
  background:var(--sheet-bg);border:1px solid var(--sheet-line);
  box-shadow:0 60px 120px -50px rgba(0,0,0,.85);pointer-events:none;
  will-change:transform,opacity,filter}
.gm-bar{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;
  border-bottom:1px solid var(--sheet-line)}
.gm-bar .k-label{color:#8f8676}
.gm-dot{width:8px;height:8px;border-radius:50%;background:var(--genie-2);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--genie-2) 24%,transparent)}
.gm-media{position:relative;aspect-ratio:16/9;background:#0e0d0b;overflow:hidden}
.gm-media video,.gm-media img{width:100%;height:100%;object-fit:cover}
/* A portrait still cropped to 16/9 loses the face on a centre crop, and the
   face is the whole point of an on-model frame. */
.gm-media img{object-position:50% 20%}
.gm-media svg{width:100%;height:100%}
.gm-sound{position:absolute;right:12px;bottom:12px;z-index:2;border:1px solid rgba(255,255,255,.24);
  background:rgba(14,13,11,.62);color:#EDE7DA;border-radius:100px;padding:.42em 1em;cursor:pointer;
  font-family:var(--mono);font-size:.6rem;letter-spacing:.16em;text-transform:uppercase;
  backdrop-filter:blur(6px);transition:border-color .3s,background .3s}
.gm-sound:hover{border-color:var(--genie-2);background:rgba(14,13,11,.85)}
.gm-foot{display:grid;gap:8px;padding:14px 16px 16px}
.gm-line{font-size:.92rem;line-height:1.5;color:rgba(237,231,218,.66)}
.gm-line b{font-family:var(--mono);font-size:.58rem;letter-spacing:.18em;text-transform:uppercase;
  color:#8f8676;margin-right:10px;font-weight:400}
.gm-out{color:#EDE7DA}
.gm-out b{color:var(--genie-2)}

/* ---- the burst ---- */
/* Appended to <body> and thrown away when the animation ends: transform,
   opacity and filter only, so the panel forming at the same moment does not
   have to share the paint path with twenty particles. */
.gsmoke,.gring,.gcore{position:fixed;border-radius:50%;pointer-events:none}
.gsmoke{z-index:60}
.gring{z-index:59;border:2px solid rgba(150,120,240,.5)}
.gcore{z-index:58;filter:blur(6px);
  background:radial-gradient(circle at 50% 50%,rgba(190,160,255,.68) 0%,rgba(201,162,75,.34) 42%,transparent 72%)}

@media(max-width:860px){
  .genie-sec .pin-wrap{height:300svh}
  /* Tall enough for the copy AND the tile to sit one under the other: at 540px
     they were being asked to share the same 540px. */
  .genie-sec .pin{min-height:640px;padding-top:clamp(58px,9vh,86px)}
  .genie-copy p{font-size:.96rem}

  /* The tile is centred in the whole pin on desktop, which works because the
     copy is short there. Wrapped to five lines on a phone the copy reaches the
     middle, and a centred tile lands on top of it. Anchored to the bottom, the
     two stack instead: copy at the top, tile below, whatever the copy's height
     turns out to be. */
  .genie-stage{align-items:flex-end;padding:0 24px clamp(48px,11vh,96px)}
  .genie-tile{width:186px;padding:18px 14px 16px}
  .gt-orb{width:64px;height:64px}
  .gm-line{font-size:.84rem}
}
@media(max-width:560px){
  /* The rewritten brief is the point of the panel; the one-line prompt above
     it is not worth the two lines it wraps to at this width. */
  .gm-foot .gm-line:not(.gm-out){display:none}
  .cats{
    padding-top:20px;
  }
}
@media(prefers-reduced-motion:reduce){
  .gt-in,.gt-orb::before{animation:none}
}

/* ---------- the output: a fan of frames that play ---------- */
/* The arc itself is written from landing.js , the angle of each card depends
   on how wide the card actually rendered, so it cannot be a static list of
   rotations. Everything here is the part that does not depend on that: the
   frame, the hover, and the two shapes the row takes. */
/* Top padding scales rather than sitting at a fixed 50px, and the phone no
   longer zeroes it — the eyebrow was landing hard against the section above
   with nothing between them. */
.reels{padding:clamp(52px,7vw,86px) 0 0;overflow:hidden}
.reels-head{text-align:center;max-width:760px}
.reels-head h2{font-size:var(--h2);margin-top:16px}
.reels-head h2 em{font-style:italic;color:var(--flame)}
.reels-head .sec-p{margin:18px auto 0;max-width:86ch}

/* The frame stays light in the dark theme: these are meant to read as prints
   laid out on a table, and a near-black border round a photo on a near-black
   page is no border at all. */
[data-theme="dark"]{--reel-frame:#EDE7DA}

.reel-arc{position:relative;margin-top:clamp(40px,6vw,45px);
  height:470px !important}

/* Outer box carries the card's place in the arc, inner box carries the hover.
   Two boxes because one transform cannot be written by two owners , the arc
   is set from JS, the lift belongs to CSS. */
.reel{position:absolute;left:50%;top:0;width:clamp(132px,15vw,212px);
  opacity:0;transform:translate(-50%,46px);
  transition:transform .75s cubic-bezier(.2,.8,.2,1),opacity .5s}
.reel.in{opacity:1}
.reel-in{display:block;width:100%;aspect-ratio:3/4;border-radius:14px;overflow:hidden;position:relative;
  background:var(--bg2);border:4px solid var(--reel-frame,var(--card));
  box-shadow:0 22px 44px -22px rgba(23,21,15,.75);
  cursor:pointer;transition:transform .45s cubic-bezier(.2,.8,.2,1),box-shadow .45s}
.reel-in img,.reel-in video{width:100%;height:100%;object-fit:cover;display:block}
/* Straightening the card out of the arc is the hover: it steps forward and
   stands up while its neighbours stay tilted. */
/* `.playing` is set by the tour in landing.js. It shares the hover rules so a
   card the row raised on its own is indistinguishable from one you raised. */
.reel:hover,.reel:focus-within,.reel.playing{z-index:40 !important}
.reel:hover .reel-in,.reel:focus-within .reel-in,.reel.playing .reel-in{
  transform:rotate(calc(var(--rot,0deg) * -0.6)) translateY(-16px) scale(1.06);
  box-shadow:0 40px 70px -26px rgba(23,21,15,.8)}
.reel-in:focus-visible{outline:2px solid var(--flame);outline-offset:3px}

/* Sits over the poster until the clip is running. */
/* Counter-rotated out of the card's own tilt: a play symbol lying on its side
   reads as a decoration, not a control. */
.reel-play{position:absolute;left:50%;top:50%;z-index:2;width:44px;height:44px;margin:-22px 0 0 -22px;
  border-radius:50%;background:rgba(23,21,15,.55);backdrop-filter:blur(4px);
  display:flex;align-items:center;justify-content:center;pointer-events:none;
  transform:rotate(calc(var(--rot,0deg) * -1));
  transition:opacity .3s,transform .3s}
.reel-play::before{content:"";border-style:solid;border-width:7px 0 7px 11px;
  border-color:transparent transparent transparent #fff;margin-left:3px}
.reel.playing .reel-play{opacity:0;transform:rotate(calc(var(--rot,0deg) * -1)) scale(.8)}

/* The caption for the hovered frame, in the gap the arc leaves beneath it.
   A fixed min-height rather than an auto one: the text swaps on every hover,
   and a box that resized with it would walk the hint below up and down. */
/* The caption, on the frame it describes.
   Sat below the arc it could only ever name one of eleven fanned cards, and
   the one it named was whichever you happened to be pointing at , so the row
   had a line of text that changed under you as you moved. On the card it is
   attached to the thing it is about, and every frame carries its own. */
.reel-cap-in{position:absolute;left:0;right:0;bottom:0;z-index:3;
  padding:26px 12px 11px;text-align:center;pointer-events:none;
  /* Reaching well above the text so it fades into the picture rather than
     ending on a visible edge. */
  background:linear-gradient(transparent,rgba(10,9,8,.42) 38%,rgba(10,9,8,.86));
  /* Legible at rest, not only on hover: every card in the arc names itself, so
     the row reads as a set of titled clips rather than eleven anonymous
     thumbnails you have to point at one at a time. */
  opacity:1;transform:none;
  transition:opacity .32s cubic-bezier(.2,.8,.2,1),
             transform .32s cubic-bezier(.2,.8,.2,1),
             background .32s cubic-bezier(.2,.8,.2,1)}
.reel-cap-in b{display:block;font-family:var(--serif);font-weight:500;
  font-size:1.02rem;line-height:1.2;color:#fff}
.reel-cap-in i{display:block;margin-top:4px;font-style:normal;font-family:var(--mono);
  font-size:.5rem;letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.72);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Strengthened , not revealed , on the card the row has raised: hover, keyboard
   focus, or the frame the tour is playing. Exactly the three states that already
   straighten a card out of the arc. The caption is on every card at rest now, so
   what these do is deepen the scrim under the one you are looking at, which is
   the card whose title you are actually trying to read. */
.reel:hover .reel-cap-in,
.reel:focus-within .reel-cap-in,
.reel.playing .reel-cap-in{
  background:linear-gradient(transparent,rgba(10,9,8,.6) 38%,rgba(10,9,8,.95))}

.reel-hint{margin-top:clamp(26px,4vw,44px);text-align:center;font-family:var(--mono);
  font-size:.66rem;letter-spacing:.22em;text-transform:uppercase;color:var(--muted)}

@media(max-width:860px){
  /* An arc of nine frames at phone width is nine slivers. The same cards
     become one swipeable strip instead, and JS stops writing arc transforms
     so nothing fights the scroller. */
  .reel-arc{display:flex;gap:12px;height:auto;position:static;overflow-x:auto;
    padding:4px 24px 10px;scroll-snap-type:x mandatory;
    scrollbar-width:none;-ms-overflow-style:none; height: 339px !important;}
  .reel-arc::-webkit-scrollbar{display:none}
  .reel{position:static;flex:0 0 min(58vw,240px);opacity:1;transform:none;scroll-snap-align:center}
  .reel:hover .reel-in,.reel:focus-within .reel-in{transform:none}
}
@media(prefers-reduced-motion:reduce){
  .reel,.reel-in,.reel-play{transition:none}
}

/* ---------- why brands choose us ---------- */
/* A dark band, like the hero and the contact sheet: the three numbers are the
   page's summary and they read louder against black than against the cream.
   Written with literals rather than theme tokens for the same reason the hero
   is , this band is dark by design, not by preference. */
.why{position:relative;overflow:hidden;background:#0B0A0F;color:#EDE7DA;
  padding:clamp(54px,7vw,92px) 0}
/* Two soft pools of colour so the black is lit rather than flat. Behind the
   content and inert, so nothing here catches a click. */
.why::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse 60% 50% at 18% 0%,rgba(124,92,255,.16),transparent 70%),
             radial-gradient(ellipse 55% 45% at 88% 12%,rgba(228,87,46,.12),transparent 72%)}
.why .wrap{position:relative;z-index:1}
.why-head{text-align:center}
.why-eyebrow{color:#B08CFF}

.why-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(12px,1.5vw,20px);margin-top:clamp(24px,3vw,38px)}
.wcard{position:relative;text-align:center;border-radius:18px;
  border:1px solid rgba(237,231,218,.1);
  background:linear-gradient(180deg,rgba(237,231,218,.055),rgba(237,231,218,.012));
  padding:clamp(26px,2.8vw,36px) clamp(18px,2vw,28px);
  transition:border-color .35s,background .35s,transform .35s cubic-bezier(.2,.8,.2,1)}
.wcard:hover{transform:translateY(-4px);border-color:rgba(237,231,218,.2);
  background:linear-gradient(180deg,rgba(237,231,218,.085),rgba(237,231,218,.02))}
/* The flame tick above each number , the one warm mark on the card, and what
   stops three bordered boxes reading as a table. */
.wcard::before{content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);
  width:54px;height:2px;border-radius:2px;
  background:linear-gradient(90deg,transparent,var(--flame),transparent)}
/* Sans, not the page's serif: these are figures to be read at a glance, and
   Playfair's high contrast works against that at this weight. */
.wcard .n{font-family:var(--sans);font-weight:700;letter-spacing:-.025em;line-height:1;
  font-size:clamp(2.4rem,4.6vw,3.5rem);color:#fff}
.wcard .t{margin-top:12px;font-size:.95rem;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;color:#EDE7DA}
.wcard .d{margin:12px auto 0;max-width:34ch;font-size:.92rem;line-height:1.6;
  color:rgba(237,231,218,.6)}

.why-sep{height:1px;margin:clamp(32px,4vw,52px) 0;
  background:linear-gradient(90deg,transparent,rgba(237,231,218,.15),transparent)}

.why-use{text-align:center}
.use-eyebrow{color:#E9B44C}
/* Edge to edge rather than inside .wrap: a ticker that starts and stops at the
   text column reads as a scrolling box, not as a band running under the page.
   Safe against 100vw's scrollbar overflow because body sets overflow-x:hidden. */
.use-marquee{margin-top:22px;width:100vw;margin-left:calc(50% - 50vw);overflow:hidden;
  /* The ends fade instead of cutting, so chips arrive and leave rather than
     popping in and out at a hard edge. */
  -webkit-mask:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
          mask:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
/* `width:max-content` so the track is as wide as its four copies and the
   percentage in the keyframe resolves against that, not against the viewport. */
.use-track{display:flex;width:max-content;animation:useMarquee 30s linear infinite}
/* One copy is 25% of a four-copy track, so travelling that far lands the next
   copy exactly where the last one started , the loop point is invisible. */
@keyframes useMarquee{from{transform:translateX(-25%)}to{transform:none}}
/* Reading a chip should not mean chasing it. */
.use-marquee:hover .use-track{animation-play-state:paused}
.use-row{display:flex;flex:0 0 auto;gap:11px;padding-right:11px}
.use-chip{display:inline-flex;align-items:center;gap:.55em;white-space:nowrap;
  border:1px solid rgba(237,231,218,.18);border-radius:100px;
  padding:.7em 1.2em;color:#EDE7DA;font-size:.95rem;font-weight:500;
  transition:border-color .25s,background .25s,transform .25s cubic-bezier(.2,.8,.2,1)}
.use-chip .arw{transition:transform .25s;color:rgba(237,231,218,.6)}
.use-chip:hover{border-color:rgba(237,231,218,.45);background:rgba(237,231,218,.07);
  transform:translateY(-2px)}
.use-chip:hover .arw{transform:translateX(4px);color:#EDE7DA}

@media(max-width:860px){
  .why-grid{grid-template-columns:1fr}
  /* The marquee already runs at every width , nothing to convert to a rail. */
  .use-chip{font-size:.9rem;padding:.62em 1.05em}
  .ens { flex-direction: column;
  }
}

/* The page-wide reduced-motion rule clamps animation-duration, which would
   leave the marquee frozen partway through its travel with chips half off the
   screen. Standing the animation down and letting the row be swiped instead is
   the honest version of "no motion". */
@media(prefers-reduced-motion:reduce){
  .use-track{animation:none!important;overflow-x:auto;max-width:100%}
  .use-marquee{-webkit-mask:none;mask:none}
}

/* ---------- ensemble: the styling map ---------- */
/* Six pieces beside one figure, each tied to the spot it is styled onto.
   Light, on the page's own surface , this sits between two light sections and
   a dark band here would read as a different site. */
.ens{ display: flex;
    align-items: center; padding:clamp(30px,3.6vw,50px) 0}
.ens-head{text-align:center;max-width:720px;margin:0 auto}
.ens-head h2{margin-top:16px}
.ens-head h2 em{font-style:italic;color:var(--flame)}
.hiw-head h2 em{font-style:italic;color:var(--flame)}
.demo-copy h2 em{font-style:italic;color:var(--flame)}
.castworld-head h2 em{font-style:italic;color:var(--flame)}
.ens-head .sec-p{color:var(--dim);font-size:1.02rem;line-height:1.6;max-width:56ch;margin:18px auto 0}

/* Sized to its contents and centred, not stretched across the text column.
   Given a `1fr` right track the stage centred inside a 700px column while the
   pieces stayed pinned left , a widget with a hole in the middle, and a
   tie-line that spanned the gap while the real distance was three times it.
   Both tracks are fixed now, so the gap IS the distance between them. */
.ens-grid{--ens-gap:clamp(18px,2.4vw,32px);
  display:grid;grid-template-columns:minmax(0,208px) minmax(0,296px);
  justify-content:center;gap:var(--ens-gap);align-items:center;
  margin-top:clamp(20px,2.4vw,32px)}

/* ---- the pieces ---- */
.ens-pieces{display:flex;flex-direction:column;gap:6px;min-width:0}
.ens-piece{position:relative;display:flex;align-items:center;gap:11px;text-align:left;
  background:var(--card);border:1px solid var(--line-soft);border-radius:12px;
  padding:7px 9px;cursor:pointer;font-family:inherit;color:var(--text);
  transition:border-color .25s,transform .25s cubic-bezier(.2,.8,.2,1),box-shadow .25s}
.ens-piece:hover{transform:translateX(2px)}
.ens-piece.on{border-color:var(--flame);
  box-shadow:0 10px 24px -18px rgba(228,87,46,.9)}

/* The tie. Drawn from the card's right edge across the grid gap to the frame,
   so an active piece is visibly connected to the pin it lands on rather than
   merely lit at the same time. */
.ens-piece::after{content:"";position:absolute;left:100%;top:50%;height:1px;
  width:var(--ens-gap);background:linear-gradient(90deg,var(--flame),transparent);
  transform:scaleX(0);transform-origin:0 50%;
  transition:transform .3s cubic-bezier(.2,.8,.2,1)}
.ens-piece.on::after{transform:none}

.ep-shot{flex:0 0 auto;width:38px;height:38px;border-radius:8px;overflow:hidden;
  background:#F5F2EB;border:1px solid var(--line-soft)}
.ep-shot svg,.ep-shot img{width:100%;height:100%;display:block}
.ep-shot img{object-fit:cover}
.ep-meta{min-width:0;flex:1;display:block}
.ep-meta b{display:block;font-size:.82rem;font-weight:700;line-height:1.2}
.ep-meta i{display:block;margin-top:1px;font-style:normal;font-size:.68rem;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ep-no{flex:0 0 auto;font-family:var(--mono);font-size:.54rem;letter-spacing:.1em;color:var(--muted)}
.ens-piece.on .ep-no{color:var(--flame)}

/* ---- the figure ---- */
.ens-stage{position:relative;width:100%;justify-self:center;
  /* The shoot's own ratio (928x1152). At 2/3 the photograph would be cropped
     at the sides , and every pin below was measured against the uncropped
     frame, so a crop would slide them off the pieces they point at. */
  aspect-ratio:928/1152;border-radius:14px;overflow:hidden;background:#EFEBE3;
  border:1px solid var(--line-soft);box-shadow:var(--shadow)}
.ens-figure,.ens-figure svg,.ens-figure img{position:absolute;inset:0;width:100%;height:100%}
.ens-figure img{object-fit:cover;display:block}

/* ---- the pins ---- */
.ens-pins{position:absolute;inset:0;pointer-events:none}
/* A white core with a flame ring and a dark halo: it has to stay legible over
   a straw hat, a black bag and a bare leg without changing colour for each. */
.ens-pin{position:absolute;width:11px;height:11px;margin:-5.5px 0 0 -5.5px;border-radius:50%;
  background:#fff;border:2px solid var(--flame);
  box-shadow:0 0 0 1px rgba(23,21,15,.35),0 2px 6px rgba(23,21,15,.4);
  transform:scale(.72);opacity:.45;
  transition:transform .3s cubic-bezier(.2,.8,.2,1),opacity .3s}
.ens-pin.on{transform:scale(1);opacity:1}
/* The ring only pulses on the active pin , six pulsing at once would be noise
   rather than a pointer. */
.ens-pin.on::after{content:"";position:absolute;inset:-5px;border-radius:50%;
  border:1.5px solid var(--flame);animation:ensPulse 1.6s ease-out infinite}
@keyframes ensPulse{from{transform:scale(.7);opacity:.75}to{transform:scale(1.9);opacity:0}}

/* The label, beside the pin it belongs to. */
.ens-flag{position:absolute;z-index:3;transform:translate(14px,-50%);
  background:rgba(23,21,15,.82);color:#fff;border-radius:100px;
  padding:3px 9px;font-family:var(--mono);font-size:.5rem;letter-spacing:.1em;
  text-transform:uppercase;white-space:nowrap;pointer-events:none;max-width:none;
  opacity:0;transition:opacity .3s,left .35s cubic-bezier(.2,.8,.2,1),top .35s cubic-bezier(.2,.8,.2,1)}
.ens-flag.on{opacity:1}
/* Opens leftward for a pin right of centre , see the note in landing.js. */
.ens-flag.flip{transform:translate(calc(-100% - 14px),-50%)}

/* Aligned to the widget, not to the page , a caption stretched to the full
   text column reads as belonging to the section, not to the thing above it. */
.ens-foot{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;
  max-width:calc(208px + 296px + 32px);margin:clamp(12px,1.6vw,18px) auto 0}
.ens-lbl{font-family:var(--mono);font-size:.56rem;letter-spacing:.16em;
  color:var(--muted);text-transform:uppercase}
.ens-same{color:var(--mint)}
.ens-same::before{content:"● "}

@media(max-width:820px){
  /* Stacked, there is nothing to the right to tie to, so the line goes and the
     pieces become a wrapping row above the figure. */
  .ens-grid{grid-template-columns:1fr;gap:20px}
  .ens-pieces{flex-direction:row;flex-wrap:wrap;order:2}
  .ens-piece{flex:1 1 auto;min-width:calc(50% - 4px)}
  .ens-piece::after{display:none}
  .ens-stage{order:1;max-width:300px}
}
@media(prefers-reduced-motion:reduce){
  .ens-pin.on::after{animation:none}
}
