/* ============================================================
   MANZAR LABS — theme layer
   ------------------------------------------------------------
   His markup, his sections, his behaviour. This file is the only
   thing that restyles them. Remove the one <link> in index.html
   and the page returns to his original appearance exactly.

   Built against the Norvin reference (see NORVIN-STUDY.md) and
   reconciled with Manzar Studio. The whole argument of this file
   is that quality comes from *fewer* values applied without
   exception, not from more decoration:

     PART 1  rhythm   — one vertical scale, no viewport-height units
     PART 2  type     — one scale, tight leading, tracking that
                        scales with size
     PART 3  surface  — exactly two radii
     PART 4  colour   — grey does the work; accent is rationed
     PART 5  structure— the guide-line layer
     PART 6  hero
     PART 7  section corrections
     PART 8  motion + accessibility
     PART 9  shell (nav + menu)
   ============================================================ */

:root{
  /* type stacks: General Sans everywhere, Tanker only for shout lines.
     Instrument Serif and Gulzar are retired to match the Studio page. */
  --disp:  "General Sans","Inter",system-ui,sans-serif;
  --body:  "General Sans","Inter",system-ui,sans-serif;
  --shout: "Tanker","General Sans",Impact,sans-serif;
  --serif: "General Sans","Inter",system-ui,sans-serif;
  --mono:  "General Sans","Inter",ui-monospace,monospace;

  /* our shell width, so Labs and Studio line up at the same measure */
  --shell: 1720px;

  /* ── PART 1 · RHYTHM ───────────────────────────────────────
     Norvin runs 120px section padding, 200px between major
     sections, 80px between blocks, and never improvises. His
     page had three competing formulas plus one 20px outlier.
     These four values replace all of it.

     Deliberately vw-based, never vh. Viewport-height units in
     layout padding mean the page re-measures whenever the
     viewport height changes, which is one of the ways a page
     ends up visibly breathing while you scroll. */
  --sp-sec:  clamp(96px, 9.4vw, 162px);   /* section top and bottom   */
  --sp-blk:  clamp(48px, 4.8vw,  84px);   /* between blocks in a section */
  --sp-rule: clamp(30px, 3.1vw,  54px);   /* after a hairline rule    */
  --sp-itm:  clamp(20px, 2.1vw,  34px);   /* between items in a group */

  /* ── PART 2 · TYPE ────────────────────────────────────────
     His page carried 22 heading sizes and 6 near-identical body
     sizes with 7 different line-heights. This is the whole scale.
     Leading is tight (Norvin never exceeds 1.25 on body) and
     tracking tightens as size grows. */
  --t-hero:    clamp(76px, 17vw,   280px);
  --t-display: clamp(52px, 8.6vw,  148px);
  --t-title:   clamp(40px, 6.2vw,   96px);
  --t-h2:      clamp(30px, 3.9vw,   58px);
  --t-h3:      clamp(22px, 2.4vw,   34px);
  --t-h4:      clamp(18px, 1.5vw,   22px);
  --t-lead:    clamp(16px, 1.15vw,  18px);
  --t-body:    15px;
  --t-small:   13.5px;
  --t-label:   clamp(11px, .78vw,  12.5px);

  --lh-tight:  1.02;
  --lh-head:   1.12;
  --lh-body:   1.5;
  --lh-small:  1.5;

  /* ── PART 3 · SURFACE ─────────────────────────────────────
     Two radii, no exceptions: pills for anything you click,
     20px for anything that holds content. */
  --r-card: 20px;
  --r-pill: 100px;
  --r-chip: 100px;

  /* ── PART 4 · COLOUR ──────────────────────────────────────
     Norvin is monochrome and stronger for it: a grey ramp does
     the hierarchy work an accent would normally do. Ours keeps
     the vermilion but rations it — see PART 4 below. */
  --g-1: rgba(233,230,221,.82);   /* near-white secondary   */
  --g-2: rgba(233,230,221,.62);   /* standard body grey     */
  --g-3: rgba(233,230,221,.42);   /* captions, meta         */
  --g-4: rgba(233,230,221,.26);   /* the quietest legible   */
}

/* the accent italic was set in a serif we no longer load: keep the
   emphasis, drop the mismatched face */
.mz-serif, em.mz-serif, .lead em, .mission-lead em{
  font-family:var(--body);font-style:italic;font-weight:500;letter-spacing:-.01em;
}

body{ -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility; }


/* ============================================================
   PART 1 · RHYTHM
   Three competing padding formulas collapse into one. This is
   the single largest quality change in the file: it is what
   makes the page feel composed rather than assembled.
   ============================================================ */

.section{ padding:var(--sp-sec) var(--pad); }
.svc{     padding:var(--sp-sec) var(--pad); }
.return-act{ padding:var(--sp-sec) var(--pad); }

/* his services intro pinned its bottom padding to 20px, an order of
   magnitude tighter than its neighbours. It is a lead-in to #svc-01,
   so it keeps a deliberately short bottom — but a proportional one. */
.services-intro{ padding-bottom:var(--sp-blk); }

/* block-level spacing inside sections, all previously ad hoc */
.stats{        margin-top:var(--sp-blk); padding-top:var(--sp-rule); }
.vel-why{      margin-top:var(--sp-blk); padding-top:var(--sp-rule); }
.svc-head{     margin-bottom:var(--sp-blk); }
.ai-list{      margin-top:var(--sp-blk); padding-top:var(--sp-rule); }
.reg-how{      margin-top:var(--sp-blk); padding-top:var(--sp-rule); }
.mach{         margin-top:var(--sp-blk); }
.return-preview{ margin-top:var(--sp-blk); }
.mission-blurb{ margin:var(--sp-itm) 0; }
.cmt-list{     margin-top:var(--sp-blk); }

/* his .svc-title carried its own large top padding to clear the ghost
   numeral. With the ghost repositioned in PART 7 it no longer needs to
   double the section padding. */
.svc-title{ padding-top:clamp(24px,3.4vw,64px); }


/* ============================================================
   PART 2 · TYPE — matched to Manzar Studio
   ------------------------------------------------------------
   Measured off the live Studio page rather than guessed. Its
   signature, by a wide margin (62 instances), is:

       58px · weight 500 · -0.022em · line-height 1.1

   Weight FIVE HUNDRED, not six. That single value is most of why
   Studio reads composed and Labs read heavy — Labs was running 600
   and 700 with -0.045em tracking, which is a denser, more compressed
   voice. Studio's headings are lighter and more open, and the tracking
   stays consistent instead of tightening hard as size grows.

   Studio's full vocabulary:
       heading      58 / 500 / -.022em / 1.1
       statement    48 / 600 / -.022em / 1.1
       sub          22 / 500 / -.012em / 1.55
       body       16.5 / 400 / normal  / 1.6
       label      15.5 / 600 / .15em
       micro         11 / 500 / .14em

   Labs now uses the same voice at its own scale.
   ============================================================ */

:root{
  /* one tracking value for display sizes, as Studio has */
  --tr-display: -.024em;
  --tr-head:    -.022em;
  --tr-sub:     -.012em;
}

/* ── the hero wordmark ────────────────────────────────────────
   It was 700 at -.055em: a heavy, condensed slab. At 500 with open
   tracking the same word reads as a mark rather than a shout, which
   is how the Studio page carries its own name. */
.hero-title{
  /* 500 read elegant but thin at this scale — the mark needs presence.
     600 gives it weight without going back to the heavy, condensed 700
     it started at. Tracking tightens a touch to match: heavier letter-
     forms need slightly less air between them to stay a single word. */
  font-weight:600;
  font-size:clamp(76px, 16.5vw, 268px);
  line-height:.88;
  letter-spacing:-.038em;
}

/* ── display and section headings ─────────────────────────── */
.giant{
  font-weight:500;
  font-size:var(--t-display);
  line-height:1.02;
  letter-spacing:var(--tr-display);
}
.giant-sm{ font-weight:500; font-size:var(--t-title); line-height:1.04; letter-spacing:var(--tr-display); }
.svc-title{ font-weight:500; }
.stat-big{ font-weight:500; font-size:var(--t-title); line-height:1; letter-spacing:var(--tr-display); }

.mission-head{ font-weight:500; font-size:var(--t-h2); line-height:1.1; letter-spacing:var(--tr-head); }
.return-title{ font-weight:500; font-size:var(--t-h2); line-height:1.1; letter-spacing:var(--tr-head); }

/* ── mid-level headings: Studio's 48/600 statement voice ──── */
.mach-title,
.ai-copy h4,
.contact-mail,
.studio-statement p,
.reg-card h4,
.acc-name,
.cmt-body h3,
.jr-stop h4{
  font-weight:600;
  font-size:var(--t-h3);
  line-height:1.14;
  letter-spacing:var(--tr-head);
}
.mach-title{ line-height:1.04; }

/* ── small headings ──────────────────────────────────────── */
.hero-sub,
.faq-q,
.ds-card h4,
.ai-list h5,
.reg-how h5{
  font-weight:600;
  font-size:var(--t-h4);
  line-height:1.24;
  letter-spacing:var(--tr-sub);
}
/* the hero's own sub follows Studio's 22/500 sub rather than a heading */
.hero-sub{ font-weight:500; font-size:clamp(19px,1.6vw,24px); line-height:1.3; letter-spacing:var(--tr-sub); }

/* ── body: Studio runs 16.5/400 at 1.6, more open than Labs had ── */
.mission-blurb, .work-lede, .studio-statement p+p, .return-lead,
.vel-sub, .cmt-sub, .svc-sub, .ai-copy p, .services-intro-sub{
  font-size:clamp(15.5px,1.05vw,16.5px);
  font-weight:400;
  line-height:1.6;
  letter-spacing:normal;
  color:var(--g-2);
}
.hero-blurb, .jr-stop p, .reg-card > p, .cmt-body p,
.mach-line, .faq-a p, .ai-msg, .contact-phone{
  font-size:clamp(14.5px,1vw,15.5px);
  font-weight:400;
  line-height:1.6;
  letter-spacing:normal;
  color:var(--g-2);
}
.jr-get, .ai-list p, .reg-how p, .stat p, .ds-card p, .cmt-risk{
  font-size:13.5px;
  line-height:1.55;
  color:var(--g-3);
}

