/* ==========================================================================
   HOME — hero-3, dashboard mockup, why, features, video, contact glow +
   globe, hero card field. Loaded only by / and /es/.
   ========================================================================== */
/* --------------------------------------------------------------------------
   13. hero-3
   The section is the spec's `mx-auto w-full max-w-5xl overflow-hidden pt-16`
   column. The Ribbon Field sits behind it full-bleed rather than inside the
   column — a 64rem-wide strip of gradient on a white page reads as a bug, and
   the gradient spec calls for a full-bleed element. Nothing else about the
   column changes: `overflow-hidden` still lives on it, which is what clips the
   media panel's right-edge bleed.
   -------------------------------------------------------------------------- */
.hero3 {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--ink-950);

  /* The header is sticky and therefore in flow, which would leave a white
     band above the field. Pull the hero up under it and add the height back
     as padding, so pt-16 is still measured from below the bar and the
     transparent-until-scrolled header has something dark to sit on. */
  margin-top: calc(var(--nav-h) * -1);

  --fg: #fff;
  --fg-muted: rgba(255, 255, 255, 0.78);
  --fg-border: rgba(255, 255, 255, 0.28);
  --fg-card: rgba(255, 255, 255, 0.1);
}

/* Ribbon Field, layer 0 — static banded gradient. Always painted, so no-JS
   and reduced-motion get the full treatment and the canvas has a base. */
.hero3__bg {
  position: absolute;
  inset: 0;
  z-index: -3;
  /* Stacked radials approximating the mesh: a white corner top-right, pale
     blue through the middle, iris weighting the bottom-left. */
  background:
    radial-gradient(115% 85% at 92% 2%, var(--rf-white) 0%, rgba(255, 255, 255, 0) 46%),
    radial-gradient(85% 75% at 68% 22%, var(--rf-sky) 0%, rgba(120, 184, 249, 0) 58%),
    radial-gradient(120% 115% at 4% 104%, var(--rf-iris) 0%, rgba(77, 47, 249, 0) 72%),
    linear-gradient(214deg, var(--rf-sky) 0%, var(--rf-ultramarine) 46%, var(--rf-iris) 100%);
}

/* Layer 1 — animated canvas, drawn small and upscaled. */
.hero3__canvas {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 600ms var(--ease-out);
  /* The mesh is drawn ~220px wide; the upscale plus this blur is what makes
     the patches read as soft cloud rather than as low-res blocks. The scale
     overscans so the blur has no transparent edge to smear inward. */
  filter: blur(22px);
  transform: scale(1.1);
}
.hero3__canvas.is-ready { opacity: 1; }

/* The hero already stacks bg(-3) / canvas(-2) / grain(-1). The aurora sits at
   -1 so it reads over the ribbon field, and DOM order puts the grain above it.
   Lower opacity here so it tints the mesh rather than competing with it. */
.hero3 .aurora { z-index: -1; opacity: 0.18; }

/* Layer 2 — spec grain (120px tile, 0.210) over two scrims. The scrims are a
   contrast requirement: the palette's pale end is pure white and the copy is
   white on top of it. */
.hero3__grain {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    /* Re-centred and strengthened: the copy is centred now and carries no wash
       of its own, so this is the only thing standing between white type and
       the pale end of the mesh. Wide and soft enough to read as part of the
       gradient rather than as a shape. */
    radial-gradient(88% 62% at 50% 30%,
      rgba(8, 12, 42, 0.40) 0%,
      rgba(8, 12, 42, 0.28) 52%,
      rgba(8, 12, 42, 0) 100%),
    linear-gradient(180deg, rgba(8, 12, 42, 0.06) 0%, rgba(8, 12, 42, 0.04) 55%, rgba(8, 12, 42, 0.20) 100%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='0.360'/%3E%3C/svg%3E");
  background-size: auto, auto, 120px 120px;
  background-blend-mode: normal, normal, overlay;
}

/* The spec column. */
.hero3__container {
  position: relative;
  width: 100%;
  max-width: 64rem;            /* max-w-5xl */
  margin-inline: auto;
  overflow: hidden;
  padding-top: calc(4rem + var(--nav-h));   /* pt-16, below the sticky bar */
  padding-bottom: 4rem;
}

/* Shades: radial-gradient(20% 80% at 20% 0%, foreground/.1, transparent) */
.hero3__shades {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
}
.hero3__shades::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(20% 80% at 20% 0%, rgba(255, 255, 255, 0.1), transparent);
}

.hero3__copy {
  position: relative;
  z-index: 10;
  display: flex;
  flex-direction: column;
  /* Centred rather than the spec's left column: the card ring now sits behind
     this block, and a centred ring behind left-aligned copy reads as two
     unrelated things that happen to overlap. Both are on the same axis now. */
  align-items: center;
  text-align: center;
  gap: 1.5rem;
  max-width: 46rem;
  margin-inline: auto;
  padding-inline: 1rem;        /* px-4 */
}

/* Readability wash. The ring crosses the copy at this radius, and the card
   faces include a pure-white logo tile — white type over one of those is 1:1.
   So this is a contrast floor, not decoration, and it is measured: at alpha
   .66 over a white card face the headline holds ~6:1.

   A blurred rounded rect rather than a radial gradient. An ellipse wide enough
   to cover the copy box's corners has to extend far past it, so it darkens a
   lot of hero to protect a little text; this covers the box at close to full
   alpha and fades over ~70px, which is both tighter and cheaper.

   z-index -1 inside .hero3__copy, which is a z-index:10 stacking context, so
   it paints above the cards (z-index -1 on .hero3) and below the type. */
.hero3__copy::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 50%;
  width: calc(100% + 120px);
  height: calc(100% + 96px);
  transform: translate(-50%, -50%);
  pointer-events: none;
  background: rgba(6, 10, 38, 0.66);
  border-radius: 56px;
  filter: blur(36px);
}

