/* ==========================================================================
   OK Studios — shared base stylesheet
   Design tokens, reset, layout shell, header, footer, theme toggle.
   Page-specific styles live inline (or in a per-page sheet) on each page.
   ========================================================================== */

/* DARK is the default theme */
:root {
  color-scheme: dark;   /* native UI (select popups, scrollbars) follow site theme, not OS */
  --paper: #0B0C0C;     /* Woodsmoke */
  --ink: #FFF8F0;       /* Floral White */
  --ink-soft: #A6A6AB;
  --purple: #8A3DFF;    /* OK Purple, lifted for dark legibility */
  --purple-deep: #6F00FF;
  --line: rgba(255, 248, 240, 0.14);
  --tag-bg: rgba(255, 248, 240, 0.05);
  --dot: rgba(255, 248, 240, 0.05);
  --glow:
    radial-gradient(55% 50% at 82% 8%, rgba(111, 0, 255, 0.13), transparent 70%),
    radial-gradient(50% 45% at 8% 96%, rgba(111, 0, 255, 0.08), transparent 70%);

  /* shared type + easing */
  --font-display: "Sora", sans-serif;
  --font-body: "Inter", system-ui, sans-serif;
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
}

:root[data-theme="light"] {
  color-scheme: light;
  --paper: #FFF8F0;     /* Floral White */
  --ink: #0B0C0C;       /* Woodsmoke */
  --ink-soft: #4A4A4D;
  --purple: #6F00FF;    /* OK Purple */
  --purple-deep: #5800CC;
  --line: rgba(11, 12, 12, 0.12);
  --tag-bg: rgba(11, 12, 12, 0.03);
  --dot: rgba(11, 12, 12, 0.15);
  --glow:
    radial-gradient(55% 50% at 82% 8%, rgba(111, 0, 255, 0.10), transparent 70%),
    radial-gradient(50% 45% at 8% 96%, rgba(111, 0, 255, 0.06), transparent 70%);
}

* { margin: 0; padding: 0; box-sizing: border-box; }
/* scrollbar-gutter: stable reserves the vertical-scrollbar slot even on pages
   that fit in the viewport (e.g. /contact/). Without it, navigating from a
   page WITH a scrollbar to a page WITHOUT a scrollbar widens the viewport by
   ~15px and shifts every centered element right by half that — most visible
   on the header / dock during cross-doc View Transitions, where the browser
   pairs view-transition-name elements (mark, dock, theme-toggle) at the OLD
   page position vs the NEW position and morphs the shift over 0.22s. Reads
   as "menu fades in/out + header parts shift to the right." */
html { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; scrollbar-gutter: stable; background: var(--paper); }

/* theme.js adds .theme-instant to <html> for one frame when it has to correct
   a stale prerendered DOM (or bfcache / cross-tab change). Kills the 400ms
   body crossfade for that single swap so the page snaps to the right theme
   instead of fading. User-driven toggle clicks don't add the class, so they
   keep the smooth animation. */
.theme-instant,
.theme-instant *,
.theme-instant *::before,
.theme-instant *::after {
  transition: none !important;
}

body {
  font-family: var(--font-body);
  background: var(--paper);
  color: var(--ink);
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
  position: relative;
  transition: background 0.4s ease, color 0.4s ease;
}

/* soft warm purple glow — restrained, minimal */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  background: var(--glow);
  pointer-events: none;
  z-index: 0;
  transition: background 0.4s ease;
}

