/* clip, not hidden: clip does not create a scroll container, so position:sticky
   keeps working. Guards against a stray full-bleed element scrolling the page. */
html,body{overflow-x:clip;}

/* MAVE Design — brand surface + card primitives
   The card/banner treatment from the email-signature concepts. Three layers on
   a dark ground:
     1. cool glow off the top-right corner
     2. warm glow off the bottom-right corner
     3. dot-matrix grid fading in from the top-right

   Keep the decoration in the empty corners, never under body text. That is both
   the look and the accessibility requirement: at full strength the glows drop
   muted text to 3.6:1. Pulled into the corners the worst measured pair is
   4.97:1. Re-verify at 4.5:1 before changing any value here.

   isolation:isolate + z-index:-1 puts the dot layer above the element's own
   background but below its text.

   This sheet is injected LAST by js/components.js (ensureCSS), so at equal
   specificity it wins against every other sheet and against page inline
   <style> blocks (which are static <head> children, always earlier). */

/* ---- weight ceiling ----
   Nothing on a MAVE surface goes above Semibold 600. The base sheets set these
   to bold/700 (normalize.css: b, strong, optgroup; webflow.css: h1-h6, label;
   mave-design.webflow.css: .text-6, .detail) and those three files are off
   limits per CLAUDE.md, so the ceiling is enforced here instead.
   Selectors are listed explicitly rather than using a blanket * rule, so
   anything deliberately set below 600 keeps its value. */
b, strong, h1, h2, h3, h4, h5, h6, label, optgroup,
.text-6, .detail{font-weight:600;}

/* ---- surface + state tokens ----
   One place the glow values live. Everything below composes these. */
:root{
  --mv-glow-cool:radial-gradient(78% 66% at 102% -4%, rgba(91,75,163,.26) 0%, rgba(91,75,163,.07) 40%, transparent 62%);
  --mv-glow-warm:radial-gradient(72% 60% at 104% 104%, rgba(255,101,7,.14) 0%, rgba(207,3,50,.05) 42%, transparent 64%);
  --mv-glow-cool-hi:radial-gradient(86% 74% at 104% -6%, rgba(91,75,163,.34) 0%, rgba(91,75,163,.10) 42%, transparent 64%);
  --mv-glow-warm-hi:radial-gradient(96% 82% at 106% 108%, rgba(255,101,7,.26) 0%, rgba(207,3,50,.11) 44%, transparent 68%);
  --mv-surface:var(--mv-glow-cool),var(--mv-glow-warm);
  --mv-surface-hi:var(--mv-glow-cool-hi),var(--mv-glow-warm-hi);

  --mv-edge:rgba(255,255,255,.10);
  --mv-edge-warm:color-mix(in srgb, var(--cta-h1) 45%, transparent);
  --mv-panel:#14141f;

  --mv-ease:cubic-bezier(.22,.61,.36,1);
  /* exponential ease-out: fast departure, long settle */
  --mv-ease-out:cubic-bezier(.16,1,.3,1);

  /* ---- type scale ----
     One ratio, one place. Display steps are deliberately wide so hierarchy
     comes from size, never weight (ceiling is 600). */
  --mv-step-display:clamp(2.6rem,6.4vw,5.2rem);
  --mv-step-h1:clamp(2.2rem,5vw,3.9rem);
  --mv-step-h2:clamp(1.65rem,3.2vw,2.6rem);
  --mv-step-h3:clamp(1.08rem,1.5vw,1.3rem);
  --mv-lead:clamp(1.02rem,1.25vw,1.16rem);

  /* ---- vertical rhythm ----
     More space above a heading than below it, so headings bind to the content
     they introduce rather than floating between blocks. */
  --mv-space-section:clamp(4rem,9vw,7.5rem);
  --mv-space-block:clamp(1.8rem,3.4vw,3rem);
  --mv-space-above-h:clamp(2.2rem,4vw,3.4rem);
  --mv-space-below-h:clamp(.7rem,1.2vw,1.1rem);
}