/* --- Badge --------------------------------------------------------------- */
.hero3__badge {
  display: flex;
  align-items: center;
  gap: 0.75rem;                /* gap-3 */
  width: fit-content;
  padding: 0.25rem;            /* p-1 */
  color: var(--fg);
  background: var(--fg-card);
  border: 1px solid var(--fg-border);
  border-radius: var(--radius-pill);
  padding-right: 0.5rem;
  box-shadow: var(--shadow-card);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.hero3__badge-chip {
  padding: 0.125rem 0.375rem;  /* px-1.5 py-0.5 */
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.75rem;          /* text-xs */
  line-height: 1.25;
  background: var(--fg-card);
  border: 1px solid var(--fg-border);
  border-radius: 0.125rem;     /* rounded-xs */
  box-shadow: var(--shadow-card);
}

.hero3__badge-label { font-size: 0.75rem; }

.hero3__badge-rule {
  display: block;
  height: 1.25rem;             /* h-5 */
  border-left: 1px solid var(--fg-border);
}

.hero3__badge-arrow { padding-right: 0.25rem; }        /* pr-1 */
.hero3__badge-arrow svg {
  display: block;
  width: 0.75rem;              /* size-3 */
  height: 0.75rem;
  transform: translateX(-0.125rem);
  transition: transform 150ms var(--ease-out);
}
.hero3__badge:hover .hero3__badge-arrow svg { transform: translateX(0.125rem); }

/* --- Type ---------------------------------------------------------------- */
.hero3__title {
  font-family: var(--font-display);
  /* Departs from the spec's text-4xl/md:text-5xl font-medium. The headline is
     the hero's whole visual weight now that nothing sits behind it: heavy,
     tight, and scaled off the viewport rather than stepped at one breakpoint. */
  font-weight: 700;
  font-size: clamp(2.5rem, 6vw, 5rem);
  line-height: 1.04;
  /* -0.02em, not the -0.035em this carried under Space Grotesk: Clash Display
     already ships tight sidebearings, and at 5rem the old value closed the
     word gaps until the line read as one word. Same call as .lp-hero__h. */
  letter-spacing: -0.02em;
  word-spacing: 0.04em;
  text-wrap: balance;
  color: var(--fg);
}

.hero3__sub {
  /* Tracking back to normal: the spec's tracking-wider was set against a
     small subhead, and at this size it reads as letter-spaced display type
     rather than as body copy under a headline. */
  font-size: clamp(1rem, 1.5vw, 1.25rem);
  line-height: 1.55;
  letter-spacing: 0;
  max-width: 40rem;
  color: var(--fg-muted);
}

.hero3__actions {
  display: flex;
  align-items: center;
  /* The spec says justify-center; inside a w-fit single row that is identical
     to flex-start. It only differs once the row wraps, where centring would
     indent the buttons away from the left-aligned copy. */
  justify-content: center;
  gap: 0.75rem;
  width: fit-content;
  padding-top: 0.75rem;
  /* Not in the spec, which pairs "Book a Call" with "Get started". Our real
     CTA labels are longer and run off a 390px screen, and the column clips
     rather than scrolls. Wrapping keeps the spec's single row wherever it
     fits and only breaks it when it would otherwise be cut off. */
  flex-wrap: wrap;
}

/* Scaled up from the shared .ui-btn h-10/text-sm. The buttons sit under a
   5rem headline; the spec's control size reads as a form field there. */
.hero3__actions .ui-btn {
  height: 3.25rem;
  padding-inline: 1.5rem;
  font-size: 1rem;
  /* Restated, not inherited: this selector outranks the liquid-glass block at
     the bottom of the file, so dropping the line here leaves the hero pair on
     the old 8px while every other button on the page is a pill. */
  border-radius: var(--radius-pill);
}
.hero3__actions .ui-btn svg { width: 1.125rem; height: 1.125rem; }

/* Standfirst under the CTAs — the qualifier that keeps the pair of buttons
   from being the last thing on the screen. */
.hero3__note {
  font-size: var(--fs-sm);
  color: rgba(255, 255, 255, 0.88);
}

/* The hero runs on the dark field, so the shadcn tokens invert here. */
.hero3__actions .ui-btn {
  --ui-primary: rgba(255, 255, 255, 0.92);
  --ui-primary-hover: rgba(255, 255, 255, 0.99);
  --ui-primary-fg: var(--ink-950);
  --ui-ring: #fff;
}
.hero3__actions .ui-btn--outline {
  --ui-fg: #fff;
  --ui-input: var(--fg-border);
  --ui-accent: rgba(255, 255, 255, 0.18);

  /* Ink-tinted glass, not white-tinted. Everywhere else the glass veil is
     white because the label is either dark (light sections) or the backdrop is
     reliably dark (features/contact/footer). Here the label is white and the
     backdrop is the ribbon field, whose pale end is literally #ffffff — a
     white veil there measures 2.31:1. Same material, same blur, border, rim
     and radius; only the tint of the veil inverts, which is what keeps the
     label legible across the whole gradient (6.0:1 at the palest point,
     14.6:1 at the deepest). */
  --glass-fill: rgba(6, 10, 38, 0.42);
  --glass-fill-hover: rgba(6, 10, 38, 0.55);
  --glass-border: rgba(255, 255, 255, 0.28);
  --glass-hi: rgba(255, 255, 255, 0.20);
}

/* --- Media --------------------------------------------------------------- */
.hero3__media { position: relative; }

/* The authoritative disclaimer for the dashboard mock. It lives OUTSIDE
   .hero3__frame on purpose: the frame clips (overflow:hidden) and at mobile the
   panel is ~600px inside a 375px viewport, so the in-panel `.d-top__right` label
   sits entirely off-screen and the panel is not draggable to reveal it. Sized in
   rem, not the panel's cqw em scale, so it cannot shrink with the mock. The
   in-panel label stays for desktop replica fidelity; this one is what a mobile
   visitor actually reads. */
/* A glass chip, not bare text on the field, and the reason is measured. The card
   ring drifts behind this line and the ribbon field runs bright violet here;
   bare white text sampled 2.11:1 against a pale card tile and 4.08-4.42:1
   against the field even with a blurred wash behind it, because a blur has no
   hard edge and the worst pixel always sits where it has fallen off. An opaque
   ink veil gives a KNOWN backdrop instead of a soft one: 11.7:1 over the palest
   card, 14.2:1 over the brightest field pixel measured here. Same ink veil the
   hero buttons use, and for the same reason — see "Buttons are glass". */
.hero3__disclaimer {
  width: fit-content;
  /* Gutter, not 100%: the Spanish string is long enough to fill a 375px viewport
     edge to edge, which clips the pill's own corners against the screen. */
  max-width: calc(100% - 32px);
  margin: 16px auto 0;
  padding: 7px 16px;
  font-size: var(--fs-sm);
  line-height: 1.45;
  text-align: center;
  color: #fff;
  text-wrap: balance;
  background: rgba(6, 10, 38, 0.72);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-pill);
  box-shadow: inset 0 1px 0 var(--glass-hi);
}

.hero3__glow {
  position: absolute;
  left: -5rem;                 /* -inset-x-20 */
  right: -5rem;
  top: 0;
  bottom: 0;
  transform: translateY(-33.333%) scale(1.2);
  border-radius: var(--radius-pill);
  background: radial-gradient(ellipse at center,
    rgba(255, 255, 255, 0.1), transparent, transparent);
  filter: blur(50px);
  pointer-events: none;
}