/* subtle signature dot-grid texture, fading in from the top */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  background-image: radial-gradient(circle, var(--dot) 1.1px, transparent 1.6px);
  background-size: 26px 26px;
  pointer-events: none;
  z-index: 0;
  -webkit-mask-image: radial-gradient(130% 110% at 50% -10%, #000 35%, transparent 78%);
  mask-image: radial-gradient(130% 110% at 50% -10%, #000 35%, transparent 78%);
  transition: background-image 0.4s ease;
}

.wrap {
  position: relative;
  z-index: 2;
  flex: 1;
  width: 100%;
  max-width: 1180px;
  margin-inline: auto;
  padding: clamp(1.75rem, 4vw, 3rem) clamp(1.75rem, 6vw, 4rem);
  display: flex;
  flex-direction: column;
}

/* ---- Header ------------------------------------------------------------- */
header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

/* brand logo (O/K Studios lockup, theme-swapped) */
.mark { display: inline-flex; align-items: center; }
.brand-logo {
  height: 38px;
  width: auto;
  display: block;
  transition: opacity 0.2s ease;
}
.logo-on-light { display: none; }
:root[data-theme="light"] .logo-on-dark { display: none; }
:root[data-theme="light"] .logo-on-light { display: block; }

.head-right { display: flex; align-items: center; gap: 0.85rem; }

/* theme toggle switch */
.theme-toggle {
  --w: 58px; --h: 30px;
  position: relative;
  width: var(--w);
  height: var(--h);
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--tag-bg);
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  transition: background 0.3s ease, border-color 0.3s ease;
}
.theme-toggle:focus-visible { outline: 2px solid var(--purple); outline-offset: 2px; }
.theme-toggle .knob {
  position: absolute;
  top: 50%;
  left: 3px;
  width: calc(var(--h) - 8px);
  height: calc(var(--h) - 8px);
  transform: translate(0, -50%);
  border-radius: 50%;
  background: var(--purple);
  display: grid;
  place-items: center;
  color: #fff;
  transition: transform 0.32s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.3s ease;
}
:root[data-theme="light"] .theme-toggle .knob {
  transform: translate(calc(var(--w) - var(--h)), -50%);
}
.theme-toggle .knob svg { width: 14px; height: 14px; }
.theme-toggle .knob .i-moon { display: block; }
.theme-toggle .knob .i-sun { display: none; }
:root[data-theme="light"] .theme-toggle .knob .i-moon { display: none; }
:root[data-theme="light"] .theme-toggle .knob .i-sun { display: block; }

/* ---- Footer ------------------------------------------------------------- */
footer {
  position: relative;
  z-index: 2;
  border-top: 1px solid var(--line);
  padding: clamp(1.25rem, 3vw, 1.75rem) clamp(1.75rem, 6vw, 6rem);
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  align-items: center;
  justify-content: space-between;
  font-size: 0.85rem;
  color: var(--ink-soft);
}
footer a { color: var(--ink-soft); text-decoration: none; transition: color 0.2s ease; }
footer a:hover { color: var(--purple); }

.footer-social { display: inline-flex; align-items: center; gap: 1rem; }
.footer-social a {
  display: inline-flex;
  color: var(--purple);
  filter: drop-shadow(0 0 4px rgba(111, 0, 255, 0.55));
  transition: color 0.2s ease, filter 0.2s ease, transform 0.2s ease;
  position: relative;
}
/* Sonar ring — sits on top of the icon and pings outward when triggered. */
.footer-social a::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  border: 1.5px solid var(--purple);
  opacity: 0;
  pointer-events: none;
}
.footer-social.pulse-on a::after { animation: socialPing 1.4s ease-out 3; }
.footer-social.pulse-on a:nth-child(2)::after { animation-delay: 0.22s; }
.footer-social.pulse-on a:nth-child(3)::after { animation-delay: 0.44s; }
.footer-social a:hover {
  color: var(--purple);
  filter: drop-shadow(0 0 9px rgba(111, 0, 255, 0.95));
  transform: translateY(-1px);
}
.footer-social svg { width: 18px; height: 18px; display: block; }

@keyframes socialPing {
  0%   { transform: scale(1);    opacity: 0.85; }
  70%  { opacity: 0.15; }
  100% { transform: scale(2.8);  opacity: 0; }
}