/* ── labels: Studio's 15.5/600 at .15em ──────────────────── */
.eb, .mz-eb, .kicker, .mz-kicker, .sec-label, .pill{
  font-weight:600 !important;
  font-size:clamp(13px,1vw,15.5px) !important;
  letter-spacing:.15em !important;
  text-transform:uppercase;
}

h1,h2,h3,h4{ letter-spacing:var(--tr-head); }
.shout,[class*="-shout"]{ letter-spacing:.005em; }


/* ============================================================
   PART 3 · SURFACE
   Every stray radius (12, 14, 15, 16, 18, 22) becomes 20.
   Circles stay circles. The studio arch stays an arch — it is
   the one deliberate exception on the page.
   ============================================================ */

.ds-card, .ai-chat, .reg-card, .faq-item, .faq-note,
.contact-form, .return-preview, .mission-fig, .acc-media,
.work-media, .plate{
  border-radius:var(--r-card);
}
.ai-msg{ border-radius:16px; }
.ai-msg--in{  border-bottom-right-radius:6px; }
.ai-msg--out{ border-bottom-left-radius:6px; }
.contact-form input,
.contact-form select,
.contact-form textarea{ border-radius:14px; }

/* pills are for the world switch and for tags — NOT for buttons.
   Buttons are defined once, in PART 7c, on Studio's measurements. */
.reg-tags li, .mach-exit, .mach-open, .mz-switch, .mz-sw-opt{
  border-radius:var(--r-pill);
}


/* ============================================================
   PART 4 · COLOUR
   The accent appeared in roughly twenty places, most of them
   decorative: a rule above every week, every rail node, every
   card icon, three background glows. Norvin proves grey is
   enough to carry hierarchy.

   Vermilion is now rationed to four moments on the page:
     · the pulsing live dot in an eyebrow pill
     · the "+" on the headline statistic
     · the filled portion of the journey rail as you scroll it
     · text selection and button-hover chips
   Everything else drops to the grey ramp.
   ============================================================ */

/* rail: the lit node and the fill stay accent because they are the
   one thing on the page that responds to your scrolling — that is a
   real signal, not decoration. The unlit nodes go quiet. */
.jr-node{ border-color:var(--g-3); background:var(--g-4); }
.jr.is-scrubbed .jr-stop.is-lit .jr-node{
  border-color:var(--acc); background:var(--acc);
  box-shadow:0 0 0 5px color-mix(in srgb,var(--acc) 12%,transparent);
}

/* small inline index numerals: grey, not accent. Five red numbers in a
   row under a section heading pull harder than the heading does. */
.reg-n, .jr-n, .vel-n, .cmt-n{ color:var(--g-3); }

/* week markers, card icons, inline numerals: grey */
.vel-why-grid h4 i{ color:var(--g-3); }
.ds-i{ color:var(--g-3); }
.ai-msg--gate .ai-cite{ color:var(--g-2); }
.ai-msg--gate{ border-color:rgba(233,230,221,.22); }
.ticker-track b, .xmarq-track b{ color:var(--g-4); }
.menu a.mlink i{ color:var(--g-3); }
.cmt-n{ color:var(--g-3); }

/* the accent glows behind the hero, the mission panel and the
   fallback tiles read as a colour cast the rest of the page does
   not have. Neutralise them to the bone ramp. */
.hero-media::after,
.mission-fig-fallback,
.af-1, .af-3{
  --acc:rgba(233,230,221,.5);
}
.hero-avatars span:nth-child(2){
  background:linear-gradient(135deg,rgba(233,230,221,.16),var(--ink-2));
  color:var(--bone);
}

/* kept accent */
.pill i{ background:var(--acc); }
.stat-big i{ color:var(--acc); }

/* hairlines: one weight, quieter than his */
.stats, .vel-why, .ai-list, .reg-how, .acc, .cmt-row, .acc-row{
  border-color:rgba(233,230,221,.10);
}


/* the marquee repeat unit built by marquee() in main.js: it has to be a
   flex row itself so the gap between phrases inside a unit matches the gap
   between one unit and the next, otherwise the seam is visible */
.mq-unit{
  display:inline-flex; align-items:center; gap:inherit; flex:none;
}
/* the phrases are longer than the single words this belt started with,
   so they need more room between them to read at speed */
.xmarq-track{ gap:clamp(40px,4vw,78px); }
.ticker-track{ gap:clamp(30px,3vw,54px); }


/* ============================================================
   PART 5 · STRUCTURE — the guide-line layer
   Norvin runs thin vertical rules behind its hero. I had extended
   them the full height of the page; Ali is right that they read as
   odd once the hero ends, because below the fold they cut through
   content instead of framing it. They now stop with the hero.
   His hero already carried the idea (.hero-grid i and .plus) — this
   just tunes the weight so it matches the rest of the page.
   ============================================================ */

.hero-grid i{ background:rgba(233,230,221,.075); }
.hero-grid .plus{ color:rgba(233,230,221,.22); }


/* ============================================================
   PART 6 · HERO
   ============================================================ */

/* the pin distance was set in vh while the pinned child was sized in
   svh. Two different units describing the same viewport is exactly the
   kind of mismatch that makes a page re-measure itself mid-scroll. */
.hero{ height:165svh; }
.hero-shell{ height:100svh; }

.hero-inner{ padding:0 var(--pad) clamp(40px,3.4vw,72px); }
.hero-title{ margin-bottom:clamp(20px,2.4vw,44px); }
.hero-sub{ margin-bottom:var(--sp-itm); }
.hero-blurb{ max-width:38ch; margin-bottom:var(--sp-itm); }

/* the guide lines in the hero match the page layer's weight */
.hero-grid i{ background:rgba(233,230,221,.075); }
.hero-grid .plus{ color:rgba(233,230,221,.22); }


/* ============================================================
   PART 7 · SECTION CORRECTIONS
   Small, specific fixes where his layout fights the new rhythm.
   ============================================================ */

/* the ghost numerals were set at 30vw — up to 460px of numeral behind
   a 98px title. Norvin numbers its services at a fraction of that and
   the sections read cleaner for it. */
.svc-ghost{ font-size:clamp(120px,17vw,300px); line-height:.8; opacity:.55; }

/* Norvin's cards are quiet: a hairline, a flat panel, no glow. */
.ds-card, .reg-card, .ai-chat, .faq-item, .faq-note, .contact-form{
  background:rgba(233,230,221,.025);
  border-color:rgba(233,230,221,.10);
}
.ds-card:hover, .reg-card:hover{
  background:rgba(233,230,221,.045);
  border-color:rgba(233,230,221,.18);
}

/* card interiors get room; his padding was tight against 20px corners */
.ds-card{ padding:clamp(26px,2.4vw,34px); min-height:0; }
.reg-card{ padding:clamp(28px,2.8vw,44px); }

/* four- and five-column rails are dense at this type size; let them
   breathe horizontally the way Norvin's do */
.ds-grid{ gap:var(--sp-itm); }
.reg-grid{ gap:var(--sp-itm); }
.ai-list{ gap:var(--sp-itm); }
.reg-how{ gap:var(--sp-itm); }
.jr{ gap:var(--sp-itm); }
.stats{ gap:var(--sp-itm); }

/* accordions: his hard caps clipped content. Let the real height decide
   within a sane ceiling, and use a px ceiling rather than a viewport one
   so an open panel does not re-measure when the viewport changes. */
.acc-item.is-open .acc-body{ max-height:760px; }
.faq-item.is-open .faq-a{ max-height:560px; }

/* two-column sections: match Norvin's wider gutter */
.faq{ gap:clamp(40px,5vw,110px); }
.contact{ gap:clamp(40px,5vw,100px); }
.mission-top{ gap:clamp(30px,4vw,80px); }
.studio-grid{ gap:clamp(36px,5vw,90px); }


/* ── eyebrows ─────────────────────────────────────────────────
   His eyebrows are pills: a rounded box, a border, a tinted fill and a
   dot. Four pieces of chrome to deliver one word. Neither Norvin nor
   the Studio page does this — both set a label as plain tracked-out
   uppercase and let the whitespace do the framing. Dropping the box is
   the single cleanest change available on this page. */
.pill{
  display:inline-flex; align-items:center; gap:10px;
  background:none !important; border:0 !important;
  padding:0 !important; border-radius:0 !important;
  color:var(--g-3) !important;
  margin-bottom:clamp(14px,1.4vw,22px);
}
.pill i{
  width:5px; height:5px; border-radius:50%;
  background:var(--acc); flex:none;
}

/* the section numbering lives in PART 7f. An earlier iteration of it
   sat here and, although PART 7f overrides most of it, that version
   carried `transform:none !important` — which PART 7f does not set,
   so it silently won and killed the numeral's drift. Removed. */


/* ── the AI transcript ────────────────────────────────────────
   This block carries the argument for the whole section, so it gets
   to be the one detailed object on the page. The brief was that a
   client should look at it and want one. That means it has to read as
   a running product, not a diagram: an identified assistant with a
   connection state, timestamps, a held-for-approval state that is
   clearly a feature rather than an error, and a composer bar. The
   composer is doing most of the work — without it this is a picture
   of a conversation; with it, it is a picture of software.
   ============================================================ */
.ai-chat{
  margin:0;
  width:min(100%, 820px);
  justify-self:end;
  padding:0;
  overflow:hidden;
  background:linear-gradient(to bottom, rgba(233,230,221,.055), rgba(233,230,221,.022));
  border:1px solid rgba(233,230,221,.14);
  border-radius:var(--r-card);
  box-shadow:0 32px 80px -32px rgba(0,0,0,.9);
  display:flex; flex-direction:column;
}