.hero3__frame {
  position: relative;
  margin-top: 2rem;            /* mt-8 */
  margin-right: -14rem;        /* -mr-56 */
  padding-inline: 0.5rem;      /* px-2 */
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, #000 60%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 60%, transparent 100%);
}
@media (min-width: 640px) { .hero3__frame { margin-top: 3rem; margin-right: 0; } }
@media (min-width: 768px) { .hero3__frame { margin-top: 5rem; } }

.hero3__panel {
  /* Query container for the dashboard inside. This has to sit on the wrapper,
     not on .dash itself — an element is a container for its descendants, never
     for its own properties, so `font-size: 1.25cqw` declared on .dash would
     resolve against the viewport instead. */
  container-type: inline-size;
  position: relative;
  max-width: 64rem;
  margin-inline: auto;
  padding: 0.5rem;             /* p-2 */
  overflow: hidden;
  background: var(--ink-950);
  border: 1px solid var(--fg-border);
  border-radius: var(--radius-sm);   /* rounded-lg */
  box-shadow: var(--shadow-card-lg),
              0 0 0 1px var(--fg-card),
              inset 0 1px 1px rgba(255, 255, 255, 0.1);
}

.hero3__img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border: 1px solid var(--fg-border);
  border-radius: var(--radius-sm);
}

/* --- Entrance ------------------------------------------------------------
   fade-in + slide-in-from-bottom-10 (2.5rem), 500ms, fill-mode backwards.
   Delays: h1 100, subhead 200, actions 300, badge 500. The media frame is
   slide-in-from-bottom-5 (1.25rem) over 1000ms at 100. */
.animate-in {
  animation: enterUp 500ms var(--ease-out) backwards;
  animation-delay: var(--enter-delay, 0ms);
  --enter-rise: 2.5rem;
}
.animate-in--slow { animation-duration: 1000ms; --enter-rise: 1.25rem; }

@keyframes enterUp {
  from { opacity: 0; transform: translateY(var(--enter-rise)); }
  to   { opacity: 1; transform: none; }
}

.no-js .animate-in { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .animate-in { animation: none; }
  .hero3__canvas { display: none; }
}

/* --------------------------------------------------------------------------
   14. Hero dashboard mockup
   A close replica of the reference product screenshot, built in markup rather
   than shipped as an image: crisp at any density, no new asset, and the copy
   is real text. Sized in `em` from one `font-size: 1.15cqw`, so it scales with
   its container like a screenshot would. Design width 960px (1.15cqw = 11px).
   The query container is .hero3__panel — see the note there.
   -------------------------------------------------------------------------- */
.dash {
  display: flex;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  font-family: var(--font-body);
  font-size: 1.15cqw;
  line-height: 1.35;
  color: var(--d-fg);
  background: var(--d-bg);
  border-radius: var(--radius-xs);
  letter-spacing: -0.005em;

  --d-bg: #09090b;
  --d-card: #101012;
  --d-line: #1e1e22;
  --d-line-soft: #17171a;
  --d-fg: #ededef;
  --d-mut: #7c7c86;
  --d-dim: #55555e;
  --d-hi: #1a1a1e;
  --d-ok: #3ecf8e;
}

@supports not (container-type: inline-size) { .dash { font-size: 0.7rem; } }

.dash i { font-style: normal; }

/* Small outline glyph standing in for the reference's icon set. */
.d-ico {
  width: 0.95em;
  height: 0.95em;
  flex: none;
  border: 1px solid currentColor;
  border-radius: 0.2em;
  opacity: 0.75;
}
.d-ico--round { border-radius: 50%; }

/* --- Sidebar ------------------------------------------------------------- */
.d-side {
  flex: none;
  width: 15.2%;
  display: flex;
  flex-direction: column;
  padding: 0.65em 0.55em;
  gap: 0.15em;
  border-right: 1px solid var(--d-line);
}

.d-org {
  display: flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.3em 0.35em 0.55em;
  font-size: 0.92em;
  font-weight: 500;
}
.d-org img { width: 1.15em; height: 1.15em; border-radius: 50%; }

.d-quick { display: flex; align-items: center; gap: 0.3em; margin-bottom: 0.5em; }
.d-quick__btn {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.35em 0.45em;
  font-size: 0.82em;
  font-weight: 500;
  background: var(--d-hi);
  border: 1px solid var(--d-line);
  border-radius: 0.35em;
}
.d-quick__mail {
  display: grid;
  place-items: center;
  width: 1.7em;
  height: 1.7em;
  border: 1px solid var(--d-line);
  border-radius: 0.35em;
  color: var(--d-mut);
}

.d-nav { display: flex; flex-direction: column; gap: 0.05em; }

.d-link {
  display: flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.3em 0.4em;
  font-size: 0.82em;
  color: var(--d-mut);
  border-radius: 0.3em;
}
.d-link--on { color: var(--d-fg); background: var(--d-hi); }

.d-cap {
  padding: 0.75em 0.4em 0.3em;
  font-size: 0.78em;
  color: var(--d-dim);
}

.d-side__foot { margin-top: auto; display: flex; flex-direction: column; gap: 0.05em; }

.d-user {
  display: flex;
  align-items: center;
  gap: 0.45em;
  margin-top: 0.5em;
  padding: 0.4em 0.35em;
  border-top: 1px solid var(--d-line);
}
.d-user__av {
  width: 1.55em;
  height: 1.55em;
  flex: none;
  border-radius: 0.35em;
  background: linear-gradient(140deg, #4d8bff, #7a4dff);
}
.d-user__name { font-size: 0.8em; font-weight: 500; line-height: 1.2; }
.d-user__mail { font-size: 0.7em; color: var(--d-dim); line-height: 1.2; }
.d-user__chev { margin-left: auto; color: var(--d-dim); font-size: 0.7em; }

/* --- Main ---------------------------------------------------------------- */
.d-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.d-top {
  display: flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.55em 0.9em;
  font-size: 0.85em;
  border-bottom: 1px solid var(--d-line);
}
.d-top__sep { width: 1px; height: 1em; background: var(--d-line); }
/* Floored out of the panel's em scale on purpose. Everything in .dash sizes from
   1.15cqw, which at a 390px viewport rendered this label at ~5px hard against the
   screen edge — a data disclaimer that itself needed a disclaimer. The floor and
   the padding are px, NOT em, so they cannot shrink with the panel; the panel
   overflows the viewport by ~14px on the right at 390px and is not draggable, so
   the padding has to clear that on its own. */
.d-top__right {
  margin-left: auto;
  color: var(--d-mut);
  font-size: max(10px, 0.95em);
  padding-right: 12px;
  min-width: 0;
}

/* --- Stat cards ---------------------------------------------------------- */
.d-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.75em;
  padding: 0.8em 0.9em 0;
}

.d-card {
  padding: 0.7em 0.75em;
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: 0.5em;
}