/* shared rise-in animation for content blocks */
@keyframes rise {
  from { opacity: 0; transform: translateY(22px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; }
  [class*="rise"], h1, .lede { transform: none !important; opacity: 1 !important; }
}

/* ==========================================================================
   Shared layout primitives (used by index + services + future pages).
   Page-specific styles still belong in each page's inline <style>.
   ========================================================================== */

/* ---- Section rhythm + eyebrow + headlines ---- */
.section { padding: clamp(3.5rem, 9vh, 6rem) 0; text-align: center; }
.section + .section { position: relative; border-top: 1px solid var(--line); }
.section + .section::before {
  content: "/";
  position: absolute;
  top: 0; left: 50%;
  transform: translate(-50%, -50%) skewX(-10deg);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  line-height: 1;
  color: var(--purple);
  background: var(--paper);
  padding: 0 0.6rem;
}
.eyebrow {
  display: block;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--purple);
  margin-bottom: 1.1rem;
}
.eyebrow::before {
  content: "/";
  display: inline-block;
  margin-right: 0.55em;
  font-weight: 800;
  letter-spacing: 0;
  transform: skewX(-10deg);
}
.section-h {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.7rem, 4vw, 2.6rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--ink);
}

/* ---- Top dock nav (frosted-glass pill that blends in on scroll) ---- */
.dock {
  position: fixed;
  left: 50%;
  /* Sit on the same horizontal row as the header logo + theme toggle.
     wrap padding-top is clamp(1.75rem, 4vw, 3rem) — match it. */
  top: clamp(1.75rem, 4vw, 3rem);
  transform: translateX(-50%);
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 0.1rem;
  padding: 0.35rem;
  border-radius: 999px;
  background: transparent;
  border: 1px solid transparent;
  backdrop-filter: blur(0);
  -webkit-backdrop-filter: blur(0);
  box-shadow: none;
  transition:
    top 0.35s var(--ease-out),
    background 0.35s ease,
    border-color 0.35s ease,
    backdrop-filter 0.35s ease,
    -webkit-backdrop-filter 0.35s ease,
    box-shadow 0.35s ease;
}
/* once the page has scrolled, the glass appears + dock lifts to viewport top */
.dock.scrolled {
  top: 0.85rem;
  background: color-mix(in srgb, var(--paper) 72%, transparent);
  border-color: var(--line);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  box-shadow:
    0 14px 36px rgba(0, 0, 0, 0.22),
    0 2px 6px rgba(0, 0, 0, 0.08),
    inset 0 1px 0 color-mix(in srgb, var(--ink) 8%, transparent);
}
.dock a {
  position: relative;
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  padding: 0.55rem 1.05rem;
  border-radius: 999px;
  color: var(--ink-soft);
  transition: color 0.25s ease, background 0.25s ease, box-shadow 0.25s ease;
}
.dock a .lbl {
  font-family: var(--font-display);
  font-size: 0.72rem; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
  white-space: nowrap;
}
.dock a .dot { display: none; }
.dock a:hover { color: var(--ink); }
.dock a.active {
  color: var(--ink);
  background: color-mix(in srgb, var(--purple) 14%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--purple) 32%, transparent);
}
/* A/D brand slash — skewed purple accent, echoing the O/K mark */
.dock .ad-slash {
  color: var(--purple);
  font-weight: 800;
  display: inline-block;
  transform: skewX(-10deg);
  margin: 0 0.5px;
}
/* Mobile/tablet: sit below the header at top of page, lift to the very top on scroll */
@media (max-width: 900px) {
  .dock { top: calc(4.5rem + env(safe-area-inset-top, 0px)); }
  .dock.scrolled { top: calc(0.85rem + env(safe-area-inset-top, 0px)); }
}
@media (max-width: 560px) {
  .dock { padding: 0.3rem; }
  .dock a { padding: 0.45rem 0.78rem; }
  .dock a .lbl { font-size: 0.66rem; letter-spacing: 0.08em; }
}
@media (max-width: 420px) {
  .dock { padding: 0.25rem; gap: 0; }
  .dock a { padding: 0.4rem 0.55rem; }
  .dock a .lbl { font-size: 0.6rem; letter-spacing: 0.05em; }
}
@media (prefers-reduced-motion: reduce) { .dock, .dock a { transition: none; } }