/* ============================================================
   HEADING REVEAL

   Structure only. The hidden and revealed states are set INLINE by
   js/components.js, deliberately.

   They used to live here as .mv-reveal--block / .in class pairs, and twice
   that shipped headings that never became visible: once because the gradient
   detection misfired, and once because the .in rule did not end up winning.
   A heading trapped at opacity 0 is the worst possible failure for this
   effect, and a class pair will always have some cascade that can defeat it.
   Inline styles have no such ambiguity, and JS is what drives the animation
   anyway. Nothing here hides text, so with JS off the headings simply render.
   ============================================================ */
.mv-reveal .mv-w{
  display:inline-block;
  overflow:hidden;
  vertical-align:top;
  /* room for descenders, which the mask would otherwise clip */
  padding-bottom:.14em;
  margin-bottom:-.14em;
}
.mv-reveal .mv-wi{display:inline-block;}

/* ---- the global-link-hover escape hatch ----
   mave-design.webflow.css sets `a{background-clip:text}`, and mave-cta.css
   sets `a:not(.mave-cta):hover{background-image:var(--cta-grad-hover)}`. That
   pair is fine for TEXT links: the warm gradient clips to the glyphs.
   Any block-level <a> that owns a real background must reset the clip to paint
   it — and that reset also un-clips the hover gradient, flooding the whole
   element. These rules give those elements their surface back on hover.
   Specificity here is 0-2-1, equal to the rule in mave-cta.css, and this sheet
   loads later, so it wins deterministically. */
a.mave-surface:hover,
a.mv-card:hover,
a.mv-frame:hover,
a.mv-frame--surface:hover,
a.mv-chip:hover{
  background-image:var(--mv-surface-hi);
}

/* Radius is deliberately NOT set on the base: consumers range from 16px cards
   to 40px pills. Cards use .mave-surface--card / .mv-card. */
.mave-surface{
  position:relative;
  isolation:isolate;
  overflow:hidden;
  background-image:var(--mv-surface);
  /* The global `a` rule sets background-clip:text, which would clip these
     gradients into the glyphs. Reset to a normal fill. See the note above. */
  -webkit-background-clip:padding-box;
          background-clip:padding-box;
}