.d-card__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.4em;
  font-size: 0.78em;
  color: var(--d-mut);
}

.d-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.2em;
  padding: 0.1em 0.4em;
  font-size: 0.92em;
  color: var(--d-fg);
  border: 1px solid var(--d-line);
  border-radius: 1em;
  white-space: nowrap;
}

.d-card__num {
  margin: 0.3em 0 0.55em;
  font-size: 2.1em;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
}

.d-card__note {
  display: flex;
  align-items: center;
  gap: 0.3em;
  font-size: 0.78em;
  font-weight: 500;
}
.d-card__sub { font-size: 0.78em; color: var(--d-mut); }

/* --- Chart --------------------------------------------------------------- */
.d-chart {
  margin: 0.75em 0.9em 0;
  padding: 0.75em 0.85em 0.5em;
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: 0.5em;
}
.d-chart__head { display: flex; align-items: flex-start; justify-content: space-between; }
.d-chart__title { font-size: 0.88em; font-weight: 500; }
.d-chart__sub { font-size: 0.78em; color: var(--d-mut); }

.d-seg {
  display: flex;
  padding: 0.13em;
  background: var(--d-hi);
  border: 1px solid var(--d-line);
  border-radius: 0.35em;
}
.d-seg span {
  padding: 0.22em 0.55em;
  font-size: 0.75em;
  color: var(--d-mut);
  border-radius: 0.25em;
}
.d-seg span.on { color: var(--d-fg); background: #26262b; }

.d-chart svg { width: 100%; height: 8.2em; margin-top: 0.5em; display: block; }

.d-axis {
  display: flex;
  justify-content: space-between;
  margin-top: 0.25em;
  font-size: 0.68em;
  color: var(--d-dim);
}

/* --- Tab row ------------------------------------------------------------- */
.d-tabs {
  display: flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.8em 0.9em 0.55em;
}
.d-tab {
  display: flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.28em 0.55em;
  font-size: 0.78em;
  color: var(--d-mut);
  border-radius: 0.3em;
}
.d-tab--on { color: var(--d-fg); background: var(--d-hi); }
.d-pillnum {
  padding: 0 0.3em;
  font-size: 0.88em;
  background: #26262b;
  border-radius: 1em;
}
.d-tabs__right { margin-left: auto; display: flex; gap: 0.35em; }
.d-btn {
  display: flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.28em 0.5em;
  font-size: 0.78em;
  color: var(--d-fg);
  border: 1px solid var(--d-line);
  border-radius: 0.35em;
}

/* --- Table --------------------------------------------------------------- */
.d-table { padding: 0 0.9em; }
.d-grid { width: 100%; border-collapse: collapse; font-size: 0.8em; }

.d-grid th {
  padding: 0.45em 0.5em;
  text-align: left;
  font-weight: 400;
  color: var(--d-mut);
  background: var(--d-card);
  border-block: 1px solid var(--d-line);
}
.d-grid th:first-child { border-radius: 0.35em 0 0 0.35em; }
.d-grid th:last-child { border-radius: 0 0.35em 0.35em 0; }

.d-grid td {
  padding: 0.5em 0.5em;
  border-bottom: 1px solid var(--d-line-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.d-grid td:nth-child(3),
.d-grid td:nth-child(4) { color: var(--d-mut); }
.d-grid .num { text-align: right; }
.d-grid .rev { color: var(--d-mut); }

.d-check {
  width: 0.85em;
  height: 0.85em;
  border: 1px solid #3a3a42;
  border-radius: 0.2em;
  display: inline-block;
}
.d-drag { color: var(--d-dim); letter-spacing: -0.15em; }
.d-more { color: var(--d-dim); text-align: right; }

.d-state { display: inline-flex; align-items: center; gap: 0.35em; }
.d-state i {
  width: 0.55em;
  height: 0.55em;
  flex: none;
  border-radius: 50%;
  border: 1px solid var(--d-mut);
}
.d-state--done i { background: var(--d-ok); border-color: var(--d-ok); }

/* --------------------------------------------------------------------------
   15. Why Loredo Labs — the section under the hero
   Editorial split: the origin story in a narrow left column, the thesis and
   the commitments on the right. No icon tiles, no cards — the hero above is
   the loud element, so this one is quiet and precise. Brand blue appears
   exactly once, on the diagonal cut mark, which is the painter's motif the
   original export used as its `.stroke`.
   -------------------------------------------------------------------------- */
.why {
  /* FIX 6: the lone hairline is gone — no other section had one, and the
     reconciled dark palette now carries the transition. */
  position: relative;
  padding-block: var(--section-y);
  background: var(--surface-0);
  --fade-rgb: 7, 12, 22;      /* --surface-deep */
}

/* The hero -> why join ramps on the HERO side, unlike the others. A band on
   why's top would have to start from a fixed colour, and the hero's bottom
   edge is the animated ribbon field — bright indigo at this scroll position,
   near-black elsewhere. Any constant is wrong most of the time, and measured
   against the real thing it looked worse than the hard cut it replaced.
   Ramping to white from the hero side is colour-agnostic: whatever the field
   is doing, it arrives at the next section's white.

   Shorter than the other bands (96px) because the dashboard panel bleeds to
   within ~105px of the hero's bottom edge, and this paints above it. */
.hero3::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 96px;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0)    0%,
    rgba(255, 255, 255, 0.06) 22%,
    rgba(255, 255, 255, 0.24) 44%,
    rgba(255, 255, 255, 0.56) 65%,
    rgba(255, 255, 255, 0.85) 83%,
    rgba(255, 255, 255, 1)    100%
  );
}


.why__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: 48px;
}
@media (min-width: 1024px) {
  .why__inner {
    grid-template-columns: 17rem minmax(0, 1fr);
    gap: 96px;
  }
}

/* --- Left: the origin ---------------------------------------------------- */
/* The story is short and the list is tall, which left a dead column beside it.
   Pinning the story makes the asymmetry intentional: the origin stays with you
   while you read what came out of it. */
@media (min-width: 1024px) {
  .why__aside {
    position: sticky;
    top: calc(var(--nav-h) + 48px);
    align-self: start;
  }
}

.why__eyebrow {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-300);
}

.why__story {
  margin-top: 20px;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--ink-700);
  text-wrap: pretty;
}

.why__by {
  margin-top: 20px;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--ink-500);
}
.why__by b { display: block; font-weight: 600; color: var(--ink-950); }

/* --- Right: thesis + commitments ----------------------------------------- */
/* The cut mark. One 4px diagonal, brand blue — the only colour in the block. */
.why__mark {
  display: block;
  width: 4px;
  height: 30px;
  margin-bottom: 26px;
  background: var(--blue-brand);
  border-radius: 1px;
  transform: skewX(-18deg);
}