/* header ------------------------------------------------------ */
.ai-chat-bar{
  display:flex; align-items:center; gap:13px;
  padding:15px 18px;
  border-bottom:1px solid rgba(233,230,221,.10);
  background:rgba(233,230,221,.03);
}
.ai-avatar{
  width:34px; height:34px; flex:none;
  border-radius:10px;
  background:var(--bone); color:var(--ink);
  display:grid; place-items:center;
  font-family:var(--disp); font-weight:700; font-size:15px; letter-spacing:-.02em;
}
.ai-chat-id{ display:flex; flex-direction:column; gap:3px; min-width:0; }
.ai-chat-name{
  font-family:var(--body); font-weight:600; font-size:14.5px;
  letter-spacing:-.015em; color:var(--fg); text-transform:none;
}
.ai-chat-status{
  display:flex; align-items:center; gap:7px;
  font-family:var(--mono); font-size:10.5px; letter-spacing:.1em;
  text-transform:uppercase; color:var(--g-3);
}
.ai-chat-status i{
  width:5px; height:5px; border-radius:50%; flex:none;
  background:#3ED07E;
  box-shadow:0 0 0 3px rgba(62,208,126,.16);
}
.ai-chat-env{
  margin-left:auto; flex:none;
  font-family:var(--mono); font-weight:600; font-size:10px;
  letter-spacing:.16em; text-transform:uppercase; color:var(--g-2);
  border:1px solid rgba(233,230,221,.16);
  border-radius:var(--r-pill); padding:5px 12px;
}

/* thread ------------------------------------------------------ */
.ai-thread{
  display:flex; flex-direction:column; gap:12px;
  padding:22px 18px;
}
.ai-msg{
  position:relative;
  max-width:86%;
  margin:0;
  padding:13px 16px 11px;
  font-size:14.5px; line-height:1.5;
  border-radius:16px;
  border:1px solid transparent;
}
.ai-msg time{
  display:block; margin-top:7px;
  font-family:var(--mono); font-size:10px; letter-spacing:.08em;
  opacity:.5;
}
/* the person: solid, right */
.ai-msg--in{
  align-self:flex-end;
  background:var(--bone); color:var(--ink);
  font-weight:500;
  border-bottom-right-radius:5px;
}
.ai-msg--in time{ text-align:right; }
/* the system: quiet, left */
.ai-msg--out{
  align-self:flex-start;
  background:rgba(233,230,221,.06);
  border-color:rgba(233,230,221,.11);
  color:var(--g-1);
  border-bottom-left-radius:5px;
}
.ai-msg b{ color:var(--fg); font-weight:600; }

/* the one that stops: a state, not an error */
.ai-msg--gate{
  border-color:color-mix(in srgb, var(--acc) 40%, transparent);
  background:color-mix(in srgb, var(--acc) 8%, transparent);
}
.ai-gate-tag{
  display:inline-flex; align-items:center; gap:7px;
  margin-bottom:9px;
  font-family:var(--mono); font-weight:600; font-size:9.5px;
  letter-spacing:.16em; text-transform:uppercase;
  color:color-mix(in srgb, var(--acc) 78%, var(--bone));
}
.ai-gate-tag::before{
  content:""; width:5px; height:5px; border-radius:50%;
  background:var(--acc); flex:none;
}

.ai-cite{
  display:block;
  margin-top:10px; padding-top:9px;
  border-top:1px solid rgba(233,230,221,.10);
  font-family:var(--mono); font-size:10px;
  letter-spacing:.13em; text-transform:uppercase;
  color:var(--g-3);
}
.ai-msg--gate .ai-cite{
  border-top-color:color-mix(in srgb, var(--acc) 22%, transparent);
  color:color-mix(in srgb, var(--acc) 68%, var(--bone));
}

/* composer — the piece that makes it a product ---------------- */
.ai-compose{
  display:flex; align-items:center; gap:12px;
  margin:0 14px 14px;
  padding:11px 11px 11px 16px;
  border:1px solid rgba(233,230,221,.12);
  border-radius:14px;
  background:rgba(11,10,8,.5);
}
.ai-compose-field{
  flex:1 1 auto; min-width:0;
  font-size:13.5px; color:var(--g-4);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.ai-compose-send{
  flex:none; width:30px; height:30px;
  border-radius:8px;
  background:var(--bone); color:var(--ink);
  display:grid; place-items:center;
}

/* keep the two halves of the lead aligned */
.ai-lead{ align-items:center; grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr); }


/* ── How we work ──────────────────────────────────────────────
   Was an unattributed claim over an unrelated photograph, which is
   the weakest thing a studio page can do. It is now a signed
   position: the founder's portrait, the statement in his voice, his
   name against it, and three facts that make it checkable. */
.studio-statement{
  margin:0;
  border-left:1px solid rgba(233,230,221,.16);
  padding-left:clamp(18px,1.8vw,30px);
}
.studio-statement p{
  font-family:var(--disp); font-weight:600;
  font-size:var(--t-h3); line-height:1.28; letter-spacing:-.026em;
  color:var(--fg);
}
.studio-statement p + p{
  margin-top:16px;
  font-family:var(--body); font-weight:400;
  font-size:var(--t-lead); line-height:var(--lh-body);
  letter-spacing:0; color:var(--g-2);
}
.studio-attrib{
  display:flex; align-items:baseline; gap:12px;
  margin:clamp(22px,2.2vw,34px) 0 0;
  padding-left:clamp(18px,1.8vw,30px);
}
.studio-attrib-name{
  font-family:var(--disp); font-weight:600;
  font-size:var(--t-h4); letter-spacing:-.02em; color:var(--fg);
}
.studio-attrib-role{
  font-family:var(--mono); font-weight:600;
  font-size:var(--t-label); letter-spacing:.15em;
  text-transform:uppercase; color:var(--g-3);
}
.studio-attrib-role::before{ content:"— "; }

/* ruled columns, matching the mission stats, so the two stat rows on the
   page read as the same object rather than two different ideas */
.studio-facts{
  list-style:none; margin:var(--sp-rule) 0 0; padding:var(--sp-rule) 0 0;
  border-top:1px solid rgba(233,230,221,.10);
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:0;
}
.studio-facts li{
  position:relative;
  display:flex; flex-direction:column; gap:10px;
  padding:0 clamp(18px,2vw,38px);
}
.studio-facts li:first-child{ padding-left:0; }
.studio-facts li:last-child{ padding-right:0; }
.studio-facts li + li::before{
  content:"";
  position:absolute; left:0; top:.2em; bottom:.3em; width:1px;
  background:linear-gradient(to bottom,
             rgba(233,230,221,.16), rgba(233,230,221,.02));
}
.studio-facts b{
  font-family:var(--disp); font-weight:500;
  font-size:clamp(34px,3.2vw,52px); line-height:1;
  letter-spacing:var(--tr-display); color:var(--fg);
  font-variant-numeric:tabular-nums;
}
/* the unit rides smaller and quieter than the figure */
.studio-facts b i{
  font-style:normal;
  font-size:.52em;
  letter-spacing:-.01em;
  color:var(--g-3);
  margin-left:.04em;
}
.studio-facts span{
  font-size:var(--t-small); line-height:1.45; color:var(--g-3);
  max-width:30ch;
}
/* the numbers arrive in sequence, same device as the mission row */
html.js .studio-facts li{ transition-delay:0s; }

@media (max-width:820px){
  .studio-facts{ grid-template-columns:minmax(0,1fr); gap:var(--sp-itm); }
  .studio-facts li{ padding:0; }
  .studio-facts li + li::before{ display:none; }
}

/* the portrait: keep his arch, tighten the crop to the face */
.studio-fig img{ object-fit:cover; object-position:50% 22%; }

/* ── footer band ──────────────────────────────────────────────
   Labs was setting its own wordmark in type — Urdu mark, lowercase
   "manzar", a chip — while the Studio page uses the real drawn
   wordmark. One brand, one mark. */
.band-logo{
  display:flex; align-items:center; gap:clamp(12px,1.2vw,20px);
  height:clamp(44px,7vw,96px);
}
.band-logo img{ height:100%; width:auto; display:block; }
/* the mark sits on the dark half of the band, above the dithered wave,
   so the chip has to be bone here — not ink as it is on the Studio page
   where the same lockup sits on the light half */
.band-logo-chip{
  font-family:var(--mono); font-weight:600; font-size:var(--t-label);
  letter-spacing:.18em; text-transform:uppercase;
  color:var(--g-3);
  padding-left:clamp(12px,1.2vw,20px);
  border-left:1px solid rgba(233,230,221,.20);
  align-self:center;
}


/* ============================================================
   PART 7b · REVEALS — the fix for the drifting layout
   ------------------------------------------------------------
   The offset lives here, in CSS, not in a JavaScript tween. A CSS
   transition always lands: set the class and the element WILL end at
   translate zero regardless of frame rate, tab state or scroll speed.
   The old approach animated the layout position itself, so any
   interruption left content parked below where it belonged.

   The no-JS fallback is deliberate and comes first: if the observer
   never runs, everything is visible and in place rather than invisible.
   ============================================================ */

[data-reveal]{ opacity:1; transform:none; }

html.js [data-reveal]{
  opacity:0;
  transform:translate3d(0,22px,0);
  transition:opacity .75s var(--e-out), transform .75s var(--e-out);
  will-change:opacity, transform;
}
html.js [data-reveal].is-in{
  opacity:1;
  transform:none;
  will-change:auto;
}

@media (prefers-reduced-motion: reduce){
  html.js [data-reveal]{ opacity:1; transform:none; transition:none; }
}


/* ============================================================
   PART 7c · BUTTONS — Studio's form, measured off the live page
   ------------------------------------------------------------
   Measured from Manzar Studio's .nav-cta, which is the button Ali
   pointed at:

     button   56px tall · radius 9px · padding 10px 10px 10px 24px
              gap 14px · 500 weight
     chip     36 x 36 · radius 7px · dark fill · light arrow

   The chip is the whole character of the thing — a dark rounded
   square sitting inside a light button. I had previously deleted the
   chip and squared the button off to a 2px rectangle, which threw
   away the one detail that made it Manzar's.

   Every button on Labs now uses this form. Two variants only:
   light (primary) and ghost (secondary).
   ============================================================ */