/* Body fade for dock navigation — paired keyframes that swap when JS toggles
   .is-navigating. main-in plays on first load and after the class is removed
   (in-page jumps); main-out plays while .is-navigating is on (cross-page
   navigations let the new page's main-in fade it back in). */
main { flex: 1; animation: main-in 0.22s ease forwards; }
@keyframes main-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes main-out { from { opacity: 1; } to { opacity: 0; } }
body.is-navigating main { animation: main-out 0.22s ease forwards; }
@media (prefers-reduced-motion: reduce) {
  main, body.is-navigating main { animation: none; opacity: 1; }
}

/* Cross-Document View Transitions — the browser snapshots the old page,
   navigates, snapshots the new page, and crossfades them so the header / dock
   never visibly flash. Browsers without support fall back to the JS body fade
   shipped in v1.14.7/8. The inline head script sets :root.vt when the API is
   present so we can skip the JS main-in/-out and let the browser handle it. */
/* RE-ENABLED 2026-06-17: cross-doc View Transitions back on. Cold-nav white
   flash has two guards: head-meta.html inlines the paper canvas so the
   destination's first paint is never white, and the persistent shell VT names
   below pin .dock/.mark/.theme-toggle across the inter-document gap. The
   localhost-only flash that drove the earlier disable was a dev-server cache
   artifact (no-store re-downloading base.css every nav), fixed in serve.sh.
   Verify on a cold first click in Vivaldi/Chrome before disabling again. */
@view-transition { navigation: auto; }
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.22s;
  animation-timing-function: var(--ease-out);
}
/* RESTORED FROM v1.14.12 (was wrongly removed in 1.19.9): persistent
   view-transition-names on the shell elements. This pairs `.mark` /
   `.dock` / `.theme-toggle` old→new across the cross-doc transition so
   they STAY VISIBLE during the inter-document gap on cold navigations —
   that's what masks the white flash that Chrome/Vivaldi otherwise paint
   between the old and new docs. The names also keep these elements
   appearing stationary while `<main>` (root) crossfades. Do NOT remove
   these again without verifying the flash doesn't return on a cold first
   click in a non-Comet Chromium browser. */
.mark { view-transition-name: brand-mark; }
.dock { view-transition-name: dock; }
.theme-toggle { view-transition-name: theme-toggle; }
/* When VT is handling the crossfade, suppress our CSS main-in/out so we don't
   double-fade on cross-page navigations. */
:root.vt main,
:root.vt body.is-navigating main { animation: none; opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}

/* ---- Service deep-dives (svc family + visuals: bw / tiles / spec) ---- */
.svc { text-align: left; }
.svc-grid { display: grid; grid-template-columns: 1.05fr 1fr; gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
.svc--flip .svc-visual { order: -1; }
.svc-copy .eyebrow { margin-bottom: 0.9rem; }
.svc-copy .section-h { font-size: clamp(1.5rem, 3.2vw, 2.05rem); margin-bottom: 1rem; }
.svc-lead { color: var(--ink-soft); line-height: 1.65; font-size: 1.02rem; max-width: 48ch; }
.svc-feat { list-style: none; margin-top: 1.5rem; display: grid; gap: 0.7rem; }
.svc-feat li { position: relative; padding-left: 1.5rem; color: var(--ink); font-size: 0.95rem; line-height: 1.4; }
.svc-feat li::before { content: "/"; position: absolute; left: 0; top: -0.02em; font-family: var(--font-display); font-weight: 800; color: var(--purple); transform: skewX(-10deg); }
.svc-visual { display: flex; justify-content: center; }
.svc-stage { position: relative; width: 100%; max-width: 460px; border-radius: 22px; border: 1px solid var(--line); background: radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--purple) 9%, transparent), transparent 60%), var(--tag-bg); padding: clamp(1.1rem, 2.6vw, 1.7rem); overflow: hidden; }