/* The thesis. First sentence solid, second ghosted: the work was present,
   the system was not. The type says what the sentence says. */
.why__thesis {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.875rem, 4.1vw, 3.25rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
  word-spacing: 0.03em;
  color: var(--ink-950);
  text-wrap: balance;
}
.why__thesis span {
  display: block;
  color: var(--ink-300);
}

.why__list { margin-top: 56px; }

.why__row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 6px;
  padding-block: 22px;
  border-top: 1px solid var(--border);
}
/* Close the list. Without it the index ends mid-air. */
.why__row:last-child { border-bottom: 1px solid var(--border); }
@media (min-width: 640px) {
  .why__row {
    grid-template-columns: 13rem minmax(0, 1fr);
    gap: 32px;
    align-items: start;
  }
}

.why__row-title {
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.45;
  color: var(--ink-950);
}

.why__row-text {
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--ink-500);
  text-wrap: pretty;
}

/* --------------------------------------------------------------------------
   17. Features / Services — two 21st.dev specs placed side by side
   Left: the bento feature grid. Right: the Spline card with the mouse-tracked
   spotlight. Neither spec was written to sit beside the other, so the only
   invented rule is the split itself (58/42, header full width above, bento
   internal grid dropped from 4 columns to 2 inside its column). Everything
   within each card follows its spec.
   -------------------------------------------------------------------------- */
.feat {
  position: relative;
  padding-block: var(--section-y);
  overflow: hidden;
  background: var(--f-bg);
  color: var(--f-fg);
  --fade-rgb: 255, 255, 255;  /* --surface-0 */

  /* Re-hued from Tailwind zinc onto the brand's 220deg. Lightness is
     unchanged step for step, so the section reads exactly as designed — only
     the neutral grey cast is gone, which is what made zinc cards on a navy
     page look like a colour bug once --f-bg was reconciled. */
  --f-bg: var(--surface-deep);
  --f-card: #0b0f17;
  --f-card-2: #101621;
  --f-line: #1d2534;
  --f-line-hi: #2d384f;
  --f-fg: #fafafa;
  --f-mut: #a1a1aa;
  --f-dim: #71717a;
}


.feat__inner {
  display: flex;
  flex-direction: column;
  gap: 48px;
  /* Was max-w-7xl with its own 1rem/2rem section padding, which put the
     heading 80px left of every other section's text edge. This is .container's
     geometry, declared inline rather than by class because the section markup
     is a port and keeps its own wrapper. */
  max-width: var(--max-content);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* --- Section header ------------------------------------------------------ */
.feat__head { display: flex; flex-direction: column; gap: 20px; max-width: 48rem; }

.feat__pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  width: fit-content;
  padding: 8px 16px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--f-mut);
  background: var(--f-card-2);
  border: 1px solid var(--f-line);
  border-radius: var(--radius-pill);
}
.feat__pill svg { width: 1rem; height: 1rem; color: var(--f-fg); }

.feat__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.25rem, 4.6vw, 3.5rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
  word-spacing: 0.03em;
  color: var(--f-fg);
  text-wrap: balance;
}

.feat__sub {
  max-width: 42rem;
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--f-mut);
}

/* --- Stacked: bento above, Spline card below ----------------------------- */
/* Full width for each, which is what both specs were drawn for — the bento
   gets its real 4-column grid back, and the scene gets room to read. */
.feat__cols { display: flex; flex-direction: column; gap: 20px; }

/* --- Bento --------------------------------------------------------------- */
.bento {
  display: grid;
  grid-template-columns: 1fr;
  grid-auto-rows: minmax(260px, auto);
  gap: 16px;
}
@media (min-width: 640px) { .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) {
  /* The spec pins rows at 280px; our real copy is taller than its filler, so
     rows may grow. Fixed 280 clipped the outcome rows and the integrations. */
  .bento { grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: minmax(280px, auto); }
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  overflow: hidden;
  padding: 24px;
  background: var(--f-card);
  border: 1px solid var(--f-line);
  border-radius: var(--radius-md);
  transition: border-color 0.3s var(--ease-out);
}
.card:hover { border-color: var(--f-line-hi); }

@media (min-width: 640px) {
  .card--wide { grid-column: span 2; }
  .card--tall { grid-column: span 2; grid-row: span 2; }
}
.card--tall { padding: 32px; }

.card__chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  width: fit-content;
  padding: 4px 12px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--f-mut);
  background: var(--f-card-2);
  border: 1px solid var(--f-line);
  border-radius: var(--radius-sm);
}
.card__chip svg { width: 0.875rem; height: 0.875rem; }

.card__icon {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  color: var(--f-fg);
  background: var(--f-card-2);
  border: 1px solid var(--f-line);
  border-radius: var(--radius-sm);
}
.card__icon svg { width: 1.125rem; height: 1.125rem; }

.card__h {
  margin-top: 16px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.75rem;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--f-fg);
}
.card__h--sm { margin-top: 12px; font-size: 0.9375rem; letter-spacing: -0.01em; }
.card__p { margin-top: 6px; font-size: 0.8125rem; line-height: 1.55; color: var(--f-mut); }

/* Feature selector — 2x2 grid of buttons */
.card__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-top: 24px;
}

.pick {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 14px;
  text-align: left;
  background: var(--f-card-2);
  border: 1px solid var(--f-line);
  border-radius: var(--radius);
  transition: background-color 0.3s var(--ease-out), border-color 0.3s var(--ease-out);
}
.pick:hover { border-color: var(--f-line-hi); }
.pick[aria-selected="true"] { background: #26262b; border-color: #4a4a54; }
.pick svg { width: 1.25rem; height: 1.25rem; color: var(--f-dim); transition: color 0.3s var(--ease-out); }
.pick[aria-selected="true"] svg { color: var(--f-fg); }
.pick b { font-size: 0.75rem; font-weight: 700; color: var(--f-fg); }
.pick span { font-size: 0.6875rem; color: var(--f-mut); }

/* Selected-feature readout */
.readout {
  margin-top: 20px;
  padding: 16px;
  background: var(--f-card-2);
  border: 1px solid var(--f-line);
  border-radius: var(--radius);
}
.readout__lab {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.6875rem;
  color: var(--f-dim);
}
.readout__t { margin-top: 4px; font-size: 1.0625rem; font-weight: 700; color: var(--f-fg); }
.readout__d { margin-top: 4px; font-size: 0.75rem; line-height: 1.5; color: var(--f-mut); }
.readout__s {
  margin-top: 12px;
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--f-fg);
}