.btn,
.mz-btn,
.nav-cta{
  display:inline-flex; align-items:center; gap:14px;
  font-family:var(--body); font-weight:500;
  font-size:clamp(15px,1.15vw,17px); letter-spacing:-.015em;
  padding:10px 10px 10px 24px;
  border-radius:9px;
  min-height:56px;          /* Studio's button height, so the two sites match */
  box-sizing:border-box;
  white-space:nowrap;
  border:1px solid transparent;
  transition:transform .35s cubic-bezier(.34,1.56,.64,1),
             background-color .45s, color .45s, border-color .45s;
}

/* the chip: a real box again, not a bare glyph */
.btn-chip,
.mz-btn-chip,
.nav-cta .arr{
  flex:none;
  width:36px; height:36px;
  border-radius:7px;
  display:grid; place-items:center;
  transition:transform .35s cubic-bezier(.34,1.56,.64,1),
             background-color .45s, color .45s;
}
.btn-chip svg,
.mz-btn-chip svg{ width:12px; height:12px; display:block; }

/* primary: light button, dark chip */
.btn-light,
.mz-btn-light,
.nav-cta{
  background:var(--bone); color:var(--ink);
  border-color:var(--bone);
}
.btn-light .btn-chip,
.mz-btn-light .mz-btn-chip,
.nav-cta .arr{
  background:var(--ink); color:var(--bone);
}
.btn-light:hover,
.mz-btn-light:hover,
.nav-cta:hover{ transform:translateY(-2px); }
.btn-light:hover .btn-chip,
.mz-btn-light:hover .mz-btn-chip,
.nav-cta:hover .arr{ transform:translate(2px,-2px); }

/* There is no outlined variant any more. Every button on the page is
   the light one — bone field, ink label, dark chip — because that is
   the button Ali picked and mixing two weights of button across one
   page was doing nothing for it. */
.btn-ghost{
  background:var(--bone); color:var(--ink);
  border-color:var(--bone);
}
.btn-ghost .btn-chip{
  background:var(--ink); color:var(--bone);
  box-shadow:none;
}
.btn-ghost:hover{ transform:translateY(-2px); border-color:var(--bone); }
.btn-ghost:hover .btn-chip{
  background:var(--ink); color:var(--bone);
  box-shadow:none;
  transform:translate(2px,-2px);
}

/* the form submit is the same object, stretched */
.btn-submit{
  width:100%;
  justify-content:space-between;
  padding-left:24px;
}

/* the header CTA keeps Studio's exact measurements */
.nav-cta{ font-size:clamp(16px,1.2vw,18px); }

/* his own .mz-btn markup nests the label in a span — keep it aligned */
.btn-label, .mz-btn-label{ display:inline-block; line-height:1; }


/* ============================================================
   PART 7d · EYEBROWS — match the Studio page
   The Labs label was 11px in grey; Studio's .eb is 13 to 15.5px in
   near-white. Side by side the Labs one read as an afterthought.
   ============================================================ */

.pill, .mz-eyebrow{
  display:inline-flex; align-items:center; gap:11px;
  background:none !important; border:0 !important;
  padding:0 !important; border-radius:0 !important;
  font-family:var(--mono) !important;
  font-weight:600 !important;
  font-size:clamp(13px,1vw,15.5px) !important;
  letter-spacing:.15em !important;
  text-transform:uppercase;
  color:var(--fg) !important;
  opacity:.92;
  margin-bottom:clamp(16px,1.6vw,26px);
}
.pill i, .mz-eyebrow i{ width:6px; height:6px; border-radius:50%; background:var(--acc); flex:none; }

/* the same treatment for his other label classes */
.vel-why-lab, .ai-proof > span:first-child, .foot .fb-lab{
  font-family:var(--mono); font-weight:600;
  font-size:clamp(12.5px,.95vw,15px); letter-spacing:.15em;
  text-transform:uppercase; color:var(--g-3);
}


/* ============================================================
   PART 7e · EMPHASIS
   The accent words were set in a faux italic of a face that has no
   italic, so they leaned into the following word and read as broken.
   The Studio page carries no serif at all — it emphasises by weight
   and brightness. Same device here.
   ============================================================ */

/* Emphasis is a change of brightness, not of mass. At 600 weight and
   full bone inside a 16px grey paragraph the phrase read as a shout —
   heavier than the heading above it. One step of weight and a lift to
   bone is enough to make it the brightest thing in the sentence, which
   is the same two-tone logic the headline uses. */
.serif, em.serif, .mz-serif, em.mz-serif, .lead em, .mission-lead em{
  font-family:var(--body);
  font-style:normal;
  font-weight:500;
  color:var(--fg);
  letter-spacing:-.008em;
}


/* ============================================================
   PART 7f · SECTION NUMBERING — the composed header
   ------------------------------------------------------------
   The heading sits ON TOP of the numeral; that overlap is the device.
   Beyond that, three things give the block life without gimmickry:

     1. the numeral is lit, not flat — a vertical gradient clipped to
        the glyph, brightest at the top, so it reads as a form catching
        light rather than a grey shape
     2. it drifts against the scroll — the numeral moves slower than
        the page, which is what stops a big background element feeling
        pasted on. Driven in JS; safe because the numeral is absolutely
        positioned and can never move anything else
     3. a soft bloom sits behind the header so the section arrives out
        of light instead of off a flat black plate

   Centring is done with text-align on a full-width box, NOT with
   translateX, so the transform is free for the drift to own.

   The two hairlines that used to be here — one above the numeral, one
   dropping below the sub — were mine and read as artifacts rather than
   design. Removed.
   ============================================================ */

.svc-head{
  position:relative;
  text-align:center;
  padding-top:clamp(74px, 9.6vw, 188px);
  margin-bottom:var(--sp-blk);
  isolation:isolate;
}

/* the bloom the section arrives out of */
.svc-head::before{
  content:"";
  position:absolute; z-index:0;
  left:50%; top:clamp(30px,4vw,90px);
  width:min(130%, 1500px); height:clamp(300px,34vw,680px);
  transform:translateX(-50%);
  background:radial-gradient(50% 50% at 50% 50%,
              rgba(233,230,221,.055) 0%,
              rgba(233,230,221,.018) 45%,
              transparent 72%);
  pointer-events:none;
}

.svc-ghost{
  position:absolute !important;
  z-index:0;
  top:0 !important; bottom:auto !important;
  /* full-width box, centred by text-align — leaves transform free for
     the drift. His stylesheet alternates left/right per section, so
     both offsets are pinned. */
  left:0 !important; right:0 !important;
  width:100%;
  text-align:center;
  font-family:var(--disp) !important;
  font-weight:700 !important;
  font-size:clamp(190px, 23vw, 470px) !important;
  line-height:.78 !important;
  letter-spacing:-.055em !important;
  /* lit from above rather than a flat tint */
  color:transparent !important;
  background:linear-gradient(180deg,
              rgba(233,230,221,.125) 0%,
              rgba(233,230,221,.055) 52%,
              rgba(233,230,221,.014) 100%);
  -webkit-background-clip:text; background-clip:text;
  -webkit-text-stroke:0 !important;
  text-shadow:none;
  opacity:var(--pgo, 1) !important;
  /* His rule is `top:50%; transform:translateY(-50%)`. My `top:0` was
     winning but his transform was not, so the glyph was hoisted half
     its own height (183px) above the header and never met the title —
     which is why there was no overlap at all.

     Killing `transform` here is safe: the parallax drives the separate
     `translate` property, not `transform`, so the two do not compete.
     A `top` offset then seats the numeral so the heading crosses its
     upper body rather than clearing it. */
  transform:none !important;
  /* Seat: on the reference the heading crosses the numeral's LOWER
     THIRD, so roughly two thirds of the figure still reads above the
     type. Title top is fixed at the header's padding (188px at wide),
     the glyph box is 367px, so two thirds above means the glyph starts
     about 54px ABOVE the header edge. Previously +64px, which buried
     it almost entirely. */
  top:clamp(-40px, -0.8vw, -10px) !important;
  /* driven by the parallax: a slight swell and lift in brightness as
     the section reaches the middle of the screen */
  scale:var(--pgs, 1);
  white-space:nowrap;
  pointer-events:none;
  user-select:none;
  margin:0 !important;
  will-change:transform;
}

.svc-title{
  position:relative;
  z-index:1;
  padding-top:0 !important;
  margin:0 auto;
  max-width:16ch;
  font-size:clamp(46px, 7vw, 132px) !important;
  line-height:.94 !important;
  letter-spacing:-.045em !important;
}

.svc-sub{
  position:relative;
  z-index:1;
  margin:clamp(18px,1.8vw,30px) auto 0 !important;
  max-width:46ch;
  text-align:center;
}

@media (max-width:760px){
  .svc-head{ padding-top:clamp(58px,16vw,110px); }
  .svc-ghost{ font-size:clamp(140px,34vw,240px) !important; }
  .svc-title{ max-width:14ch; }
}

@media (prefers-reduced-motion: reduce){
  .svc-ghost{ transform:none !important; }
}


/* ============================================================
   PART 7g · MISSION — proportion, and a stats row that arrives
   ------------------------------------------------------------
   Three problems: the image was ~8% of the width against a headline
   at 58px, so the pair had no relationship; a decorative "M" floated
   at the right edge doing nothing (removed in the markup); and the
   stats row was four static numbers on a hairline.
   ============================================================ */

/* the image earns its place — Norvin's equivalent card is about a
   fifth of the measure, not a twelfth */
.mission-top{
  grid-template-columns:minmax(260px, 26%) minmax(0, 1fr);
  gap:clamp(34px,4.4vw,86px);
  align-items:center;
}
.mission-fig{
  margin-top:clamp(6px,.8vw,16px);
  aspect-ratio:4/3.1;
  border-radius:var(--r-card);
  border:1px solid rgba(233,230,221,.10);
}

/* the two-tone headline is the section's device: bright statement,
   grey consequence. Hold the two lines apart properly. */