/* browser-frame mock */
.bw { border-radius: 12px; overflow: hidden; border: 1px solid var(--line); background: var(--paper); box-shadow: 0 22px 55px -30px rgba(0, 0, 0, 0.65); animation: bw-float 7s var(--ease-out) infinite; }
.bw-bar { display: flex; align-items: center; gap: 6px; padding: 9px 12px; background: var(--tag-bg); border-bottom: 1px solid var(--line); }
.bw-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--ink-soft); opacity: 0.45; }
.bw-dot:first-child { background: var(--purple); opacity: 1; }
.bw-url { margin-left: 8px; font-size: 0.68rem; color: var(--ink-soft); background: var(--paper); border: 1px solid var(--line); border-radius: 999px; padding: 3px 14px; }
.bw-body { padding: 16px; display: grid; gap: 10px; }
.bw-hero { height: 56px; border-radius: 8px; background: linear-gradient(120deg, color-mix(in srgb, var(--purple) 75%, transparent), color-mix(in srgb, var(--purple-deep) 50%, transparent)); }
.bw-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.bw-card { height: 42px; border-radius: 8px; background: var(--tag-bg); border: 1px solid var(--line); }
.bw-ln { height: 9px; border-radius: 999px; background: var(--line); }
.bw-ln.w8 { width: 80%; }
.bw-ln.w6 { width: 60%; }
@keyframes bw-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }

/* creative tile grid */
.tiles { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 58px; grid-auto-flow: dense; gap: 10px; }
.tile { position: relative; overflow: hidden; border-radius: 12px; border: 1px solid var(--line); background: var(--tag-bg); animation: tile-float 6s var(--ease-out) infinite; }
.tile::after { content: ""; position: absolute; inset: 0; background: linear-gradient(115deg, transparent 35%, color-mix(in srgb, var(--ink) 10%, transparent) 50%, transparent 65%); transform: translateX(-130%); animation: tile-shimmer 5s ease-in-out infinite; }
.tile.fill { background: linear-gradient(150deg, color-mix(in srgb, var(--purple) 78%, transparent), color-mix(in srgb, var(--purple-deep) 52%, transparent)); border-color: transparent; }
.tile.tint { background: color-mix(in srgb, var(--purple) 16%, var(--tag-bg)); }
.tile.tall { grid-row: span 2; }
.tile.wide { grid-column: span 2; }
.tile:nth-child(2), .tile:nth-child(2)::after { animation-delay: 0.6s; }
.tile:nth-child(3), .tile:nth-child(3)::after { animation-delay: 1.2s; }
.tile:nth-child(4), .tile:nth-child(4)::after { animation-delay: 0.9s; }
.tile:nth-child(5), .tile:nth-child(5)::after { animation-delay: 1.5s; }
.tile:nth-child(6), .tile:nth-child(6)::after { animation-delay: 0.3s; }
@keyframes tile-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@keyframes tile-shimmer { 0% { transform: translateX(-130%); } 55%, 100% { transform: translateX(130%); } }

/* brand-system specimen */
.spec { display: grid; gap: 12px; }
.spec-card { border: 1px solid var(--line); border-radius: 12px; background: var(--paper); }
.spec-mark { display: flex; align-items: center; gap: 12px; padding: 14px 16px; }
.spec-logo { font-family: var(--font-display); font-weight: 800; font-size: 1.8rem; letter-spacing: -0.02em; color: var(--ink); }
.spec-logo i { font-style: normal; color: var(--purple); display: inline-block; transform: skewX(-10deg); margin: 0 1px; }
.spec-chip { margin-left: auto; font-family: var(--font-display); font-weight: 700; font-size: 0.8rem; color: var(--ink-soft); border: 1px solid var(--line); border-radius: 8px; padding: 6px 10px; }
.spec-chip.solid { margin-left: 8px; color: #fff; background: var(--purple); border-color: transparent; }
.spec-swatches { display: flex; gap: 10px; }
.spec-swatches span { flex: 1; height: 46px; border-radius: 10px; background: var(--sw); border: 1px solid var(--line); }
.spec-type { display: grid; grid-template-columns: auto 1fr auto 1fr; align-items: center; gap: 10px 14px; padding: 12px 16px; }
.spec-aa { font-size: 2rem; font-weight: 700; line-height: 1; color: var(--ink); }
.spec-meta { display: flex; flex-direction: column; gap: 2px; }
.spec-meta strong { font-family: var(--font-display); font-size: 0.88rem; color: var(--ink); }
.spec-meta em { font-style: normal; font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft); }

