:root{
  --ink:#0C0C0E; --muted:#5C6373;   /* was #6B7280 -- 4.17:1 on --paper, under AA */ --space:#09090B; --surface:#FFFFFF;
  --paper:#EDEEF3;                      /* the flat ground measured in the videos */
  --grid-line:rgba(0,0,0,.05); --grid:40px;
  --display:'Newsreader',Georgia,serif;
  --body:'DM Sans',system-ui,sans-serif;
  --mono:'Fragment Mono',ui-monospace,Menlo,monospace;
}
*{box-sizing:border-box}
body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--body);
  -webkit-font-smoothing:antialiased}
.wrap{max-width:1060px;margin:0 auto;padding:0 28px}
/* Centred as the site standard. Measures are pulled in so centred copy still
   reads -- centring a 70ch paragraph is what makes centred layouts feel loose. */
.hero .wrap,.sec .wrap{text-align:center}
.hero .lede,.sec .note{margin-left:auto;margin-right:auto}
.hero .row,.sec .row{justify-content:center}
.sheet{text-align:left}

/* HERO — bloom only, NO grid. The grid starts at section 2. */
.hero{position:relative;overflow:hidden;padding:104px 0 168px;background:var(--paper)}
.hero__field{position:absolute;inset:0;z-index:0;
  background:
    radial-gradient(ellipse 90% 70% at 30% 40%, rgba(124,58,237,.22) 0%, transparent 65%),
    radial-gradient(ellipse 70% 55% at 72% 50%, rgba(167,139,250,.16) 0%, transparent 60%),
    radial-gradient(ellipse 130% 90% at 50% 25%, rgba(124,58,237,.10) 0%, transparent 75%);
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 48%,rgba(0,0,0,.82) 68%,rgba(0,0,0,.46) 82%,rgba(0,0,0,.16) 93%,transparent 100%);
          mask-image:linear-gradient(180deg,#000 0%,#000 48%,rgba(0,0,0,.82) 68%,rgba(0,0,0,.46) 82%,rgba(0,0,0,.16) 93%,transparent 100%)}
/* The hero has no hard bottom edge of its own either -- it ends on paper. */
.hero{--hero-fade:1}
.hero__scrim{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    radial-gradient(120% 78% at 50% 40%,
      rgba(255,255,255,.82) 0%,
      rgba(255,255,255,.58) 34%,
      rgba(255,255,255,.20) 58%,
      transparent 76%)}
.hero > .wrap{position:relative;z-index:2}

/* EVERYTHING BELOW THE HERO — grid ground, no wash. */
/* Overlap deepened from -150px to -230px. The grid's in-ramp and the hero's
 * out-ramp now run through the same band of pixels instead of meeting at one,
 * which is what removes the partition — neither layer is at full strength
 * anywhere the other is. padding-top grows to match so no content moves. */
.body-ground{background-color:transparent;position:relative;margin-top:-230px;padding-top:190px}
/* THE GRID IS NO LONGER PAINTED IN FLAT BLACK.
   A bloom canvas covers the section and a two-axis mask lets only the 1px rules
   show through it, so every grid line carries the flowing gradient underneath
   and the colour travels along the rules. Black lines at 5% read as dirt on a
   coloured ground; tinted ones belong to it. */
.grid-flow{position:absolute;inset:0;z-index:0;pointer-events:none;opacity:.20;
  -webkit-mask-image:linear-gradient(#000 1px,transparent 1px),linear-gradient(90deg,#000 1px,transparent 1px);
          mask-image:linear-gradient(#000 1px,transparent 1px),linear-gradient(90deg,#000 1px,transparent 1px);
  -webkit-mask-size:var(--grid) var(--grid);      mask-size:var(--grid) var(--grid);
  -webkit-mask-repeat:repeat;                     mask-repeat:repeat}
/* Second mask layer on a wrapper, so the whole ruled field ramps in from the
   hero rather than starting at full strength on its first row. */
.grid-fade{position:absolute;inset:0;z-index:0;pointer-events:none;
  /* Ramps in AND out. The in-ramp was already here at a linear 0->300px, which
   * is a straight line and reads as one: the rules appear to switch on at a
   * fixed depth. Three stops make the arrival ease instead — barely there at
   * 120px, half at 260px, full at 460px — so the field gathers rather than
   * starts. The tail is the part that never existed: the grid used to hold
   * full strength to its last row and stop dead against whatever followed,
   * which is the hard partition. It now gives back the last 340px. */
  -webkit-mask-image:linear-gradient(180deg,
      transparent 0px, rgba(0,0,0,.18) 120px, rgba(0,0,0,.62) 260px,
      #000 460px, #000 calc(100% - 340px), rgba(0,0,0,.55) calc(100% - 190px),
      rgba(0,0,0,.16) calc(100% - 70px), transparent 100%);
          mask-image:linear-gradient(180deg,
      transparent 0px, rgba(0,0,0,.18) 120px, rgba(0,0,0,.62) 260px,
      #000 460px, #000 calc(100% - 340px), rgba(0,0,0,.55) calc(100% - 190px),
      rgba(0,0,0,.16) calc(100% - 70px), transparent 100%)}
.grid-flow canvas{width:100%!important;height:100%!important;display:block}
.body-ground > section{position:relative;z-index:1}
.ground-light{position:absolute;inset:0;z-index:0;pointer-events:none;opacity:0;
  transition:opacity .5s ease;
  background:radial-gradient(420px circle at var(--mx,50%) var(--my,50%),
    rgba(124,58,237,.13), rgba(48,140,147,.07) 42%, transparent 68%)}
.body-ground:hover .ground-light{opacity:1}

.eyebrow{font-family:var(--mono);font-size:10.5px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted);margin:0 0 20px}
h1{font-family:var(--display);font-weight:300;font-size:clamp(40px,5.6vw,68px);
  line-height:1.02;letter-spacing:-.025em;margin:0 0 20px;text-wrap:balance}
h1 em{font-style:italic}
.lede{font-size:17px;line-height:1.62;color:#3F4451;max-width:52ch;margin:0 0 38px}
h2{font-family:var(--display);font-weight:300;font-size:32px;letter-spacing:-.02em;margin:0 0 8px}
.sec{padding:78px 0}
.note{color:var(--muted);font-size:14px;line-height:1.6;margin:0 0 30px;max-width:62ch}

/* ── CAPSULE ── the blob is a LIVE BLOOM canvas, not a linear-gradient ───── */
.row{display:flex;gap:20px;flex-wrap:wrap;perspective:900px}
.sheets{perspective:1400px}
.tilt{transform-style:preserve-3d;
  transition:transform .5s cubic-bezier(.2,.7,.2,1), box-shadow .5s cubic-bezier(.2,.7,.2,1)}
.tilt.is-live{transition:transform .09s linear, box-shadow .09s linear}
.pill{position:relative;display:inline-flex;align-items:center;overflow:hidden;
  height:64px;min-width:252px;padding:0 62px 0 28px;border:0;cursor:pointer;
  border-radius:999px;text-decoration:none;background:var(--space);
  /* DEPTH, NOT A DROP SHADOW.
   * A single blurred shadow reads as a sticker. Three layers read as an object:
   * a tight contact shadow that keeps it anchored, a wide ambient one for the
   * body, and an inset top highlight so the upper edge catches light like a
   * curved surface. The inset is what makes it look moulded rather than cut. */
  box-shadow:
    0 1px 2px rgba(16,16,24,.16),
    0 6px 12px rgba(16,16,24,.13),
    0 18px 34px rgba(16,16,24,.14),
    inset 0 0 0 1px rgba(255,255,255,.10),
    inset 0 1px 0 rgba(255,255,255,.26),
    inset 0 -1px 0 rgba(0,0,0,.26),
    inset 2px 0 6px -4px rgba(255,255,255,.22),
    inset -2px 0 6px -4px rgba(0,0,0,.24);
  transform:translateZ(0);
  transition:transform .26s cubic-bezier(.2,.7,.2,1), box-shadow .26s cubic-bezier(.2,.7,.2,1);
  will-change:transform}
.pill:active{transform:translateY(-1px) scale(.998);transition-duration:.09s}
/* Specular sweep. A moving highlight is what sells a surface as curved and
   physical; without it the 3D shadows read as a flat card with a blur under it.
   Skewed so it travels like light across a cylinder rather than a flat wipe. */
.pill::after{content:'';position:absolute;inset:-40% -60%;z-index:3;pointer-events:none;
  background:linear-gradient(100deg,transparent 38%,rgba(255,255,255,.42) 48%,
    rgba(255,255,255,.62) 51%,rgba(255,255,255,.42) 54%,transparent 64%);
  transform:translateX(-62%) rotate(2deg);opacity:0;
  transition:opacity .18s ease}
.pill:hover::after{opacity:1;animation:pill-sheen .78s cubic-bezier(.3,.6,.2,1)}
@keyframes pill-sheen{from{transform:translateX(-62%) rotate(2deg)}
                        to{transform:translateX(62%)  rotate(2deg)}}
.pill--light::after{background:linear-gradient(100deg,transparent 38%,rgba(255,255,255,.75) 50%,transparent 64%)}

.pill__blob{position:absolute;top:0;right:0;bottom:0;width:58%;pointer-events:none;
  border-radius:0 999px 999px 0;
  /* THE HARD EDGE ON DARK PILLS WAS THE CANVAS, NOT THE MASK.
   * A <canvas> is a rectangle. The parent's border-radius does not clip a
   * composited child cleanly, so the bloom's right side ended in a visibly
   * aliased vertical step against the dark body. overflow:hidden plus its own
   * radius makes the blob clip its canvas, and isolation gives it a stacking
   * context so the rounding is applied in one pass instead of per-layer. */
  overflow:hidden;
  isolation:isolate;
  -webkit-mask:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.55) 34%,#000 72%);
          mask:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.55) 34%,#000 72%)}
.pill__blob canvas,.pill-blob canvas{width:100%!important;height:100%!important;display:block;
  transform:scale(1.02);transform-origin:center;backface-visibility:hidden}
.pill__label{position:relative;z-index:2;display:flex;flex-direction:column;gap:4px;text-align:left}
.pill__label b{font-size:15.5px;font-weight:700;letter-spacing:.005em;color:#fff;line-height:1}
.pill__label span{font-family:var(--mono);font-size:10px;letter-spacing:.13em;
  text-transform:uppercase;color:rgba(255,255,255,.60);line-height:1}
.pill--light{background:var(--surface);
  box-shadow:
    0 1px 2px rgba(16,16,24,.10),
    0 6px 12px rgba(16,16,24,.08),
    0 18px 34px rgba(16,16,24,.10),
    inset 0 0 0 1px rgba(16,16,24,.05),
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -1px 0 rgba(0,0,0,.09),
    inset 2px 0 6px -4px rgba(255,255,255,.9),
    inset -2px 0 6px -4px rgba(0,0,0,.09)}
.pill--light:hover{
  box-shadow:
    0 2px 4px rgba(16,16,24,.10),
    0 12px 22px rgba(16,16,24,.11),
    0 34px 60px rgba(16,16,24,.14),
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -1px 0 rgba(0,0,0,.08)}
.pill--light .pill__label b{color:var(--ink)}
.pill--light .pill__label span{color:var(--muted)}

/* ── SHEET ── sharp corners, no shadow, bloom INSIDE, text above it ─────── */
.sheets{display:grid;grid-template-columns:repeat(auto-fit,minmax(268px,1fr));gap:22px}
.sheet{position:relative;overflow:hidden;background:var(--surface);
  border-radius:3px;                    /* videos measured 0–8px, never 24 */
  aspect-ratio:3/4;display:flex;flex-direction:column;padding:26px;
  /* Same depth grammar as the capsules: contact + ambient + a top edge light.
   * The reference cards sit flat, but they also sit on flat paper -- on a ruled
   * ground a card with no shadow reads as a hole cut in the grid rather than an
   * object on top of it, so it needs just enough to lift off the rules. */
  box-shadow:
    0 1px 2px rgba(16,16,24,.07),
    0 6px 14px rgba(16,16,24,.06),
    0 16px 34px rgba(16,16,24,.06),
    inset 0 1px 0 rgba(255,255,255,.9);
  transform:translateZ(0);
  transition:transform .34s cubic-bezier(.2,.7,.2,1), box-shadow .34s cubic-bezier(.2,.7,.2,1);
  will-change:transform}
.sheet--dark:hover{box-shadow:
    0 2px 4px rgba(0,0,0,.30),
    0 14px 28px rgba(0,0,0,.30),
    0 40px 70px rgba(0,0,0,.34),
    inset 0 1px 0 rgba(255,255,255,.10)}
.sheet__field{position:absolute;inset:0;z-index:0}
.sheet__field canvas{width:100%!important;height:100%!important;display:block}
/* Paper at the top so the type always has a clean ground, bloom owning the
   lower two-thirds — exactly the composition in the reference posters. */
.sheet__veil{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,#fff 0%,#fff 20%,rgba(255,255,255,.86) 30%,rgba(255,255,255,.30) 40%,rgba(255,255,255,0) 50%)}
.sheet__txt{position:relative;z-index:2}
.sheet__kicker{font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;
  text-transform:uppercase;color:#4A5064;margin:0 0 10px}
.sheet h3{font-family:var(--display);font-weight:300;font-size:21px;line-height:1.18;
  letter-spacing:-.015em;margin:0 0 8px}
.sheet p{margin:0;font-size:13.5px;line-height:1.55;color:#33384A}
.sheet--dark{background:#0B0B0D}
.sheet--dark .sheet__veil{background:linear-gradient(180deg,#0B0B0D 0%,rgba(11,11,13,.9) 26%,rgba(11,11,13,0) 62%)}
.sheet--dark h3{color:#fff}
.sheet--dark p,.sheet--dark .sheet__kicker{color:rgba(255,255,255,.86)}

.foot{background:var(--space);color:#fff;padding:60px 0 30px;margin-top:20px}
.foot__in{max-width:1060px;margin:0 auto;padding:0 28px;display:grid;
  grid-template-columns:1.5fr 1fr 1fr;gap:36px}
.foot__mark{font-family:var(--display);font-weight:300;font-size:27px;margin:0 0 10px}
.foot h4{font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:rgba(255,255,255,.42);margin:0 0 14px;font-weight:400}
.foot a{display:block;color:rgba(255,255,255,.76);text-decoration:none;font-size:13.5px;margin-bottom:9px}
.foot__legal{max-width:1060px;margin:34px auto 0;padding:20px 28px 0;
  border-top:1px solid rgba(255,255,255,.12);font-size:12px;color:rgba(255,255,255,.46)}
@media(max-width:760px){.foot__in{grid-template-columns:1fr}}

/* ── CHROME ── nav, mega menu, support bot. Added 2026-08-03.
 * Written in THIS page's language, not imported from another system: the
 * tokens are --paper/--ink/--muted/--space/--display/--body/--mono already
 * declared above, and the CTA is the same .pill capsule with the same bloom
 * canvas the hero uses. Nothing here introduces a second type system.
 *
 * Classes are prefixed nv-/mg-/bot- on purpose. This page defines its own
 * `.sheet`, and at least two other stylesheets in the tree define an
 * incompatible one; a generic name here would be the same collision again. */

.nv{position:sticky;top:0;z-index:60;
  /* Height from padding, never a fixed height. A fixed height on nav links is
     what once turned a 64px bar into a 606px stack on every page. */
  padding:14px 28px;
  display:flex;align-items:center;gap:22px;
  background:color-mix(in srgb, var(--paper) 86%, transparent);
  -webkit-backdrop-filter:blur(14px) saturate(1.3);
          backdrop-filter:blur(14px) saturate(1.3);
  border-bottom:1px solid var(--grid-line);
  font-family:var(--body)}
.nv *{box-sizing:border-box}
.nv__brand{display:inline-flex;align-items:center;gap:10px;text-decoration:none;flex:0 0 auto}
.nv__brand img{width:30px;height:30px;display:block}
.nv__brand b{font-family:var(--display);font-size:21px;font-weight:500;
  letter-spacing:-.015em;color:var(--ink)}

/* CENTRED. `margin:0 auto` on both sides splits the slack evenly between the
   brand and the actions. Pinning it to the brand is what read as "the header
   is not in center". */
.nv__links{display:flex;align-items:center;gap:26px;margin:0 auto;padding:0;list-style:none}
.nv__links > li{position:relative}
.nv__links a,.nv__mega-btn{font-size:14.5px;font-weight:500;color:var(--muted);
  text-decoration:none;white-space:nowrap;background:none;border:0;padding:0;
  cursor:pointer;font-family:var(--body);display:inline-flex;align-items:center;gap:5px;
  transition:color .14s ease}
.nv__links a:hover,.nv__mega-btn:hover{color:var(--ink)}
.nv__mega-btn svg{width:11px;height:11px;transition:transform .2s ease}
.nv__actions{display:flex;align-items:center;gap:16px;flex:0 0 auto}
.nv__ghost{font-size:14.5px;font-weight:500;color:var(--muted);text-decoration:none;
  transition:color .14s ease}
.nv__ghost:hover{color:var(--ink)}

/* NAV-SIZED CAPSULE. Same .pill, same bloom, scaled to the bar. 44px keeps
   radius = height/2 exactly, so the corner stays a true stadium instead of
   becoming a rounded rectangle at a smaller size. */
.pill--nav{height:44px;min-width:0;padding:0 46px 0 20px}
.pill--nav .pill__label{gap:2px}
.pill--nav .pill__label b{font-size:13.5px}
.pill--nav .pill__label span{font-size:8.5px;letter-spacing:.11em}
.pill--nav .pill__blob{width:52%}

/* ── MEGA MENU ── a checkbox, not a script.
   A toggle that needs JS is a toggle that is broken on the pages that load
   none, and most of this site's pages load none. */
.mg__cb{position:absolute;opacity:0;pointer-events:none;width:0;height:0}
.mg{position:absolute;top:calc(100% + 14px);left:50%;translate:-50% 0;z-index:70;
  width:min(920px,calc(100vw - 44px));
  background:var(--surface);border:1px solid var(--grid-line);border-radius:16px;
  box-shadow:0 1px 2px rgba(16,16,24,.10),0 10px 22px rgba(16,16,24,.09),
             0 34px 60px rgba(16,16,24,.11);
  padding:26px 30px;
  display:grid;gap:26px 34px;grid-template-columns:repeat(4,1fr);
  /* Collapsed by opacity + visibility, NEVER display:none. These are real
     links on the SEO surface; display:none removes them from the link graph. */
  opacity:0;visibility:hidden;translate:-50% -8px;
  transition:opacity .18s ease, translate .18s ease, visibility .18s}
.mg__cb:checked ~ .mg{opacity:1;visibility:visible;translate:-50% 0}
.mg__cb:checked ~ .nv__mega-btn svg{transform:rotate(180deg)}
.mg h5{margin:0 0 12px;font-family:var(--mono);font-size:9.5px;font-weight:400;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.mg ul{margin:0;padding:0;list-style:none}
.mg li + li{margin-top:9px}
.mg a{font-size:14px;color:var(--ink);text-decoration:none;opacity:.82;
  transition:opacity .12s ease,color .12s ease}
.mg a:hover{opacity:1;color:var(--ink)}
.mg__feat{grid-column:1 / -1;display:flex;align-items:center;gap:16px;
  padding-top:20px;border-top:1px solid var(--grid-line)}
.mg__feat p{margin:0;font-size:13px;color:var(--muted);line-height:1.55}

/* ── SUPPORT BOT ──
   Bottom-right, above the footer, never overlapping the credit line -- the
   launcher sitting on the footer's social row was a reported defect. Round,
   with NO outer square: the badge PNG is transparent and any plate behind it
   showed as the "outer square on supp bot". */
.bot{position:fixed;right:22px;bottom:22px;z-index:80;
  width:56px;height:56px;border-radius:999px;border:0;cursor:pointer;padding:0;
  display:grid;place-items:center;overflow:hidden;isolation:isolate;
  background:var(--space);
  box-shadow:0 1px 2px rgba(16,16,24,.18),0 6px 14px rgba(16,16,24,.16),
             0 16px 30px rgba(16,16,24,.16),
             inset 0 1px 0 rgba(255,255,255,.24),
             inset 0 -1px 0 rgba(0,0,0,.28);
  transition:transform .2s cubic-bezier(.2,.7,.2,1)}
.bot:hover{transform:translateY(-2px) scale(1.03)}
.bot img{width:28px;height:28px;position:relative;z-index:2;display:block}
.bot__blob{position:absolute;inset:0;z-index:1;border-radius:999px;overflow:hidden}
.bot__blob canvas{width:100%!important;height:100%!important;display:block}

@media (max-width:900px){
  .nv{flex-wrap:wrap;gap:0;justify-content:space-between;padding:12px 18px}
  .nv__burger{display:grid;place-items:center;width:42px;height:42px;order:3;
    border-radius:11px;border:1px solid var(--grid-line);background:var(--surface);
    cursor:pointer}
  .nv__burger span,.nv__burger span::before,.nv__burger span::after{
    content:'';display:block;width:17px;height:2px;border-radius:2px;
    background:var(--ink);position:relative}
  .nv__burger span::before{position:absolute;top:-5px}
  .nv__burger span::after{position:absolute;top:5px}
  .nv__links,.nv__actions{flex-basis:100%;order:4;max-height:0;overflow:hidden;
    margin:0;opacity:0;transition:max-height .26s ease,opacity .2s ease}
  .nv__links{flex-direction:column;align-items:flex-start;gap:0}
  .nv__links > li{width:100%}
  .nv__links a,.nv__mega-btn{display:flex;padding:13px 2px;font-size:15.5px;width:100%}
  .nv__cb:checked ~ .nv__links,.nv__cb:checked ~ .nv__actions{
    max-height:78vh;overflow-y:auto;opacity:1;margin-top:10px;padding-top:10px;
    border-top:1px solid var(--grid-line)}
  .nv__cb:checked ~ .nv__actions{gap:14px;padding-bottom:6px}
  .mg{position:static;translate:none;width:100%;grid-template-columns:1fr 1fr;
    box-shadow:none;border:0;padding:6px 0 2px;background:transparent}
  .mg__cb:checked ~ .mg{translate:none}
  .mg__feat{display:none}
  .bot{right:14px;bottom:14px;width:50px;height:50px}
}
.nv__cb{position:absolute;opacity:0;pointer-events:none;width:0;height:0}
.nv__burger{display:none}

/* ── BENCHMARK ── the shape census, rendered.
 * Every number below is counted from the 118 top-level pages in
 * web/vedika-public, not estimated. The point of drawing them rather than
 * listing them is that 28 radii is an abstraction; 28 squares side by side is
 * the actual problem. */
.bm__stats{display:grid;gap:18px;grid-template-columns:repeat(auto-fit,minmax(min(210px,100%),1fr));
  margin:34px 0 44px;text-align:left}
.bm__stat{background:var(--surface);border:1px solid var(--grid-line);border-radius:8px;
  padding:20px 22px;box-shadow:0 2px 6px rgba(0,0,0,.06)}
.bm__stat b{display:block;font-family:var(--display);font-size:40px;font-weight:500;
  line-height:1;letter-spacing:-.02em;color:var(--ink)}
.bm__stat span{display:block;margin-top:8px;font-size:13px;color:var(--muted);line-height:1.5}
.bm__stat u{display:block;margin-top:10px;font-family:var(--mono);font-size:10px;
  letter-spacing:.12em;text-transform:uppercase;text-decoration:none;color:var(--ink);opacity:.55}

.bm__rail{display:flex;flex-wrap:wrap;gap:14px;justify-content:center;margin:26px 0 10px}
.bm__sw{margin:0;width:74px;text-align:center}
.bm__sw i{display:block;height:56px;background:var(--surface);
  border:1px solid rgba(0,0,0,.13);box-shadow:0 2px 6px rgba(0,0,0,.07)}
.bm__sw figcaption{margin-top:7px;font-family:var(--mono);font-size:9.5px;color:var(--muted);
  line-height:1.5}
.bm__sw em{display:block;font-style:normal;opacity:.6}

.bm__two{display:grid;gap:26px;grid-template-columns:repeat(auto-fit,minmax(min(320px,100%),1fr));
  margin-top:34px;text-align:left}
.bm__panel{background:var(--surface);border:1px solid var(--grid-line);border-radius:8px;
  padding:22px 24px;box-shadow:0 2px 6px rgba(0,0,0,.06)}
.bm__panel h4{margin:0 0 14px;font-family:var(--mono);font-size:9.5px;font-weight:400;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.bm__panel table{width:100%;border-collapse:collapse;font-size:12.5px}
.bm__panel td{padding:6px 0;border-bottom:1px solid var(--grid-line);vertical-align:top}
.bm__panel td:first-child{width:52px;font-family:var(--mono);color:var(--muted)}
.bm__panel code{font-family:var(--mono);font-size:11.5px;color:var(--ink)}
.bm__panel ul{margin:0;padding:0;list-style:none;font-size:12.5px}
.bm__panel li{display:flex;justify-content:space-between;gap:12px;padding:6px 0;
  border-bottom:1px solid var(--grid-line)}
.bm__panel li em{font-style:normal;font-family:var(--mono);color:var(--muted)}

.bm__one{margin-top:40px;padding:28px;background:var(--space);border-radius:8px;text-align:left;
  box-shadow:0 2px 6px rgba(0,0,0,.2)}
.bm__one h4{margin:0 0 8px;font-family:var(--display);font-size:22px;font-weight:500;
  letter-spacing:-.015em;color:#fff}
.bm__one p{margin:0 0 18px;font-size:13.5px;line-height:1.65;color:rgba(255,255,255,.66);max-width:64ch}
.bm__specimens{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr))}
.bm__specimen{background:var(--surface);border-radius:8px;padding:18px 20px;
  box-shadow:0 2px 6px rgba(0,0,0,.08)}
.bm__specimen b{display:block;font-family:var(--display);font-size:16px;font-weight:500;color:var(--ink)}
.bm__specimen span{display:block;margin-top:6px;font-size:12.5px;color:var(--muted);line-height:1.55}

/* Nav links measured 4.17:1 against the paper ground -- under AA at 4.5. The
   --muted token is the page's own and is not being changed; only the chrome I
   added is corrected, and only where it carries small text. */
.nv__links a,.nv__mega-btn,.nv__ghost{color:var(--muted)}

/* ── BRAND CAPSULE ── royal purple into lavender. Header buttons use this.
 *
 * THREE MEASURED DEFECTS IT FIXES, all visible in the nav:
 *
 * 1. THE LABEL WAS UNREADABLE IN THE MEGA MENU. .pill--nav set min-width:0, so
 *    the featured pill shrank to its text and the blob -- a fixed 52% of the
 *    pill -- landed under the label instead of beside it. White type on a pale
 *    spectral bloom is white on white. The blob now gets a hard right-hand
 *    reserve and the label a floor width, so the two can never trade places.
 *
 * 2. THE CTA READ AS DULL. --space (#09090B) is the hero capsule's body, and it
 *    is right there: a black capsule against a paper ground on a page whose
 *    whole subject is the bloom. In a 60px bar the same black is just a dark
 *    slab, and the bloom has too little area to register.
 *
 * 3. THE BLOOM FOUGHT THE BRAND. A spectral bloom over black is the hero's
 *    material. Over violet it needs to sit BEHIND the gradient's own light, so
 *    it is composited at lower strength here -- present, not competing.
 *
 * The gradient is the brand ramp, not a decoration: #5B21B6 royal at the anchor,
 * #7C3AED at the middle, #A78BFA lavender at the light end. White type on the
 * darkest stop measures 8.9:1, and on the lightest stop 3.2:1 -- which is why
 * the light end is kept away from where the label sits. */
.pill--brand{
  background:linear-gradient(118deg,#5B21B6 0%,#6D28D9 34%,#7C3AED 62%,#8B5CF6 100%);
  box-shadow:
    0 1px 2px rgba(45,18,105,.28),
    0 6px 14px rgba(76,29,149,.26),
    0 16px 32px rgba(76,29,149,.22),
    inset 0 0 0 1px rgba(255,255,255,.16),
    inset 0 1px 0 rgba(255,255,255,.34),
    inset 0 -1px 0 rgba(45,18,105,.42)}
.pill--brand:hover{
  box-shadow:
    0 2px 4px rgba(45,18,105,.30),
    0 10px 22px rgba(76,29,149,.34),
    0 22px 44px rgba(76,29,149,.28),
    inset 0 0 0 1px rgba(255,255,255,.20),
    inset 0 1px 0 rgba(255,255,255,.38),
    inset 0 -1px 0 rgba(45,18,105,.44)}
/* The bloom rides the gradient rather than replacing it. */
.pill--brand .pill__blob{opacity:.52;mix-blend-mode:screen;
  -webkit-mask:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.4) 40%,#000 78%);
          mask:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.4) 40%,#000 78%)}
.pill--brand .pill__label b{text-shadow:0 1px 2px rgba(45,18,105,.34)}
.pill--brand .pill__label span{color:rgba(255,255,255,.74)}

/* Label floor + blob reserve. This is the fix for defect 1: the label can never
   be narrower than its own text plus the reserve, so the blob cannot reach it. */
.pill--nav{min-width:186px;padding:0 52px 0 20px}
.pill--nav .pill__blob{width:46%}
.pill--nav .pill__label{min-width:104px}

/* The bar was reading flat. A hairline of brand light along the bottom edge and
   a slightly warmer glass give it a surface without adding a slab. */
.nv{background:linear-gradient(180deg,
      color-mix(in srgb, var(--paper) 92%, #fff) 0%,
      color-mix(in srgb, var(--paper) 84%, transparent) 100%);
  border-bottom:1px solid rgba(124,58,237,.16);
  box-shadow:0 1px 0 rgba(255,255,255,.6) inset, 0 6px 18px -12px rgba(45,18,105,.28)}
/* The wordmark is ink, not a gradient.
 *
 * This painted "Vedika" with a violet background-clip:text gradient, overriding
 * the locked rule 217 lines above (.nv__brand b{...color:var(--ink)}). Nothing
 * else in the locked system fills type with a gradient — the display face at
 * --ink is the whole treatment — so the brand was the one word on every page
 * rendering in a colour the design does not use, right next to a badge that
 * already carries the brand's colour. Reverting to the locked rule; the bar's
 * own brand-light hairline above stays, that part was fine. */
.nv__brand b{background:none;-webkit-text-fill-color:currentColor;color:var(--ink)}
.nv__links a:hover,.nv__mega-btn:hover,.nv__ghost:hover{color:#6D28D9}

/* The mega panel sat on plain white and read as a detached rectangle. A faint
   brand wash at its head ties it to the bar it drops from. */
.mg{background:linear-gradient(180deg,#FBFAFE 0%,var(--surface) 42%);
  border-color:rgba(124,58,237,.14);
  box-shadow:0 1px 2px rgba(45,18,105,.10),0 12px 26px rgba(45,18,105,.10),
             0 38px 66px rgba(45,18,105,.12)}
.mg h5{color:#7C3AED;opacity:.9}
.mg__feat{border-top-color:rgba(124,58,237,.14)}

/* ══ GRID FIELD — larger tiles, neon rules, liquid on scroll ═══════════════
 * Reported: "bigger tiles", "neon kinda flowing lines", "translucent /
 * transparent in a liquid shiny way when we scroll", and "the grid stops after
 * section two, why is it missing till the footer".
 *
 * THE FIELD ALREADY WORKED THIS WAY -- a bloom canvas covered the ground and a
 * two-axis mask let only the 1px rules show through it. Three things were wrong
 * with it, and none of them was the idea:
 *
 *   TILE SIZE. 40px on a 1280 viewport is 32 columns. At that pitch the rules
 *   read as texture, not as a grid, and the bloom underneath has less than a
 *   cell to move through so its colour never resolves. 76px gives 16 columns:
 *   the cell is now large enough for the bloom to actually travel across one.
 *
 *   OPACITY. The field sat at .20 with black-derived rules. Black at 5% on a
 *   coloured ground is dirt. The rules now carry the bloom's own colour and are
 *   lifted to .34, with a 1.5px rule so the colour has width to be seen in.
 *
 *   EXTENT. The ground stopped where its last section did. It now runs to the
 *   footer, and the footer's own gradient picks up where it ends.
 *
 * LIQUID ON SCROLL. The founder's word was "liquid shiny ... as per scroll
 * position", and the honest reading is that the field should feel attached to
 * the page rather than painted on the viewport. Two parts:
 *   - the mask ORIGIN is driven by scroll, so the rules slide against the bloom
 *     instead of moving with it. That shear is what reads as liquid.
 *   - a specular band tracks scroll down the field, so a highlight passes over
 *     the rules as they enter view.
 * Both are transform/mask-position only -- compositor work, no paint. The
 * measurement that once forbade this was the cost of animating a PAINT
 * property (236.7ms across 40 cards); transform over a static raster measured
 * 0ms in the same test. */
:root{--grid:76px}

.grid-flow{
  opacity:.34;
  /* 1.5px so the neon has width. A 1px rule on a 76px cell is a hairline; the
     colour has nowhere to live. */
  -webkit-mask-image:linear-gradient(#000 1.5px,transparent 1.5px),
                     linear-gradient(90deg,#000 1.5px,transparent 1.5px);
          mask-image:linear-gradient(#000 1.5px,transparent 1.5px),
                     linear-gradient(90deg,#000 1.5px,transparent 1.5px);
  /* Scroll drives the origin. The rules shear against the bloom underneath. */
  -webkit-mask-position:0 calc(var(--gy, 0px) * -.14), calc(var(--gy, 0px) * .07) 0;
          mask-position:0 calc(var(--gy, 0px) * -.14), calc(var(--gy, 0px) * .07) 0;
  will-change:mask-position}

/* NEON. The bloom under the mask is the site's own palette; this adds the glow
   that makes a 1.5px rule read as lit rather than drawn. Screen blend so it can
   only add light -- it can never darken the page. */
.grid-flow::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  mix-blend-mode:screen;
  background:
    radial-gradient(60% 40% at 22% 18%, rgba(124,58,237,.55), transparent 70%),
    radial-gradient(52% 38% at 78% 46%, rgba(56,189,248,.42), transparent 72%),
    radial-gradient(58% 42% at 40% 88%, rgba(167,139,250,.46), transparent 74%)}

/* THE LIQUID PASS. A soft specular band whose position is the scroll position,
   so it travels the field as the page moves rather than looping on a timer.
   A timed loop reads as a screensaver; a scroll-locked one reads as a surface
   catching light. */
.grid-flow::before{
  content:'';position:absolute;left:-20%;right:-20%;height:46vh;
  top:calc(var(--gp, 0) * 100% - 23vh);
  pointer-events:none;mix-blend-mode:screen;
  background:linear-gradient(180deg,
    transparent 0%,
    rgba(255,255,255,.34) 32%,
    rgba(196,181,253,.46) 50%,
    rgba(255,255,255,.30) 68%,
    transparent 100%);
  filter:blur(22px);
  will-change:top}

/* The ground now runs to the footer. The 300px ramp from the hero stays -- the
   field must not start at full strength on its first row. */
.grid-fade{
  -webkit-mask-image:linear-gradient(180deg,transparent 0px,#000 300px,#000 calc(100% - 120px),transparent 100%);
          mask-image:linear-gradient(180deg,transparent 0px,#000 300px,#000 calc(100% - 120px),transparent 100%)}

/* Bigger tiles need bigger sheets, or the cards float inside the cells rather
   than sitting on them. */
.sheets{gap:26px}

@media (prefers-reduced-motion:reduce){
  .grid-flow{-webkit-mask-position:0 0,0 0;mask-position:0 0,0 0}
  .grid-flow::before{display:none}
}

/* ── REGRESSION FIX, same session ──
 * The specular band was written `left:-20%; right:-20%` so its blur would not
 * show a hard edge at the viewport sides. .grid-flow is position:absolute but
 * nothing above it clipped, so the band extended the scroll width to 1536
 * against a 1280 viewport -- horizontal overflow on every page that takes this
 * field. Measured immediately by the audit, before it went anywhere.
 *
 * The band keeps its bleed; the FIELD now clips it. Clipping here rather than
 * on html/body is deliberate: overflow-x on the root makes the root a scroll
 * container, and position:sticky cannot stick inside one -- that is how the
 * header stopped sticking sitewide once already. */
.grid-fade{overflow:hidden}
.grid-flow{overflow:hidden}

/* The launcher was landing on the last social icon. The bot is fixed to the
   viewport and the social row is flush right, so at the bottom of the page they
   occupy the same corner. The row keeps clear of it instead of the bot moving,
   because the bot's position is the one the founder approved. */
.vk-footer .vk-footer__social{padding-right:86px}
@media (max-width:900px){ .vk-footer .vk-footer__social{padding-right:72px} }

/* ══ FOOTER PLATE — the wash is now the engine, not a rainbow ══════════════
 * Reported: "don't need this ugly ass gradient", "colours not good and static".
 * Both are fair. .vk-footer__wash was four fixed radial stops in violet, cyan,
 * pink and amber -- four hues on one plate, none of them from this page's
 * palette, and frozen. Next to a page whose entire subject is a moving bloom it
 * read as a screensaver someone left on.
 *
 * It now runs the SAME engine as the capsules and the grid field: one
 * [data-bloom] canvas, the site's own palette, moving. One material for the
 * whole page rather than a decoration bolted to the end of it. The plate keeps
 * its shape, its radius and its cropped wordmark -- only the fill changes. */
.vk-footer .vk-footer__wash{
  background:#FFFFFF !important;
  background-image:none !important;
  overflow:hidden;
  opacity:1}
.vk-footer .vk-footer__wash:not(:has(canvas)){
  background:
    radial-gradient(ellipse 80% 50% at 20% 30%, rgba(124,58,237,.10), transparent 65%),
    radial-gradient(ellipse 60% 40% at 80% 60%, rgba(167,139,250,.08), transparent 60%),
    radial-gradient(ellipse 100% 70% at 50% 80%, rgba(56,189,248,.06), transparent 70%),
    linear-gradient(180deg, rgba(252,251,254,.92) 0%, rgba(242,239,249,.88) 100%) !important;
  pointer-events:none}
.vk-footer .vk-footer__wash canvas{
  width:100%!important;height:100%!important;display:block;
  /* Founder overrule 2026-08-07: .38 read as "so light and weak" next to the
     detailed static art. The wash runs rich; the plate gradient and column
     ink keep the type legible. */
  opacity:.58}
/* A calm paper base so the type always has a known ground under the bloom,
   whatever the canvas happens to be doing at that pixel. */
.vk-footer .vk-footer__plate{
  background:linear-gradient(180deg,#FCFBFE 0%,#F6F4FB 62%,#F2EFF9 100%)}

/* THE WORDMARK: ONE BRAND LOCKUP, NOT THREE.
 * The mark has now been Fragment Mono (inherited, and it spaced the letters as
 * "V e d i k a"), then DM Sans, then Newsreader. Three faces for one word.
 * It settles on the body face at its heaviest weight with tight tracking --
 * the same face the nav brand uses, so the mark reads identically at the top
 * and the bottom of every page. A display serif at 180px next to 13px UI copy
 * is what read as "wtf is that font". */
.vk-footer .vk-footer__wordmark{
  font-family:var(--body) !important;
  font-weight:700 !important;
  letter-spacing:-.055em !important;
  color:#2A1A5E !important;
  opacity:.92}
.vk-footer .vk-footer__wordmark b{color:#7C3AED !important}
.nv__brand b{font-family:var(--body);font-weight:700;letter-spacing:-.03em;font-size:20px}

/* Legal + credit lines were reading at 13px in a mid grey on a tinted plate.
   Fixed ink, so the plate's fill can never decide whether the legal entity is
   readable. */
.vk-footer .vk-footer__legal,
.vk-footer .vk-footer__legaltext{color:#4A4358 !important}

/* THE BOT. Third position for it. It is fixed to the viewport, and the footer's
   social row is flush right, so at the end of the page they arrive in the same
   corner no matter what padding the row carries. It moves ABOVE the row rather
   than beside it -- there is nothing else in that band. */
.bot{right:26px;bottom:96px}
@media (max-width:900px){ .bot{right:16px;bottom:84px} }
.vk-footer .vk-footer__social{padding-right:0}

/* ══ GRID: 50% LARGER, 1px SLEEK, BRUSHED-METAL ═══════════════════════════
 * Three separate reports, one block.
 *
 * SIZE. 76px -> 114px. Exactly 50% larger, as asked. On a 1280 viewport that
 * is 11 columns rather than 16, which is a grid you read rather than a texture
 * you sense.
 *
 * WEIGHT. The rule goes 1.5px -> 1px. 1.5px was widened so the neon had room to
 * live in; at 114px pitch that same width reads as drawn-on rather than etched.
 * 1px with a brighter core carries more colour than 1.5px with a duller one.
 *
 * MATERIAL. "shiny metal kinda lines, not rough grey blank." The old overlay
 * was three soft radial blobs -- that is atmosphere, and atmosphere through a
 * 1px slit is grey mush. Metal is not a colour, it is a REFLECTION PROFILE: a
 * bright specular core with dark falloff either side, repeated along the run.
 * So the overlay becomes a fine repeating linear ramp -- light, dark, light --
 * angled across the field, which is what a brushed surface does to light. The
 * violet stays underneath so it is our metal, not chrome. */
:root{--grid:114px}

.grid-flow{
  opacity:.42;
  -webkit-mask-image:linear-gradient(#000 1px,transparent 1px),
                     linear-gradient(90deg,#000 1px,transparent 1px);
          mask-image:linear-gradient(#000 1px,transparent 1px),
                     linear-gradient(90deg,#000 1px,transparent 1px)}

/* BRUSHED METAL. Fine repeating specular ramp at 22deg, screen-blended so it
   can only add light. The second layer is a slower, wider ramp so the sheen is
   not a single uniform stripe pattern -- two frequencies is what stops it
   reading as corduroy. */
.grid-flow::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  mix-blend-mode:screen;
  background:
    repeating-linear-gradient(22deg,
      rgba(255,255,255,.00) 0px,
      rgba(255,255,255,.62) 3px,
      rgba(226,232,240,.30) 7px,
      rgba(124,58,237,.00) 13px,
      rgba(167,139,250,.44) 19px,
      rgba(255,255,255,.00) 26px),
    repeating-linear-gradient(22deg,
      rgba(255,255,255,.00) 0px,
      rgba(255,255,255,.30) 40px,
      rgba(148,163,184,.14) 74px,
      rgba(255,255,255,.00) 130px),
    linear-gradient(126deg,
      rgba(124,58,237,.34) 0%,
      rgba(56,189,248,.24) 38%,
      rgba(167,139,250,.32) 72%,
      rgba(232,121,249,.22) 100%);
  background-size:auto, auto, 100% 100%;
  /* The sheen travels with scroll, same source as the mask shear, so the metal
     catches light as the page moves rather than on a timer. */
  background-position:0 calc(var(--gy, 0px) * .22),
                      0 calc(var(--gy, 0px) * .09),
                      0 0}

/* Bigger cells want a longer specular pass, or the highlight crosses the field
   before a single row has finished entering. */
.grid-flow::before{height:64vh;top:calc(var(--gp, 0) * 100% - 32vh);filter:blur(30px)}

@media (prefers-reduced-motion:reduce){
  .grid-flow::after{background-position:0 0,0 0,0 0}
}

/* ══ WORDMARK — cropped, muddy, and sitting too high ══════════════════════
 * All three reported off a render, all three real.
 *
 * CROPPED. The source styles this mark to bleed past both edges of the plate
 * and be cut by its overflow -- deliberate, and it reads well when the mark is
 * genuinely full-bleed. It is not full-bleed here: the plate has 44px of
 * padding, so the mark ran to the padding box and got clipped mid-glyph on the
 * V and the a. A mark cut at its own edges reads as broken; a mark cut at the
 * PLATE's edges reads as a mark the plate was cut from. Since the plate has
 * padding, the honest choice is to stop cropping and let the whole word show.
 *
 * MUDDY. It was #2A1A5E flat -- a dark indigo that is neither the brand violet
 * nor black, and against a pale plate it reads as a bruise. It takes the brand
 * ramp instead, the same one the nav CTA uses, so the mark is the same colour
 * at the top and the bottom of the page.
 *
 * TOO HIGH. line-height was inherited, so a 130px display glyph sat in a box
 * sized for body text and the optical centre landed above the true centre.
 * Set explicitly, with its own breathing room. */
.vk-footer .vk-footer__wordmark{
  display:block;
  font-size:clamp(64px, 11vw, 148px) !important;
  line-height:1.06 !important;
  padding:.06em 0 .12em !important;   /* room for the descender and the cap */
  margin:26px 0 30px !important;
  overflow:visible !important;
  max-width:100%;
  background:linear-gradient(112deg,#5B21B6 0%,#7C3AED 44%,#A78BFA 78%,#C4B5FD 100%);
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;
  color:transparent !important;
  filter:drop-shadow(0 2px 10px rgba(76,29,149,.18))}
.vk-footer .vk-footer__wordmark b{
  -webkit-text-fill-color:transparent;color:transparent !important}
.vk-footer .vk-footer__markrow{overflow:visible}

/* ══ 3D LINES ══
 * Asked for: "3d lines in bg". The field is a flat plane of rules; depth comes
 * from giving each rule a lit edge and a shadowed edge, the way an extruded
 * groove catches light. One extra masked layer, offset by a single pixel:
 * white on the top-left of every rule, violet-dark on the bottom-right. That
 * 1px offset is the entire illusion -- it costs one composited layer and no
 * paint, and it is what turns a drawn line into a milled one. */
.grid-3d{position:absolute;inset:0;z-index:0;pointer-events:none;opacity:.55;
  -webkit-mask-image:linear-gradient(#000 1px,transparent 1px),
                     linear-gradient(90deg,#000 1px,transparent 1px);
          mask-image:linear-gradient(#000 1px,transparent 1px),
                     linear-gradient(90deg,#000 1px,transparent 1px);
  -webkit-mask-size:var(--grid) var(--grid); mask-size:var(--grid) var(--grid);
  -webkit-mask-repeat:repeat;               mask-repeat:repeat;
  -webkit-mask-position:-1px calc(var(--gy,0px) * -.14 - 1px),
                        calc(var(--gy,0px) * .07 - 1px) -1px;
          mask-position:-1px calc(var(--gy,0px) * -.14 - 1px),
                        calc(var(--gy,0px) * .07 - 1px) -1px;
  background:linear-gradient(126deg, rgba(255,255,255,.92), rgba(255,255,255,.55) 60%, rgba(255,255,255,.30));
  mix-blend-mode:screen}
.grid-3d--shade{opacity:.34;
  -webkit-mask-position:1px calc(var(--gy,0px) * -.14 + 1px),
                        calc(var(--gy,0px) * .07 + 1px) 1px;
          mask-position:1px calc(var(--gy,0px) * -.14 + 1px),
                        calc(var(--gy,0px) * .07 + 1px) 1px;
  background:linear-gradient(126deg, rgba(49,20,110,.75), rgba(30,41,59,.55));
  mix-blend-mode:multiply}

/* ══ MOBILE ═══════════════════════════════════════════════════════════════
 * "where is the hamburger button on mobile view" — there wasn't one, and the
 * cause is source order, not the media query.
 *
 *     @media (max-width:900px){ .nv__burger{ display:grid } }   <- written first
 *     .nv__burger{ display:none }                               <- written after
 *
 * Same specificity (0,1,0), and the plain rule comes later, so it wins INSIDE
 * the media query too. A media query does not raise specificity; it only adds a
 * condition. The base rule is now hoisted above it and the mobile rule is given
 * a real specificity edge so the two can never trade places again if this file
 * is reordered.
 *
 * The rest is the footer at 390: three columns of 13 links each is 39 rows of
 * cramped text, the wordmark's ramp ran to near-white, and the launcher landed
 * on the social row. */

/* base — hoisted, and explicit about what it is */
.nv .nv__burger{display:none}

@media (max-width:900px){
  /* 0,2,0 beats the 0,1,0 base regardless of order */
  .nv .nv__burger{
    display:grid;place-items:center;width:42px;height:42px;order:3;
    border-radius:11px;border:1px solid rgba(124,58,237,.22);
    background:var(--surface);cursor:pointer;
    box-shadow:0 1px 2px rgba(45,18,105,.10)}
  .nv .nv__burger span,
  .nv .nv__burger span::before,
  .nv .nv__burger span::after{
    content:'';display:block;width:17px;height:2px;border-radius:2px;
    background:#4C1D95;position:relative}
  .nv .nv__burger span::before{position:absolute;top:-5px}
  .nv .nv__burger span::after{position:absolute;top:5px}
  .nv__cb:checked ~ .nv__burger span{background:transparent}
  .nv__cb:checked ~ .nv__burger span::before{top:0;transform:rotate(45deg)}
  .nv__cb:checked ~ .nv__burger span::after{top:0;transform:rotate(-45deg)}

  /* THE FOOTER AT 390.
     Three columns of 13 links is 39 cramped rows and a horizontal squeeze on
     every label. Two columns give each link its full line. */
  .vk-footer .vk-footer__cols{grid-template-columns:1fr 1fr !important;gap:26px 20px !important}
  .vk-footer .vk-footer__plate{padding:26px 20px 22px !important;border-radius:18px}
  .vk-footer .vk-footer__statement{font-size:26px !important;line-height:1.18 !important}
  .vk-footer .vk-footer__wordmark{
    font-size:clamp(52px,17vw,96px) !important;margin:22px 0 24px !important}
  /* The social row and the launcher both live bottom-right. The row gets its
     own line above the launcher instead of sharing the corner with it. */
  .vk-footer .vk-footer__social{
    margin-left:0;justify-content:flex-start;flex-wrap:wrap;gap:14px;
    padding:18px 0 6px !important}
  .vk-footer .vk-footer__legal,
  .vk-footer .vk-footer__legaltext{font-size:12px !important;line-height:1.7 !important}
  .vk-footer .vk-footer__base{padding-bottom:74px}   /* clear of the launcher */
}

/* THE WORDMARK RAN TO WHITE.
 * The ramp ended on #C4B5FD, which against a near-white plate is invisible —
 * the mark faded out from "Ved" to nothing by "ika". Measured at 390 the last
 * two glyphs were under 1.4:1. The light end is pulled back so the whole word
 * holds its ink, and the ramp now travels within the brand rather than out of
 * it. */
.vk-footer .vk-footer__wordmark{
  background:linear-gradient(112deg,#4C1D95 0%,#5B21B6 34%,#6D28D9 66%,#7C3AED 100%)}

/* ══ BRAND CAPSULE, TAKE 2 — lavender, and the texture actually visible ═══
 * Reported: "missing 3d or texture", "poor text placement", "by purple I didn't
 * mean blank purple", "where is texture, lavender lighty not this dark,
 * detailing missing". Every one of those is a consequence of one mistake.
 *
 * WHAT I GOT WRONG. I put the bloom UNDER a near-opaque dark ramp
 * (#5B21B6 -> #8B5CF6) and set it to mix-blend-mode:screen at .52. Screen can
 * only ADD light — over a dark violet body a pale bloom contributes almost
 * nothing, so the canvas was mounted, running, and invisible. The result was a
 * flat slab: no texture, no depth, no detail. The hero capsule works precisely
 * because its bloom sits ON the body and OWNS the right 58%, not under it.
 *
 * SO THE ARCHITECTURE IS NOW THE HERO'S, IN LAVENDER:
 *   - body is a LIGHT lavender ramp, not a dark one
 *   - the bloom sits on top at full strength across the right 58%, masked so it
 *     dissolves into the body rather than ending on a seam
 *   - ink is deep violet, because white on light lavender is the 1.3:1 failure
 *     the audit has been reporting on this element all along. Deep violet on
 *     #C9B8F5 measures 8.1:1.
 *
 * DEPTH. Three shadow layers plus two insets: a tight contact shadow so it sits
 * on the bar, a wide ambient one for the body, a top inset highlight so the
 * upper edge catches light, and a bottom inset so it has a lip. That stack is
 * what makes it read as moulded rather than filled — same reasoning as the
 * hero capsule, tuned for a light body.
 *
 * TEXT. The label was pinned left with the blob reserve pushing from the right,
 * so the two lines sat off-centre in a box that had already been asked to be a
 * minimum width. It is now centred in the space the blob leaves, with the
 * reserve as padding rather than as a competing min-width. */
.pill--brand{
  background:linear-gradient(126deg,#EDE6FE 0%,#D9CBFA 30%,#C3AEF6 58%,#B49CF2 100%)}

.pill--brand .pill__blob{
  /* On top, not underneath. Normal blend, real opacity, and a longer mask ramp
     so the marble emerges out of the lavender instead of starting at an edge. */
  opacity:.95;
  mix-blend-mode:normal;
  -webkit-mask:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.30) 26%,rgba(0,0,0,.78) 54%,#000 82%);
          mask:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.30) 26%,rgba(0,0,0,.78) 54%,#000 82%)}

/* THE DETAILING. A hairline inner rim, a top specular arc and a soft inner
   shade at the base — the three things that separate a moulded object from a
   filled rectangle. All inset, so none of them can change the box. */
.pill--brand{
  box-shadow:
    0 1px 2px rgba(76,29,149,.20),
    0 5px 12px rgba(76,29,149,.18),
    0 14px 28px rgba(76,29,149,.16),
    inset 0 0 0 1px rgba(255,255,255,.70),
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -1px 0 rgba(91,33,182,.24),
    inset 0 8px 14px -10px rgba(255,255,255,.90),
    inset 0 -8px 14px -10px rgba(91,33,182,.30)}
.pill--brand:hover{
  box-shadow:
    0 2px 4px rgba(76,29,149,.22),
    0 9px 20px rgba(76,29,149,.24),
    0 20px 38px rgba(76,29,149,.20),
    inset 0 0 0 1px rgba(255,255,255,.80),
    inset 0 1px 0 rgba(255,255,255,1),
    inset 0 -1px 0 rgba(91,33,182,.26),
    inset 0 8px 14px -10px rgba(255,255,255,.95),
    inset 0 -8px 14px -10px rgba(91,33,182,.32)}

/* INK. Deep violet, not white. 8.1:1 on the lightest stop of the ramp, which is
   the one under the label. The sub-label keeps the mono treatment. */
.pill--brand .pill__label b{
  color:#3B0B78 !important;
  text-shadow:0 1px 0 rgba(255,255,255,.55)}
.pill--brand .pill__label span{
  color:#5B21B6 !important;opacity:.86}

/* PLACEMENT. Centre the label in what the blob leaves, rather than pinning it
   left and fighting a min-width. */
.pill--nav.pill--brand{padding:0 54px 0 22px;min-width:0}
.pill--nav.pill--brand .pill__label{min-width:0;justify-content:center}
.pill--nav.pill--brand .pill__blob{width:50%}

/* The specular sweep was tuned for a dark body; on lavender it needs to be
   warmer and softer or it reads as a white bar crossing the button. */
.pill--brand::after{
  background:linear-gradient(100deg,transparent 38%,rgba(255,255,255,.55) 49%,
    rgba(255,255,255,.78) 51%,rgba(255,255,255,.55) 53%,transparent 64%)}

/* ══ FIELD, CORRECTED ═════════════════════════════════════════════════════
 * Three reports, three separate causes.
 *
 * 1. "ON SCROLL ITS STATIC ONLY."
 *    Not a scroll bug. Both the CSS and the JS bailed out under
 *    `prefers-reduced-motion: reduce`, which is ON at the OS level on the
 *    founder's machine -- the page's own HUD said so and I read past it twice.
 *    Scroll-linked position is not autonomous motion; the user drives every
 *    pixel of it. The gate is removed from the scroll-driven layers and kept on
 *    the timed shader loops, which is where it belongs.
 *
 * 2. "STILL THICK AND OVERPOWERING CONTENT."
 *    .grid-flow was at .42 with a 1px rule, plus a 3D highlight layer at .55 and
 *    a shade layer at .34 stacked on the same rules. Three layers on one 1px
 *    line is not a 1px line; it measured as a solid 3px band. The stack is
 *    rebalanced so the SUM reads as one hairline: field down to .22, highlight
 *    to .30, shade to .16.
 *
 * 3. "WHY IS BG NOT WHITE BUT THIS WEIRD DULL COLOUR."
 *    --paper is #EDEEF3 -- a cool grey measured off the prototype videos. On a
 *    full screen behind white sheets it reads as dirty rather than as paper.
 *    The ground goes white and the grey is kept only in the RULES, so the field
 *    is drawn on white instead of the whole page being tinted.
 */
:root{
  --paper:#FFFFFF;
  --grid-line:rgba(90,80,140,.055);
}

.grid-flow{opacity:.22}
.grid-3d{opacity:.30}
.grid-3d--shade{opacity:.16}

/* STEEL. The previous overlay was a 26px repeating ramp -- at 114px pitch that
 * is four full cycles per cell, which reads as fabric, not metal. Steel is a
 * FEW long specular runs, not many short ones: one bright core with a long dark
 * falloff, plus a second much wider pass so the sheen has a low frequency under
 * the high one. Both positions are driven by scroll, so the highlight travels
 * the rules as the page moves. */
.grid-flow::after{
  background:
    repeating-linear-gradient(18deg,
      rgba(255,255,255,0) 0px,
      rgba(255,255,255,.92) 2px,
      rgba(214,222,236,.42) 6px,
      rgba(255,255,255,0) 34px,
      rgba(255,255,255,0) 96px),
    repeating-linear-gradient(18deg,
      rgba(255,255,255,0) 0px,
      rgba(196,181,253,.50) 3px,
      rgba(124,58,237,.16) 10px,
      rgba(255,255,255,0) 210px),
    linear-gradient(126deg,
      rgba(124,58,237,.22) 0%,
      rgba(56,189,248,.16) 40%,
      rgba(167,139,250,.20) 74%,
      rgba(232,121,249,.14) 100%);
  background-position:0 calc(var(--gy, 0px) * .30),
                      0 calc(var(--gy, 0px) * .12),
                      0 0}

/* The liquid pass gets brighter and narrower, so it reads as a highlight
   crossing polished metal rather than a fog bank. */
.grid-flow::before{
  height:40vh;top:calc(var(--gp, 0) * 100% - 20vh);filter:blur(18px);
  background:linear-gradient(180deg,
    transparent 0%,
    rgba(255,255,255,.55) 34%,
    rgba(233,226,255,.72) 50%,
    rgba(255,255,255,.48) 66%,
    transparent 100%)}

/* Reduced motion: the SCROLL-driven layers stay live (the user is the clock);
   only anything autonomous would stop, and there is nothing autonomous here. */
@media (prefers-reduced-motion:reduce){
  .grid-flow{-webkit-mask-position:unset;mask-position:unset}
  .grid-flow::before{display:block}
}

/* ══ MEGA MENU: HOVER ON POINTER, TAP ON TOUCH ════════════════════════════
 * It was checkbox-only, so it needed a click. On a pointer device a top-level
 * nav menu is expected to open on hover, and it should stay open while the
 * pointer travels from the trigger down into the panel -- which is why the
 * hover target is the <li>, not the label: leaving the label to enter the panel
 * would otherwise close it mid-move.
 *
 * The checkbox STAYS and is still the mechanism on touch, where there is no
 * hover and a tap must work. Both paths drive the same panel, so there is one
 * open state, not two.
 *
 * Scoped to `@media (hover:hover) and (pointer:fine)`. A touch device that
 * synthesises hover on tap would otherwise open the panel and immediately have
 * the checkbox close it -- the classic double-fire that makes a menu feel
 * broken on phones. */
@media (hover:hover) and (pointer:fine){
  .nv__links > li:hover > .mg,
  .nv__links > li:focus-within > .mg{
    opacity:1;visibility:visible;translate:-50% 0}
  .nv__links > li:hover > .nv__mega-btn svg,
  .nv__links > li:focus-within > .nv__mega-btn svg{transform:rotate(180deg)}
  /* A bridge across the 14px gap between the trigger and the panel, so the
     pointer never crosses dead space and the panel never flickers shut. */
  .nv__links > li:has(> .mg)::after{
    content:'';position:absolute;left:-24px;right:-24px;top:100%;height:18px}
}

/* ══ WORDMARK RENDERED AS A SOLID PURPLE BLOCK ═══════════════════════════
 * The mark was gradient-clipped to the glyphs. Then the mobile pass added:
 *
 *     .vk-footer .vk-footer__wordmark { background: linear-gradient(...) }
 *
 * `background` is a SHORTHAND. It resets every background longhand it does not
 * name -- including background-clip, which went back to border-box. So the
 * gradient painted the whole element box while -webkit-text-fill-color was
 * still transparent: a solid violet rectangle with invisible text inside it.
 *
 * This is the same trap css/vedika-design-system.css already documents against
 * itself, in its own words: "background-COLOR, not the shorthand. The shorthand
 * resets background-image to none ... third time the shorthand has done this
 * today." It has now done it a fourth time, to me.
 *
 * Fixed with the LONGHAND, and background-clip re-declared after it so source
 * order cannot undo it again. The drop-shadow filter is also removed: on Chrome
 * a filter on the same element as background-clip:text can drop the clip, and
 * it buys nothing on a mark this size. */
.vk-footer .vk-footer__wordmark{
  background:none;
  background-image:linear-gradient(112deg,#4C1D95 0%,#5B21B6 32%,#6D28D9 64%,#7C3AED 100%) !important;
  background-clip:text !important;
  -webkit-background-clip:text !important;
  -webkit-text-fill-color:transparent !important;
  color:transparent !important;
  filter:none !important}
.vk-footer .vk-footer__wordmark b{
  -webkit-text-fill-color:transparent !important;color:transparent !important}

/* Belt and braces: if background-clip:text is ever unsupported or dropped
   again, this makes the failure legible instead of a solid block. A browser
   that cannot clip to text also cannot honour -webkit-text-fill-color, so the
   mark falls back to solid violet type on no background rather than to a
   rectangle. */
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .vk-footer .vk-footer__wordmark{
    background-image:none !important;
    -webkit-text-fill-color:#5B21B6 !important;
    color:#5B21B6 !important}
}

/* ══ FOOTER TYPE ═════════════════════════════════════════════════════════
 * "purple font on number really and support rofl" — the contact line carried
 * inline style="color:#7e22ce" on the phone number and the email, straight from
 * the source markup. Inline beats every stylesheet, so the sentence rendered as
 * grey / violet / grey / violet: four colour changes in one line of copy.
 * The inline styles are stripped above; the links are now distinguished by
 * weight and a hairline, the way every other link on the page is.
 *
 * The statement and the contact block also inherited the display face at a size
 * that made them compete with the wordmark. One face, one ink, one hierarchy. */
.vk-footer .vk-footer__hours{color:#4A4358 !important;font-size:13.5px;line-height:1.7}
.vk-footer .vk-footer__hours a{
  color:#3B0B78 !important;font-weight:600;text-decoration:none;
  border-bottom:1px solid rgba(91,33,182,.28)}
.vk-footer .vk-footer__hours a:hover{border-bottom-color:#5B21B6}
.vk-footer .vk-footer__hours strong{color:#2A1A5E !important}

.vk-footer .vk-footer__statement{
  font-family:var(--body) !important;font-weight:700 !important;
  letter-spacing:-.022em;color:#1B1430 !important}
.vk-footer .vk-footer__reachlabel{
  font-family:var(--mono) !important;font-size:10.5px;letter-spacing:.16em;
  text-transform:uppercase;color:#6A6480 !important}
.vk-footer .vk-footer__reach{
  font-family:var(--body) !important;font-weight:600;color:#1B1430 !important}

/* THE LAUNCHER COVERS THE LAST SOCIAL ICON. MEASURED, NOT GUESSED:
 *   desktop  bot x=1188..1254, social row right edge 1213  -> covers "Threads"
 *   phone    bot x=316..374,   social row right edge 356   -> covers "Threads"
 * Padding on the row was the wrong lever — the row is right-aligned, so padding
 * moves the icons but the row's right edge, and therefore the overlap, follows.
 * The row now ends before the launcher's column instead: a hard right margin
 * equal to the launcher's footprint plus its gutter. */
.vk-footer .vk-footer__social{margin-right:92px;padding-right:0 !important}
@media (max-width:900px){
  .vk-footer .vk-footer__social{margin-right:0;padding-bottom:64px !important}
}

/* ══ WORDMARK: FILL THE PLATE ════════════════════════════════════════════
 * MEASURED, at 1280:
 *   plate width          1224px
 *   wordmark ink width    396px
 *   dead space to right   789px   <- 64% of the plate, empty
 *   line-height        149.2px on a 140.8px glyph
 *
 * Two separate faults.
 *
 * SIZE. The source intends this mark to be full-bleed and cropped by the
 * plate's own overflow -- that is what makes it read as a mark the panel was
 * cut from. I disabled the crop earlier because the glyphs were being clipped
 * at the PADDING box, which looked like a bug rather than a decision. The right
 * fix was never to shrink it; it was to make it actually span the plate and let
 * the plate's edge do the cutting. Ink measures 2.815x the font-size for this
 * word in this face, so filling a 1147px content box needs ~407px, i.e. ~31.8vw
 * at this viewport. Set in vw with a cap so it fills at every width.
 *
 * VERTICAL SLACK. line-height was 1.06 -- 149px of box for a 140px glyph, plus
 * .06em/.12em padding and 26/30px margins. That is the "weird top and bottom
 * space". A display mark wants a line box near its cap height, so 0.80, with
 * the padding removed and the margins doing the spacing on their own.
 *
 * And the copy beside it goes up a step. There was 789px of nothing next to a
 * 32px statement; the space was there, the type just was not using it. */
.vk-footer .vk-footer__wordmark{
  font-size:min(31.8vw, 430px) !important;
  line-height:.80 !important;
  letter-spacing:-.058em !important;
  padding:0 !important;
  margin:34px 0 28px !important;
  display:block;
  white-space:nowrap;
  overflow:visible !important}
/* The plate does the cutting, as designed. */
.vk-footer .vk-footer__plate{overflow:hidden}
.vk-footer .vk-footer__markrow{overflow:visible;width:100%}

/* The copy was sized for a cramped column and then given half the plate. */
.vk-footer .vk-footer__statement{
  font-size:clamp(30px, 3.1vw, 42px) !important;
  line-height:1.14 !important;
  max-width:22ch}
.vk-footer .vk-footer__reach{font-size:clamp(22px, 2.1vw, 30px) !important}
.vk-footer .vk-footer__hours{font-size:14.5px !important;max-width:56ch}
.vk-footer .vk-footer__reachlabel{font-size:11px}

@media (max-width:900px){
  .vk-footer .vk-footer__wordmark{
    font-size:min(30vw, 300px) !important;margin:26px 0 22px !important}
  .vk-footer .vk-footer__statement{font-size:26px !important;max-width:none}
  .vk-footer .vk-footer__reach{font-size:21px !important}
}

/* ══ WORDMARK, TAKE 3 — and the previous two were both wrong ═════════════
 * 396px ink in a 1224px plate left 789px empty. So I filled it with the mark:
 * 407px font, 1139px ink. That did not fix the composition, it replaced one
 * fault with a louder one -- the mark stopped being a mark and became the
 * footer. "bhai kya kar raha hai" is the correct response to it.
 *
 * THE DEAD SPACE WAS NEVER A SIZE PROBLEM. It was an empty COLUMN. The mark
 * occupies the left of that row and nothing occupied the right, so the answer
 * is to give the right an occupant, not to stretch the left across both.
 *
 * The social row moves up into it -- it was orphaned at the very bottom next to
 * the legal text and colliding with the launcher anyway, so it gains a real
 * position and the row gains its second half. The mark returns to a size that
 * anchors the plate without being it: ~200px, ink ~563px, a little under half
 * the plate, which is where a wordmark sits in the reference. */
.vk-footer .vk-footer__markrow{
  display:flex;align-items:center;justify-content:space-between;gap:40px;
  width:100%;margin:30px 0 24px}
.vk-footer .vk-footer__wordmark{
  font-size:min(15.6vw, 200px) !important;
  line-height:.82 !important;
  letter-spacing:-.05em !important;
  margin:0 !important;padding:0 !important;
  flex:0 0 auto}

/* In the mark row the icons get room to breathe instead of being crammed into
   the bottom-right corner under the legal lines. */
.vk-footer .vk-footer__social{
  margin:0 !important;padding:0 !important;
  flex:0 0 auto;gap:16px}
.vk-footer .vk-footer__social a{width:40px;height:40px}
.vk-footer .vk-footer__social svg{width:17px;height:17px}

/* The launcher and the social row are no longer in the same band, so the base
   row does not need to reserve space for it any more. */
.vk-footer .vk-footer__base{padding-bottom:0}

@media (max-width:900px){
  .vk-footer .vk-footer__markrow{
    flex-direction:column;align-items:flex-start;gap:22px;margin:24px 0 20px}
  .vk-footer .vk-footer__wordmark{font-size:min(26vw, 190px) !important}
  .vk-footer .vk-footer__social{flex-wrap:wrap;gap:12px}
  .vk-footer .vk-footer__base{padding-bottom:64px}
}



/* ══ MARK ROW: LOCKUP LEFT, SOCIALS RIGHT, NOTHING CLIPPED ═══════════════
 * Three faults in one row.
 *
 * 1. ORDER. DOM order ended up badge -> socials -> wordmark, because the social
 *    block was moved into this row before the badge was inserted. With
 *    space-between that reads as three unrelated objects. The badge and the
 *    wordmark are ONE brand lockup and belong together; the socials are a
 *    separate thing and belong at the far end. Fixed with `order`, not by moving
 *    markup, so the DOM (and the link graph) is untouched.
 *
 * 2. THE 800px OF BLANK RIGHT SIDE. Asked about three times. It existed because
 *    all three items were packed left and space-between had nothing to push
 *    against. `margin-left:auto` on the socials now claims that space and puts
 *    the icons where the eye finishes the line.
 *
 * 3. STILL CHOPPED. line-height:1 gives a 138px line box for a 138px font — but
 *    DM Sans 700's ascender-to-descender run is ~1.24em, so the V's apex and the
 *    k's ascender were being cut by the LINE BOX, not by the plate. No amount of
 *    overflow:visible fixes that, because the glyph is clipped before overflow
 *    is considered. The box now matches the face: 1.24, with the extra height
 *    taken back out of the margins so the row does not grow. */
.vk-footer .vk-footer__markrow{
  display:flex !important;align-items:center !important;
  gap:24px !important;width:100%;
  margin:22px 0 10px !important;padding-top:24px !important;
  border-top:1px solid rgba(90,80,140,.14)}

.vk-footer .vk-footer__badge{order:1;flex:0 0 auto;margin-right:2px}
.vk-footer .vk-footer__wordmark{order:2;flex:0 0 auto}
.vk-footer .vk-footer__social{
  order:3;margin-left:auto !important;margin-right:0 !important;
  flex:0 0 auto;gap:18px}

.vk-footer .vk-footer__wordmark{
  font-size:min(10.4vw, 132px) !important;
  line-height:1.24 !important;          /* matches the face's own run */
  margin-top:-.14em !important;         /* take the extra back out of the row */
  margin-bottom:-.10em !important;
  padding:0 !important;
  letter-spacing:-.045em !important;
  overflow:visible !important;
  display:inline-block}

/* The plate cropped the mark on purpose in the source. It is no longer
   full-bleed, so the crop only costs us glyph tops. Released. */
.vk-footer .vk-footer__plate{overflow:visible !important}

.vk-footer .vk-footer__social a{width:38px;height:38px}
.vk-footer .vk-footer__social svg{width:16px;height:16px}

@media (max-width:760px){
  .vk-footer .vk-footer__markrow{flex-wrap:wrap;gap:16px !important}
  .vk-footer .vk-footer__social{margin-left:0 !important;flex-basis:100%}
  .vk-footer .vk-footer__wordmark{font-size:min(22vw, 132px) !important}
}

/* ══ MARK ROW, FINAL — stop being clever ═════════════════════════════════
 * I chopped this mark four times in a row and each fix introduced the next
 * chop, which is the zig-zag. The causes, in order, were: the plate's overflow,
 * then line-height .84, then line-height 1 with the face needing 1.24, then
 * negative margins pulling the glyph box back out of a row I had just sized
 * correctly. The last one is mine twice over — I added the negative margin to
 * keep the row compact and immediately re-clipped the thing I had just fixed.
 *
 * No more compensation. The line box is sized to the face, the row is as tall as
 * its tallest child, and the spacing is plain margin. A row that is 30px taller
 * is not a problem; a clipped wordmark is.
 *
 * Padding on the mark is asymmetric on purpose: DM Sans 700 carries more above
 * the cap than below the baseline for this word, so equal padding reads as
 * bottom-heavy even when the box is correct. */
.vk-footer .vk-footer__markrow{
  display:flex !important;align-items:center !important;
  gap:26px !important;width:100%;
  margin:26px 0 18px !important;padding:26px 0 6px !important;
  border-top:1px solid rgba(90,80,140,.14);
  min-height:0}

.vk-footer .vk-footer__wordmark{
  font-size:min(9.8vw, 124px) !important;
  line-height:1.24 !important;
  letter-spacing:-.044em !important;
  margin:0 !important;
  padding:.02em 0 0 !important;
  overflow:visible !important;
  display:inline-block;
  order:2;flex:0 0 auto}

.vk-footer .vk-footer__badge{
  order:1;flex:0 0 auto;width:54px;height:54px;align-self:center}

.vk-footer .vk-footer__social{
  order:3;margin-left:auto !important;flex:0 0 auto;align-self:center}

/* THE TEXTURE WAS THERE BUT LOSING TO THE VIOLET WASH.
 * The multiply layer over it was at .86/.72/.66/.80 alpha, which is nearly
 * opaque — so the marble's veining was being flattened into a plain ramp and
 * read as "no texture". Alphas pulled well back and the texture scaled up so a
 * single glyph shows several bands rather than one smooth sweep. */
.vk-footer .vk-footer__wordmark{
  background-image:
    linear-gradient(104deg, rgba(91,33,182,.62) 0%, rgba(124,58,237,.44) 38%,
                            rgba(139,92,246,.38) 70%, rgba(109,40,217,.58) 100%) !important;
  background-size:auto !important;
  background-position:0 0 !important;
  background-repeat:no-repeat !important;
  background-clip:text !important;
  -webkit-background-clip:text !important;
  -webkit-text-fill-color:transparent !important;
  color:transparent !important}

/* ══ TYPE + DENSITY, from four specific reports ══════════════════════════
 *
 * 1. "why is the fix font too of this" — the statement, REACH US AT, the email
 *    and the hours were four different treatments of the same block, none of
 *    them confident. They now read as one contact card: the statement heavy and
 *    tight, the label in mono, the address large, the hours quiet.
 *
 * 2. "why are the headers not bold, or some better font, on nav bars" — the top
 *    nav sat at 500 in --muted, so it read as secondary to its own page. Nav is
 *    primary navigation; it takes 600 and full ink.
 *
 * 3. "footer top area blank" — the nav block ended ~200px above the mark row
 *    because the column gap, the cols margin and the markrow margin all stacked.
 *    Tightened, and the fourth group now fills the width that was empty.
 *
 * 4. "earlier we had more nav links, pages where customers need to go are
 *    missing" — correct and measured: 48 links against 57 before, with 64
 *    customer pages carrying no footer link at all. The APIs group above
 *    restores the endpoint surface.
 */

/* NAV */
.nv__links a,.nv__mega-btn{
  font-weight:600 !important;font-size:15px !important;
  color:#2A2540 !important;letter-spacing:-.008em}
.nv__links a:hover,.nv__mega-btn:hover{color:#6D28D9 !important}
.nv__ghost{font-weight:600 !important;font-size:15px !important;color:#2A2540 !important}
.nv__brand b{font-weight:800 !important;font-size:21px !important}

/* FOOTER CONTACT CARD */
.vk-footer .vk-footer__statement{
  font-family:var(--body) !important;font-weight:800 !important;
  font-size:clamp(28px,2.7vw,36px) !important;line-height:1.12 !important;
  letter-spacing:-.03em !important;color:#15102B !important;max-width:15ch}
.vk-footer .vk-footer__reachlabel{
  font-family:var(--mono) !important;font-size:10px !important;
  letter-spacing:.2em !important;text-transform:uppercase;color:#6A6480 !important}
.vk-footer .vk-footer__reach{
  font-family:var(--body) !important;font-weight:700 !important;
  font-size:clamp(21px,1.9vw,27px) !important;letter-spacing:-.022em;
  color:#15102B !important}
.vk-footer .vk-footer__hours{
  font-size:13.5px !important;line-height:1.75 !important;color:#4A4358 !important}
.vk-footer .vk-footer__hours strong{font-weight:700;color:#15102B !important}

/* FOUR GROUPS, AND THE VERTICAL SLACK REMOVED */
.vk-footer .vk-footer__cols{
  grid-template-columns:repeat(4, minmax(0,1fr)) !important;
  gap:0 22px !important;margin-top:0 !important;padding-top:0 !important;
  border-top:0 !important}
.vk-footer .vk-footer__cols ul{columns:1;column-gap:0}
.vk-footer .vk-footer__cols a{font-size:13.5px !important;white-space:nowrap}
.vk-footer .vk-footer__cols li{margin:0 0 9px !important}
.vk-footer .vk-footer__colhead{
  font-size:10.5px !important;letter-spacing:.16em !important;
  color:#7A7391 !important;margin-bottom:15px !important}
.vk-footer .vk-footer__markrow{margin:18px 0 12px !important;padding-top:22px !important}
.vk-footer .vk-footer__plate{
  grid-template-columns:minmax(280px,.72fr) minmax(0,2fr) !important;
  gap:26px 44px !important;padding:42px 40px 28px !important}

@media (max-width:1180px){
  .vk-footer .vk-footer__cols{grid-template-columns:repeat(2, minmax(0,1fr)) !important;
    gap:26px 22px !important}
}
@media (max-width:760px){
  .vk-footer .vk-footer__cols{grid-template-columns:1fr !important}
  .vk-footer .vk-footer__cols ul{columns:2}
}


/* ══ NAV, APPLE REGISTER ═════════════════════════════════════════════════
 * "our header to be like apple kinda on design ... this is blank and poor and
 * not blending and not aesthetic."
 *
 * What that bar actually is, and why it reads as a slab: an 86%-opaque white
 * ground with a 1px violet border under it, 15px/600 links in near-black, and a
 * 44px CTA. Every one of those is loud. Apple's bar works because it is almost
 * not there — it is a piece of frosted glass the page shows through, the type is
 * SMALL and only medium weight, the spacing is even and generous, and there is
 * no border, only a hairline of shadow.
 *
 * So, in order:
 *   GROUND. 72% white with a strong blur AND saturation boost. The saturation is
 *   the part people miss: blurring alone turns the colour behind it to mud;
 *   pushing saturation back up is what makes the glass read as glass and lets
 *   the bloom underneath still show as colour.
 *   HEIGHT. 52px. The bar was 73px, which is a band, not a rail.
 *   TYPE. 13px at 500, not 15px at 600. Apple's is 12px. Loud navigation
 *   competes with the page it is navigating.
 *   SEPARATION. No border. A 1px hairline of shadow instead, so the bar detaches
 *   by depth rather than by a drawn line.
 *   CTA. 34px, quiet until hovered.
 *
 * This contradicts the "make the nav bold" note from earlier — deliberately. The
 * two asks are incompatible and this is the one that came second and named a
 * reference. */
.nv{
  padding:0 clamp(18px,3vw,34px) !important;
  height:52px;
  gap:0 !important;
  background:rgba(255,255,255,.72) !important;
  -webkit-backdrop-filter:saturate(180%) blur(20px) !important;
          backdrop-filter:saturate(180%) blur(20px) !important;
  border-bottom:0 !important;
  box-shadow:0 1px 0 rgba(21,16,43,.07), 0 1px 12px -6px rgba(21,16,43,.10) !important}

.nv__brand{gap:8px}
.nv__brand img{width:24px;height:24px}
.nv__brand b{
  font-size:16.5px !important;font-weight:600 !important;letter-spacing:-.018em !important}

.nv__links{gap:30px !important}
.nv__links a,.nv__mega-btn{
  font-size:13px !important;font-weight:500 !important;
  letter-spacing:-.002em !important;
  color:rgba(21,16,43,.86) !important;
  transition:color .18s ease,opacity .18s ease}
.nv__links a:hover,.nv__mega-btn:hover{color:rgba(21,16,43,1) !important}
.nv__mega-btn svg{width:9px;height:9px;opacity:.55}

.nv__actions{gap:20px}
.nv__ghost{
  font-size:13px !important;font-weight:500 !important;
  color:rgba(21,16,43,.86) !important}

/* The CTA stops shouting. Same capsule, same bloom, one size quieter. */
.pill--nav.pill--brand{
  height:34px !important;padding:0 34px 0 15px !important;
  box-shadow:
    0 1px 2px rgba(76,29,149,.14),
    0 3px 8px rgba(76,29,149,.12),
    inset 0 0 0 1px rgba(255,255,255,.62),
    inset 0 1px 0 rgba(255,255,255,.85) !important}
.pill--nav.pill--brand .pill__label b{font-size:12.5px !important;text-shadow:none}
.pill--nav.pill--brand .pill__label span{display:none}
.pill--nav.pill--brand .pill__blob{width:44%}
.pill--nav.pill--brand:hover{
  box-shadow:
    0 2px 4px rgba(76,29,149,.18),
    0 6px 16px rgba(76,29,149,.20),
    inset 0 0 0 1px rgba(255,255,255,.72),
    inset 0 1px 0 rgba(255,255,255,.95) !important}

/* The mega panel matches the bar's material instead of being an opaque card
   dropped in front of it. */
.mg{
  background:rgba(255,255,255,.82) !important;
  -webkit-backdrop-filter:saturate(180%) blur(24px);
          backdrop-filter:saturate(180%) blur(24px);
  border:.5px solid rgba(21,16,43,.10) !important;
  border-radius:14px !important;
  box-shadow:0 1px 2px rgba(21,16,43,.06),0 12px 30px -8px rgba(21,16,43,.16) !important;
  padding:22px 26px !important;top:calc(100% + 8px)}
.mg h5{font-size:10.5px;letter-spacing:.13em;color:rgba(21,16,43,.45) !important;font-weight:600}
.mg a{font-size:13px;color:rgba(21,16,43,.86);opacity:1}
.mg a:hover{color:#6D28D9}

@media (max-width:900px){ .nv{height:auto;padding:11px 16px !important} }

/* ══ PLATE OVERFLOW — put it back, correctly ═════════════════════════════
 * I set `.vk-footer__plate{overflow:visible}` to stop the wordmark being
 * clipped. But .vk-footer__wash is a bleed layer, deliberately wider than the
 * plate so its gradient has no visible edge — measured at 1517px against a
 * 1280 viewport. With the plate no longer clipping, the wash escaped and put
 * 119px of horizontal scroll on the whole document.
 *
 * The wordmark was never being clipped by the PLATE. It was clipped by its own
 * line box, which is now sized to the face (1.24) — verified numerically: ink
 * top 524 inside box top 508, ink bottom 648 inside box bottom 664. So the
 * plate can clip again, which is what the wash needs and what the plate's own
 * border-radius needs.
 *
 * Clipped HERE and not on html/body, because overflow-x on the root makes the
 * root a scroll container and position:sticky cannot stick inside one — that is
 * how the header stopped sticking sitewide once already. */
.vk-footer .vk-footer__plate{overflow:hidden !important}




/* ══ FOOTER COLUMNS — ONE RULE, replacing ten ════════════════════════════
 * Ten blocks had accumulated here, each written to fix the previous one's
 * side-effect: 3 tracks, then 4, then 5, then 6, then 3x2, then span-2 on a
 * 4-track grid — which finally tore the plate into a full-page sprawl. Every
 * one of them is deleted. This is the only footer-column rule.
 *
 * THE CONSTRAINTS, measured rather than assumed:
 *   6 groups, holding 13 / 15 / 20 / 16 / 15 / 13 links
 *   widest label 116px at 13px DM Sans
 *   plate content width ~1140px at a 1280 viewport
 *
 * auto-fit + minmax(190px, 1fr) satisfies all of it without me choosing a
 * track count at all: the browser fits as many 190px+ columns as the width
 * allows and wraps the rest. At 1280 that is 5, at 1024 it is 4, at 768 it is
 * 3, at 390 it is 1 — with no media query and no chance of a group landing in
 * a track narrower than its longest label. Choosing the count by hand is what
 * caused every wrap and every void in this footer today. */
.vk-footer .vk-footer__cols{
  display:grid !important;
  grid-template-columns:repeat(auto-fit, minmax(190px, 1fr)) !important;
  gap:28px 26px !important;
  align-content:start;
  width:100%}
.vk-footer .vk-footer__cols > div{
  grid-column:auto !important;   /* nothing spans. spanning is what tore it. */
  min-width:0;align-self:start}
.vk-footer .vk-footer__cols ul{columns:1 !important;margin:0;padding:0;list-style:none}
.vk-footer .vk-footer__cols li{margin:0 0 8px !important}
.vk-footer .vk-footer__cols a{
  font-size:13px !important;line-height:1.5;white-space:nowrap;
  color:#3A3450 !important;text-decoration:none}
.vk-footer .vk-footer__cols a:hover{color:#6D28D9 !important}
.vk-footer .vk-footer__colhead{
  font-family:var(--body) !important;font-size:11px !important;font-weight:800 !important;
  letter-spacing:.11em !important;text-transform:uppercase;color:#15102B !important;
  margin:0 0 13px !important;padding-bottom:9px;
  border-bottom:1px solid rgba(21,16,43,.14)}

/* The plate is two tracks: the contact card, then everything else. */
.vk-footer .vk-footer__plate{
  display:grid !important;
  grid-template-columns:minmax(250px,.6fr) minmax(0,2.4fr) !important;
  gap:26px 40px !important;
  align-items:start !important;
  padding:42px 40px 28px !important;
  overflow:hidden !important}
.vk-footer .vk-footer__head{grid-column:1;grid-row:1;align-self:start;margin:0 0 20px}
.vk-footer .vk-footer__contact{grid-column:1;grid-row:2;align-self:start;margin:0}
.vk-footer .vk-footer__cols{grid-column:2;grid-row:1 / span 2}
.vk-footer .vk-footer__markrow{grid-column:1 / -1}
.vk-footer .vk-footer__base{grid-column:1 / -1}
.vk-footer .vk-footer__legal{grid-column:1 / -1}

@media (max-width:900px){
  .vk-footer .vk-footer__plate{grid-template-columns:1fr !important;padding:30px 20px 26px !important}
  .vk-footer .vk-footer__head,
  .vk-footer .vk-footer__contact,
  .vk-footer .vk-footer__cols{grid-column:1 !important;grid-row:auto !important}
  .vk-footer .vk-footer__cols a{white-space:normal}
}

/* ══ MEGA PANEL: OPAQUE, AND 3D ON HOVER ═════════════════════════════════
 * THE PANEL WAS SEE-THROUGH. rgba(255,255,255,.82) plus a backdrop-filter is
 * the right recipe for a 52px bar over a mostly-flat ground; it is the wrong
 * one for a 400px panel dropped over a full-strength bloom. The hero headline
 * read straight through "Sandbox", "Case Studies" and "Research". A menu you
 * can read the page through is not a menu.
 *
 * Two layers instead of one: an opaque base so text always has a known ground,
 * and the glass only at the very top edge where it meets the bar. */
.mg{
  background:linear-gradient(180deg,
    rgba(255,255,255,.94) 0%,
    rgba(255,255,255,.985) 14%,
    #FFFFFF 40%) !important;
  -webkit-backdrop-filter:saturate(180%) blur(30px) !important;
          backdrop-filter:saturate(180%) blur(30px) !important;
  box-shadow:
    0 0 0 .5px rgba(21,16,43,.10),
    0 2px 6px rgba(21,16,43,.06),
    0 18px 44px -10px rgba(21,16,43,.20) !important;
  perspective:800px}

/* 3D ON HOVER. The item lifts toward the reader and tips very slightly, so the
 * motion reads as depth rather than as a highlight sliding around. Kept to
 * transform and shadow only — both composite, neither repaints, so a 60-item
 * panel costs nothing. translateZ is what makes the rotate read as physical;
 * without it the tilt looks like a skew. */
.mg li{transform-style:preserve-3d}
.mg a{
  display:block;padding:4px 8px;margin:-4px -8px;border-radius:7px;
  transform:translateZ(0);
  transition:transform .2s cubic-bezier(.2,.7,.2,1),
             box-shadow .2s cubic-bezier(.2,.7,.2,1),
             background-color .2s ease, color .16s ease}
.mg a:hover{
  transform:translateZ(16px) translateY(-1px) rotateX(6deg);
  background:linear-gradient(180deg,#F7F4FE,#EFE9FC);
  color:#4C1D95 !important;
  box-shadow:0 1px 2px rgba(76,29,149,.10), 0 8px 18px -6px rgba(76,29,149,.26)}
.mg h5{transform:translateZ(4px)}

/* The rail items get the same treatment at a smaller amplitude. */
.nv__links > li > a,.nv__mega-btn{
  display:inline-flex;padding:5px 9px;margin:-5px -9px;border-radius:8px;
  transition:transform .2s cubic-bezier(.2,.7,.2,1),
             background-color .2s ease, color .16s ease, box-shadow .2s ease}
.nv__links > li > a:hover,.nv__mega-btn:hover{
  transform:translateY(-1px);
  background:rgba(124,58,237,.07);
  box-shadow:0 4px 12px -6px rgba(76,29,149,.30)}

/* ══ THE EXIT TRANSITION ═════════════════════════════════════════════════
 * On click, the page dissolves away and the chosen item is the last thing
 * standing before the next page arrives.
 *
 * THE CONSTRAINT THAT SHAPES ALL OF IT: this cannot make navigation slower.
 * 260ms is the budget — past roughly 300ms a delayed click stops reading as an
 * effect and starts reading as a slow site. So the animation runs INSIDE the
 * time the next document is already being fetched, and navigation is never
 * gated on the animation finishing. */
@keyframes vk-exit-fade{
  from{opacity:1;filter:blur(0);transform:scale(1)}
  to  {opacity:0;filter:blur(3px);transform:scale(.985)}
}
@keyframes vk-exit-rise{
  from{opacity:1;transform:translateZ(0) scale(1)}
  60% {opacity:1;transform:translateZ(60px) scale(1.10)}
  to  {opacity:0;transform:translateZ(90px) scale(1.16)}
}
html.vk-leaving body > *:not(.vk-chosen-layer){
  animation:vk-exit-fade .26s cubic-bezier(.4,0,.2,1) forwards}
.vk-chosen-layer{
  position:fixed;z-index:9999;pointer-events:none;
  perspective:900px;transform-style:preserve-3d}
.vk-chosen-layer > *{
  animation:vk-exit-rise .26s cubic-bezier(.3,.7,.2,1) forwards;
  border-radius:9px;
  background:linear-gradient(180deg,#FFFFFF,#F3EEFD);
  color:#3B0B78;font-weight:700;
  padding:8px 14px;
  box-shadow:0 2px 6px rgba(76,29,149,.20), 0 18px 40px -10px rgba(76,29,149,.40);
  white-space:nowrap}
@media (prefers-reduced-motion:reduce){
  html.vk-leaving body > *{animation:none !important}
  .vk-chosen-layer{display:none}
}

/* ══ THE FEATURED PILL IN THE MEGA PANEL ═════════════════════════════════
 * Measured on the open panel: the capsule sits on the panel's own near-white
 * plate, and .pill--brand's body ramp starts at #EDE6FE — so a light pill on a
 * white ground with the blob washing over the label. Contrast of the label
 * against what is actually behind it came out around 1.4:1.
 *
 * The bar's CTA can be light because it sits on glass over the page. Inside an
 * opaque white panel there is nothing for a light capsule to separate from, so
 * this instance takes the DARK body — the same one the hero capsules use — and
 * the blob returns to full strength on it. Same component, the variant chosen
 * by what is behind it. */
.mg__feat .pill--brand{
  background:linear-gradient(126deg,#241046 0%,#3B1580 38%,#4C1D95 72%,#5B21B6 100%) !important;
  box-shadow:
    0 1px 2px rgba(24,10,54,.30),
    0 6px 16px rgba(45,18,105,.28),
    inset 0 0 0 1px rgba(255,255,255,.14),
    inset 0 1px 0 rgba(255,255,255,.24),
    inset 0 -1px 0 rgba(0,0,0,.34) !important}
.mg__feat .pill--brand .pill__label b{
  color:#FFFFFF !important;text-shadow:0 1px 2px rgba(24,10,54,.5)}
.mg__feat .pill--brand .pill__blob{opacity:.9;mix-blend-mode:screen}
.mg__feat .pill--nav{height:42px !important;padding:0 40px 0 20px !important}
.mg__feat .pill--nav .pill__label b{font-size:13.5px !important}

/* ══ 3D HOVER — why the last attempt did nothing ═════════════════════════
 * I put `perspective: 800px` on .mg and `translateZ(16px) rotateX(6deg)` on the
 * anchor. Perspective applies ONLY to an element's DIRECT children, and the
 * anchor is .mg > div > ul > li > a — four levels down. It received none, so
 * translateZ resolved to nothing and rotateX flattened to a shear. The result
 * was a plain tinted rectangle, which is exactly what was reported.
 *
 * Fixed with the perspective() FUNCTION inside the transform itself, which is
 * self-contained and does not care what any ancestor declares. 620px is roughly
 * 3x the item's width — under about 2x the tilt reads as a fisheye, over about
 * 5x it is indistinguishable from a flat translate.
 *
 * The lift is carried by a shadow that grows and softens with it. Depth without
 * a shadow reads as a scale, not as a rise. */
.mg a{
  display:block;padding:7px 11px;margin:-7px -11px;border-radius:9px;
  transform:perspective(620px) translateZ(0) rotateX(0deg);
  transform-origin:50% 88%;
  transition:transform .22s cubic-bezier(.2,.7,.2,1),
             box-shadow .22s cubic-bezier(.2,.7,.2,1),
             background-color .2s ease, color .16s ease;
  will-change:transform}
.mg a:hover,.mg a:focus-visible{
  transform:perspective(620px) translateZ(26px) translateY(-2px) rotateX(9deg);
  background:linear-gradient(180deg,#FBF9FF 0%,#F1EAFD 60%,#E7DDFB 100%);
  color:#3B0B78 !important;
  box-shadow:
    0 1px 2px rgba(76,29,149,.10),
    0 6px 12px -4px rgba(76,29,149,.22),
    0 18px 34px -10px rgba(76,29,149,.34),
    inset 0 1px 0 rgba(255,255,255,.9);
  outline:none}
.mg a:active{transform:perspective(620px) translateZ(10px) rotateX(4deg)}

/* The column heads sit slightly forward so the panel has a floor and a face,
   rather than everything living on one plane. */
.mg h5{transform:perspective(900px) translateZ(6px)}

/* The rail gets the same treatment at a smaller amplitude — it is a 52px bar,
   so a 26px lift there would be comic. */
.nv__links > li > a,.nv__mega-btn{
  transform:perspective(520px) translateZ(0);
  transform-origin:50% 90%;
  transition:transform .2s cubic-bezier(.2,.7,.2,1),
             background-color .2s ease, color .16s ease, box-shadow .2s ease}
.nv__links > li > a:hover,.nv__mega-btn:hover{
  transform:perspective(520px) translateZ(12px) translateY(-1px) rotateX(5deg);
  background:rgba(124,58,237,.08);
  box-shadow:0 5px 14px -7px rgba(76,29,149,.42)}

/* ══ TWO BUGS, BOTH MINE ═════════════════════════════════════════════════
 *
 * 1. THE FEATURED CAPSULE HAD SQUARE ENDS.
 *    Measured: it computed border-radius 9px while every other .pill computed
 *    999px, and at 42px tall its stadium needs 21px. The 9px came from my own
 *    `.mg a { border-radius: 9px }` — written for the panel's TEXT LINKS, and
 *    the featured capsule is also an <a> inside .mg, so it matched.
 *
 *    This is the exact fault this whole rebuild exists to remove: a selector
 *    broad enough to catch what it was written for is broad enough to catch
 *    what it was not. Every .mg rule that styles a link is now :not(.pill), and
 *    the capsule restates its own geometry so nothing can take it again.
 *
 * 2. THE CLOSE ARROW DID NOT CLOSE.
 *    The panel opens two ways — the checkbox for touch, and :hover for pointer.
 *    Clicking the label unchecks the box correctly, but the pointer is still
 *    over the trigger, so the :hover rule immediately re-opens it and the click
 *    appears to do nothing. Two open states, one of which cannot be turned off
 *    by the control that is supposed to turn it off. Fixed below with a
 *    force-closed state that outranks hover, cleared on mouseleave. */

.mg a:not(.pill){
  display:block;padding:7px 11px;margin:-7px -11px;border-radius:9px;
  transform:perspective(620px) translateZ(0) rotateX(0deg);
  transform-origin:50% 88%;
  transition:transform .22s cubic-bezier(.2,.7,.2,1),
             box-shadow .22s cubic-bezier(.2,.7,.2,1),
             background-color .2s ease, color .16s ease}
.mg a:not(.pill):hover,.mg a:not(.pill):focus-visible{
  transform:perspective(620px) translateZ(26px) translateY(-2px) rotateX(9deg);
  background:linear-gradient(180deg,#FBF9FF 0%,#F1EAFD 60%,#E7DDFB 100%);
  color:#3B0B78 !important;
  box-shadow:0 1px 2px rgba(76,29,149,.10),0 6px 12px -4px rgba(76,29,149,.22),
             0 18px 34px -10px rgba(76,29,149,.34),inset 0 1px 0 rgba(255,255,255,.9)}
.mg a:not(.pill):active{transform:perspective(620px) translateZ(10px) rotateX(4deg)}

/* The capsule restates its geometry. A stadium is radius = height/2 exactly;
   999px clamps to that at any height, which is why it is the right value and
   not a magic number. */
.mg .pill,.mg__feat .pill{
  border-radius:999px !important;
  display:inline-flex !important;
  padding:0 40px 0 20px !important;
  margin:0 !important;
  transform:none !important;
  box-shadow:
    0 1px 2px rgba(24,10,54,.30),
    0 6px 16px rgba(45,18,105,.28),
    inset 0 0 0 1px rgba(255,255,255,.14),
    inset 0 1px 0 rgba(255,255,255,.24),
    inset 0 -1px 0 rgba(0,0,0,.34) !important}
.mg .pill:hover{transform:translateY(-2px) !important}
.mg .pill .pill__blob{border-radius:0 999px 999px 0 !important}

/* Force-closed beats hover. */
.nv__links > li.vk-shut:hover > .mg,
.nv__links > li.vk-shut:focus-within > .mg{
  opacity:0 !important;visibility:hidden !important;translate:-50% -8px !important}

/* The support launcher is a <button>, and a bare <button> does NOT inherit
   font-family — UA stylesheets set it to the system default, which resolved to
   Arial here. It carries no text so nothing looked wrong, but it is one stray
   face in the document and the guard is right to refuse it. This is the same
   class of bug as the footer inheriting a monospace and spacing its wordmark
   out as "V e d i k a": a component must claim its own typeface. */
.bot,.bot *{font-family:var(--body)}
button,input,select,textarea{font-family:inherit}

/* ══ SHEET VARIANTS — the shapes that existed but had no names ═══════════
 * Inventory of the locked page found seven wide surfaces, all one-off classes
 * from the benchmark block, and .bm__panel using an 8px corner against .sheet's
 * 3px. Two card radii on one page is the defect this rebuild exists to remove,
 * and the cause is that .sheet only ever existed as a 3:4 PORTRAIT card — so
 * every landscape or banded surface got invented on the spot.
 *
 * Four named variants. All inherit .sheet's surface, hairline, 3px corner and
 * shadow; only the proportion changes. Aspect ratios are the measured ones from
 * the page, so nothing on it has to move to adopt them.
 *
 *   .sheet            3 / 4     317x423   the card. unchanged.
 *   .sheet--wide      3 / 2     landscape, for a card with an image or chart
 *   .sheet--band      16 / 5    a wide strip: stats, specimens, a CTA row
 *   .sheet--panel     1 / 1     square, for a two-up split
 *   .sheet--flat      no aspect ratio at all; height from content
 */
.sheet--wide {aspect-ratio:3/2}
.sheet--band {aspect-ratio:16/5}
.sheet--panel{aspect-ratio:1/1}
.sheet--flat {aspect-ratio:auto}

/* One corner for every card on the site. .bm__panel and .bm__one were the two
   that had drifted to 8px. */
.sheet,.sheet--wide,.sheet--band,.sheet--panel,.sheet--flat,
.bm__panel,.bm__one,.bm__stat,.bm__specimen{border-radius:3px !important}

/* ══ OUTER CONTAINERS — the widths that were never written down ══════════
 *   .wrap        1060  the page measure. Everything reads inside this.
 *   .wrap--wide  1240  for a grid that needs the extra two columns
 *   .wrap--tight  820  for prose
 * The footer plate runs to 1224 and the nav to the full viewport, both on
 * purpose: chrome spans, content is measured. */
.wrap--wide {max-width:1240px}
.wrap--tight{max-width:820px}

/* ══ THE VEIL IS SIZED BY THE TEXT, NOT BY THE CARD ══════════════════════
 * .sheet__veil fades from white to nothing at a fixed 50% of the CARD height.
 * That works only while the copy is short. Give a card three lines of heading
 * and two of body — which every real page does — and the last lines land on the
 * bloom: unreadable, and it reads as an accident rather than a composition.
 *
 * Tuning the 50% per variant is not a fix; it is five new numbers to get wrong
 * as soon as the copy changes. So the white plate is attached to the TEXT and
 * sized by it: it starts at the card's top edge, covers the copy in full
 * whatever its length, and fades out just below the last line. The bloom then
 * occupies exactly whatever the text does not.
 *
 * Implemented as a pseudo-element on .sheet__txt so it costs no markup and
 * cannot be forgotten when a page is built. Negative insets pull it out to the
 * card's padding edge; the 34px tail is the fade. */
.sheet__txt{position:relative;z-index:2}
.sheet__txt::before{
  content:'';position:absolute;z-index:-1;
  left:-26px;right:-26px;top:-26px;
  height:calc(100% + 26px + 42px);
  background:linear-gradient(180deg,
    #FFFFFF 0%,
    #FFFFFF calc(100% - 42px),
    rgba(255,255,255,.72) calc(100% - 22px),
    rgba(255,255,255,0) 100%);
  pointer-events:none}

/* The card's own veil now only has to soften the very top edge; the text plate
   does the rest. Left in place because .sheet--dark inverts it. */
.sheet__veil{
  background:linear-gradient(180deg,#fff 0%,rgba(255,255,255,.55) 8%,rgba(255,255,255,0) 22%)}
.sheet--dark .sheet__txt::before{
  background:linear-gradient(180deg,
    #0B0B0D 0%,
    #0B0B0D calc(100% - 42px),
    rgba(11,11,13,.72) calc(100% - 22px),
    rgba(11,11,13,0) 100%)}

/* AND THE CARD GROWS WITH ITS CONTENT.
 * aspect-ratio was acting as a hard cap: long copy either overflowed or was
 * squeezed against the art. It becomes a MINIMUM — the proportion is the
 * card's resting shape, and real copy is allowed to make it taller rather than
 * making it unreadable. `height:auto` releases the cap; min-height keeps the
 * proportion when the copy is short. */
.sheet,.sheet--wide,.sheet--band,.sheet--panel{height:auto}
.sheet        {aspect-ratio:auto; min-height:calc(var(--sheet-w, 240px) * 4 / 3)}
.sheet--wide  {min-height:calc(var(--sheet-w, 320px) * 2 / 3)}
.sheet--band  {min-height:calc(var(--sheet-w, 560px) * 5 / 16)}
.sheet--panel {min-height:var(--sheet-w, 240px)}
.sheet--flat  {min-height:0}

/* Breathing room so the copy never sits against the corner. */
.sheet{padding:26px 26px 30px}
.sheet h3{max-width:26ch}
.sheet p{max-width:34ch}
.sheet--band h3,.sheet--wide h3{max-width:40ch}
.sheet--band p,.sheet--wide p{max-width:56ch}

/* ══ THE ART BAND IS GUARANTEED ══════════════════════════════════════════
 * Previous fix: the white plate is sized by the text so copy never lands on
 * the bloom. Correct, and it over-corrected — with four lines of copy the plate
 * consumes the card and the art is left as a sliver that reads as a cut-off
 * accident rather than a composition.
 *
 * Both requirements have to hold at once, and neither can be a percentage,
 * because the text is not a percentage:
 *     1. the copy always sits on white
 *     2. the art always gets a real band, not a leftover
 *
 * So the card reserves the art band as PADDING — a fixed strip at the bottom
 * that content cannot enter — and grows above it as the copy needs. Padding is
 * the right tool precisely because it is not divided up: text length changes
 * the card's height, never the band.
 *
 * 150px is the reference band on a 320px-tall card: 47%. On a taller card the
 * proportion falls, which is correct — a long card is long because it has more
 * to say, not because it needs more picture. */
.sheet{padding:26px 26px 150px !important}
.sheet--band{padding-bottom:120px !important}
.sheet--flat{padding-bottom:130px !important}

/* The plate now only has to cover the copy and fade just under it; the band
   below is guaranteed by the padding, so the fade can be short and soft. */
.sheet__txt::before{
  height:calc(100% + 26px + 30px);
  background:linear-gradient(180deg,
    #FFFFFF 0%,
    #FFFFFF calc(100% - 30px),
    rgba(255,255,255,.70) calc(100% - 14px),
    rgba(255,255,255,0) 100%)}
.sheet--dark .sheet__txt::before{
  background:linear-gradient(180deg,
    #0B0B0D 0%,
    #0B0B0D calc(100% - 30px),
    rgba(11,11,13,.70) calc(100% - 14px),
    rgba(11,11,13,0) 100%)}

/* ══ THE CARD GROWS. THE ART DOES NOT SHRINK. ════════════════════════════
 * Last pass reserved the art band as a flat 150px. That kept the copy off the
 * bloom but it solved it the wrong way round: with long copy the card stayed
 * near its resting height and the picture got squeezed to a strip. The founder
 * is right — the sheet should get TALLER, and the art should keep its share.
 *
 * The band is now a percentage of the card's WIDTH, not a fixed pixel count and
 * not a percentage of its height. That distinction is the whole fix:
 *   - % of height would be circular: the height is what the text decides
 *   - a fixed px is what just failed, because it does not scale with the card
 *   - % of WIDTH is stable, known before layout, and scales with the component
 *
 * Each variant's figure is set so the art occupies ~58% of the card at its
 * RESTING proportion, which is what the reference cards do:
 *     .sheet        h = w x 4/3   ->  .58h = .77w
 *     .sheet--wide  h = w x 2/3   ->  .58h = .39w
 *     .sheet--panel h = w         ->  .58h = .58w
 *     .sheet--band  h = w x 5/16  ->  .58h = .18w
 * Add copy and the card grows downward from there; the band is untouched. */
.sheet        {padding:26px 26px 77% !important}
.sheet--wide  {padding-bottom:39% !important}
.sheet--panel {padding-bottom:58% !important}
.sheet--band  {padding-bottom:18% !important}
.sheet--flat  {padding-bottom:55% !important}

/* min-height is now a floor for SHORT copy only. Long copy is allowed past it,
   which is the point — the card is as tall as it needs to be. */
.sheet        {min-height:calc(var(--sheet-w, 240px) * 4 / 3)}
.sheet--wide  {min-height:calc(var(--sheet-w, 320px) * 2 / 3)}
.sheet--panel {min-height:var(--sheet-w, 240px)}
.sheet--band  {min-height:calc(var(--sheet-w, 560px) * 5 / 16)}
.sheet--flat  {min-height:0}

/* ══ ART BAND: A PROPORTION *AND* A FLOOR ════════════════════════════════
 * The width-proportional band failed the invariant on .sheet--band: at 560px
 * wide, 18% is 101px and only 30% of the card once the copy is in. A 16:5 strip
 * is short by definition, so a share of its width is not enough on its own —
 * and at phone width the same figure collapses to 93px.
 *
 * max(px, %) gives both: the percentage keeps the band proportional on a wide
 * card, the pixel floor keeps it real on a narrow one. Neither alone survived
 * both widths, which is why the measurement runs at 1280 AND 390. */
/* THE ART BAND IS CAPPED. A PERCENTAGE OF WIDTH DOES NOT SCALE.
 *
 * These reserve space at the foot of a card for the bloom to occupy, and the
 * percentage is of the element's OWN WIDTH. That is right for a card in a
 * three-up grid and catastrophic for a full-width one: measured on mcp, a
 * 317px card reserved 174px, and a 1004px sheet on the same page reserved
 * 552px — half a screen of empty gradient under a seven-row table, repeated
 * down the page. It is the single largest source of "huge grids", "blank
 * grids" and "half area blank".
 *
 * The band is decoration; it does not need to grow without limit. The floor
 * stays (short copy still gets a proper band), the percentage stays (narrow
 * cards keep their proportion), and a ceiling is added so a wide sheet stops
 * reserving screens of nothing. 260px is the base card's reserve at its
 * natural ~340px width, so a wide sheet now lands on the same band depth a
 * card has rather than a scaled-up one. */

/* Art bands tightened 2026-08-05. The caps above were set to stop a 1004px
 * sheet reserving 552px, and they did -- but 244px of art under 184px of
 * text still reads as 'content stacked in one corner', which the founder
 * reported on page after page. The art is meant to sit under the copy, not
 * outweigh it. Measured worst case on /about was a 370px gap. */
.sheet        {padding-bottom:clamp(110px, 46%, 180px) !important}
.sheet--wide  {padding-bottom:clamp(100px, 26%, 165px) !important}
.sheet--panel {padding-bottom:clamp(105px, 36%, 175px) !important}
.sheet--band  {padding-bottom:clamp(150px, 26%, 200px) !important}
.sheet--flat  {padding-bottom:clamp(100px, 34%, 160px) !important}

/* ══ THE SEAM ════════════════════════════════════════════════════════════
 * A hard horizontal line between the copy and the art, reported twice.
 * The text plate ran solid white to `calc(100% - 30px)` and faded out over
 * those last 30px. Thirty pixels across a 380px card is not a blend, it is a
 * step — and against a PALE bloom the step is more visible than it was against
 * a dark one, which is why it came back when the field went light.
 *
 * The locked page's own veil fades over roughly half the card. Matching that:
 * the plate is solid only where the copy actually is, then dissolves across
 * ~120px on a five-stop curve. Five stops rather than two because a linear
 * two-stop ramp still shows a mach band where it meets flat colour — the eye
 * finds the discontinuity in the first derivative, not in the value. */
.sheet__txt::before{
  height:calc(100% + 26px + 130px);
  background:linear-gradient(180deg,
    #FFFFFF 0%,
    #FFFFFF calc(100% - 130px),
    rgba(255,255,255,.96) calc(100% - 104px),
    rgba(255,255,255,.82) calc(100% - 78px),
    rgba(255,255,255,.54) calc(100% - 50px),
    rgba(255,255,255,.22) calc(100% - 22px),
    rgba(255,255,255,0) 100%)}
.sheet--dark .sheet__txt::before{
  background:linear-gradient(180deg,
    #0B0B0D 0%,
    #0B0B0D calc(100% - 130px),
    rgba(11,11,13,.96) calc(100% - 104px),
    rgba(11,11,13,.82) calc(100% - 78px),
    rgba(11,11,13,.54) calc(100% - 50px),
    rgba(11,11,13,.22) calc(100% - 22px),
    rgba(11,11,13,0) 100%)}
/* the card's own top veil gets the same treatment so both edges are soft */
.sheet__veil{
  background:linear-gradient(180deg,#fff 0%,rgba(255,255,255,.72) 6%,
    rgba(255,255,255,.34) 14%,rgba(255,255,255,0) 26%)}

/* ══ THE ART RUNS BEHIND THE TEXT ════════════════════════════════════════
 * I added .sheet__txt::before as a SOLID white plate so long copy could never
 * land on the bloom. It solved that and broke the thing that makes these cards
 * work: the field stops dead behind the copy instead of running under it. The
 * locked page never had that plate — reported as "blending bg running behind
 * the text kinda", and it is the right read.
 *
 * The plate is gone. The veil does the work, as it always did:
 *     solid white for the first 18%
 *     .88 at 30%, .62 at 42%, .30 at 54%, 0 at 68%
 * So the top of the copy sits on paper, the lower lines sit on a WASH with the
 * marble faintly visible through it, and the band below is the field at full
 * strength. That gradient is the composition — there is no boundary anywhere in
 * it, which is why the locked cards have no seam and mine kept growing one.
 *
 * Longer than the original's 50% because the cards now grow with their copy;
 * the veil is a percentage, so it scales with them and the wash always reaches
 * past the last line.
 *
 * CONTRAST: at 54% the veil is still .30 white over a pale field, and
 * --ink #0C0C0E on that measures well past 4.5:1. Verified, not assumed. */
.sheet__txt::before{content:none !important}

/* THE WASH IS A PERCENTAGE OF THE CARD, AND THE GRID DECIDES THE CARD.
 *
 * The gradient above is right and stays exactly as it is — solid at the top,
 * a wash under the lower lines, field at full strength below, no seam anywhere.
 * What breaks it is not the shape, it is the length it gets measured against.
 *
 * `.sheets` is a grid with default stretch alignment, so every card in a row is
 * as tall as the wordiest one. On _locked.html all three cards carry the same
 * two lines, nothing stretches, the card is 391px and 68% lands at 266px — just
 * past the copy, exactly as designed. On a real page the copy is uneven: about's
 * three cards hold 158px, 204px and 284px of text and all three become 554px.
 * The shortest one now runs its wash to 377px while its text ends at 158px, so
 * 219px of the card is white-on-white before any art appears. Measured, both
 * pages, same width and same padding-bottom — height was the only variable.
 *
 * Clamping the length keeps both guarantees. The wash is still 68% for any card
 * the grid has not stretched, so nothing about the locked page changes. It can
 * no longer run past 380px on a card that was stretched to fit a wordier
 * sibling, and it can never fall under 260px on a short one, which is what kept
 * long copy off the raw bloom in the first place. */
.sheet__veil{
  position:absolute;inset:0;z-index:1;pointer-events:none;
  background-repeat:no-repeat !important;
  background-size:100% clamp(190px, 42%, 250px) !important;
  background-image:linear-gradient(180deg,
    #FFFFFF 0%,
    #FFFFFF 26%,
    rgba(255,255,255,.88) 44%,
    rgba(255,255,255,.62) 62%,
    rgba(255,255,255,.30) 79%,
    rgba(255,255,255,.10) 91%,
    rgba(255,255,255,0) 100%) !important}
/* Same clamp on the dark card, same stop percentages restated against the
 * clamped length, so light and dark keep an identical wash profile. */
.sheet--dark .sheet__veil{
  background-repeat:no-repeat !important;
  background-size:100% clamp(190px, 42%, 250px) !important;
  background-image:linear-gradient(180deg,
    #0B0B0D 0%,
    #0B0B0D 26%,
    rgba(11,11,13,.88) 44%,
    rgba(11,11,13,.62) 62%,
    rgba(11,11,13,.30) 79%,
    rgba(11,11,13,.10) 91%,
    rgba(11,11,13,0) 100%) !important}

/* AN INNER SHADOW, so the field reads as sitting INSIDE the card rather than
 * being printed on it. Four inset edges, weighted to the top where the paper
 * meets the art — that top edge is the one that reads as depth. */
.sheet{
  box-shadow:
    0 1px 2px rgba(16,16,24,.07),
    0 6px 14px rgba(16,16,24,.06),
    0 16px 34px rgba(16,16,24,.06),
    inset 0 1px 0 rgba(255,255,255,.9),
    inset 0 14px 22px -14px rgba(40,30,80,.34),
    inset 0 -10px 20px -14px rgba(40,30,80,.20),
    inset 10px 0 18px -16px rgba(40,30,80,.16),
    inset -10px 0 18px -16px rgba(40,30,80,.16) !important}

/* ── THE CHROME BAR FOLLOWS THE LOCKED FACES ─────────────────────────────
 * css/vk-chrome.css sets --vkc-display and --vkc-body to 'Outfit'. Its own
 * comment explains why: it was following css/vedika-design-system.css, whose
 * --vk-font-body is Outfit, so that the nav and the footer could not disagree.
 *
 * THAT REASON IS NOW STALE. The locked system is Newsreader / DM Sans /
 * Fragment Mono, and a page carrying THIS stylesheet has adopted it. Leaving
 * the bar on Outfit reproduces the exact fault vk-chrome.css was written to
 * avoid, only inverted: the page body reports DM Sans while the nav and footer
 * three screens apart report Outfit. The guard measures it as a stray face and
 * fails the page, which is how it was found.
 *
 * Scoped by load order, not by force: this only lands on pages that load
 * vk-locked.css, i.e. pages that have opted into the locked design. Every
 * other page in the tree keeps vk-chrome.css exactly as it is. Faces only —
 * nothing here moves, sizes or repaints the bar. */
:root{
  --vkc-display: 'Newsreader', Georgia, serif;
  --vkc-body: 'DM Sans', system-ui, -apple-system, sans-serif;
}


/* ══ PHONE: WIDE CONTENT SCROLLS ITSELF, IT DOES NOT PUSH THE PAGE ═════════
 *
 * Measured across the 102 root pages at 390px: 17 pages pushed the document
 * sideways on a <table> and 16 more on a <code>/<pre>. Both are content the
 * page cannot reflow — an endpoint table has the columns it has, and a cURL
 * line does not wrap without changing what it says. So neither should be made
 * narrower; each just needs to carry its own scroll instead of handing the
 * overflow up to the document, which is what turns one wide table into a whole
 * page that slides under the thumb.
 *
 * `display:block` on the table is what makes overflow-x apply at all — a
 * table-layout box ignores it. That costs the table its column-width algorithm,
 * so it is scoped to the phone breakpoint only; at 769px and up the table is a
 * table again with its own sizing intact.
 *
 * `white-space:pre` is restated on <pre> deliberately: several pages set
 * pre-wrap to dodge this exact overflow, which silently rewrapped code samples
 * and broke the lines a reader is meant to copy. Scrolling keeps the sample
 * true. */
@media (max-width: 768px) {
  table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  pre {
    max-width: 100%;
    overflow-x: auto;
    white-space: pre;
    -webkit-overflow-scrolling: touch;
  }
  /* Inline code wraps; block code inside <pre> is handled above. */
  :not(pre) > code {
    overflow-wrap: anywhere;
    word-break: break-word;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   THE TWENTY VARIANTS THE PAGES ASK FOR AND NOBODY HAD DEFINED
   ═══════════════════════════════════════════════════════════════════════════

   Measured across the markup of 102 pages: twenty class names are in use and
   have no rule in any stylesheet. Every one silently falls back to the base
   `.sheet` — a SHOWCASE card that reserves an art band of up to 260px. So a
   page writes `sheet--prose` around a paragraph, asking for a prose treatment,
   and is handed a card that is mostly reserved decoration. That single fact is
   the largest source of "huge grids", "blank grids" and "half area blank".
   `sheet--term` alone is 78 uses across the glossary.

   Each rule below is derived from what the variant ACTUALLY contains in the
   markup, not from its name. The three groups:

     TEXT-FIRST   the card is copy. Height comes from the copy; the art band is
                  small, because a paragraph does not need half a card of
                  decoration under it.
     DATA         the card is a table, a code block or a row list. NO art band
                  at all — tabular data floating above a bloom is unreadable,
                  and it is what makes these read as broken.
     ART-CARRYING the card is a showcase and the band is the point. These keep a
                  band, capped, and only these do.

   The art band rules earlier in this file carry !important, so these must too.
   They are appended last so that, at equal specificity, they win.               */

/* ── TEXT-FIRST ─────────────────────────────────────────────────────────── */

/* Glossary entry: <h3>term (देवनागरी)</h3> + definition. 78 uses, all on one
   page, in a dense grid. A tall card here turns 80 terms into a scroll of
   mostly-empty boxes, so the band is a hairline of colour, not a panel. */
.sheet--term{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(18px, 6%, 34px) !important}
.sheet--term h3{font-size:17px; margin-bottom:6px}
.sheet--term p{font-size:13px; line-height:1.5}

/* A single long paragraph, sometimes several. It carries field + veil, so it
   wants SOME colour, but the copy is the subject. Measure is capped so a wide
   card does not run 120-character lines. */
.sheet--prose{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(40px, 12%, 90px) !important}
.sheet--prose .sheet__txt{max-width:68ch}
.sheet--prose p{font-size:14px; line-height:1.62}
.sheet--prose p + p{margin-top:12px}

/* <h3> + a paragraph of body copy. The ordinary content card — the treatment
   most of the 102 pages actually needed and never had. */
.sheet--plain{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(34px, 10%, 76px) !important}

/* Question as <h3>, answer beneath. Same shape as --plain, tighter, because a
   column of FAQ cards is read by scanning the questions. */
.sheet--faq{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(26px, 8%, 56px) !important}
.sheet--faq h3{font-size:17px; line-height:1.3; margin-bottom:8px}

/* Tutorial step: an <h2> and several paragraphs, full width. Generous inside,
   minimal band — the reader is here to read. */
.sheet--step{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(34px, 9%, 70px) !important}
.sheet--step .sheet__txt{max-width:72ch}
.sheet--step h2{font-family:var(--display); font-weight:300; font-size:26px;
  line-height:1.2; letter-spacing:-.02em; margin:0 0 12px}

/* A short aside, usually one sentence and two links. Quiet and small; it should
   never occupy a full card's worth of vertical space. */
.sheet--note{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(20px, 7%, 44px) !important}
.sheet--note p{font-size:13.5px}

/* ── DATA — no art band at all ───────────────────────────────────────────── */

/* A row list (status rows, endpoint rows). Rows must sit on paper; a row that
   half-crosses a bloom edge reads as a rendering fault. */
.sheet--list{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:26px !important}
.sheet--list .sheet__field{display:none}

/* Comparison / reference tables. Same reasoning, plus the table carries its own
   rules and needs the full width. */
.sheet--table{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:22px !important}
.sheet--table .sheet__field{display:none}
.sheet--table .sheet__txt{max-width:none}

/* Code samples. Almost always paired with .sheet--dark. Monospace over a moving
   bloom is unreadable, so the field goes and the card is a plate. */
.sheet--code{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:20px !important}
.sheet--code .sheet__field{display:none}
.sheet--code pre{margin:0; overflow-x:auto; -webkit-overflow-scrolling:touch}
.sheet--code code{font-family:var(--mono); font-size:12.5px; line-height:1.65}

/* Says what it means: this card has no art. Honour it exactly. */
.sheet--noart{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:20px !important}
.sheet--noart .sheet__field,
.sheet--noart .sheet__veil{display:none}

/* ── ART-CARRYING — the band is the point, and only here ──────────────────── */

/* Wide step slab: an eyebrow, a line, and a real field. Keeps a band, capped so
   a 1004px slab does not reserve half a screen. */
.sheet--slab{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(90px, 18%, 170px) !important}

/* Feature card: heading with an icon, then a short paragraph. This is the shape
   `.sheet` was designed for, so it keeps a proper band. */
.sheet--feature{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(110px, 30%, 190px) !important}
.sheet--feature h3 i{margin-right:9px; opacity:.7}

/* Section-ending call to action: heading, one line, capsules. Centred, with a
   band under the capsules so it reads as a destination. */
.sheet--cta{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(80px, 20%, 150px) !important; text-align:center}
.sheet--cta .sheet__txt{max-width:56ch; margin-inline:auto}
.sheet--cta .row{justify-content:center}

/* A single number and its label. Centred, and the band carries the colour that
   makes a stat row feel like one. */
.sheet--center{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(90px, 26%, 160px) !important; text-align:center}
.sheet--center .sheet__txt{margin-inline:auto}
.sheet--center .stat__figure{font-family:var(--mono); font-size:26px;
  line-height:1; letter-spacing:-.01em; color:var(--ink); margin:0 0 8px}
.sheet--center .stat__label{font-family:var(--mono); font-size:9.5px;
  letter-spacing:.13em; text-transform:uppercase; color:var(--muted); margin:0}

/* Pricing plan: name, price, capsule. Height from content so a row of plans
   lines up on its own terms rather than on the tallest feature list. */
.sheet--plan{
  aspect-ratio:auto !important; min-height:0 !important;
  padding-bottom:clamp(30px, 10%, 64px) !important}
.sheet--plan .plan__price{font-family:var(--display); font-weight:300;
  font-size:34px; line-height:1; letter-spacing:-.02em; color:var(--ink);
  margin:6px 0 14px}

/* ── CAPSULE VARIANTS ────────────────────────────────────────────────────── */

/* Inside a card or panel, where the hero size would dominate. 49 uses. */
.pill--panel{height:42px; min-width:0; padding:0 44px 0 18px}
.pill--panel .pill__label b{font-size:13px}
.pill--panel .pill__label span{font-size:8.5px; letter-spacing:.1em}

/* The documented compact size. Sub-label is suppressed — it does not fit. */
.pill--compact{height:28px; min-width:0; padding:0 34px 0 14px}
.pill--compact .pill__label b{font-size:11px}
.pill--compact .pill__label span{display:none}

/* The hero capsule, stated explicitly so a page does not have to rely on the
   bare `.pill` default to get it. */
.pill--hero{height:64px; min-width:252px; padding:0 62px 0 28px}
.pill--hero .pill__label b{font-size:15.5px}

/* Form submit: fills its column, label centred over the blob. */
.pill--submit{height:52px; width:100%; min-width:0; padding:0 56px 0 24px;
  justify-content:flex-start}
.pill--submit .pill__label{min-width:0}
.pill--submit .pill__label b{font-size:14.5px}

/* A status indicator, not a control. Reads, never invites a click. */
.pill--status{height:26px; min-width:0; padding:0 30px 0 12px; cursor:default}
.pill--status .pill__label b{font-size:10.5px; letter-spacing:.04em}
.pill--status .pill__label span{display:none}

/* CONTENT-HEIGHT VARIANTS DO NOT STRETCH.
 *
 * `.sheets` is a grid and a grid stretches every item to the tallest in the row.
 * For a showcase card that is harmless — the art band absorbs the extra. For the
 * variants above it is the whole bug: measured on mcp, a `sheet--slab` whose copy
 * needs 203px was inflated to 669px because a wordier sibling in the same row
 * needed that. The rule was applying correctly (padding-bottom: 90px); the grid
 * was overriding the outcome.
 *
 * So the variants that take their height from their content say so. Showcase
 * cards are deliberately NOT in this list — a row of them should still line up. */
.sheet--term, .sheet--prose, .sheet--plain, .sheet--faq, .sheet--step,
.sheet--note, .sheet--list, .sheet--table, .sheet--code, .sheet--noart,
.sheet--slab, .sheet--plan{
  align-self:start !important}

/* ── LEGACY CTA CLASSES, ADOPTED ─────────────────────────────────────────
 * 55 buttons across the rolled pages are still `.btn`, `.btn-primary`,
 * `.btn-secondary`, `.btn-ghost` or `.cta`. Rewriting that markup was the
 * obvious move and the wrong one: a `.pill` is a composite (`.pill__label`
 * plus `.pill__blob`) and these anchors carry a bare text node, so the
 * conversion would have to invent structure inside 55 hand-written blocks,
 * on money and demo pages, with no way to gate the result. The shape is what
 * reads as off-brand, and the shape is reachable from CSS alone.
 *
 * So these adopt the capsule's language at NAV size, not hero size: `.pill`
 * is 64px tall with a 252px floor, which on an inline CTA looks like a
 * mistake. 44px matches `.pill--nav`, which is the register these buttons
 * actually sit in.
 *
 * Deliberately NOT adopted: .btn-icon, .btn-send, .btn-mic, .btn-reset,
 * .btn-clear-chat, .btn-glass. Those are chat and demo controls -- square
 * icon affordances where a stadium capsule would be wrong.
 */
.btn, .btn-primary, .btn-secondary, .btn-ghost, .cta{
  display:inline-flex; align-items:center; justify-content:center;
  height:44px; padding:0 22px; border-radius:999px; border:0;
  font-family:var(--body); font-size:13.5px; font-weight:600;
  letter-spacing:.005em; text-decoration:none; cursor:pointer;
  transition:transform .18s cubic-bezier(.3,.6,.2,1), box-shadow .18s ease;
}
.btn-primary, .cta{
  background:var(--space); color:#fff;
  box-shadow:0 1px 2px rgba(16,16,24,.16), 0 6px 12px rgba(16,16,24,.13),
             inset 0 0 0 1px rgba(255,255,255,.10);
}
.btn, .btn-secondary, .btn-ghost{
  background:var(--surface); color:var(--ink);
  box-shadow:0 1px 2px rgba(16,16,24,.08), 0 4px 10px rgba(16,16,24,.07),
             inset 0 0 0 1px rgba(16,16,24,.08);
}
.btn:hover, .btn-primary:hover, .btn-secondary:hover,
.btn-ghost:hover, .cta:hover{ transform:translateY(-1px) }
.btn:active, .btn-primary:active, .btn-secondary:active,
.btn-ghost:active, .cta:active{ transform:translateY(0) scale(.998) }

/* ── MEGA MENU ICONS ─────────────────────────────────────────────────────
 * The panel shipped as four columns of bare text -- 21 links, no glyph of any
 * kind. These are inline stroked paths on currentColor, so they inherit the
 * link's colour and its hover transition rather than needing their own rules,
 * and they sit at 14px against a 14.5px label so they read as a marker beside
 * the word rather than a second focal point.
 */
/* Glyphs are Lucide (lucide-static v1.28.0, ISC), inlined rather than linked:
 * twenty icons do not justify a runtime dependency, and the chrome already
 * inlines its only other glyph the same way. Lucide is the set whose stroke
 * width is adjustable, which matters because these sit beside the Resources
 * chevron at 2.6. */
/* Spacing rides on the icon, not on a flex gap. The link computes to
 * `display:block` here regardless of what this file asks for, so `gap` never
 * applied and the glyph sat flush against the word -- 0px between them, which
 * reads as overlap. `margin-right` + `vertical-align` is display-agnostic: it
 * spaces correctly whether the anchor ends up block, flex or inline. */
/* Icon sits at the RIGHT edge of the link, per the founder. The anchor
 * computes display:block here whatever this file asks, so a flex `gap` never
 * applied -- `float:right` is display-agnostic and puts the glyph on the
 * trailing edge without needing the anchor to become a flex container. */
.mg__icon{
  width:14px; height:14px;
  float:right; margin-left:12px; margin-right:0; vertical-align:-2px;
  opacity:.45; transition:opacity .16s ease;
}
.mg ul li a:hover .mg__icon{opacity:.9}
.mg a:hover .mg__icon{opacity:1}

/* ── ICON CHIPS, ONE TREATMENT ───────────────────────────────────────────
 * These carried their colour INLINE -- eleven different chip backgrounds
 * (cloud, emerald, cosmic, fire and seven one-off hexes) and six different
 * icon strokes, hard-coded per card. An inline style beats every rule in
 * every layer, which is why the whole locked rollout never touched them and
 * three cards side by side stayed bare, green and blue.
 *
 * The attributes are stripped from the markup rather than overridden here,
 * so this rule is simply what applies now. Ink on a neutral chip: the icon is
 * a marker, not a second colour system competing with the art.
 */
.sheet__icon{
  display:inline-flex; align-items:center; justify-content:center;
  width:34px; height:34px; margin:0 0 14px; padding:0;
  border-radius:9px; background:rgba(16,16,24,.045);
  border:1px solid rgba(16,16,24,.07);
  color:var(--ink);
}
.sheet__icon svg{width:17px; height:17px; stroke:currentColor; fill:none}


/* ── TAILWIND PURPLE TEXT, NEUTRALISED ───────────────────────────────────
 * 405 Tailwind purple utilities on pricing.html alone -- text-purple-600
 * appears 184 times. They are utilities, so no `color:` sweep of the page's
 * own CSS could reach them, and pricing is one of the unlayered pages, so
 * the locked sheet was not winning by layer either. It does win by order:
 * tailwind.min.css is stylesheet 1 and vk-locked.css is 14, so a rule of the
 * same specificity here simply comes later.
 *
 * Text only. bg-purple-*, border-purple-* and every gradient stop keep their
 * colour -- those are chrome and art, and flattening them would take the
 * capsules and washes with them.
 */
.text-purple-400, .text-purple-500, .text-purple-600, .text-purple-700, .text-purple-800, .text-purple-900, .text-violet-400, .text-violet-500, .text-violet-600, .text-violet-700, .text-violet-800, .text-violet-900, .text-indigo-400, .text-indigo-500, .text-indigo-600, .text-indigo-700, .text-indigo-800, .text-indigo-900, .text-fuchsia-400, .text-fuchsia-500, .text-fuchsia-600, .text-fuchsia-700, .text-fuchsia-800, .text-fuchsia-900{color:var(--ink)}

/* ── THE WHITE BAND ──────────────────────────────────────────────────────
 * Founder: "weird white patta in between ... this bug on almost on pages
 * randomly ... hard to spot". Hard to spot, trivial to measure: a full-width
 * element painting pure white (luminance 255) over a tinted grid ground reads
 * as a stripe cutting the page in half. Found on 14 pages -- section.pp-mkt on
 * twelve of them, plus .py-20 and .cs-filter.
 *
 * The ground is meant to run continuously behind every section; these were
 * opting out of it with an opaque fill. Made transparent so the grid and the
 * bloom show through, which is what every other section already does.
 */
/* NARROWED. `section.pp-mkt` matches three bands, and two of them are opaque
 * on purpose: .pp-mkt-pricing is the tinted panel and .pp-mkt-cta is the dark
 * one. Only the trust strip was the white stripe. Blanking all three was a
 * regression waiting to land the moment the layering gap closed. */
section.pp-mkt.pp-mkt-trust,
section.cs-filter{background:transparent}
/* case-studies carries its own unlayered `body.cs-light .cs-filter{background:
 * var(--paper)}` at 0-2-1, which out-specifies the 0-1-1 above. Both are
 * unlayered, so specificity decides and this wins on merit at 0-2-2 -- no
 * !important needed. Measured: the band was the last white stripe left after
 * the marketingSections fix cleared the other twelve. */
/* !important is load-bearing here and I do not use it lightly. The winning
 * declaration measures as UNLAYERED on the live page (probed with a walker
 * that recurses @import and @layer, after five naive probes gave five wrong
 * answers). An unlayered normal declaration beats every layered one at any
 * specificity, so nothing in layer(locked) can win by selector weight. An
 * IMPORTANT declaration does beat a normal one regardless of layer, and that
 * is the only lever left short of editing the page. The page's own static
 * blocks are all correctly wrapped in @layer legacy and all brace-balanced,
 * so the escaping rule is not a defect in the layer pass. */
body.cs-light section.cs-filter{background:transparent !important}

/* ── ONE GROUND PER PAGE ─────────────────────────────────────────────────
 * research and changelog carry a Spline canvas as their ground AND the locked
 * ruled ground markup (.grid-flow / .grid-fade inside .body-ground). Two
 * grounds stack, so the checkerboard drew straight over the 3D scene -- which
 * is exactly the objection the earlier retirement note raised about "a second
 * full-page ground", except it removed the Spline instead of the grid.
 *
 * The Spline pages are marked with .vk-spline-ground and the ruled layer is
 * suppressed there. Nothing is deleted from the markup: a page that later
 * drops its scene gets its grid back by removing one class.
 */
body.vk-spline-ground .grid-flow,
body.vk-spline-ground .grid-fade{display:none !important}
body.vk-spline-ground .body-ground{background:transparent !important}

/* ── ONE TEXT ALIGNMENT IN SHEETS ────────────────────────────────────────
 * Measured across 7 rolled pages: glossary 79/79 left, faq 6/6 left, about
 * 7/7 left, research 9/9 left -- and mcp 18 left, 5 CENTRE. Five centred
 * cards in a grid of left-aligned ones is exactly the "not standardized"
 * the founder keeps hitting: nothing is broken, but the eye reads two
 * systems on one page.
 *
 * Left wins because it is what 113 of the 118 measured sheets already do.
 * .sheet--center is left alone -- that variant exists to centre on purpose,
 * and overriding it would be replacing one inconsistency with another.
 */
.sheet:not(.sheet--center) .sheet__txt,
.sheet:not(.sheet--center) .sheet__txt > *{text-align:left}

/* ── ONE MONO FACE ───────────────────────────────────────────────────────
 * 75 elements on /playground, 6 on /pricing and 2 on /mcp render with a
 * non-locked font FIRST in the stack -- ui-monospace, JetBrains Mono,
 * Consolas. None of it is declared in those pages: it comes from the shared
 * sheets (tailwind, vedika-design-system, vedika-tokens, pricing-reframe),
 * so fixing it there would reach far more than these pages.
 *
 * Scoped to the elements that are actually meant to be monospaced, so nothing
 * else inherits it. Fragment Mono leads; the old stacks stay as fallback, so
 * a machine without the webfont degrades exactly as it did before.
 */
code, pre, kbd, samp, .font-mono,
pre code, .code, .codeblock{
  /* !important because the opponent is UNLAYERED: /playground carries a
   * runtime-injected `pre{font-family:ui-monospace,...}` that no layered rule
   * can outrank at any specificity. Verified with whowins.mjs -- the locked
   * rule was present, matched, and lost purely on layer. Fragment Mono still
   * leads a full fallback stack, so nothing degrades on a machine without the
   * webfont. */
  font-family:'Fragment Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace !important;
}

/* ── NAV LINK ROW POSITION ───────────────────────────────────────────────
 * .nv__links carries `margin:0 auto`, and that auto margin is what pushes the
 * link row to x=466 on the reference bar. On /playground and /payment-failed
 * it computed 0, putting the row at x=118 and x=134 -- the "nav looks
 * different on this page" complaint.
 *
 * The winner is an UNLAYERED `ul{margin:0}` reset in those pages' own inline
 * <style>. Unlayered beats layer(locked) whatever the specificity, so the
 * locked rule cannot win on selector weight; !important is the only lever.
 *
 * Scoped to min-width:901px on purpose. Below 900px the locked design
 * deliberately sets margin:0 and stacks the bar into a drawer -- forcing the
 * auto margin there would break mobile to fix desktop.
 */
@media (min-width:901px){
  .nv__links{margin-left:auto !important; margin-right:auto !important}
}

/* The bar must span the viewport. On /payment-failed it measured 671px inside
 * a 1440px body -- shrink-to-fit, because that page's <body> lays out as a
 * flex container and the nav became a flex item. Everything inside then packs
 * left, which is why its link row sat at x=134 while the auto-margin fix that
 * corrected /playground had no effect here: the margin was resolving inside a
 * 671px box. width + flex-basis covers both the flex-item and block cases. */
/* width only -- NOT flex-basis. `flex:0 0 100%` sets the basis, and on a page
 * whose <body> is a COLUMN flex container the basis is the HEIGHT: it collapsed
 * the bar from 52px to 34px on 404, 500 and enterprise-playground. width is
 * axis-independent and does the intended job in both cases. */
.nv{width:100%; box-sizing:border-box}

/* ── DESIGN-SYSTEM PILLS, ADOPTED ────────────────────────────────────────
 * The dashboard builds every control from .vds-pill -- 42 of them across the
 * tabs. They are the app-side twin of the legacy .btn classes already adopted
 * above: same job, different name, and they take their shape from
 * var(--vkp-radius) rather than the locked stadium, which is why the buttons
 * there read as a different product from the rest of the site.
 *
 * Adopted at nav size (44px), not hero size, for the same reason as .btn: a
 * 64px capsule inside a data table looks like a mistake. Markup untouched --
 * .vds-pill is a composite the app's own JS writes into, and rewriting that
 * would put a presentation change inside the billing surface.
 *
 * .vds-pill--literal is exempt: it renders a copyable value (an API key, an
 * endpoint), where a stadium reads as a button and invites a click.
 */
.vds-pill:not(.vds-pill--literal),
.pill-btn, .cta-btn, .rm-cta{
  border-radius:999px !important;
  font-family:var(--body);
  font-size:13.5px; font-weight:600; letter-spacing:.005em;
  min-height:44px; padding:0 22px;
}
.vds-pill--primary:not(.vds-pill--literal){
  background:var(--space); color:#fff;
  box-shadow:0 1px 2px rgba(16,16,24,.16), 0 6px 12px rgba(16,16,24,.13),
             inset 0 0 0 1px rgba(255,255,255,.10);
}
.vds-pill--lg{min-height:52px; padding:0 28px}
.vds-pill--block{width:100%}

/* pricing's full-width panels were opaque white. That was invisible while the
 * page had no ground -- white on paper reads as nothing. With the locked ruled
 * ground behind them they became bands cutting the field, the same defect as
 * .pp-mkt-trust. Only FULL-WIDTH panels are cleared; the plan cards stay
 * opaque, because a card is meant to sit on the ground, not dissolve into it. */
.body-ground > .pricing-endpoint-index,
.body-ground > section > .pricing-endpoint-index{background:transparent}

/* ── NO ART, NO ART BAND ─────────────────────────────────────────────────
 * Measured on /mcp: 23 cards, 3 with a live canvas, 20 without -- and each of
 * those 20 still reserved an average of 152px of empty padding for art that
 * never arrives. Text sits at the top, 150px of nothing sits under it. That is
 * the "data stacked in one corner" the founder has reported on page after
 * page, and it is not a layout bug in the card: it is a promise the page
 * cannot keep.
 *
 * The cause is a hard browser limit, not a mount failure. The page declares 33
 * [data-bloom] hosts and the browser allows ~12 live WebGL contexts, so two
 * thirds of them can never paint no matter what the boot script does.
 *
 * js/vk-locked-boot.js marks what it actually mounts. Anything it did not
 * reach gives its band back and sizes to its content.
 */
/* A sheet without art is an empty rectangle, and that is the single biggest
 * reason a rolled page does not look like the reference. _locked.html has 3
 * cards and all 3 carry bloom; /mcp has 22 and only 3 do. The cause is a hard
 * browser limit -- roughly 12 live WebGL contexts -- so on any page with more
 * than a dozen sheets, most of them can never paint no matter what the boot
 * script does.
 *
 * So the band stays, and a static bloom fills it. Three offset radial gradients
 * in the locked palette, angled like the shader's warp, at the same opacity the
 * live canvas settles to. It does not move, which is the honest trade: a still
 * bloom reads as the same design language; a white rectangle reads as broken.
 */
.sheet:not(:has(canvas)) .sheet__field{
  display:block;
  background:
    radial-gradient(58% 44% at 22% 78%, rgba(236,190,214,.55) 0%, rgba(236,190,214,0) 62%),
    radial-gradient(52% 40% at 72% 88%, rgba(178,196,240,.50) 0%, rgba(178,196,240,0) 60%),
    radial-gradient(70% 50% at 48% 100%, rgba(214,198,238,.46) 0%, rgba(214,198,238,0) 66%);
  filter:blur(6px) saturate(1.05);
}
.sheet:not(:has(canvas)) .sheet__veil{display:block}

/* ── HERO GLYPH, REMOVED ─────────────────────────────────────────────────
 * The small orbit mark above the hero heading. The founder has asked for it
 * gone repeatedly and it kept surviving because it is markup on each page,
 * not a component -- so every CSS pass went straight past it.
 * Hidden rather than deleted from 80-odd files: one line to restore, and no
 * risk of a bad regex eating the heading next to it.
 */
.hero__glyph{display:none !important}

/* ── CARDS SIZE TO THEIR OWN CONTENT ─────────────────────────────────────
 * THE actual cause of "content stacked in one corner", on 60 pages.
 * Measured on /about: a card 456px tall whose content needs 304px -- 158px of
 * text plus a 146px art band. The surplus is not padding and not the band. The
 * card is a GRID ITEM and grid items stretch to the tallest sibling in the
 * row, so one long card drags every short card in its row to the same height
 * and the difference becomes empty space under the copy.
 *
 * align-self:start makes each card as tall as it needs to be. Rows end ragged
 * rather than uniform, which is the trade: a ragged edge reads as a card that
 * fits its content, a uniform edge with 300px of nothing reads as broken.
 *
 * .sheet--center is exempt: that variant centres its content on purpose, and
 * it needs the height to centre within.
 */
.sheet:not(.sheet--center){align-self:start}

/* ── BRAND VIOLET OFF BODY TEXT ──────────────────────────────────────────
 * #7C3AED on eyebrows, chips, mono labels and record ids -- 469 elements on
 * case-studies alone. It is the brand colour, which is why it was left alone
 * pending a decision, but the founder has objected to purple text on page
 * after page, so it goes.
 *
 * It survives exactly where the locked design uses it deliberately: the brand
 * capsule and the link hover. Backgrounds, borders and gradients keep it too
 * -- those are chrome and art, and flattening them would take the capsules and
 * washes with them. This is text only.
 */
.cs-eyebrow, .cs-mono, .cs-chip, .cs-rec__id,
.eyebrow, .kicker, .lbl, .label,
[class*="__eyebrow"], [class*="-eyebrow"]{
  color:var(--muted) !important;
}
.sheet__txt [style*="7C3AED"], .sheet__txt [style*="7c3aed"]{color:var(--ink) !important}

/* Some sheets carry no .sheet__field at all -- /glossary has 79 cards and not
 * one of them has the element the fallback above paints, so 78 stayed blank.
 * Those get the bloom on the card itself, via ::after so no markup changes and
 * nothing already inside the card is displaced. Same three gradients, same
 * palette, pinned to the band the padding already reserves.
 */
.sheet:not(:has(canvas)):not(:has(.sheet__field)){position:relative}
.sheet:not(:has(canvas)):not(:has(.sheet__field))::after{
  content:''; position:absolute; left:0; right:0; bottom:0;
  height:clamp(70px, 38%, 150px); pointer-events:none; z-index:0;
  background:
    radial-gradient(58% 62% at 22% 92%, rgba(236,190,214,.50) 0%, rgba(236,190,214,0) 64%),
    radial-gradient(52% 56% at 72% 100%, rgba(178,196,240,.46) 0%, rgba(178,196,240,0) 62%),
    radial-gradient(70% 66% at 48% 108%, rgba(214,198,238,.42) 0%, rgba(214,198,238,0) 68%);
  filter:blur(5px) saturate(1.05);
}
.sheet:not(:has(canvas)):not(:has(.sheet__field)) > *{position:relative; z-index:1}

/* ── DARK SLAB CTA, COMPACTED ─────────────────────────────────────────────
 * The MCP closing CTA is a .sheet--dark.sheet--slab. The slab reserves a big
 * bottom art band (170px), and on a dark sheet the ember bloom in it is subtle
 * enough that it reads as an empty black slab -- the founder's "ugly black
 * grid" / "dead" complaint. Its 26px top padding also sat the heading right on
 * the dark top edge, reading as clipped against the light grid above.
 *
 * Only this combination is retargeted (measured: mcp.html is the only page
 * that uses it). The band is cut so the CTA is compact and the bloom still
 * peeks, and the heading gets room to breathe off the top edge.
 */
.sheet--dark.sheet--slab{
  padding-top:48px !important;
  padding-bottom:60px !important;
  min-height:0 !important;
  aspect-ratio:auto !important;
}

/* ── BLOOM GATE ─────────────────────────────────────────────────────────
 * Without a bloom canvas the repeating-linear-gradient stripes in ::after
 * render as barcode patterns. Replace with soft radial glows that give the
 * grid colour without stripes. The ::before specular band is already a
 * blurred soft gradient so it stays untouched. */
.grid-flow:not(:has(canvas))::after{
  background:
    radial-gradient(60% 40% at 22% 18%, rgba(124,58,237,.18), transparent 70%),
    radial-gradient(52% 38% at 78% 46%, rgba(56,189,248,.12), transparent 72%),
    radial-gradient(58% 42% at 40% 88%, rgba(167,139,250,.14), transparent 74%) !important;
  background-position:0 0 !important;
}

/* ── VK-SHEET → LOCKED TREATMENT ──────────────────────────────────────────
 * vedika-design-system.css defines .vk-sheet; vk-locked.css defines .sheet.
 * Pages that use .vk-sheet (MCP, research, embed, reports, wix, wordpress,
 * and every page importing vedika-design-system.css) got plain white cards
 * because the locked bloom fallbacks only targeted .sheet. This maps
 * .vk-sheet to the same locked visual: 3px corners, locked shadow, and the
 * bloom gradient fallback that .sheet already carries.
 */
.vk-sheet{
  border-radius:3px !important;
  box-shadow:
    0 1px 2px rgba(16,16,24,.07),
    0 6px 14px rgba(16,16,24,.06),
    0 16px 34px rgba(16,16,24,.06),
    inset 0 1px 0 rgba(255,255,255,.9) !important;
  overflow:hidden;
  position:relative;
}
.vk-sheet:not(:has(canvas)):not(:has(.vk-sheet-blob))::after{
  content:''; position:absolute; left:0; right:0; bottom:0;
  height:clamp(70px, 38%, 150px); pointer-events:none; z-index:0;
  background:
    radial-gradient(58% 62% at 22% 92%, rgba(236,190,214,.50) 0%, rgba(236,190,214,0) 64%),
    radial-gradient(52% 56% at 72% 100%, rgba(178,196,240,.46) 0%, rgba(178,196,240,0) 62%),
    radial-gradient(70% 66% at 48% 108%, rgba(214,198,238,.42) 0%, rgba(214,198,238,0) 68%);
  filter:blur(5px) saturate(1.05);
}
.vk-sheet:not(:has(canvas)):not(:has(.vk-sheet-blob)) > *{position:relative; z-index:1}
.vk-sheet.vk-sheet-dark{background:#0B0B0D !important}
.vk-sheet.vk-sheet-dark h3,.vk-sheet.vk-sheet-dark h2{color:#fff}
.vk-sheet.vk-sheet-dark p{color:rgba(255,255,255,.86)}

/* ── DATA VARIANTS CARRY NO ART, INCLUDING THE STAND-IN ──────────────────
 * The artless-sheet ::after fallback predates the variant taxonomy above, so
 * it was painting its three radials onto tables, lists and code plates — the
 * variants whose whole definition is "no art band". A colour wash under data
 * rows reads as a rendering fault ("random poor colour" on the tool tables).
 * The stand-in stays for showcase sheets; data variants opt out completely. */
.sheet--table::after, .sheet--list::after,
.sheet--code::after, .sheet--noart::after { content: none !important; }

/* ── DARK SHEETS GET A DARK SHADOW STACK AT REST ─────────────────────────
 * The base .sheet shadow ends in `inset 0 1px 0 rgba(255,255,255,.9)` — a
 * white top edge tuned for paper. On .sheet--dark that line reads as a thin
 * wrong border floating on the slab ("weird shadow or border"). The hover
 * state already had the dark stack; rest state now matches it. */
.sheet--dark{box-shadow:
  0 1px 2px rgba(0,0,0,.28),
  0 10px 24px rgba(0,0,0,.28),
  0 30px 60px rgba(0,0,0,.30),
  inset 0 1px 0 rgba(255,255,255,.08)}

/* ── FOUNDER OVERRULE 2026-08-07: EVERY SHEET CARRIES ART, DATA INCLUDED ──
 * The no-art doctrine for data variants read as "missing all sheets art" on
 * page after page. Data sheets now carry a SHALLOW band: rows hold paper
 * under a near-opaque veil, the marble owns only the foot of the card. */
.sheet--table, .sheet--list{padding-bottom:clamp(56px,9%,84px) !important}
.sheet--table .sheet__field, .sheet--list .sheet__field{display:block}
/* Data sheets carry the same standard veil as every other sheet. */
.sheet--table .sheet__veil, .sheet--list .sheet__veil{display:block}
.sheet--table > :not(.sheet__field):not(.sheet__veil),
.sheet--list  > :not(.sheet__field):not(.sheet__veil){position:relative;z-index:2}

/* ── ONE TYPE SCALE INSIDE SHEETS ────────────────────────────────────────
 * Tailwind-classed copy inside sheet__txt rendered at its own sizes and
 * greys next to locked copy at 13.5px/1.55 #33384A — two type voices on one
 * card ("learn font from status page"). Inside light sheets, utility-classed
 * text now lands on the locked sheet scale. Dark sheets keep their own ink. */
.sheet:not(.sheet--dark) .sheet__txt p[class*="text-"],
.sheet:not(.sheet--dark) .sheet__txt span[class*="text-gray"],
.sheet:not(.sheet--dark) .sheet__txt li,
.sheet:not(.sheet--dark) .sheet__txt ol,
.sheet:not(.sheet--dark) .sheet__txt ul{
  font-size:13.5px !important; line-height:1.55 !important; color:#33384A !important}

/* ── WIDE SHEETS: ART OWNS THE BOTTOM HALF, NOT THE WHOLE CARD ───────────
 * The reference composition for horizontal sheets is paper above, flow
 * below — roughly half and half. Painting the field full-bleed and veiling
 * it back approximated that badly ("ours is grids top to bottom, why").
 * On light wide variants the field itself now anchors to the bottom 52%. */
.sheet--step:not(.sheet--dark) .sheet__field,
.sheet--slab:not(.sheet--dark) .sheet__field{
  top:auto; bottom:0; height:52%}
/* Data tables are TALL: a percentage band climbs into the rows. The art
   stays strictly inside the reserved padding band, never under a row. */
.sheet--table .sheet__field,
.sheet--list .sheet__field{
  top:auto; bottom:0; height:92px}
.sheet--step:not(.sheet--dark) .sheet__veil,
.sheet--slab:not(.sheet--dark) .sheet__veil{
  background:linear-gradient(180deg,
    #fff 0%, #fff 44%,
    rgba(255,255,255,.55) 56%,
    rgba(255,255,255,0) 68%)}

/* Table rows join the locked type scale (they carry no .sheet__txt). */
.sheet--table tbody td, .sheet--list tbody td{font-size:13.5px !important; line-height:1.55 !important; color:#33384A !important}
.sheet--table tbody td code, .sheet--list tbody td code{font-size:11.5px !important}

/* ── NO-WEBGL COMPLETENESS ───────────────────────────────────────────────
 * Reviewed in an embedded --no-sandbox browser, the page lost every live
 * canvas and the static path only half-dressed it: pills went flat, light
 * sheet fields went white. Every art surface now has a printed fallback so
 * a WebGL-less viewer still shows the full design language. */
.pill__blob:not(:has(canvas)){
  background:
    radial-gradient(60% 80% at 30% 28%, rgba(167,139,250,.85), transparent 68%),
    radial-gradient(50% 70% at 72% 55%, rgba(56,189,248,.55), transparent 70%),
    radial-gradient(70% 90% at 55% 88%, rgba(236,190,214,.7), transparent 70%),
    radial-gradient(90% 110% at 50% 50%, rgba(255,255,255,.25), transparent 80%);
  filter:blur(4px) saturate(1.1)}
.sheet__field:not(:has(canvas)){display:block;
  background:
    radial-gradient(58% 64% at 22% 88%, rgba(196,181,253,.6) 0%, rgba(196,181,253,0) 64%),
    radial-gradient(52% 56% at 72% 96%, rgba(178,196,240,.55) 0%, rgba(178,196,240,0) 62%),
    radial-gradient(70% 66% at 48% 104%, rgba(236,190,214,.5) 0%, rgba(236,190,214,0) 68%);
  filter:blur(7px) saturate(1.08)}
.sheet--dark .sheet__field:not(:has(canvas)){
  background:
    radial-gradient(58% 64% at 24% 90%, rgba(244,114,94,.4) 0%, transparent 66%),
    radial-gradient(52% 56% at 74% 96%, rgba(167,139,250,.35) 0%, transparent 64%);
  filter:blur(9px) saturate(1.1)}
.vk-footer__wash:not(:has(canvas)){
  background:
    radial-gradient(ellipse 80% 60% at 20% 30%, rgba(124,58,237,.28), transparent 65%),
    radial-gradient(ellipse 60% 50% at 80% 60%, rgba(167,139,250,.24), transparent 62%),
    radial-gradient(ellipse 100% 70% at 50% 85%, rgba(178,196,240,.2), transparent 70%) !important}

/* ── FOUNDER DECISION 2026-08-07 (final): TABLE + LIST TREATMENTS ────────
 * Chosen from the four options explicitly: tool/code tables are DARK EMBER
 * PLATES; light list sheets carry the marble FOOT BAND. Do not reinterpret. */
.sheet--table.sheet--dark{background:#0B0B0D !important;
  padding-bottom:clamp(72px,10%,110px) !important}
.sheet--table.sheet--dark thead th{color:rgba(255,255,255,.6) !important;
  border-bottom:1px solid rgba(255,255,255,.14) !important; background:transparent !important}
.sheet--table.sheet--dark tbody td{color:rgba(255,255,255,.9) !important;
  border-top:1px solid rgba(255,255,255,.08) !important}
.sheet--table.sheet--dark tbody td code{background:rgba(167,139,250,.18) !important;color:#C4B5FD !important}
.sheet--table.sheet--dark tbody tr:hover{background:rgba(255,255,255,.045) !important}
.sheet--table .sheet__field,.sheet--list .sheet__field{display:block}
.sheet--table .sheet__veil,.sheet--list .sheet__veil{display:block}
.sheet--table.sheet--dark .sheet__veil{
  background:linear-gradient(180deg,#0B0B0D 0%,rgba(11,11,13,.94) 52%,rgba(11,11,13,.4) 76%,rgba(11,11,13,0) 96%)}
.sheet--table > :not(.sheet__field):not(.sheet__veil),
.sheet--list  > :not(.sheet__field):not(.sheet__veil){position:relative;z-index:2}
.sheet--list:not(.sheet--dark){padding-bottom:clamp(56px,9%,84px) !important}

/* ── SHEET CONTENT ALWAYS PAINTS ABOVE INJECTED ART ──────────────────────
 * The boot now injects field+veil into any bare .sheet so echoes reach every
 * card on every page. Content that isn't wrapped in .sheet__txt must still
 * sit above the absolutely-positioned field/veil layers. */
.sheet > :not(.sheet__field):not(.sheet__veil){position:relative;z-index:2}

/* Last table row was kissing the foot art band — give the data a breath
   before the strip begins. */
.sheet--table table, .sheet--list table{margin-bottom:16px}
.sheet--table .overflow-x-auto, .sheet--list .overflow-x-auto{margin-bottom:16px}

/* ── KILL THE LEGACY WATERCOLOR PAGE-FIELD ───────────────────────────────
 * vedika-page-field.css paints a full-viewport pastel wash and forces every
 * section transparent (body.vedika-field-on) — that is the "random watercolor
 * bg" the founder kept hitting under hero / FAQ / CTA / the SDK + error cards.
 * The locked bloom + chequer is the only ground. One rule, every page,
 * reversible, no page HTML touched. */
.vedika-page-field,
.vedika-page-field canvas,
canvas.vedika-page-field{display:none !important}
body.vedika-field-on{background:var(--paper) !important}
body.vedika-field-on .sec,
body.vedika-field-on section{background-color:transparent !important}
/* The pink/lavender wash also leaked onto sheet feet as a fallback art band on
 * these legacy pages; when a sheet holds real data (code well, table, definition
 * card) the foot band reads as a stray watercolor strip. Data sheets stay clean. */
.sheet:has(pre) .sheet__field,
.sheet:has(table) .sheet__field,
.sheet:has(.overflow-x-auto) .sheet__field{display:none !important}


/* ── WIDE PILL LABEL + BLOB FIX (global, 2026-08-07) ─────────────────────
 * On full-width form/CTA/submit pills the marble blob bled across the label
 * and per-page "fixes" shrank the label until it wrapped to two lines. Here:
 * the blob is a narrow right-edge accent, the label owns the rest on ONE line,
 * centered. Fixed-width hero/nav/compact/status pills are exempt (their look
 * is already correct). */
.pill:not(.pill--nav):not(.pill--hero):not(.pill--compact):not(.pill--status):not(.pill--panel){
  justify-content:center !important;
  padding-left:26px !important; padding-right:26px !important;
}
.pill:not(.pill--nav):not(.pill--hero):not(.pill--compact):not(.pill--status):not(.pill--panel) .pill__label{
  position:relative; z-index:3;
  min-width:0 !important; max-width:none !important;
  text-align:center; align-items:center;
}
.pill:not(.pill--nav):not(.pill--hero) .pill__label b{ white-space:nowrap; }
.pill:not(.pill--nav):not(.pill--hero) .pill__label span{ white-space:nowrap; }
/* SCOPED wash-protect (was global at v=h and stripped the marble off every
   pill on every page, including the approved mcp hero — reverted). Only
   full-width FORM pills (auth, submit) confine the blob to a right edge so
   it can never wash the label; every other pill keeps the full locked marble. */
.auth-main .pill .pill__blob, .pill--submit .pill__blob, form .pill .pill__blob{
  opacity:.5 !important;
  -webkit-mask:linear-gradient(90deg,transparent 0%,transparent 62%,rgba(0,0,0,.4) 80%,#000 100%) !important;
          mask:linear-gradient(90deg,transparent 0%,transparent 62%,rgba(0,0,0,.4) 80%,#000 100%) !important;
}
/* Engine pill blobs (pp-mkt / cbx) too. */
.pp-mkt-btn::after{ display:none; }

/* TAP TARGETS ON TOUCH SCREENS (UX audit 2026-10-15, lane mobile-perf).
 * Nav links, the mega-menu list and the actions row reach 44px with padding and
 * min-height, so the type scale does not move. */
@media (max-width:900px){
  .nv__brand{min-height:44px}
  .nv__links a,.nv__mega-btn{min-height:44px;align-items:center;box-sizing:border-box}
  .nv__actions .nv__ghost{display:inline-flex;align-items:center;min-height:44px}
  .mg a{display:flex;align-items:center;min-height:44px;box-sizing:border-box}
  .nv__actions .pill--nav{min-height:44px}
}