.mission-head .line-a{ display:block; color:var(--fg); }
.mission-head .line-b{ display:block; color:var(--g-2); }

/* the headline needs a wide measure — capping the whole copy column
   turned a three-line statement into a seven-line ribbon. Only the
   supporting text is constrained. */
.mission-copy{ max-width:none; }
.mission-head{ max-width:22ch; }
.mission-blurb{ max-width:46ch; }

/* ── the stats row ───────────────────────────────────────────
   Ruled columns rather than four numbers floating on one line, and
   they arrive in sequence. The stagger is CSS transition-delay on the
   reveal class, so it inherits the same guarantee as everything else:
   it cannot stall part-way and leave a number sitting low. */
.stats{
  border-top:1px solid rgba(233,230,221,.12);
  padding-top:clamp(34px,3.6vw,62px);
  gap:0;
}
.stat{
  position:relative;
  padding:0 clamp(18px,2.2vw,40px);
}
.stat:first-child{ padding-left:0; }
.stat:last-child{ padding-right:0; }
.stat + .stat::before{
  content:"";
  position:absolute; left:0; top:.28em; bottom:.4em;
  width:1px;
  background:linear-gradient(to bottom,
             rgba(233,230,221,.16), rgba(233,230,221,.02));
}
.stat-big{
  font-variant-numeric:tabular-nums;
  margin-bottom:clamp(12px,1.2vw,20px);
}
.stat p{ color:var(--g-3); }

/* sequence: each column a beat behind the last */
html.js .stat[data-reveal]{ transition-delay:0s; }
html.js .stat[data-reveal]:nth-child(2){ transition-delay:.09s; }
html.js .stat[data-reveal]:nth-child(3){ transition-delay:.18s; }
html.js .stat[data-reveal]:nth-child(4){ transition-delay:.27s; }

@media (max-width:1080px){
  .stat{ padding:0 clamp(12px,2vw,22px); }
  .stat:nth-child(3){ padding-left:0; }
  .stat:nth-child(3)::before{ display:none; }
}
@media (max-width:760px){
  .mission-top{ grid-template-columns:minmax(0,1fr); }
  .mission-copy, .mission-blurb{ max-width:none; }
}


/* ============================================================
   PART 7h · THE TIMELINE TRACK + the mechanics under it
   ------------------------------------------------------------
   Both halves stay. The track is the promise — four dated milestones
   on a rail that draws as you scroll, with a travelling head the eye
   follows. The four mechanics below are the proof that the dates are
   real. Section 01 no longer repeats the schedule; it covers the same
   six weeks from the client's side, so the two read as claim and
   detail rather than the same list twice.

   --vfill (0-1) is written by ScrollTrigger. Everything downstream is
   a scaleX, a colour, or `left` on an absolutely positioned dot — no
   layout.
   ============================================================ */

.vel-track{
  --vfill:0;
  position:relative;
  margin-top:var(--sp-blk);
  padding-top:clamp(44px,3.6vw,68px);
  gap:var(--sp-itm);
}
.vel-track::before{
  content:"";
  position:absolute; top:0; left:0; right:0; height:1px;
  background:rgba(233,230,221,.14);
}
.vel-track::after{
  content:"";
  position:absolute; top:0; left:0; right:0; height:1px;
  transform-origin:0 50%;
  transform:scaleX(var(--vfill));
  background:linear-gradient(to right,
             color-mix(in srgb, var(--acc) 34%, transparent) 0%,
             color-mix(in srgb, var(--acc) 88%, transparent) 82%,
             var(--acc) 100%);
}

/* the travelling head */
.mz-track-head{
  position:absolute; top:0;
  width:10px; height:10px; margin:-5px 0 0 -5px;
  border-radius:50%;
  background:var(--acc);
  left:calc(var(--vfill) * 100%);
  box-shadow:0 0 0 6px color-mix(in srgb, var(--acc) 15%, transparent),
             0 0 26px 4px color-mix(in srgb, var(--acc) 42%, transparent);
  opacity:calc(.15 + var(--vfill) * .85);
  pointer-events:none;
  z-index:2;
}
.mz-track-head::after{
  content:"";
  position:absolute; top:50%; right:6px;
  width:64px; height:1px; margin-top:-.5px;
  background:linear-gradient(to left,
             color-mix(in srgb, var(--acc) 62%, transparent), transparent);
}

/* nodes: hollow until the head arrives */
.vel-step{ position:relative; }
.vel-step::before{
  content:"";
  position:absolute; top:calc(var(--rail-offset, 68px) * -1); left:0;
  width:11px; height:11px; margin-top:-5px;
  border-radius:50%;
  background:var(--ink);
  border:1px solid rgba(233,230,221,.30);
  z-index:1;
  transition:background-color .5s var(--e-out),
             border-color .5s var(--e-out),
             box-shadow .5s var(--e-out),
             scale .5s var(--e-spring);
}
.vel-step.is-lit::before{
  background:var(--acc);
  border-color:var(--acc);
  scale:1.18;
  box-shadow:0 0 0 6px color-mix(in srgb, var(--acc) 14%, transparent);
}
.vel-wk{ color:var(--g-4); transition:color .55s var(--e-out); }
.vel-step.is-lit .vel-wk{ color:color-mix(in srgb, var(--acc) 74%, var(--bone)); }
.vel-step h3{ color:var(--g-3); transition:color .6s var(--e-out); }
.vel-step.is-lit h3{ color:var(--fg); }
.vel-step p{ opacity:.55; transition:opacity .6s var(--e-out); color:var(--g-2); }
.vel-step.is-lit p{ opacity:1; }

/* ── the mechanics, under the track ──────────────────────── */
.vel-why{
  margin-top:var(--sp-blk);
  padding-top:var(--sp-rule);
  border-top:1px solid rgba(233,230,221,.10);
  display:block;
}
.vel-why-grid{
  display:grid;
  grid-template-columns:repeat(2, minmax(0,1fr));
  gap:clamp(30px,3vw,56px) clamp(40px,5vw,110px);
}
.vel-why-grid h4{
  display:flex; align-items:baseline; gap:clamp(12px,1.1vw,18px);
  font-family:var(--disp); font-weight:500;
  font-size:clamp(19px,1.7vw,26px);
  line-height:1.2; letter-spacing:var(--tr-head);
  color:var(--fg); margin:0;
}
.vel-why-grid h4 i{
  flex:none; font-style:normal;
  font-family:var(--mono); font-weight:600;
  font-size:clamp(11px,.8vw,12.5px); letter-spacing:.16em;
  color:var(--g-4); transform:translateY(-.25em);
}
.vel-why-grid p{
  margin-top:clamp(10px,.9vw,15px);
  max-width:46ch; color:var(--g-2);
}

@media (max-width:820px){ .vel-why-grid{ grid-template-columns:minmax(0,1fr); } }

@media (prefers-reduced-motion: reduce){
  .mz-track-head{ display:none; }
  .vel-track::after{ transform:scaleX(1); }
  .vel-step::before{ background:var(--acc); border-color:var(--acc); }
  .vel-step h3{ color:var(--fg); }
  .vel-step p{ opacity:1; }
}


/* ============================================================
   PART 7k · SECTION 01 — the engagement, not the schedule
   ------------------------------------------------------------
   The Timeline above states the dates. This section now covers the
   axis it cannot: what the client actually has to do. Every stop
   already said what you leave with; each now also says what we need
   from you, which is the question a founder is really asking and the
   thing that stops the two sections reading as one list twice.
   ============================================================ */

.jr-ask{
  display:block;
  margin-top:clamp(14px,1.2vw,20px);
  padding-top:clamp(12px,1vw,16px);
  border-top:1px solid rgba(233,230,221,.10);
  font-size:13px;
  line-height:1.5;
  color:var(--g-3);
}
.jr-ask i{
  display:block;
  margin-bottom:6px;
  font-style:normal;
  font-family:var(--mono); font-weight:600;
  font-size:10px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--g-4);
}


/* ============================================================
   PART 7i · CARDS — a silver edge, and nothing inside
   ------------------------------------------------------------
   The interior wash is gone. Lighting the face of a card muddies the
   copy sitting on it and reads as a smudge rather than a finish. The
   whole effect is now the edge: the card's own 1px border brightens to
   silver where the pointer is, masked to the border itself with
   mask-composite so it is genuinely the rim lighting up rather than a
   glow behind the panel.

   The icon still responds — that part was working.
   ============================================================ */

.ds-card, .reg-card{
  position:relative;
  isolation:isolate;
  transition:border-color .45s var(--e-out),
             transform .55s var(--e-out);
}

/* the lit rim — brighter and cooler than before so it reads as metal */
.ds-card::before, .reg-card::before{
  content:"";
  position:absolute; inset:0;
  border-radius:inherit;
  padding:1px;
  background:radial-gradient(
    300px circle at var(--mx,50%) var(--my,50%),
    rgba(246,246,244,1) 0%,
    rgba(233,230,221,.55) 30%,
    rgba(233,230,221,.10) 58%,
    transparent 76%);
  -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 .45s var(--e-out);
  pointer-events:none;
  z-index:1;
}
.ds-card:hover::before, .reg-card:hover::before{ opacity:1; }

/* the card face stays exactly as it is at rest */
.ds-card:hover, .reg-card:hover{
  transform:translateY(-3px);
  background:rgba(233,230,221,.025);
}

.ds-card > *, .reg-card > *{ position:relative; z-index:2; }

/* the icon acknowledges the pointer — this part was already right */
.ds-i{ transition:color .45s var(--e-out), transform .55s var(--e-spring); }
.ds-card:hover .ds-i{ color:var(--fg); transform:translateY(-2px); }

@media (hover: none){
  .ds-card::before, .reg-card::before{ display:none; }
  .ds-card:hover, .reg-card:hover{ transform:none; }
}