@media (max-width: 820px) {
  .svc-grid { grid-template-columns: 1fr; gap: 2.2rem; }
  .svc--flip .svc-visual { order: 0; }
  .svc-stage { max-width: 440px; margin-inline: auto; }
  .svc-lead { max-width: none; }
}

/* ---- Sticky mobile CTA ---- */
.sticky-cta {
  position: fixed;
  bottom: max(1rem, env(safe-area-inset-bottom));
  left: 50%;
  z-index: 45;
  display: none;
  align-items: center;
  gap: 0.4em;
  transform: translateX(-50%);
  background: var(--purple);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.92rem;
  letter-spacing: 0.01em;
  text-decoration: none;
  padding: 0.85rem 1.4rem;
  border-radius: 999px;
  box-shadow: 0 14px 36px -10px rgba(111, 0, 255, 0.55);
  transition: transform 0.4s var(--ease-out), opacity 0.4s var(--ease-out), background 0.25s ease;
}
.sticky-cta:hover, .sticky-cta:active { background: var(--purple-deep); }
.sticky-cta .arr { display: inline-block; transition: transform 0.25s ease; }
.sticky-cta:hover .arr { transform: translateX(2px); }
.sticky-cta.is-hidden { opacity: 0; transform: translate(-50%, 140%); pointer-events: none; }
@media (max-width: 900px) { .sticky-cta { display: inline-flex; } }

/* ---- First-visit boot loader ----
   The overlay element is created by the inline <head> script (so it paints
   before content, no flash) and removed on load. These rules add the slash +
   progress-bar animation; the fullscreen backdrop is set inline by that script
   so it's correct even before this sheet parses. Shows once per tab session. */
.ok-loader { background: var(--paper); }
.ok-loader__inner {
  position: relative;
  width: 84px;
  height: 84px;
  display: grid;
  place-items: center;
}
/* circular progress around the signature slash — fills once, smoothly */
.ok-loader__ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;           /* let the arc's glow halo out — svg clips to a square otherwise */
  transform: rotate(-90deg);   /* start the fill at 12 o'clock */
}
.ok-loader__track {
  fill: none;
  stroke: var(--line);
  stroke-width: 5;
}
.ok-loader__prog {
  fill: none;
  stroke: var(--purple);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-dasharray: 289;       /* 2π·46 ≈ circumference */
  stroke-dashoffset: 289;      /* start empty */
  will-change: stroke-dashoffset, filter;
  /* Matching glow with the slash. Trade: re-rastered every frame, so under
     heavy main-thread contention it can jitter. Linear easing keeps any
     dropped frames as small even jumps. Paused until first paint. */
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--purple) 55%, transparent));
  animation: ok-fill 0.7s linear forwards;
  animation-play-state: paused;
}
/* Sora glyph — hidden until document.fonts.load resolves, so the user never
   sees a fallback-font flash. The inline head script flips .is-ready when
   Sora 800 is loaded (2s safety cap), and only then does the fade-in run. */
.ok-loader__slash {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 2rem;
  line-height: 1;
  color: var(--purple);
  transform: skewX(-10deg);
  opacity: 0;
  visibility: hidden;
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--purple) 55%, transparent));
}
.ok-loader__slash.is-ready {
  visibility: visible;
  animation: ok-fade-in 0.4s var(--ease-out) forwards;
}
@keyframes ok-fill { to { stroke-dashoffset: 0; } }
@keyframes ok-fade-in { to { opacity: 1; } }