/* Before / After toggle replacing the spec's "Live" badge */
.toggle { display: flex; padding: 2px; background: var(--f-card-2); border: 1px solid var(--f-line); border-radius: var(--radius-sm); }
.toggle button {
  padding: 4px 10px;
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--f-mut);
  border-radius: var(--radius-xs);
}
.toggle button[aria-selected="true"] { color: var(--f-fg); background: #2f2f37; }

.rows { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }
.row {
  padding: 10px 12px;
  text-align: left;
  background: var(--f-card-2);
  border: 1px solid var(--f-line);
  border-radius: var(--radius-sm);
  transition: background-color 0.2s var(--ease-out), border-color 0.2s var(--ease-out);
}
.row:hover { border-color: var(--f-line-hi); }
.row[aria-selected="true"] { background: #26262b; border-color: #4a4a54; }
.row b { display: block; font-size: 0.625rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--f-dim); }
.row span { display: block; margin-top: 3px; font-size: 0.75rem; line-height: 1.45; color: var(--f-fg); }

/* Integrations */
.ints { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 16px; }
.int {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 12px 6px;
  background: var(--f-card-2);
  border: 1px solid var(--f-line);
  border-radius: var(--radius-sm);
  transition: border-color 0.2s var(--ease-out);
}
.int:hover { border-color: var(--f-line-hi); }
.int svg { width: 1.125rem; height: 1.125rem; color: var(--f-fg); transition: transform 0.2s var(--ease-out); }
.int:hover svg { transform: scale(1.2); }
.int span { font-size: 0.5625rem; line-height: 1.3; text-align: center; color: var(--f-dim); }

/* Terminal / system flow */
.term {
  margin-top: 16px;
  padding: 16px;
  overflow: auto;
  background: #000;
  border: 1px solid var(--f-line);
  border-radius: var(--radius-sm);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.75rem;
  line-height: 1.75;
}
.term__l { display: flex; gap: 10px; }
.term__n { width: 1.25rem; text-align: right; color: #52525b; user-select: none; flex: none; }
.term__c { color: var(--f-mut); white-space: pre; }
.term__c--hi { color: var(--f-fg); }
.term__c--dim { color: #52525b; }

/* --- Spline card --------------------------------------------------------- */
.spline {
  position: relative;
  display: flex;
  flex-direction: column;
  /* Mobile height is content + a fixed scene, not a fixed card height: pinning
     the card at 560 while the scene needs 340 would squeeze the copy instead. */
  height: auto;
  overflow: hidden;
  background: #000;
  border: 1px solid var(--f-line);
  border-radius: var(--radius-md);
}
/* Copy left, scene right — the spec's row layout. The scene takes the larger
   share so the figure reads at size rather than being cropped into a sliver. */
@media (min-width: 768px) { .spline { flex-direction: row; height: 560px; } }
@media (min-width: 1280px) { .spline { height: 620px; } }

.spline__copy {
  position: relative;
  z-index: 10;
  display: flex;
  flex: none;
  flex-direction: column;
  justify-content: center;
  padding: 28px;
}
@media (min-width: 768px) { .spline__copy { flex: 0 1 44%; padding: 40px; } }
@media (min-width: 1280px) { .spline__copy { padding: 56px; } }

.spline__h {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.75rem, 3.4vw, 3rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  word-spacing: 0.03em;
  background: linear-gradient(to bottom, #fafafa, #a1a1aa);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  text-wrap: balance;
}

.spline__p { margin-top: 16px; font-size: 0.9375rem; line-height: 1.6; color: #d4d4d8; }

.spline__list { margin-top: 18px; display: grid; gap: 8px; }
.spline__list li { display: flex; gap: 8px; font-size: 0.8125rem; line-height: 1.5; color: var(--f-mut); }
.spline__list svg { flex: none; width: 0.875rem; height: 0.875rem; margin-top: 0.25em; color: var(--f-fg); }

/* Scene holder. Keeps its box whether or not the runtime ever arrives. */
/* Mobile: a fixed 340px stage. At 240 the figure was too small to read as
   something you can interact with, which is the whole reason for keeping the
   real scene over a static fallback. */
.spline__scene {
  position: relative;
  flex: none;
  align-self: stretch;
  height: 340px;
}
@media (min-width: 768px) { .spline__scene { flex: 1 1 56%; height: auto; } }

/* Pin the viewer to the box rather than sizing it with height:100%. The custom
   element has its own intrinsic size, and a percentage height against a
   stretched flex item is not reliably definite — when it resolved to `auto`
   the whole scene column collapsed to the element's intrinsic ~164px. */
.spline__scene spline-viewer {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}
/* Kill the viewer's "Built with Spline" badge. It sits in the component's
   shadow DOM, so the ::part hook only lands on builds that expose it — the
   JS in site.js strips the node directly as the reliable path. */
.spline__scene spline-viewer::part(logo) { display: none !important; }

/* Fallback painted underneath: a soft figure-shaped glow, so a blocked CDN or
   a reduced-motion visitor still sees a composed card rather than a hole. */
.spline__fallback {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background:
    radial-gradient(38% 30% at 50% 34%, rgba(255, 255, 255, 0.22), transparent 70%),
    radial-gradient(60% 50% at 50% 60%, rgba(255, 255, 255, 0.08), transparent 75%);
}
.spline__fallback svg { width: 46%; max-width: 190px; height: auto; color: rgba(255, 255, 255, 0.5); }
.spline--ready .spline__fallback { opacity: 0; transition: opacity 500ms var(--ease-out); }

/* The spotlight: a blurred disc following the pointer inside the card. */
.spline__spot {
  position: absolute;
  top: 0;
  left: 0;
  width: 320px;
  height: 320px;
  margin: -160px 0 0 -160px;
  pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(circle at center, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.12) 45%, transparent 80%);
  filter: blur(28px);
  opacity: 0;
  transition: opacity 200ms var(--ease-out);
  will-change: transform;
  z-index: 5;
}
.spline.is-lit .spline__spot { opacity: 1; }

/* --- Bottom stats -------------------------------------------------------- */
.feat__stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
@media (min-width: 768px) { .feat__stats { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.stat {
  padding: 16px;
  background: var(--f-card);
  border: 1px solid var(--f-line);
  border-radius: var(--radius);
  transition: border-color 0.3s var(--ease-out);
}
.stat:hover { border-color: var(--f-line-hi); }
.stat svg { width: 1rem; height: 1rem; color: var(--f-fg); }
.stat__v {
  margin-top: 12px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.5rem;
  letter-spacing: -0.02em;
  color: var(--f-fg);
}
.stat__l { margin-top: 4px; font-size: 0.75rem; line-height: 1.45; color: var(--f-mut); }
/* Attribution rides inside the label, not as a sibling, so a screen reader hears
   the figure, the claim and its source as one sentence. */
.stat__src { display: block; margin-top: 4px; font-size: 0.6875rem; opacity: 0.72; }

@media (prefers-reduced-motion: reduce) {
  .spline__spot { display: none; }
  .int:hover svg { transform: none; }
}

/* --------------------------------------------------------------------------
   18. Video — "See it in action"
   Sits between the dark features section and the dark footer, so it runs
   light: the player becomes the only dark object on the page at that point
   instead of a third black band. Same editorial language as `.why` — eyebrow,
   Clash Display headline, one brand cut mark.

   The Drive iframe is NOT in the initial document. It is injected on click, so
   a homepage visit does not pull Google's player, its cookies and its weight
   for a video most visitors never start. A real link to the file sits below
   the frame for anyone with JS off or the embed blocked.
   -------------------------------------------------------------------------- */
.vid {
  position: relative;
  padding-block: var(--section-y);
  background: var(--surface-0);
  --fade-rgb: 7, 12, 22;      /* --surface-deep */
}

.vid__mark {
  display: block;
  width: 4px;
  height: 30px;
  margin-bottom: 24px;
  background: var(--blue-brand);
  border-radius: 1px;
  transform: skewX(-18deg);
}

.vid__eyebrow {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-300);
}

.vid__title {
  margin-top: 18px;
  max-width: 20ch;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.875rem, 3.6vw, 3rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
  word-spacing: 0.03em;
  color: var(--ink-950);
  text-wrap: balance;
}

.vid__body {
  margin-top: 20px;
  max-width: 46rem;
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink-500);
  text-wrap: pretty;
}

/* --- Player -------------------------------------------------------------- */
.vid__frame {
  position: relative;
  margin-top: 44px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--ink-950);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card-lg);
}

.vid__frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* The click target that stands in for the player until it is asked for. */
.vid__facade {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  width: 100%;
  color: #fff;
  /* Transparent: the poster sits underneath and the ::before scrim below is
     what darkens it. An opaque fill here hides the frame entirely. */
  background: transparent;
}
.vid__facade[hidden] { display: none; }

/* Poster: a real frame from the demo. The frame is a pale, high-key UI
   screenshot, so it is dimmed here as well as scrimmed below — a white play
   control on untouched pale blue has nothing to sit against. */
.vid__poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: brightness(0.58) saturate(0.85);
}

/* Scrim over the poster. The frame is a pale UI screenshot, so the white play
   control needs something to sit on — without this it disappears into it. */
.vid__facade::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(42% 42% at 50% 50%, rgba(6, 10, 32, 0.55), transparent 74%),
    linear-gradient(180deg, rgba(6, 10, 32, 0.28) 0%, rgba(6, 10, 32, 0.44) 100%);
}
.vid__facade > * { position: relative; z-index: 1; }
.vid__label { text-shadow: 0 1px 12px rgba(6, 10, 32, 0.8); }

