/* ==========================================================================
   hero-24 — the globe hero, on NetrAI's system

   Ported from the Originkit component and then re-pointed at this site's
   semantic layer. The port arrived with its own palette hardcoded — #fff,
   rgba(255,255,255,0.1), a #f0f0f0 button plate, a #101216 ground — which is
   exactly the thing css/base/style.css exists to prevent. Every one of those is
   now a token read, so the hero follows the theme for the same reason every
   other component does, and there is no per-component dark block to keep in
   sync.

   ── WHAT IS THEME-DEPENDENT ────────────────────────────────────────────
   Two things, and only two:

     1. The two art layers. The backdrop and the hand cutout are raster, so
        they cannot be tokenised — each ships as a light file and a dark
        file and the pair is swapped by [data-theme] on <html>. Both are
        pigmented from the ramps in the recolour script, whose control
        points are these same tokens, so the art and the CSS agree.
     2. --h24-scrim: a floor-coloured veil under the copy. The backdrop art
        is the same picture in both themes and its bright corners can rise
        under the headline; the scrim keeps the text contrast constant
        without touching the art.

   Everything else — ink, hairlines, the filled action — is one token used
   twice, because the token already carries the theme.

   ── WHAT IS NOT HERE ───────────────────────────────────────────────────
   The component's own nav — it shipped with a logo, a link row and a
   "Get started" button of its own, and this site has a header already — and
   the two glass cards, the stat and the testimonial, which were removed
   with their markup. Their tokens went with them; if they ever come back,
   the fill needs to be a token, because a 10% white plate is lit on black
   and invisible on Frost.
   ========================================================================== */

/* ---------------------------------------------------------------- root --- */

.ok-hero24 {
  /* Veil under the copy column, in the theme's own floor colour. */
  --h24-scrim:        rgba(0, 0, 0, 0.34);
  /* Hairline on the secondary action. --line is tuned for a flat surface;
     over moving art it needs the extra alpha to stay visible. */
  --h24-border:       rgba(255, 255, 255, 0.14);
  --h24-ink:          var(--color-ink-dark);
  --h24-ink-muted:    rgba(255, 255, 255, 0.70);
  /* The outlined action. Dark gets a raised plate; light gets the page's
     own white surface, which is what a secondary button is everywhere else
     on this site. */
  --h24-secondary-bg: rgba(255, 255, 255, 0.10);

  /* The globe. Declared here rather than in js/hero/hero-24.js so the hero's
     whole palette lives in one file; the script reads these off the mount's
     computed style when it builds the scene, and rebuilds on themechange.
     The ocean is the sphere's own fill, which is why it is a step off the
     canvas rather than the canvas itself — the globe has to read as an
     object sitting on the artwork, not a hole cut in it. */
  --h24-globe-dots:  #2997ff;
  --h24-globe-grid:  rgba(41, 151, 255, 0.42);
  --h24-globe-ocean: #05090f;

  position: relative;
  width: 100%;
  overflow: hidden;
  background: var(--surface-canvas);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;

  padding: 0;
}

/* Five stylesheets set `section { padding: … }` for the page's vertical
   rhythm — css/base/style.css at 172px down to css/layout/mobile-app.css at 56px inside
   the phone shell. This one is a fixed-size stage whose every element is
   positioned against the stage box, so that padding does not space it: it
   drops the whole composition down the page and adds twice its value in
   empty canvas. The hero owns its own spacing; the rhythm resumes below.

   Doubled selector on purpose. `html.m-app section` is more specific than a
   single class, so `.ok-hero24 { padding: 0 }` loses to it no matter which
   file loads last — a second class outranks the extra element instead. */
.ok-hero24.ok-hero24 { padding: 0; }

[data-theme="light"] .ok-hero24 {
  --h24-scrim:        rgba(245, 245, 247, 0.55);
  --h24-border:       rgba(0, 0, 0, 0.10);
  --h24-ink:          var(--color-carbon);
  --h24-ink-muted:    #4a4a4f;
  --h24-secondary-bg: rgba(255, 255, 255, 0.86);

  /* --accent-fill for the land, so the continents are the one saturated
     blue on a light stage. The ocean is a white sphere a shade off Frost —
     the same "object on the page, not hole in it" step as the dark side. */
  --h24-globe-dots:  #0071e3;
  --h24-globe-grid:  rgba(0, 113, 227, 0.30);
  --h24-globe-ocean: #ffffff;
}

/* Scoped stand-in for Tailwind's preflight. The original relies on it, so
   these have to be restated or the layout drifts inside an unreset site. */