/* ---- Scroll reveal ---- */
[data-reveal], [data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(34px);
  transition: opacity 1.1s var(--ease-out), transform 1.1s var(--ease-out);
  transition-delay: var(--rd, 0s);
}
[data-reveal].reveal-in,
[data-reveal-stagger].reveal-in > * { opacity: 1; transform: none; }
[data-reveal-stagger].reveal-in > *:nth-child(2) { transition-delay: 0.14s; }
[data-reveal-stagger].reveal-in > *:nth-child(3) { transition-delay: 0.28s; }
[data-reveal-stagger].reveal-in > *:nth-child(4) { transition-delay: 0.42s; }
[data-reveal-stagger].reveal-in > *:nth-child(5) { transition-delay: 0.56s; }
[data-reveal-stagger].reveal-in > *:nth-child(6) { transition-delay: 0.70s; }
[data-reveal-stagger].reveal-in > *:nth-child(7) { transition-delay: 0.84s; }
/* Returning visits (sessionStorage `ok-booted` is set: not the first paint
   in this tab session): the cross-document View Transition crossfade already
   provides the entrance fade. The slower per-element rise / data-reveal
   animations compounding on top of its 220ms ramp produce a velocity-kink
   stutter — most visible on the 1s-delayed hero CTA. Skip the per-element
   entrances on subsequent visits; the user saw the choreography once. */
:root.is-returning h1,
:root.is-returning .lede,
:root.is-returning .cta-row,
:root.is-returning .actions,
:root.is-returning .services,
:root.is-returning [data-reveal],
:root.is-returning [data-reveal-stagger] > * {
  animation: none !important;
  opacity: 1 !important;
  transform: none !important;
  transition: none !important;
}
@media (prefers-reduced-motion: reduce) {
  [data-reveal], [data-reveal-stagger] > * {
    opacity: 1 !important; transform: none !important; transition: none !important;
  }
}

/* ---- Buttons + ghost links (shared; migrated from page-inline so /contact/ can reuse) ---- */
.btn {
  position: relative;
  overflow: hidden;
  font-family: var(--font-display);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.98rem;
  background: var(--purple);
  color: #fff;
  padding: 0.95rem 1.6rem;
  border-radius: 999px;
  box-shadow: 0 6px 20px rgba(111, 0, 255, 0.22);
  translate: var(--mgx, 0) var(--mgy, 0);
  transition: translate 0.22s var(--ease-out), transform 0.2s ease, box-shadow 0.2s ease;
}
/* slash-angle shine that sweeps across on hover */
.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 38%, rgba(255, 255, 255, 0.28) 50%, transparent 62%);
  transform: translateX(-130%);
  transition: transform 0.65s var(--ease-out);
  pointer-events: none;
}
.btn:hover { transform: translateY(-2px); box-shadow: 0 10px 26px rgba(111, 0, 255, 0.28); }
.btn:hover::after { transform: translateX(130%); }
@media (prefers-reduced-motion: reduce) { .btn::after { display: none; } }
.ghost {
  font-family: var(--font-display);
  text-decoration: none;
  color: var(--ink);
  font-weight: 600;
  font-size: 0.98rem;
  border-bottom: 2px solid var(--purple);
  padding-bottom: 2px;
  transition: color 0.2s ease;
}
.ghost:hover { color: var(--purple); }
.ghost .at { color: var(--purple); font-weight: 700; }

/* ---- Contact + lead form (shared by homepage contact section + /contact/ page) ---- */
.contact { text-align: center; }
.contact .section-h { max-width: 20ch; margin-inline: auto; }
.contact-sub { margin: 1.1rem auto 2rem; max-width: 48ch; color: var(--ink-soft); line-height: 1.6; }
.contact .cta-row { justify-content: center; animation: none; opacity: 1; margin-top: 0; }
.lead-form {
  width: 100%;
  max-width: 560px;
  margin: 2rem auto 0;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.lf-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 520px) { .lf-row { grid-template-columns: 1fr; } }
.lf-field { display: flex; flex-direction: column; gap: 0.4rem; }
.lf-label {
  font-family: var(--font-display);
  font-size: 0.74rem; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--ink-soft);
}
.lead-form input,
.lead-form select,
.lead-form textarea {
  font-family: var(--font-body);
  font-size: 0.96rem;
  color: var(--ink);
  background: var(--tag-bg);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0.8rem 0.95rem;
  width: 100%;
  transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}