.vid__play {
  display: grid;
  place-items: center;
  width: 76px;
  height: 76px;
  color: var(--ink-950);
  background: rgba(255, 255, 255, 0.82);
  border: 1px solid var(--glass-border);
  border-radius: 50%;
  backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  box-shadow: var(--shadow-card-lg), inset 0 1px 0 var(--glass-hi);
  transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.vid__play svg { width: 26px; height: 26px; margin-left: 4px; }
.vid__facade:hover .vid__play { transform: scale(1.07); background: rgba(255, 255, 255, 0.94); }
.vid__facade:focus-visible .vid__play { transform: scale(1.07); }

.vid__label { font-size: 0.9375rem; font-weight: 500; letter-spacing: 0.01em; }
.vid__facade .vid__label { text-shadow: 0 1px 12px rgba(6, 10, 32, 0.8); }

.vid__note {
  margin-top: 16px;
  font-size: 0.8125rem;
  color: var(--ink-500);
}
.vid__note a { color: var(--ink-950); font-weight: 500; }
.vid__note a:hover { color: var(--blue-brand); text-decoration: underline; }

@media (prefers-reduced-motion: reduce) {
  .vid__facade:hover .vid__play,
  .vid__facade:focus-visible .vid__play { transform: none; }
}

/* --------------------------------------------------------------------------
   19. Contact — glow-horizon + interactive globe
   glow-horizon's framer-motion entrance is ported to keyframes: the wrapper
   runs y -100% -> -50%, scaleY 1.5 -> 1, opacity 0 -> 1, blur 15px -> 0 over
   2s on cubic-bezier(.16,1,.3,1); the inner arcs that declare an initialOffset
   run their own y -40% -> 0 on the same curve at 0s / 0.6s / 1.2s. The spec's
   #A558FB is swapped for our ultramarine so the glow stays on-brand; the arc
   count, sizes, blurs and box-shadow are the spec's.
   -------------------------------------------------------------------------- */
.ct {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: var(--section-y);
  background: var(--surface-deep);
  color: #fafafa;
  /* Same colour as the footer below: this band exists to flatten the residual
     luminance from the globe glow, which was the last visible step at that
     join even after both sections were reconciled to --surface-deep. */
  --fade-rgb: 7, 12, 22;      /* --surface-deep */
}


/* --- glow-horizon -------------------------------------------------------- */
.glow {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  /* Back to a share of the section, where the horizon sweeps across rather
     than sitting tucked at the top edge. */
  height: 58%;
  isolation: isolate;
  pointer-events: none;
  z-index: -1;
  transform: translateY(-50%) scaleY(1);
  animation: glowIn 2s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.glow__arc {
  position: absolute;
  inset: 0;
  border-radius: 100%;
}

/* Sizes, blurs and paint order are the spec's; only the mid hue is ours.
   Order is load-bearing: the black arc is painted LAST so it masks the centre
   and only a lit rim shows. Painting white last fills the whole section. */
.glow__arc--white {
  transform: scale(1.32);
  background: #fff;
  box-shadow: 0 -4px 23px 0 rgba(255, 255, 255, 0.71);
}
.glow__arc--mid  { transform: scale(1.2);  background: var(--rf-ultramarine); filter: blur(31px); }
.glow__arc--deep { transform: scale(1.24); background: var(--rf-iris);        filter: blur(21px); }
.glow__arc--mask { transform: scale(1.2);  background: var(--surface-deep);     filter: blur(51px); }

/* The three arcs that declare an initialOffset slide from -40% to 0. */
.glow__arc--mid,
.glow__arc--deep,
.glow__arc--mask { animation: arcIn 2s cubic-bezier(0.16, 1, 0.3, 1) both; }
.glow__arc--mid  { animation-delay: 0.6s; }
.glow__arc--deep { animation-delay: 0s; }
.glow__arc--mask { animation-delay: 0s; }

@keyframes arcIn {
  from { translate: 0 -40%; }
  to   { translate: 0 0; }
}

/* --- Shell --------------------------------------------------------------- */
.ct__inner {
  /* Same reconciliation as .feat__inner — was max-w-6xl on a 1rem/2rem
     section pad, landing 16px right of the standard edge. */
  max-width: var(--max-content);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* No card. The content sits directly on the section so the glow behind it
   reads as one continuous field instead of being interrupted by a panel. */
.ct__card { position: relative; }

.ct__grid { display: flex; flex-direction: column; min-height: 500px; }
@media (min-width: 768px) { .ct__grid { flex-direction: row; } }

.ct__copy {
  position: relative;
  z-index: 10;
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: center;
  padding-block: 40px;
}
@media (min-width: 768px) { .ct__copy { padding-block: 56px; } }

.ct__pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  width: fit-content;
  margin-bottom: 24px;
  padding: 5px 12px;
  font-size: 0.75rem;
  color: #a1a1aa;
  border: 1px solid #2f2f37;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.03);
}
.ct__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--success);
  animation: ctPulse 2s ease-in-out infinite;
}
@keyframes ctPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