/* ============================================================
   PART 7j · PARALLAX ON THE CAPABILITY HEADERS
   ------------------------------------------------------------
   The numeral and its heading now travel at different rates as the
   section passes: the ghost drifts further and faster, the heading
   drifts a little the other way. Two planes moving at two speeds is
   what reads as depth — a single element moving alone just reads as
   an element moving.

   Both are pure transforms on elements whose resting position is set
   by CSS, so neither can alter layout. --pg and --pt are written by
   ScrollTrigger; the fallbacks keep the header correct on the frame
   before JS runs and if it never does.
   ============================================================ */

/* The heading cannot carry the drift itself: GSAP writes
   `translate:none` inline whenever it takes over an element's
   transform, and the title is already a GSAP target for its own
   line-mask reveal. So the header block carries the type's drift, and
   the ghost carries the DIFFERENCE — which is what produces the two
   speeds without either rule fighting the animation library. */
.svc-head{
  translate:0 calc(var(--pt, 0) * 1px);
}
.svc-ghost{
  translate:0 calc((var(--pg, 0) - var(--pt, 0)) * 1px);
}

@media (prefers-reduced-motion: reduce){
  .svc-head, .svc-ghost{ translate:none !important; }
}


/* ============================================================
   PART 7l · THE CROSSOVER SECTION
   ------------------------------------------------------------
   This is the one place on Labs that is about somewhere else, so it
   is allowed to look like somewhere else. It sits on a warmer, lighter
   surface than the rest of the page with a hairline top and bottom —
   enough to read as a different room without breaking the palette.

   The preview is Studio's hero rebuilt in markup rather than
   photographed. A JPEG had already gone stale once when Studio's hero
   changed; this cannot. It also stays sharp at any size, and the
   browser chrome around it states "another website" more plainly than
   a caption ever would.
   ============================================================ */

/* ── the crossover as a lit stage ─────────────────────────────
   Flat panel + flat plate gave two rectangles of nearly the same
   value, which is why the contrast read as weak. It is now built as a
   room with a light in it:

     · the SURFACE lifts to #1A1916, a clear step above the page's
       #0B0A08, warm rather than neutral
     · a BLOOM sits behind the plate and brightens as the section
       reaches the middle of the screen, so the plate arrives out of
       light rather than sitting on a slab
     · a VIGNETTE darkens the edges, which pushes the eye inward and
       widens the value range between the darkest corner and the lit
       centre — that range is what contrast actually is
     · the PLATE itself drops to near-black, further from the surface
       than before

   Three planes then move at three rates as the section passes: bloom
   slowest, plate in between, type slightly against them. Everything is
   transform and opacity on absolutely positioned layers, so none of it
   can touch layout. */
.studio-return{
  position:relative;
  overflow:hidden;
  background:#1A1916;
  border-top:1px solid rgba(233,230,221,.12);
  border-bottom:1px solid rgba(233,230,221,.12);
}

/* The light, as a wash from above rather than a lamp in the middle.

   A radial gradient sized to sit inside the frame always shows you its
   ellipse — a soft-edged oval is still an oval, and on a near-black
   field the eye finds that boundary immediately. Two changes fix it:
   the radial is now enormous and anchored OFF the top edge, so only its
   long tail is ever on screen and no boundary exists inside the frame;
   and a linear wash does most of the work, because a linear gradient
   has no shape to see at all. */
.studio-return::before{
  content:"";
  position:absolute; inset:-20% -10% -10%; z-index:0;
  pointer-events:none;
  background:
    linear-gradient(180deg,
      rgba(233,230,221,.075) 0%,
      rgba(233,230,221,.022) 34%,
      transparent 62%),
    radial-gradient(160% 120% at 50% -14%,
      rgba(233,230,221,.07) 0%,
      rgba(233,230,221,.02) 38%,
      transparent 70%);
  opacity:calc(.42 + var(--rp, 0) * .58);
  transform:translate3d(0, calc(var(--rpy, 0) * -0.30px), 0);
}

/* Edge falloff as an inset shadow, not a radial. A shadow follows the
   rectangle it is inside, so it darkens all four edges evenly and can
   never draw an ellipse across the middle. */
.studio-return::after{
  content:"";
  position:absolute; inset:0; z-index:0;
  pointer-events:none;
  box-shadow:inset 0 0 clamp(140px, 16vw, 300px) clamp(40px, 5vw, 90px) rgba(0,0,0,.55);
}

/* content sits above both layers */
.return-act{ position:relative; z-index:1; }

/* Grain across the whole room. A large near-black field rendered from
   gradients bands into faint steps on 8-bit displays — that stepping is
   most of what reads as "low quality" on a dark section. Noise breaks
   the steps up and gives the surface a physical texture rather than a
   flat digital wash. Same technique the plate uses, and the same one
   the site already applies globally. */
.return-act::before{
  content:"";
  position:absolute; inset:0; z-index:0;
  pointer-events:none;
  opacity:.055;
  mix-blend-mode:overlay;
  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='.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.return-inner{ position:relative; z-index:1; }

/* His .return-inner caps the whole block at 720px, which is right for the
   text but was also strangling the preview. The cap is lifted here and the
   text measures are set per element instead (title 20ch, lead 48ch), so
   the copy stays readable while the plate can run wide. */
.return-inner{
  position:relative; z-index:1;
  text-align:center;
  max-width:none;
  margin-inline:auto;
  translate:0 calc(var(--rpy, 0) * -0.42px);
}
.return-title{ margin-left:auto; margin-right:auto; max-width:20ch; }
.return-lead{ margin-left:auto; margin-right:auto; max-width:48ch; }
.return-cta{
  display:flex; align-items:center; justify-content:center;
  gap:clamp(14px,1.4vw,22px); flex-wrap:wrap;
  margin-top:var(--sp-blk);
}

/* ── the framed preview ─────────────────────────────────────── */
/* No chrome, no outline. A frame drawn around it only made it look like
   a screenshot of a browser rather than a piece of the other site. It is
   now simply a large, clean plate — the hero itself, sitting in its own
   light, with depth coming from shadow rather than from a border. */
.return-preview{
  position:relative;
  width:min(100%, 1180px);
  margin:var(--sp-blk) auto 0;
  background:#070605;
  /* His rule sets aspect-ratio:16/10 on this frame, from the old
     single-image version. My screen inside is 16/9.2, so the frame was
     59px taller than its own content and that strip showed the frame's
     #070605 under the screen's #0B0A08 — two near-blacks meeting in a
     hard horizontal line across the bottom. The frame now takes its
     height from the screen. */
  aspect-ratio:auto !important;
  translate:0 calc(var(--rpy, 0) * 1px);
  border:0;
  border-radius:clamp(16px, 1.6vw, 26px);
  overflow:hidden;
  box-shadow:
    0 2px 0 0 rgba(233,230,221,.07) inset,     /* a hairline of light on the top edge only */
    0 40px 90px -40px rgba(0,0,0,.85),
    0 90px 180px -70px rgba(0,0,0,.7);
  transition:transform .7s var(--e-out), box-shadow .7s var(--e-out);
}
.return-preview:hover{
  transform:translateY(-6px);
  box-shadow:
    0 2px 0 0 rgba(233,230,221,.11) inset,
    0 54px 110px -44px rgba(0,0,0,.88),
    0 110px 210px -70px rgba(0,0,0,.75);
}

/* the screen: Studio's hero, rebuilt */
.rp-screen{
  position:relative;
  aspect-ratio:16/9.2;
  /* identical to the frame behind it — belt and braces against the
     seam above ever reappearing */
  background:#070605;
  overflow:hidden;
  display:grid; place-items:center;
}
/* Studio's hero is a dark film with bokeh in it. Three radial blobs
   standing in for that just look like three blobs — which is exactly
   what they looked like. Dropped.

   What is left is what actually reads at this size: the field falls
   from very slightly lifted at the top to true black at the foot, with
   one enormous glow anchored below the frame so the wordmark sits in a
   pool of warmth. No stop sits inside the frame, so there is no edge
   anywhere to notice. Grain over the top breaks the banding that dark
   gradients produce on 8-bit displays. */
.rp-glow{
  position:absolute; inset:0;
  background:
    linear-gradient(180deg,
      rgba(233,230,221,.045) 0%,
      rgba(233,230,221,.012) 30%,
      transparent 58%),
    radial-gradient(150% 88% at 50% 112%,
      rgba(255,186,132,.10) 0%,
      rgba(255,170,120,.035) 34%,
      transparent 66%);
}
/* fine grain — the thing that stops a dark gradient banding into rings */
.rp-glow::after{
  content:"";
  position:absolute; inset:0;
  opacity:.05;
  mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.rp-hero{
  position:absolute; inset:0;
  padding:clamp(16px,4%,38px) clamp(14px,3%,30px) 0;
  text-align:center;
  display:flex; flex-direction:column; align-items:center;
  justify-content:flex-start;
  gap:clamp(5px,1%,11px);
}
.rp-eyebrow{
  font-family:var(--mono); font-weight:600;
  font-size:clamp(6px,.85cqw,9px);
  letter-spacing:.22em; text-transform:uppercase;
  color:rgba(233,230,221,.72);
}
.rp-head{
  margin:0;
  font-family:var(--disp); font-weight:500;
  font-size:clamp(15px,2.5cqw,30px);
  line-height:1.1; letter-spacing:-.024em;
  color:var(--bone);
}
.rp-sub{
  margin:0;
  font-size:clamp(6.5px,.95cqw,11px);
  line-height:1.5;
  color:rgba(233,230,221,.55);
}
/* Studio runs the drawn wordmark full-bleed along the bottom edge of
   its hero; the preview does the same rather than centring it.

   Scoped to `.return-preview .rp-mark` because his stylesheet carries
   `.return-preview img{width:100%;height:100%;object-fit:cover}` from
   the old single-image markup — more specific than a bare class, so it
   was stretching the wordmark to fill the frame and cropping it into
   nothing. */
.return-preview .rp-mark{
  position:absolute;
  left:50%; bottom:0; top:auto; right:auto;
  transform:translateX(-50%);
  width:88%;
  height:auto;
  object-fit:contain;
  display:block;
}

/* ── the live frame ───────────────────────────────────────────
   Studio rendered at a real desktop width and scaled down to fit, so
   it reads as the actual site rather than a phone layout squeezed into
   a box. --rp-scale is computed in JS from the frame's measured width.

   pointer-events are off and scrolling is disabled: it is a portrait of
   the site, not something to interact with, and it must never capture
   the page's scroll. */
.rp-frame{
  position:absolute; top:0; left:0; z-index:2;
  width:var(--rp-vw, 1600px);
  height:var(--rp-vh, 920px);
  border:0;
  transform-origin:0 0;
  transform:scale(var(--rp-scale, 0.7375));
  pointer-events:none;
  opacity:0;
  transition:opacity 1.1s var(--e-out);
}
/* once the real thing has painted, the stand-in fades away beneath it */
.rp-screen.is-live .rp-frame{ opacity:1; }
.rp-screen.is-live .rp-hero,
.rp-screen.is-live .rp-glow{
  opacity:0;
  transition:opacity .7s var(--e-out);
}
.rp-hero, .rp-glow{ transition:opacity .7s var(--e-out); }

/* container queries so the mini hero scales with the frame, not the page */
.return-preview{ container-type:inline-size; }

@media (max-width:760px){
  .rp-url{ max-width:none; }
  .return-preview{ width:100%; }
}


/* ============================================================
   PART 8 · MOTION + ACCESSIBILITY
   ============================================================ */

:focus-visible{ outline:1.5px dashed var(--acc); outline-offset:3px; }
.skip-link:focus{ left:8px; }

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001s !important;
    transition-duration:.001s !important;
    scroll-behavior:auto !important;
  }
  .hero{ height:auto !important; }
  .hero-shell,[data-sticky]{
    position:relative !important; top:auto !important; height:auto !important;
  }
}