.ok-hero24 *,
.ok-hero24 *::before,
.ok-hero24 *::after { box-sizing: border-box; }

.ok-hero24 h1,
.ok-hero24 p {
  margin: 0;
  font-size: inherit;
  font-weight: 400;          /* preflight makes headings inherit weight */
}

.ok-hero24 a { color: inherit; text-decoration: none; }
.ok-hero24 img { display: block; max-width: none; }

/* ---------------------------------------------------------- animations --- */

@keyframes ok-hero-reveal {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes ok-hand-slide-in-left {
  from { opacity: 0; transform: translateX(-30%); }
  to   { opacity: 1; transform: translateX(0); }
}

@keyframes ok-hand-slide-in-right {
  from { opacity: 0; transform: translateX(30%); }
  to   { opacity: 1; transform: translateX(0); }
}

.ok-reveal {
  animation: ok-hero-reveal 300ms cubic-bezier(0.215, 0.61, 0.355, 1) both;
}

/* The hand cutouts are absolutely positioned, so their slide animation has to
   compose with nothing else — keep transform free of layout offsets here. */
.ok-hand--left  { animation: ok-hand-slide-in-left  900ms cubic-bezier(0.16, 1, 0.3, 1) both; }
.ok-hand--right { animation: ok-hand-slide-in-right 900ms cubic-bezier(0.16, 1, 0.3, 1) both; }

@media (prefers-reduced-motion: reduce) {
  @keyframes ok-hero-reveal {
    from { opacity: 0; transform: none; }
    to   { opacity: 1; transform: none; }
  }
  @keyframes ok-hand-slide-in-left {
    from { opacity: 0; transform: none; }
    to   { opacity: 1; transform: none; }
  }
  @keyframes ok-hand-slide-in-right {
    from { opacity: 0; transform: none; }
    to   { opacity: 1; transform: none; }
  }
}

/* ------------------------------------------------------------ backdrop --- */
/* Full-bleed art, one per breakpoint × theme. Deliberately a sibling of the
   scale frames so the frame transform never touches it.

   All six live in the markup at once and five are display:none. They are
   background-image on a <div>, NOT <img src>: the preload scanner reads
   src attributes out of the raw HTML before any stylesheet has been
   consulted, so six <img> tags would pull all six files — ~360 KB — to show
   one of them. A background-image on a display:none element is never
   fetched, so this way exactly one file crosses the wire.

   Swapping one element's background-image on theme change would be the
   other option, and is worse: it re-decodes and shows the page floor for a
   frame or two mid-swap. Both themes' art is already decoded here. */

.ok-backdrop {
  pointer-events: none;
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  min-height: 100%;
  width: 100%;
  background-position: center top;
  background-repeat: no-repeat;
  background-size: cover;
}

.ok-backdrop--phone.ok-backdrop--dark    { background-image: url("../../assets/hero24/bg-phone-dark.webp"); }
.ok-backdrop--phone.ok-backdrop--light   { background-image: url("../../assets/hero24/bg-phone-light.webp"); }
.ok-backdrop--tablet.ok-backdrop--dark   { background-image: url("../../assets/hero24/bg-tablet-dark.webp"); }
.ok-backdrop--tablet.ok-backdrop--light  { background-image: url("../../assets/hero24/bg-tablet-light.webp"); }
.ok-backdrop--desktop.ok-backdrop--dark  { background-image: url("../../assets/hero24/bg-desktop-dark.webp"); }
.ok-backdrop--desktop.ok-backdrop--light { background-image: url("../../assets/hero24/bg-desktop-light.webp"); }

/* --------------------------------------------------------- scale frame --- */
/* Fixed-width design frame scaled to the available width. The factor is
   measured in JS — CSS can't divide a vw by a px. */

.ok-frame {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.ok-frame-inner {
  transform-origin: top left;
  --frame-scale: 1;
}

.ok-frame--phone   .ok-frame-inner { width: 402px; }
.ok-frame--tablet  .ok-frame-inner { width: 744px; }
.ok-frame--desktop .ok-frame-inner { width: 1280px; }

.ok-stage { position: relative; overflow: clip; }
.ok-stage--phone   { height: 836px; width: 402px; }
.ok-stage--tablet  { height: 994px; width: 744px; }
.ok-stage--desktop { height: 913px; width: 1280px; }

/* ------------------------------------------------------ breakpoint show --- */
/* phone < 640 · tablet 640–1279 · desktop >= 1280
   crossed with light / dark on the backdrops. */

.ok-backdrop,
.ok-frame--tablet,
.ok-frame--desktop { display: none; }

.ok-backdrop--phone.ok-backdrop--dark { display: block; }

[data-theme="light"] .ok-backdrop--phone.ok-backdrop--dark  { display: none; }
[data-theme="light"] .ok-backdrop--phone.ok-backdrop--light { display: block; }

@media (min-width: 640px) {
  .ok-frame--phone { display: none; }
  .ok-frame--tablet { display: block; }

  .ok-backdrop--phone.ok-backdrop--dark,
  [data-theme="light"] .ok-backdrop--phone.ok-backdrop--light { display: none; }

  .ok-backdrop--tablet.ok-backdrop--dark { display: block; }
  [data-theme="light"] .ok-backdrop--tablet.ok-backdrop--dark  { display: none; }
  [data-theme="light"] .ok-backdrop--tablet.ok-backdrop--light { display: block; }
}

@media (min-width: 1280px) {
  .ok-frame--tablet  { display: none; }
  .ok-frame--desktop { display: block; }

  .ok-backdrop--tablet.ok-backdrop--dark,
  [data-theme="light"] .ok-backdrop--tablet.ok-backdrop--light { display: none; }

  .ok-backdrop--desktop.ok-backdrop--dark { display: block; }
  [data-theme="light"] .ok-backdrop--desktop.ok-backdrop--dark  { display: none; }
  [data-theme="light"] .ok-backdrop--desktop.ok-backdrop--light { display: block; }
}

/* --------------------------------------------------------------- copy ---- */

.ok-copy {
  position: absolute;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* The veil. Sits behind the copy column only, in the theme's floor colour,
   so the headline's contrast does not depend on which part of the artwork
   happens to be bright behind it. Radial rather than a box so it has no
   edge to notice. */
.ok-copy::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 50%;
  width: 150%;
  height: 190%;
  translate: -50% -50%;
  background: radial-gradient(closest-side, var(--h24-scrim) 0%, transparent 100%);
  pointer-events: none;
}

/* The copy column sits near the top of the stage — it used to start much
   lower, which read as a large empty band under the site header before the
   headline began.

   These tops are in STAGE units and the stage is scaled to the viewport, so
   the gap you actually see is `top × scale`, not `top`. At 1440px the
   desktop scale is 1.125, so 56 here lands about 63px under the header;
   raise it and the gap grows faster than the number suggests.

   The floor is the globe, whose position is baked into the backdrop art and
   cannot move: the copy block runs roughly 290px tall on desktop, so a top
   much past 110 pushes the buttons into the sphere. */
.ok-copy--phone {
  left: 50%;
  top: 52px;
  width: 372px;
  translate: -50% 0;
  gap: 20px;
}
.ok-copy--tablet  { left: 72px;  top: 46px; width: 600px; gap: 28px; }
.ok-copy--desktop { left: 330px; top: 56px; width: 620px; gap: 28px; }

.ok-copy-text {
  position: relative;
  display: flex;
  width: 100%;
  flex-shrink: 0;
  flex-direction: column;
  align-items: center;
  text-align: center;
  color: var(--h24-ink);
}
.ok-copy--phone .ok-copy-text { gap: 10px; }
.ok-copy--tablet .ok-copy-text,
.ok-copy--desktop .ok-copy-text { gap: 14px; }

/* The headline is the site's, which is a whole sentence rather than the
   component's four words, so the type steps down and the column widens to
   keep it inside three lines. Below three it collides with the globe, whose
   position is baked into the backdrop art. */
/* The hero ships this sentence three times, once per design frame, because
   only the frame matching the breakpoint is displayed. Only the phone frame's
   copy is an <h1> — Googlebot crawls smartphone-first, so that is the frame
   it renders, and three H1s in one document is three too many. The tablet and
   desktop copies are <p> carrying this same class, so colour and margin are
   set here rather than inherited from the global h1 rule. */
.ok-title {
  position: relative;
  flex-shrink: 0;
  margin: 0;
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: var(--font-weight-semibold);
}
.ok-copy--phone .ok-title {
  width: 340px;
  font-size: 30px;
  line-height: 34px;
  letter-spacing: -1.0px;
}
.ok-copy--tablet .ok-title,
.ok-copy--desktop .ok-title {
  width: 100%;
  font-size: 44px;
  line-height: 50px;
  letter-spacing: -1.6px;
}

/* "intent" carries the accent, the same job it does in the headline this
   replaces. --accent, not --accent-fill: this is a word, not a control. */
.ok-title .ok-accent-word {
  color: var(--accent);
  white-space: nowrap;
}

.ok-sub {
  position: relative;
  width: 100%;
  flex-shrink: 0;
  line-height: 1.5;
  letter-spacing: var(--tracking-body);
  color: var(--h24-ink-muted);
}
.ok-copy--phone .ok-sub { font-size: 13px; }
.ok-copy--tablet .ok-sub,
.ok-copy--desktop .ok-sub { font-size: 16px; }

.ok-actions { position: relative; flex-shrink: 0; display: flex; }
.ok-actions--phone {
  width: 100%;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.ok-actions--wide { align-items: center; justify-content: center; gap: 12px; }

/* ------------------------------------------------------------ buttons ---- */
/* The component's primary was a white plate with near-black ink — correct on
   its own dark artwork, wrong here twice over: it is invisible on Frost, and
   this site already has exactly one filled action colour that does not
   change with the theme. Both buttons are rebuilt on the site's pair. */

.ok-btn {
  position: relative;
  display: flex;
  flex-shrink: 0;
  cursor: pointer;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  transition: background-color var(--transition), border-color var(--transition);
}

.ok-btn--primary { background: var(--accent-fill); }
.ok-btn--primary:hover { background: var(--accent-dim); }
.ok-btn--primary .ok-btn-label { color: var(--on-accent); }

.ok-btn--secondary {
  border: 1px solid var(--h24-border);
  background: var(--h24-secondary-bg);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}
.ok-btn--secondary:hover { border-color: var(--accent); }
.ok-btn--secondary .ok-btn-label { color: var(--h24-ink); }

.ok-btn-label {
  position: relative;
  flex-shrink: 0;
  white-space: nowrap;
  font-size: 15px;
  font-weight: var(--font-weight-regular);
  line-height: 1.15;
  letter-spacing: -0.24px;
}

.ok-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* per-breakpoint padding */
.ok-btn--pad-phone   { padding: 12px 20px; }
.ok-btn--pad-wide    { padding: 15px 26px; }

/* --------------------------------------------------------------- globe --- */

.ok-globe {
  position: absolute;
  overflow: clip;
  border-radius: var(--radius-full);
}

.ok-stage--phone .ok-globe {
  left: calc(50% + 0.5px);
  top: 418px;
  height: 324px;
  width: 323px;
  translate: -50% 0;
}
.ok-stage--tablet .ok-globe  { left: 163px; top: 432px; height: 420px; width: 418px; }
.ok-stage--desktop .ok-globe { left: 431px; top: 448px; height: 420px; width: 418px; }

/* the canvas mount the JS writes into */
.ok-globe-mount {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ok-globe-error {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 16px;
  text-align: center;
  color: var(--h24-ink);
  font-family: var(--font-body);
}
.ok-globe-error b { font-size: 16px; font-weight: var(--font-weight-semibold); }
.ok-globe-error span { font-size: 13px; color: var(--h24-ink-muted); margin-top: 4px; }

/* ---------------------------------------------------------- hand cutout -- */
/* One photo, revealed through its own alpha mask. A second gradient mask
   layer dissolves the wrist at the frame edge so the cutout never reads as a
   hard crop while it slides in — the two layers are intersected.

   The photo itself is pigmented per theme; only the <img> src differs, so
   every mask and crop below is shared. */

.ok-hand {
  position: absolute;
  z-index: 1;
  mask-mode: alpha;
  mask-composite: intersect;
  -webkit-mask-composite: source-in;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
}

.ok-hand-clip {
  pointer-events: none;
  position: absolute;
  inset: 0;
  overflow: hidden;
}

.ok-hand-clip img { position: absolute; max-width: none; }

/* Theme pair, same rule as the backdrops. */
.ok-hand-clip .ok-hand-img--light { display: none; }
[data-theme="light"] .ok-hand-clip .ok-hand-img--dark  { display: none; }
[data-theme="light"] .ok-hand-clip .ok-hand-img--light { display: block; }

/* left-hand and right-hand photo crops are the same at every breakpoint */
.ok-hand--right .ok-hand-clip img {
  left: -97.68%;
  top: -17.2%;
  height: 170.95%;
  width: 197.68%;
}
.ok-hand--left .ok-hand-clip img {
  left: -15.3%;
  top: -63.32%;
  height: 163.32%;
  width: 232.73%;
}

/* phone */
.ok-stage--phone .ok-hand--right {
  left: 172px; top: 344.46px; height: 177.31px; width: 230px;
  mask-image: url("../../assets/hero24/hand-mask-top.svg"),
              linear-gradient(to left, transparent 0%, #000 18%, #000 100%);
  -webkit-mask-image: url("../../assets/hero24/hand-mask-top.svg"),
              linear-gradient(to left, transparent 0%, #000 18%, #000 100%);
  mask-size: 230px 177.309px, 100% 100%;
  -webkit-mask-size: 230px 177.309px, 100% 100%;
}
.ok-stage--phone .ok-hand--left {
  left: -27px; top: 571.65px; height: 212.8px; width: 224px;
  mask-image: url("../../assets/hero24/hand-mask-bottom.svg"),
              linear-gradient(to right, transparent 0%, #000 18%, #000 100%);
  -webkit-mask-image: url("../../assets/hero24/hand-mask-bottom.svg"),
              linear-gradient(to right, transparent 0%, #000 18%, #000 100%);
  mask-size: 224px 212.801px, 100% 100%;
  -webkit-mask-size: 224px 212.801px, 100% 100%;
}

/* tablet */
.ok-stage--tablet .ok-hand--right {
  left: 401px; top: 383.289px; height: 264.423px; width: 343px;
  mask-image: url("../../assets/hero24/ipad-mask-top.svg"),
              linear-gradient(to left, transparent 0%, #000 18%, #000 100%);
  -webkit-mask-image: url("../../assets/hero24/ipad-mask-top.svg"),
              linear-gradient(to left, transparent 0%, #000 18%, #000 100%);
  mask-size: 343px 264.423px, 100% 100%;
  -webkit-mask-size: 343px 264.423px, 100% 100%;
}
.ok-stage--tablet .ok-hand--left {
  left: 0; top: 692.875px; height: 267.9px; width: 282px;
  mask-image: url("../../assets/hero24/ipad-mask-bottom.svg"),
              linear-gradient(to right, transparent 0%, #000 18%, #000 100%);
  -webkit-mask-image: url("../../assets/hero24/ipad-mask-bottom.svg"),
              linear-gradient(to right, transparent 0%, #000 18%, #000 100%);
  mask-size: 282px 267.9px, 100% 100%;
  -webkit-mask-size: 282px 267.9px, 100% 100%;
}

/* desktop */
.ok-stage--desktop .ok-hand--right {
  left: 794px; top: 269.169px; height: 374.664px; width: 486px;
  mask-image: url("../../assets/hero24/desk-mask-top.svg"),
              linear-gradient(to left, transparent 0%, #000 18%, #000 100%);
  -webkit-mask-image: url("../../assets/hero24/desk-mask-top.svg"),
              linear-gradient(to left, transparent 0%, #000 18%, #000 100%);
  mask-size: 486px 374.664px, 100% 100%;
  -webkit-mask-size: 486px 374.664px, 100% 100%;
}
.ok-stage--desktop .ok-hand--left {
  left: 0; top: 592.398px; height: 420.85px; width: 443px;
  mask-image: url("../../assets/hero24/desk-mask-bottom.svg"),
              linear-gradient(to right, transparent 0%, #000 18%, #000 100%);
  -webkit-mask-image: url("../../assets/hero24/desk-mask-bottom.svg"),
              linear-gradient(to right, transparent 0%, #000 18%, #000 100%);
  mask-size: 443px 420.85px, 100% 100%;
  -webkit-mask-size: 443px 420.85px, 100% 100%;
}

/* ------------------------------------------------------------- the seam --- */
/* The hero's floor is the page's floor in both themes, so the join to the
   client marquee below needs nothing but the shared canvas colour. The rule
   is here rather than assumed so that changing --surface-canvas cannot open
   a band between the two. */

.ok-hero24 + .client-marquee { background: var(--surface-canvas); }

/* The stage is 913px of a picture that does not end there — the backdrop's
   bright lower corners and the left hand both run into the section's bottom
   edge and get sliced by it. A short dissolve to the canvas colour turns
   that cut into a fade, so the hero ends rather than stops.

   96px, and only at the bottom: enough to soften the brightest corner
   without climbing far enough to dim the globe. pointer-events:none, so it
   cannot swallow a click on anything beneath it. */
.ok-hero24::after {
  content: "";
  pointer-events: none;
  position: absolute;
  z-index: 3;
  left: 0;
  right: 0;
  bottom: 0;
  height: 96px;
  background: linear-gradient(to bottom, transparent 0%, var(--surface-canvas) 100%);
}