.ct__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.875rem, 3.4vw, 3rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
  word-spacing: 0.03em;
  color: #fff;
  text-wrap: balance;
}
.ct__title span {
  background: linear-gradient(to right, var(--rf-sky), #b9c6ff);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}

.ct__body {
  margin-top: 18px;
  max-width: 34rem;
  font-size: 0.9375rem;
  line-height: 1.65;
  color: #a1a1aa;
}

.ct__stats { display: flex; align-items: center; gap: 22px; margin-top: 32px; flex-wrap: wrap; }
.ct__stat p:first-child {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: #fff;
}
.ct__stat p:last-child { margin-top: 2px; font-size: 0.75rem; color: #8b8b95; }
/* Dividers only make sense while the three stats sit on one line. CSS cannot
   detect wrap, so they are hidden until the column is wide enough to hold the
   row — otherwise they strand as loose vertical ticks beside stacked stats. */
.ct__rule { display: none; width: 1px; height: 34px; background: #2f2f37; }
@media (min-width: 1280px) { .ct__rule { display: block; } }

.ct__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 34px; }
.ct__actions .ui-btn {
  --ui-primary: rgba(255, 255, 255, 0.92);
  --ui-primary-hover: rgba(255, 255, 255, 0.99);
  --ui-primary-fg: #0b1220;
  --ui-ring: #fff;
}
.ct__actions .ui-btn--outline {
  --ui-bg: rgba(255, 255, 255, 0.06);
  --ui-fg: #fff;
  --ui-input: #3a3a42;
  --ui-accent: rgba(255, 255, 255, 0.12);
}

/* --- Globe --------------------------------------------------------------- */
.ct__globe {
  position: relative;
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  min-height: 340px;
  padding: 16px;
}
@media (min-width: 768px) { .ct__globe { min-height: 500px; padding: 0; } }

.ct__globe canvas {
  width: 100%;
  max-width: 520px;
  aspect-ratio: 1;
  touch-action: none;
  cursor: grab;
}
.ct__globe canvas.is-grabbing { cursor: grabbing; }

.ct__hint {
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.75rem;
  color: #71717a;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  /* glow-horizon lands in its rest state with no entrance at all. */
  .glow,
  .glow__arc--mid,
  .glow__arc--deep,
  .glow__arc--mask { animation: none; }
  .glow { transform: translateY(-50%) scaleY(1); opacity: 1; filter: none; }
  .ct__dot { animation: none; }
}

/* --------------------------------------------------------------------------
   21. Hero card field — scroll-morph-hero, load-fired
   The 21st.dev component's intro sequence ported to vanilla: scatter -> line
   -> halo, spring settle, mouse parallax, hover flip. The component's circle
   and arc stages are gone; the field orbits the dashboard panel as a loose
   scatter, deliberately not a ring. Framer's spring is a rAF velocity integrator.

   Deliberately dropped: the virtual-scroll driver and the circle -> arc morph
   it powers. Those attach `wheel` and `touchmove` with preventDefault, which
   inside a hero means the page cannot be scrolled. Firing on load — as asked —
   removes the need for them entirely, so the listeners are never attached.

   Also dropped: the component's own headline and kicker. This hero already has
   both; the cards are a layer, not a replacement.

   Sits at z-index -1 in DOM order after the aurora and before .hero3__grain,
   so the grain scrim still passes over the cards and hero copy keeps its
   contrast.
   -------------------------------------------------------------------------- */
.smh {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  perspective: 1000px;
}

/* The field orbits its own origin, and that origin is the centre of the
   dashboard panel. JS overwrites left/top in px from the measured
   .hero3__panel box; these values are the pre-measure fallback only. Every
   stage derives from this point, so one offset moves them all. */
.smh__stage {
  position: absolute;
  top: 66%;
  left: 50%;
  width: 0;
  height: 0;
}

.smh__card {
  display: block;
  position: absolute;
  width: 60px;
  height: 85px;
  margin: -42.5px 0 0 -30px;   /* centre the card on its own origin */
  transform-style: preserve-3d;
  pointer-events: auto;
  cursor: pointer;
  opacity: 0;
  will-change: transform;
}
@media (max-width: 767px) {
  .smh__card { width: 42px; height: 60px; margin: -30px 0 0 -21px; }
}

/* display:block is load-bearing — these are spans, and position:relative does
   not blockify, so width/height:100% would be ignored and the faces would
   have no box to fill. */
.smh__inner {
  display: block;
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.smh__card:hover .smh__inner { transform: rotateY(180deg); }

.smh__face {
  display: block;
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card-md);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.smh__face img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A dim wash that lifts on hover, per the component's group-hover treatment. */
.smh__face--front::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.04);
  transition: background-color 0.3s var(--ease-out);
}
.smh__card:hover .smh__face--front::after { background: transparent; }

/* Faces built from the assets that actually exist. */
.smh__face--mark {
  display: grid;
  place-items: center;
  background: var(--surface-0);
}
.smh__face--mark img { width: 52%; height: auto; object-fit: contain; }

.smh__face--mark-dark { background: var(--ink-950); }

.smh__face--brand {
  background: linear-gradient(150deg, var(--rf-sky), var(--rf-ultramarine) 55%, var(--rf-iris));
}

/* Back face — the spec's small label + title, filled with a real service. */
.smh__face--back {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 6px;
  text-align: center;
  background: #111116;
  border: 1px solid #2b2b33;
  transform: rotateY(180deg);
}
.smh__kicker {
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--rf-sky);
  margin-bottom: 2px;
}
.smh__label {
  font-size: 9px;
  font-weight: 500;
  line-height: 1.2;
  color: #fff;
}

@media (prefers-reduced-motion: reduce) {
  /* No scatter, no travel, no flip — the ring is simply there. */
  .smh__inner { transition: none; }
  .smh__card:hover .smh__inner { transform: none; }
}