/* The pointer now lives in /assets/css/cursor.css, linked first in the
   <head> of every page. It was moved out of here because this file
   loads late and only on this page, which is why the pointer kept
   falling back to the browser default. */
/* ============================================================
   PART 9 · SHELL — header and menu
   ------------------------------------------------------------
   HEADER: ours. Wordmark and Studio/Labs switch left, links
   centred, CTA and Menu right — the same header as the Studio
   page so the two worlds read as one product.

   MENU: his. I had replaced his flight deck with a flat two-column
   index, which threw away the best thing on his site. The panel is
   back to his architecture — a glass sheet that drops from under the
   header, three numbered groups, a live preview that swaps as you
   move down the rows, and a foot bar with the world switcher, the
   address, both clocks and the CTA. MZ.menu() drives it again, so
   the focus trap, scroll lock, image preloading and the auto-fit
   that scales the rows to the viewport all come back with it.

   Everything below re-skins that object onto our type, our greys and
   our geometry. The structure is his; the surface is ours.
   ============================================================ */

/* ── header ─────────────────────────────────────────────────── */
.nav{
  position:fixed;inset:0 0 auto 0;z-index:190;mix-blend-mode:difference;color:#fff;
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  padding:16px var(--pad);
}
.nav-left{justify-self:start;display:flex;align-items:center;gap:clamp(14px,1.6vw,26px)}
.brand{display:flex;align-items:center}
.brand img{height:clamp(26px,2.1vw,33px);width:auto;display:block}
.nav-links{
  justify-self:center;display:flex;gap:clamp(22px,2.6vw,40px);
  font-family:var(--body);font-weight:500;
  font-size:clamp(17px,1.32vw,21px);letter-spacing:-.022em;
}
.nav-links a{position:relative;padding:5px 0;color:#fff;opacity:.88;transition:opacity .35s}
.nav-links a:hover{opacity:1}
.nav-links a::after{
  content:"";position:absolute;left:0;bottom:0;height:1.5px;width:100%;background:#fff;
  transform:scaleX(0);transform-origin:right;transition:transform .45s cubic-bezier(.6,0,.3,1);
}
.nav-links a:hover::after{transform:scaleX(1);transform-origin:left}
.nav-right{justify-self:end;display:flex;align-items:center;gap:clamp(10px,1.1vw,18px)}

/* the switch in the header only — his menu foot carries the same class
   and must keep his sliding-lozenge treatment */
.nav .mz-switch{
  display:inline-flex;align-items:center;gap:3px;padding:3px;
  border-radius:var(--r-pill);border:1px solid rgba(255,255,255,.4);
  background:transparent;
}
.nav .mz-switch::before{display:none !important;content:none !important}
.nav .mz-sw-opt{
  position:relative;z-index:1;
  font-family:var(--body);font-weight:500;font-size:clamp(14.5px,1.1vw,16.5px);
  letter-spacing:-.01em;padding:9px 22px;border-radius:var(--r-pill);
  color:#fff;opacity:.7;
  transition:opacity .3s,background-color .35s var(--e-out),color .35s;
}
.nav .mz-sw-opt:hover{opacity:1}
.nav .mz-sw-opt.is-on{background:#fff;color:#000;opacity:1}

/* the header CTA is the button Ali pointed at as the reference, so it
   carries Studio's exact measurements: 9px on the button, 7px on the
   chip. It was a 100px pill with a round chip, which is what made it
   the odd one out. */
.nav-cta{
  font-family:var(--body);font-weight:500;font-size:clamp(16px,1.2vw,18px);letter-spacing:-.015em;
  background:#fff;color:#000;padding:10px 10px 10px 24px;border-radius:9px;
  display:inline-flex;gap:14px;align-items:center;
  transition:transform .3s cubic-bezier(.34,1.56,.64,1);
}
.nav-cta:hover{transform:translateY(-2px)}
.nav-cta .arr{
  width:36px;height:36px;border-radius:7px;background:#0B0A08;color:#fff;
  display:grid;place-items:center;font-size:13px;transition:transform .3s;
}
.nav-cta:hover .arr{transform:translate(2px,-2px)}

.menu-btn{
  display:inline-flex;align-items:center;gap:9px;
  font-family:var(--body);font-weight:500;font-size:clamp(15px,1.15vw,17px);letter-spacing:-.015em;
  color:#fff;padding:10px 4px;background:none;border:0;cursor:pointer;
}
.menu-btn span{display:block;width:20px;height:1.5px;background:currentColor;transition:transform .35s,width .35s}
.menu-btn span:nth-child(2){width:13px}
.menu-btn:hover span:nth-child(2){width:20px}
/* MZ.menu() adds .is-open to the trigger. The two rules sit side by side
   rather than stacked, so the cross is made by sliding the second one back
   over the first (20px rule + 9px gap = 29px) and counter-rotating. */
.menu-btn.is-open span:nth-child(1){transform:rotate(45deg)}
.menu-btn.is-open span:nth-child(2){width:20px;transform:translateX(-29px) rotate(-45deg)}


/* ── menu: his sheet, our surface ───────────────────────────── */

/* our header is taller than his 72px bar, so the sheet has to start
   below ours or the two overlap */
:root{ --nav-h:88px; }
@media (max-width:900px){ :root{ --nav-h:78px; } }

.mz-menu{
  top:var(--nav-h);
  /* Height is set in /assets/css/menu.css, which every page with a menu
     loads. It used to be pinned to the full viewport here; see the note
     there for why that could never settle. --nav-h is read from this
     file, so the ceiling still clears this page's taller nav bar. */
  border-radius:0;
  border-bottom:1px solid rgba(233,230,221,.16);
  background:
    linear-gradient(to bottom, rgba(233,230,221,.05), transparent 42%),
    color-mix(in srgb, var(--ink) 92%, transparent);
  -webkit-backdrop-filter:blur(30px) saturate(150%);
  backdrop-filter:blur(30px) saturate(150%);
}
.mz-menu-scrim{ background:color-mix(in srgb, var(--ink) 72%, transparent); }

.mz-menu-head{ padding:24px var(--pad) 14px; }
.mz-menu-eyebrow{
  font-family:var(--mono);font-weight:600;font-size:var(--t-label);
  letter-spacing:.15em;text-transform:uppercase;color:var(--g-3);
}
.mz-menu-close{
  font-family:var(--body);font-weight:500;font-size:15px;letter-spacing:-.015em;
  height:auto;padding:8px 0;border:0;background:none;color:var(--bone);
  gap:10px;
}
.mz-menu-close:hover{ transform:none; color:var(--bone); }
.mz-menu-close span:last-child{ color:var(--g-3);font-size:13px }

.mz-menu-body{
  grid-template-columns:minmax(0,1fr) clamp(260px,25vw,400px);
  gap:clamp(8px,1.4vh,16px) clamp(28px,3.4vw,64px);
  padding:clamp(10px,2.2vh,32px) var(--pad) clamp(10px,1.8vh,26px);
}
.mz-menu-groups{ gap:calc(clamp(6px,1.2vh,22px) * var(--mfs)) clamp(24px,2.8vw,48px); }

.mz-menu-group-label{
  font-family:var(--mono);font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;color:var(--g-3);
  border-bottom:1px solid rgba(233,230,221,.12);
}

.mz-menu-row{ border-radius:12px; }
.mz-menu-row-num{
  font-family:var(--mono);font-weight:600;
  letter-spacing:.1em;color:var(--g-4);
}
.mz-menu-row-label{
  font-family:var(--disp);font-weight:600;
  letter-spacing:-.028em;line-height:1.1;color:var(--fg);
}
.mz-menu-row-desc{
  font-family:var(--body);line-height:1.4;color:var(--g-3);
}
/* the arrow is the one accent in the panel: it only exists on hover,
   so it is a real signal rather than decoration */
.mz-menu-row-arrow{ color:var(--acc); }
.mz-menu-row:hover,
.mz-menu-row:focus-visible{ background:rgba(233,230,221,.05); }
.mz-menu-row:hover .mz-menu-row-num,
.mz-menu-row:focus-visible .mz-menu-row-num{ color:var(--g-1); }
.mz-menu-row:hover .mz-menu-row-desc,
.mz-menu-row:focus-visible .mz-menu-row-desc{ color:var(--g-2); }
.mz-menu-row::after{ background:rgba(233,230,221,.22); }

.mz-menu-feature-frame{
  border-radius:var(--r-card);
  border:1px solid rgba(233,230,221,.12);
  background:rgba(233,230,221,.03);
}
.mz-menu-feature-kicker{
  font-family:var(--mono);font-weight:600;font-size:var(--t-label);
  letter-spacing:.15em;text-transform:uppercase;color:var(--g-3);
}
.mz-menu-feature-caption{
  font-family:var(--body);font-size:var(--t-small);line-height:1.5;color:var(--g-2);
}

.mz-menu-foot{
  padding:clamp(12px,1.8vh,20px) var(--pad);
  border-top:1px solid rgba(233,230,221,.12);
}
.mz-menu-foot-mail{
  font-family:var(--mono);font-size:var(--t-small);letter-spacing:.02em;color:var(--g-2);
}
.mz-menu-foot-mail:hover{ color:var(--fg); }
.mz-menu-foot-clocks{
  font-family:var(--mono);font-size:var(--t-label);letter-spacing:.04em;color:var(--g-3);
}
/* the foot switch and CTA take our sizing but keep his behaviour */
.mz-menu-foot .mz-switch-opt{
  font-family:var(--body);font-weight:500;font-size:15px;letter-spacing:-.01em;
}
.mz-menu-foot .mz-btn-label{ font-family:var(--body);font-weight:500;letter-spacing:-.015em; }


/* ── reveal defaults his stylesheet sets ──────────────────────
   style.css hides .svc-title and .svc-ghost with .js{opacity:0} and
   parks the title 60px low, then relies on a tween to bring them back —
   the same stall-prone pattern that put the whole page 34px out. The
   animations set their own start values, so these defaults are pure
   risk: if a tween never runs, the heading is simply invisible. */
html.js .svc-title{ opacity:1; transform:none; }
html.js .svc-ghost{ opacity:1; }


@media (prefers-reduced-motion: reduce){
  .studio-return::before{ transform:none; opacity:.7; }
  .return-preview, .return-inner{ translate:none; }
}


/* ============================================================
   PART 10 · THE COMMITMENTS, AS DIAGRAM CARDS
   ============================================================
   Three versions of this section now, and it is worth saying why it
   moved twice.

   It began as a ledger: number, a paragraph, the risk it retires, in a
   56px / 1fr / 210px row. That worked while the copy was long. Cut to a
   line each, the middle column is 2054px on a wide screen against a
   380px sentence, so every row was text, a hole, then a stranded label.

   The grid that replaced it fixed the hole but said the same thing six
   times in the same shape — correct and dull. A promise about money, a
   promise about cadence and a promise about ownership are different
   ideas, and text alone made them look identical.

   So: six cards, each led by a drawn diagram that animates when the
   card arrives. The diagram carries the idea and the words confirm it,
   which is the right way round for a section people skim. Two columns,
   so each diagram gets real size rather than being a thumbnail.

   The animations are CSS on inline SVG, held paused until the card has
   [data-reveal].is-in, so nothing runs off-screen. Every draw-on uses
   pathLength="1", so the dash maths does not depend on path length.
   ============================================================ */

.cmt-list{
  display:grid;
  /* Three across on a wide screen, not two. At two, a card on a 1920
     screen is 937px wide and its diagram is 937x586 — over half the
     viewport for a one-line promise, and the section ran 2838px, which
     is three screens of scrolling for six sentences. Three across puts
     the diagram back in proportion to the text it illustrates and
     halves the height. */
  grid-template-columns:repeat(3, minmax(0,1fr));
  /* every card the same height, so a promise that wraps to two lines
     does not leave its row taller than the one beneath it */
  grid-auto-rows:1fr;
  gap:clamp(18px,1.5vw,26px);
  /* and a ceiling, so an ultrawide monitor does not inflate them again */
  max-width:1780px;
  margin:var(--sp-blk) auto 0;
  padding:0;
  list-style:none;
  border:0;
  background:none;
}
@media (max-width:1400px){ .cmt-list{ grid-template-columns:repeat(2, minmax(0,1fr)); } }
@media (max-width:900px){  .cmt-list{ grid-template-columns:minmax(0,1fr); } }

.cmt-card{
  display:flex; flex-direction:column;
  min-width:0;
  /* Was clamp(18px,1.5vw,24px), which put the promise almost against
     the card border — it read as cramped rather than composed. */
  padding:clamp(24px,2vw,36px);
  border:1px solid var(--line);
  border-radius:var(--r-card);
  background:linear-gradient(180deg, rgba(233,230,221,.022), rgba(233,230,221,0) 46%), #0D0C0A;
  transition:border-color .5s var(--e-out), background-color .5s var(--e-out);
}
.cmt-card:hover{ border-color:var(--line2); }

.cmt-fig{
  margin:0 0 clamp(22px,1.9vw,32px);
  border-radius:calc(var(--r-card) - 8px);
  overflow:hidden;
  background:
    linear-gradient(180deg, rgba(233,230,221,.03), rgba(233,230,221,0) 60%),
    #0A0908;
  border:1px solid rgba(233,230,221,.07);
}
.cd{ display:block; width:100%; height:auto; }
.cd text.cd-t{
  font-family:var(--mono);
  font-size:11px; letter-spacing:.13em;
  fill:rgba(233,230,221,.34);
  text-transform:uppercase;
}

.cmt-meta{
  display:flex; align-items:center; justify-content:space-between;
  gap:14px; margin-bottom:14px;
}
.cmt-n{
  font-family:var(--mono); font-size:11px; letter-spacing:.13em;
  color:var(--g-3); padding:0;
}
.cmt-card:hover .cmt-n{ color:var(--g-1); }
.cmt-risk{
  display:inline-flex; align-items:center; gap:8px;
  padding:0; font-size:12px; line-height:1; color:var(--g-3);
  font-family:var(--mono); letter-spacing:.1em; text-transform:uppercase;
}
.cmt-risk::before{
  content:"";                       /* his rule wrote "RISK IT RETIRES" here; the
                                       column that needed the label is gone */
  display:inline-block; width:5px; height:5px; border-radius:50%;
  background:var(--g-3); margin:0;
}
.cmt-card h3{
  margin:0;
  font-family:var(--disp); font-weight:600;
  font-size:clamp(18px,1.35vw,23px); letter-spacing:-.026em; line-height:1.2;
  color:var(--bone);
  max-width:none;
}
.cmt-card p{
  margin:12px 0 0;
  font-size:14.5px; line-height:1.62; color:var(--g-2);
  max-width:52ch;
}

/* ── the animations ───────────────────────────────────────────
   Everything is paused until the card is in view. `.is-in` is added by
   the reveal observer in main.js, which already watches [data-reveal]. */
.cmt-card .cd *{ animation-play-state:paused; }
.cmt-card.is-in .cd *{ animation-play-state:running; }

/* a stroke that draws itself on, then holds */
.cd-draw{
  stroke-dasharray:1; stroke-dashoffset:1;
  animation:cd-draw 4.8s var(--e-out) infinite;
  animation-delay:var(--d, 0s);
}
@keyframes cd-draw{
  0%        { stroke-dashoffset:1; }
  34%, 88%  { stroke-dashoffset:0; }
  100%      { stroke-dashoffset:0; opacity:0; }
}

/* 01 — the dot running along the fixed line */
.cd-run01{
  animation:cd-run01 4.8s var(--e-out) infinite;
  animation-delay:1.5s;
}
@keyframes cd-run01{
  0%,  30%  { transform:translateX(152px); opacity:0; }
  34%       { transform:translateX(152px); opacity:1; }
  86%       { transform:translateX(432px); opacity:1; }
  100%      { transform:translateX(432px); opacity:0; }
}

/* 02 — a block landing in each slot, in order */
.cd-drop{
  transform-origin:center bottom;
  animation:cd-drop 4.8s var(--e-out) infinite;
  animation-delay:calc(var(--i) * .13s);
}
@keyframes cd-drop{
  0%, 4%   { opacity:0; transform:translateY(-16px); }
  14%, 88% { opacity:1; transform:none; }
  100%     { opacity:0; transform:none; }
}

/* 03, 05, 06 — small marks arriving in sequence */
.cd-pop{
  animation:cd-pop 4.8s var(--e-out) infinite;
  animation-delay:calc(1.1s + var(--i) * .22s);
}
@keyframes cd-pop{
  0%, 8%   { opacity:0; }
  22%, 88% { opacity:1; }
  100%     { opacity:0; }
}

/* 04 — the playhead, the early mark, the ghost of the late one */
.cd-play{
  animation:cd-play 4.8s cubic-bezier(.5,0,.5,1) infinite;
}
@keyframes cd-play{
  0%       { transform:translateX(48px); opacity:0; }
  6%       { opacity:1; }
  92%      { transform:translateX(440px); opacity:1; }
  100%     { transform:translateX(440px); opacity:0; }
}
.cd-early{ animation:cd-pop 4.8s var(--e-out) infinite; animation-delay:.55s; }
.cd-ring{
  transform-origin:122px 116px;
  animation:cd-ring 4.8s var(--e-out) infinite; animation-delay:.55s;
}
@keyframes cd-ring{
  0%, 10%  { opacity:0; transform:scale(.35); }
  26%      { opacity:.9; transform:scale(1); }
  46%,100% { opacity:0; transform:scale(1.25); }
}
.cd-ghost{ animation:cd-ghost 4.8s var(--e-out) infinite; }
@keyframes cd-ghost{
  0%, 60%  { opacity:.9; }
  84%,100% { opacity:.18; }
}

@media (prefers-reduced-motion: reduce){
  /* hold every diagram at its finished state rather than looping */
  .cd *{ animation:none !important; }
  .cd-draw{ stroke-dashoffset:0; }
  .cd-run01{ transform:translateX(432px); }
  .cd-ring{ opacity:0; }
}

/* PART 11 (the menu) moved to /assets/css/menu.css. The menu is a
   shared component that appears on six pages; this file is loaded by
   one of them, so keeping its overrides here meant the capability and
   pricing pages got the unfixed version — a 0.42-ratio preview frame
   and a full-height sheet. Shared component, shared stylesheet. */