.lead-form textarea { resize: vertical; min-height: 116px; }
.lead-form select { appearance: none; cursor: pointer; }
/* Force the native option popup to match the dark theme regardless of
   browser/OS — var(--tag-bg) is translucent, so options need a solid color. */
.lead-form select option {
  background-color: #14161A;
  color: var(--ink);
}
:root[data-theme="light"] .lead-form select option {
  background-color: #FFFFFF;
  color: #0B0C0C;
}
.lead-form input::placeholder,
.lead-form textarea::placeholder { color: var(--ink-soft); opacity: 0.7; }
.lead-form input:focus,
.lead-form select:focus,
.lead-form textarea:focus {
  outline: none;
  border-color: var(--purple);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--purple) 22%, transparent);
  background: transparent;
}
/* honeypot — hidden from humans, catnip for bots */
.lf-hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.lf-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.9rem 1.2rem; }
.lead-form .btn { border: 0; cursor: pointer; }
.lead-form .btn[disabled] { opacity: 0.6; cursor: progress; }
.lf-status { font-size: 0.88rem; color: var(--ink-soft); }
.lf-status.is-ok { color: var(--purple); font-weight: 600; }
.lf-status.is-err { color: #ff5a6e; }
.lf-alt { margin: 1.2rem auto 0; font-size: 0.9rem; color: var(--ink-soft); }
.lead-form.is-sent { opacity: 0.96; }

/* ---- Newsletter signup (Log opt-in capture; shared by blog index + posts) ---- */
.newsletter {
  width: 100%;
  max-width: 580px;
  margin: 3.4rem auto 0;
  padding: 2.2rem 1.8rem;
  text-align: center;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--tag-bg);
}
.newsletter h2 {
  margin: 0.5rem 0 0.6rem;
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 3vw, 1.8rem);
}
.nl-sub { margin: 0 auto 1.5rem; max-width: 44ch; color: var(--ink-soft); line-height: 1.6; font-size: 0.95rem; }
.nl-form { display: flex; flex-wrap: wrap; gap: 0.7rem; justify-content: center; }
.nl-input {
  flex: 1 1 240px;
  max-width: 320px;
  font-family: var(--font-body);
  font-size: 0.96rem;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0.8rem 0.95rem;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.nl-input::placeholder { color: var(--ink-soft); opacity: 0.7; }
.nl-input:focus {
  outline: none;
  border-color: var(--purple);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--purple) 22%, transparent);
}
.nl-form .btn { border: 0; cursor: pointer; }
.nl-form .btn[disabled] { opacity: 0.6; cursor: progress; }
.nl-status { display: block; margin-top: 1rem; min-height: 1.2em; font-size: 0.88rem; color: var(--ink-soft); }
.nl-status.is-ok { color: var(--purple); font-weight: 600; }
.nl-status.is-err { color: #ff5a6e; }
.newsletter.is-sent .nl-form { opacity: 0.55; }

/* ---- shared page intro (migrated from src/pages/contact.html + services.html) ---- */
.page-intro { padding: clamp(2.5rem, 7vh, 4.5rem) 0 clamp(1.5rem, 4vh, 2.5rem); text-align: center; }
.page-intro h1 {
  font-family: var(--font-display); font-weight: 800; letter-spacing: -0.025em;
  line-height: 1.05; font-size: clamp(2.2rem, 5.5vw, 3.6rem);
  margin: 0.4rem auto 1.2rem; max-width: 18ch; color: var(--ink);
}
.page-intro h1 .accent { color: var(--purple); }
.page-intro .lede {
  color: var(--ink-soft); font-size: clamp(1rem, 2vw, 1.12rem);
  line-height: 1.6; max-width: 56ch; margin: 0 auto;
}

/* ---- shared service-list cell typography (migrated from index.html + coming-soon.html) ---- */
.service-num {
  font-family: var(--font-display);
  font-size: 0.72rem; font-weight: 600;
  letter-spacing: 0.14em; color: var(--purple);
}
.service-name {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 1.6vw, 1.4rem);
  font-weight: 700; color: var(--ink); line-height: 1.1;
}