.mave-surface::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:-1;
  pointer-events:none;
  background-image:radial-gradient(#ffffff .8px, transparent .9px);
  background-size:8px 8px;
  opacity:.06;
  -webkit-mask-image:linear-gradient(228deg,#000 0%,rgba(0,0,0,.30) 30%,transparent 52%);
          mask-image:linear-gradient(228deg,#000 0%,rgba(0,0,0,.30) 30%,transparent 52%);
}

.mave-surface--card{border-radius:16px;}

/* Image-topped cards: a full-bleed image covers the top-right, so the texture
   belongs in the copy area instead. Flips the dot grid to the bottom-right. */
.mave-surface--lower::before,
.mv-card--lower::before{
  -webkit-mask-image:linear-gradient(310deg,#000 0%,rgba(0,0,0,.30) 30%,transparent 55%);
          mask-image:linear-gradient(310deg,#000 0%,rgba(0,0,0,.30) 30%,transparent 55%);
}

/* Sits on a lighter panel: soften so the glows do not wash the text out. */
.mave-surface--soft{
  background-image:
    radial-gradient(70% 60% at 102% -4%, rgba(91,75,163,.18) 0%, transparent 60%),
    radial-gradient(64% 54% at 104% 104%, rgba(255,101,7,.10) 0%, transparent 62%);
}
.mave-surface--soft::before{opacity:.045;}

/* Small chips: glows only, the dot grid reads as noise below ~120px wide. */
.mave-surface--chip::before{display:none;}
.mave-surface--chip{
  background-image:
    radial-gradient(90% 140% at 104% -20%, rgba(91,75,163,.22) 0%, transparent 68%),
    radial-gradient(90% 140% at 104% 120%, rgba(255,101,7,.11) 0%, transparent 70%);
}

/* ============================================================
   CARD PRIMITIVE

   Every flat card on this site was the same three declarations
   (#14141f / 1px solid #ffffff14 / 14px radius) repeated ~91 times across 19
   case-study pages. The legacy .cs-* names are aliased onto the primitive
   below so all of them pick up the brand surface with ZERO markup edits.

   Migrate markup to .mv-card over time and delete names from the alias list.

   IMPORTANT: every entry must be a single class so the :is() group stays at
   specificity 0-1-0 and never outranks a page's own overrides. Do not add
   descendant selectors here — see .cs-flow .step below for why.
   ============================================================ */

:is(.mv-card,.cs-lesson,.cs-stat,.cs-jstep,.cs-spec,.cs-persona,
    .cs-site,.cs-seo,.cs-entity-map){
  position:relative;
  isolation:isolate;
  overflow:hidden;
  border-radius:16px;
  border:1px solid var(--mv-edge);
  background-color:var(--mv-panel);
  background-image:var(--mv-surface);
  -webkit-background-clip:padding-box;
          background-clip:padding-box;
  transition:border-color .3s ease,
             background-image .45s ease,
             transform .35s var(--mv-ease),
             box-shadow .35s ease;
}

/* The dot layer is listed separately because .mave-t-card keeps its own
   vertical base gradient (it is a hero-scale card) and only borrows the dots.
   Everything above plus .mave-t-card. */
:is(.mv-card,.cs-lesson,.cs-stat,.cs-jstep,.cs-spec,.cs-persona,
    .cs-site,.cs-seo,.cs-entity-map,.mave-t-card)::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:-1;
  pointer-events:none;
  background-image:radial-gradient(#ffffff .8px,transparent .9px);
  background-size:8px 8px;
  opacity:.06;
  -webkit-mask-image:linear-gradient(228deg,#000 0%,rgba(0,0,0,.30) 30%,transparent 52%);
          mask-image:linear-gradient(228deg,#000 0%,rgba(0,0,0,.30) 30%,transparent 52%);
}

/* .cs-flow .step is deliberately NOT in the :is() group: its own ::before is a
   numbered counter, and a descendant selector would push the whole group to
   0-2-0 and clobber it. Same tokens, no pseudo-element. */
.cs-flow .step{
  background-color:var(--mv-panel);
  background-image:var(--mv-surface);
  border:1px solid var(--mv-edge);
  border-radius:12px;
  -webkit-background-clip:padding-box;
          background-clip:padding-box;
}

/* Hover only where the card is actually a control. */
a.mv-card:hover,
button.mv-card:hover,
.mv-card--action:hover{
  border-color:var(--mv-edge-warm);
  background-image:var(--mv-surface-hi);
  transform:translateY(-6px);
  box-shadow:0 18px 44px rgba(0,0,0,.45),
             inset 0 0 0 1px color-mix(in srgb, var(--cta-h1) 20%, transparent);
}

/* ---- chips (40px pills) ---- */
:is(.mv-chip,.cs-tool,.cs-chip){
  border-radius:40px;
  border:1px solid rgba(255,255,255,.14);
  background-color:var(--mv-panel);
  background-image:
    radial-gradient(90% 140% at 104% -20%, rgba(91,75,163,.22) 0%, transparent 68%),
    radial-gradient(90% 140% at 104% 120%, rgba(255,101,7,.11) 0%, transparent 70%);
  -webkit-background-clip:padding-box;
          background-clip:padding-box;
  transition:border-color .25s ease,background-image .3s ease,transform .25s var(--mv-ease);
}
a.mv-chip:hover,button.mv-chip:hover{
  border-color:color-mix(in srgb, var(--cta-h1) 50%, transparent);
  transform:translateY(-2px);
}

/* ---- image frames ----
   <img> cannot carry a ::before, and an image covers the glow anyway, so these
   get the edge treatment only. */
:is(.mv-frame,.cs-shot,.cs-final-img,.cs-video){
  display:block;
  border-radius:14px;
  border:1px solid var(--mv-edge);
  overflow:hidden;
}
.cs-gallery img{border-radius:12px;border:1px solid var(--mv-edge);}

/* Container variant: a frame that also owns a surface (prev/next tiles). */
.mv-frame--surface{
  border-radius:16px;
  background-color:var(--mv-panel);
  background-image:var(--mv-surface);
  -webkit-background-clip:padding-box;
          background-clip:padding-box;
}

/* ---- focus ----
   Warm means contact, and focus is contact. There was effectively no
   focus-visible treatment sitewide; the only :focus rule REMOVED the outline
   (mave-intake.css) and mave-design.webflow.css used a non-brand #0050bd.
   :where() is 0-specificity so it never fights a component's own styling. */
:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{
  outline:2px solid var(--cta-h1);
  outline-offset:3px;
}
/* Explicit, because these carry their own focus rules that would otherwise win. */
.nav-link:focus-visible,.nav-link[data-wf-focus-visible],
.mv-link:focus-visible,.mv-cta:focus-visible,
.mave-cta:focus-visible,.mave-proj-tab:focus-visible,
.mave-t-dot:focus-visible,.mf-in:focus-visible{
  outline:2px solid var(--cta-h1);
  outline-offset:3px;
}
/* Filled pills: the ring sits outside the fill, so give it room. */
.mave-cta--main:focus-visible,
.mave-cta--viewall:focus-visible,
.mave-cta--submit:focus-visible{outline-offset:4px;}

/* ============================================================
   PROCESS FRAMEWORK
   Three named phases + one continuation beat. The numerals are load-bearing
   here — this genuinely is a sequence, which is the only thing that earns
   01/02/03 markers.
   ============================================================ */
.mv-process{padding:var(--mv-space-section) 0;}
/* Matches .standard-content (1400px) so the section lines up with
   Featured Projects and What We Do rather than sitting narrower. */
.mv-process-wrap{width:90%;max-width:1400px;margin:0 auto;}
.mv-process-head{max-width:56ch;margin-bottom:clamp(2.4rem,4.5vw,3.6rem);}
.mv-process-kicker{
  display:inline-flex;align-items:center;gap:.75rem;
  font-family:'Roboto',Verdana,sans-serif;font-weight:300;
  text-transform:uppercase;letter-spacing:.24em;font-size:.72rem;
  background:var(--cta-grad);-webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;margin:0 0 1rem;
}
.mv-process-kicker::before{
  content:"";width:26px;height:2px;border-radius:2px;flex:none;
  background:linear-gradient(90deg,var(--cta-h1),var(--cta-h2));
  -webkit-background-clip:border-box;background-clip:border-box;
}
/* mave-design.webflow.css sets h2{text-transform:capitalize}, which turns
   "then made to shine" into "Then Made To Shine". The brand voice is low
   punctuation and sentence case, so headings opt out. */
.mv-process-heading{
  font-family:var(--headings,'Montserrat',sans-serif);font-weight:600;
  font-size:var(--mv-step-h2);line-height:1.06;letter-spacing:-.022em;
  color:#fff;-webkit-text-fill-color:#fff;text-wrap:balance;margin:0 0 .9rem;
  text-transform:none;
}
.mv-process-sub{margin:0;color:#c6c9e0;-webkit-text-fill-color:#c6c9e0;
  font-size:var(--mv-lead);line-height:1.65;}

.mv-process-list{
  list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(3,1fr);gap:1.1rem;
}
.mv-phase{padding:1.9rem 1.7rem 1.8rem;display:flex;flex-direction:column;}
.mv-phase-num{
  font-family:var(--headings,'Montserrat',sans-serif);font-weight:600;
  font-size:.95rem;letter-spacing:.06em;
  background:var(--cta-grad);-webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;
}
.mv-phase-title{
  font-family:var(--headings,'Montserrat',sans-serif);font-weight:600;
  font-size:1.42rem;line-height:1.15;letter-spacing:-.015em;
  color:#fff;-webkit-text-fill-color:#fff;margin:.5rem 0 .6rem;text-transform:none;
}
.mv-phase-desc{margin:0 0 1.15rem;color:#c6c9e0;-webkit-text-fill-color:#c6c9e0;
  font-size:.94rem;line-height:1.6;}
/* Deliverables. Premium buyers de-risk by seeing artifacts, so these are the
   same words the proposal uses. */
.mv-phase-deliv{list-style:none;margin:auto 0 0;padding:.95rem 0 0;
  border-top:1px solid var(--mv-edge);display:grid;gap:.42rem;}
.mv-phase-deliv li{position:relative;padding-left:1.05rem;
  font-size:.85rem;line-height:1.45;color:#aeb2cd;-webkit-text-fill-color:#aeb2cd;}
.mv-phase-deliv li::before{
  content:"";position:absolute;left:0;top:.52em;width:5px;height:5px;border-radius:50%;
  background:var(--cta-grad);
}

/* The continuation beat reads as a different kind of thing: wider, warm-led. */
.mv-process-after{
  margin-top:1.1rem;padding:1.6rem 1.7rem;
  display:flex;align-items:center;justify-content:space-between;gap:1.5rem;flex-wrap:wrap;
}
.mv-after-copy{max-width:62ch;}
.mv-after-label{
  margin:0 0 .3rem;font-size:.72rem;text-transform:uppercase;letter-spacing:.2em;
  background:linear-gradient(90deg,var(--cta-h1),var(--cta-h2));
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;
}
.mv-after-title{
  font-family:var(--headings,'Montserrat',sans-serif);font-weight:600;
  font-size:1.3rem;line-height:1.2;color:#fff;-webkit-text-fill-color:#fff;margin:0 0 .45rem;text-transform:none;
}
.mv-after-desc{margin:0;color:#c6c9e0;-webkit-text-fill-color:#c6c9e0;
  font-size:.92rem;line-height:1.6;}

/* ---- phase card motion ----
   Entrance is staggered by index (set inline by js/components.js). Hover
   intensifies the surface and draws a warm rule across the top edge; there is
   deliberately no lift and no cursor change, because a phase card is content,
   not a control. */
.mv-phase{
  position:relative;
  transition:background-image .5s ease,border-color .4s ease,transform .7s var(--mv-ease-out),opacity .6s ease;
}
.mv-phase::after{
  content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,var(--cta-h1),var(--cta-h2));
  transform:scaleX(0);transform-origin:left;
  transition:transform .55s var(--mv-ease-out);
  border-radius:16px 16px 0 0;
}
.mv-phase:hover{background-image:var(--mv-surface-hi);border-color:var(--mv-edge-warm);}
.mv-phase:hover::after{transform:scaleX(1);}
.mv-phase:hover .mv-phase-num{background:var(--cta-grad-hover);
  -webkit-background-clip:text;background-clip:text;}
.mv-phase-num{transition:background .4s ease;}

/* entrance */
.mv-process-list .mv-phase,
.mv-process-after{opacity:0;transform:translateY(26px);}
.mv-process-list.in .mv-phase,
.mv-process-after.in{opacity:1;transform:none;}
/* deliverables settle a beat after their card */
.mv-phase-deliv li{opacity:0;transform:translateY(8px);
  transition:opacity .5s ease,transform .5s var(--mv-ease-out);}
.mv-process-list.in .mv-phase-deliv li{opacity:1;transform:none;}

@media (prefers-reduced-motion: reduce){
  .mv-phase,.mv-phase::after,.mv-phase-num,.mv-phase-deliv li{transition:none;}
  .mv-process-list .mv-phase,.mv-process-after,
  .mv-phase-deliv li{opacity:1;transform:none;}
  .mv-phase:hover::after{transform:scaleX(1);}
}

@media (max-width:900px){
  .mv-process-list{grid-template-columns:1fr;}
  .mv-phase{padding:1.6rem 1.4rem;}
  .mv-process-after{flex-direction:column;align-items:flex-start;}
}

/* ---- motion ---- */
@media (prefers-reduced-motion: reduce){
  :is(.mv-card,.cs-lesson,.cs-stat,.cs-jstep,.cs-spec,.cs-persona,
      .cs-site,.cs-seo,.cs-entity-map,.mave-t-card),
  :is(.mv-chip,.cs-tool,.cs-chip){transition:none;}
  a.mv-card:hover,button.mv-card:hover,.mv-card--action:hover{transform:none;}
}
