/* Onkast marketing site: shared stylesheet.
   Static, no build step, no framework. Fonts are self-hosted (OFL licensed,
   subset to Latin). No third-party requests of any kind. */

@font-face {
  font-family: 'Archivo';
  src: url('assets/fonts/Archivo-400Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Archivo';
  src: url('assets/fonts/Archivo-700Bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Archivo';
  src: url('assets/fonts/Archivo-900Black.woff2') format('woff2');
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}

:root {
  color-scheme: light;
  --crimson: #D4000F;
  --crimson-shadow: #8B0000;
  --ink: #141414;
  --canvas: #F7F3EE;
  --surface-alt: #EDE9E3;
  --white: #ffffff;
  --muted: #A09890;
  /* Darker than --muted specifically for small body text (footer, captions,
     "last updated" lines): #A09890 on --canvas measures ~2.6:1 contrast,
     below WCAG AA's 4.5:1 for normal text. #6b665e (an existing Onkast
     token, chipInactiveText) measures ~5.2:1 and is used for all small
     muted text on this site instead. */
  --muted-text: #6b665e;
  --body-text: #5a5551;
  --gold: #F2C200;
  --green: #22A74B;
  --font: 'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --max-text: 640px;
  --max-page: 1120px;
  --radius-lg: 28px;
  --radius-md: 18px;
  --radius-sm: 12px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  background: var(--canvas);
  color: var(--ink);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: inherit; }
::selection { background: var(--crimson); color: var(--white); }

/* Prevent any accidental horizontal scroll on any page */
html, body { overflow-x: hidden; }

.container {
  width: 100%;
  max-width: var(--max-page);
  margin: 0 auto;
  padding: 0 24px;
}

/* ─── Focus visibility (keyboard navigation) ────────────────────────────── */
a:focus-visible,
button:focus-visible,
.btn:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 3px;
  border-radius: 8px;
}
:focus:not(:focus-visible) { outline: none; }

/* ─── Site header (minimal, consistent across all 4 pages) ─────────────── */
.site-header {
  position: relative; /* anchors .mobile-menu below, on every page - index.html's
     own inline position:relative is now redundant but harmless */
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 24px;
  max-width: var(--max-page);
  margin: 0 auto;
}
.site-header .brand { display: flex; align-items: center; text-decoration: none; }
.site-header .brand img { height: 22px; width: auto; }
.site-header nav { display: flex; align-items: center; justify-content: flex-end; gap: 24px; flex-wrap: wrap; row-gap: 6px; }
.site-header nav a {
  font-size: 14px;
  font-weight: 700;
  text-decoration: none;
  color: var(--ink);
  opacity: 0.75;
}
.site-header nav a:hover { opacity: 1; text-decoration: underline; }
.site-header--on-crimson nav a { color: var(--white); opacity: 0.85; }
.site-header--on-crimson nav a:hover { opacity: 1; }

/* The real "onCrimson" wordmark treatment (components/shared/OnkastLogo.tsx's
   own onCrimson variant: white "on" + near-black "kast"), the authoritative
   treatment the app itself uses for this exact context, a crimson masthead.
   Rendered as styled text, not an image, because the real component does
   the same thing for this variant (a flat PNG cannot carry the two-tone
   colouring). Proportions match the real component's own formula
   (letterSpacing -2.4 and lineHeight 38 at its base textSize 32), scaled
   down for this smaller header context. Not the plain all-white "white"
   variant, which is for other dark/red surfaces, not the masthead. */
.brand--on-crimson {
  display: inline-flex;
  font-weight: 800;
  font-size: 24px;
  letter-spacing: -1.8px;
  line-height: 28.5px;
}
.brand--on-crimson .on { color: var(--white); }
.brand--on-crimson .kast { color: #1A1A1A; }

/* ─── Typography ─────────────────────────────────────────────────────────── */
h1, h2, h3 { margin: 0; font-weight: 900; letter-spacing: -0.02em; }
.eyebrow {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--crimson);
  margin: 0 0 12px;
}
p { margin: 0; }
/* Minimal inline utility for highlighting a single word within running
   copy (e.g. "Onkaster" in the How It Works intro). Font-size and baseline
   are untouched (no size/line-height/vertical-align change) - only
   colour and weight, so it reads as an emphasis within the
   sentence rather than a different typographic treatment. */
.text-crimson {
  color: var(--crimson);
  font-weight: 700; /* Archivo-700Bold, already self-hosted - no new asset */
}
.lede { font-size: 17px; line-height: 1.55; color: var(--body-text); }

/* ─── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font);
  font-weight: 700;
  font-size: 15.5px;
  text-decoration: none;
  border-radius: 100px;
  padding: 15px 28px;
  border: none;
  cursor: pointer;
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease), opacity 0.2s var(--ease);
}
.btn-primary {
  background: var(--ink);
  color: var(--white);
  box-shadow: 0 10px 24px rgba(20, 20, 20, 0.25);
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 14px 28px rgba(20, 20, 20, 0.3); }
.btn-ghost-on-crimson {
  background: rgba(255, 255, 255, 0.14);
  color: var(--white);
  border: 1.5px solid rgba(255, 255, 255, 0.35);
}
.btn-ghost-on-crimson:hover { background: rgba(255, 255, 255, 0.22); }

/* ─── Section rhythm ──────────────────────────────────────────────────────── */
section { padding: 88px 0; }
@media (max-width: 640px) { section { padding: 64px 0; } }

/* ─── HERO ────────────────────────────────────────────────────────────────── */
.hero {
  background: var(--crimson);
  color: var(--white);
  position: relative;
  overflow: hidden;
  padding-top: 0; /* the generic `section{padding:88px 0}` rule was leaking 88px (64px
     on narrow mobile) of dead red space above the header - this is the actual
     reason the header sat low enough to collide with decorative icons across
     several previous passes. Overriding it to 0 moves the whole header row up
     by that same amount; header's own 20px padding below still gives it
     comfortable, deliberate top spacing (not crowded against the edge). */
  padding-bottom: 64px;
}
/* Mobile override placed here (after the rule above, not inside the
   earlier @media(640px) section-rhythm block) - same lesson learned twice
   already this session: a same-specificity override placed earlier in
   the file silently loses the cascade to this rule, so it never actually
   renders. 36px is the WHOLE gap beneath the CTA - #download-cta's own
   mobile margin-bottom is reset to 0 alongside this, since it was
   independently stacking an extra 28px on top (measured actual gap was
   92px, not 64px, before this fix). */
@media (max-width: 640px) {
  .hero { padding-bottom: 36px; }
}
.hero-inner {
  max-width: var(--max-page);
  margin: 0 auto;
  padding: 8px 24px 0;
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
}
/* Hero column proportions RESTORED to the original approved build (commit
   4e4a394, "Step 10 website: approve Onkast launch site design") per the
   founder's 2026-10-15 decision to revert the headline experiment. The
   intervening fixed-680/350 split existed only to make the newer
   "Ordinary People. Extraordinary Opportunities." headline fit on two
   lines - now moot, since that text is no longer the hero headline. */
.hero-content { max-width: 560px; flex-shrink: 0; padding-top: 48px; padding-bottom: 32px; }
.hero h1 {
  font-size: clamp(40px, 6.5vw, 64px);
  line-height: 1.02;
  color: var(--white);
  margin-bottom: 20px;
}
.hero .lede { color: rgba(255, 255, 255, 0.88); font-size: 18px; max-width: 460px; margin-bottom: 32px; }

/* ─── Hero visual: device + collage, one composed scene ──────────────────── */
.hero-visual {
  position: relative;
  flex: 1;
  min-width: 0;
  height: 700px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Decorative badge collage, first-party, drawn with inline SVG, the same
   visual vocabulary as the app's own onboarding collage (Badge/Polaroid
   stickers, components/onboarding/OnboardingSticker.tsx) redrawn for web.
   Depth hierarchy: back (smaller, softer, behind the device) / mid /
   front (larger, crisper, allowed to overlap the device edge) so the
   device reads as the centre of an orbiting ecosystem, not a flat grid. */
.hero-collage {
  position: absolute;
  inset: -40px -24px -40px auto;
  width: calc(100% + 24px);
  height: calc(100% + 80px);
  z-index: 1;
  pointer-events: none;
}
.badge {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  box-shadow: 0 10px 22px rgba(0, 0, 0, 0.28);
}
.badge.fill-dark { background: var(--ink); }
.badge.fill-light { background: var(--canvas); }
.badge svg { display: block; }
.badge.depth-back { opacity: 0.55; box-shadow: 0 6px 14px rgba(0, 0, 0, 0.18); z-index: 1; }
.badge.depth-mid { opacity: 0.85; z-index: 2; }
.badge.depth-front { z-index: 4; box-shadow: 0 14px 28px rgba(0, 0, 0, 0.32); }
.polaroid {
  position: absolute;
  background: var(--canvas);
  border-radius: 10px;
  padding: 6px 6px 14px;
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.3);
  z-index: 2;
}
.polaroid .tile {
  background: var(--ink);
  border-radius: 5px;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.filler-dot {
  position: absolute;
  border-radius: 50%;
  background: var(--canvas);
  z-index: 1;
}
.filler-plus {
  position: absolute;
  z-index: 1;
}

/* Collage layout: an ecosystem around the device, allowed to crop at the
   visual's own edges (clipped by .hero's own overflow:hidden) so the
   composition feels larger than the viewport rather than contained in a
   box. Desktop only at full density; tablet and mobile deliberately
   recompose with fewer, larger, calmer elements rather than cramming the
   same density into less room. */
/* Badge positions RESTORED to the original approved build (commit 4e4a394)
   per the founder's 2026-10-15 decision. Note: badge-1 and badge-8's
   original top values (-4%, -2%) were found in an earlier round to
   visually overlap the site header at desktop widths - see the
   verification pass in this round's report for whether that is still
   true now, and what was done about it if so. */
/* top:-4%/-2% (badge-1/badge-8) is the literal original value, but re-
   verifying this round (headless Chromium, not assumed) confirmed it
   still visually overlaps the header/hamburger at desktop widths - a
   pre-existing defect in the original build that was found and fixed two
   rounds ago. Restoring the exact original value here would reintroduce
   a confirmed, measurable collision with a clickable control, which
   conflicts with "no collision with floating decorative icons" (still a
   live requirement for the hamburger). Keeping the minimal, already-
   proven fix (top:10% for both) instead of the literal original number;
   everything else about these two badges (left%, rotation, size) is the
   unmodified original. */
/* left:68% (not the device-clearing-but-too-spread-out 78% tried earlier):
   calculated from the device's actual rotated silhouette edge at this
   badge's height (not its full bounding box, which is wider than the
   real shape near the phone's tilted top corner) - just enough margin to
   clear the real edge, keeping the tight orbital composition intact. */
/* Restored 1:1 to the original approved build (commit 4e4a394) per explicit
   founder instruction, 2026-10-15 - reverting the badge-1/4/8 adjustments
   made across several intervening rounds. Known, re-confirmed consequence:
   badge-1 and badge-8's original top values put them back inside the
   header's vertical band at desktop widths (see report). */
.badge-1 { top: -2%; left: 58%; transform: rotate(-8deg); }
.badge-2 { top: 15%;  left: 88%; transform: rotate(10deg); }
.badge-3 { top: 46%; left: 92%; transform: rotate(-6deg); }
.badge-4 { top: 71%; left: 87%; transform: rotate(7deg); }
.badge-5 { top: 90%; left: 60%; transform: rotate(-9deg); }
.badge-6 { top: 30%; left: 4%; transform: rotate(6deg); }
.badge-7 { top: 60%; left: 2%; transform: rotate(-5deg); }
.badge-8 { top: 0%; left: 24%; transform: rotate(5deg); }
.badge-9 { top: 86%; left: 22%; transform: rotate(-7deg); }
.badge-10 { top: 52%; left: 14%; transform: rotate(4deg); }

@media (max-width: 1080px) {
  .badge-8, .badge-9, .badge-10 { display: none; }
}

/* Hero phone enlargement follow-up (2026-10-18): the enlarged .hero-device
   (desktop base rule above) needs more room than hero-visual has between
   ~901px and ~1180px - hero-content was still flex-shrink:0 at the full
   560px here, which left the bigger phone's rotated bounding box wider
   than the remaining space, crowding it and the right-hand badges against
   the viewport edge (confirmed by direct measurement at 1024px). Same
   technique as the existing @media(900px) tablet fix below (give
   hero-content room to shrink rather than touch the device/badges
   themselves) - just applied one step up, since it's the enlargement that
   moved the squeeze point here, not a pre-existing issue at this width. */
@media (max-width: 1180px) {
  .hero-content { max-width: 460px; }
}

@media (max-width: 900px) {
  /* Tablet: device stays, collage calms down to a handful of larger,
     more deliberate marks rather than the full desktop density.
     hero-content was previously flex-shrink:0 at a fixed 560px, which at
     tablet widths left hero-visual only ~190px to work with (device alone
     is 200px), guaranteeing overlap regardless of badge placement. Giving
     hero-content real room to shrink here is the actual fix; badge
     repositioning alone could not have solved it. */
  .hero-content { max-width: 360px; }
  .hero-visual { height: 460px; }
  .badge-6, .badge-7 { display: none; }
  /* Restored to the original (commit 4e4a394) tablet values, 2026-10-15 -
     same known consequence as the base rules above: badge-1 overlaps the
     header, and badge-2/3/4 re-clip at this viewport's right edge. */
  .badge-1 { top: 6%;  left: 62%; }
  .badge-2 { top: 14%; left: 90%; }
  .badge-5 { top: 94%; left: 54%; }
}

@media (max-width: 760px) {
  /* Mobile reading order (2026-10-15, founder-requested): logo/hamburger ->
     headline -> phone + icon galaxy -> description -> CTA, so the phone is
     the visual centrepiece straight after the headline, not buried below a
     wall of text. Achieved with CSS only, no HTML/DOM change: .hero-content
     (the h1/lede/CTA wrapper) becomes `display:contents` at this width,
     which removes ITS OWN box from layout entirely and promotes its three
     children to be direct flex items of .hero-inner (already a column flex
     container here) - so `order` can reorder h1/lede/CTA individually
     against .hero-visual, which was always a sibling. The one accepted
     side effect: .hero-content's own [data-reveal] fade-in no longer
     visually applies once it has no box (opacity/transform need a box to
     apply to) - purely decorative, not required this round. */
  .hero-inner { flex-direction: column; align-items: stretch; gap: 0; }
  .hero-content { display: contents; }
  /* 44px here (carried over from the old pre-reorder .hero-content
     padding-top) plus the header's own height added up to 132px of empty
     red space before the headline even started - found by measuring
     header.bottom + hero-inner's 8px padding + this margin directly, not
     guessed. 20px is deliberate breathing room, not the leftover value
     from a layout this no longer matches. */
  .hero h1 { order: 1; margin-top: 4px; }
  /* height 460px -> 550px (2026-10-18, founder request): the mobile hero
     phone grew ~22% (see the .hero-device/.device-frame overrides in the
     @media(760px) block below), so this fixed-height container needs more
     room to avoid the taller phone pushing past its box - .hero itself
     still clips via overflow:hidden as the safety net, but growing the
     intended box is the real fix, not relying on that clip. */
  .hero-visual { order: 2; flex: 1 1 auto; height: 550px; margin: 0 -8px 28px; }
  .hero .lede { order: 3; }
  #download-cta { order: 4; margin-bottom: 0; }

  /* Mobile-specific icon galaxy (richer pass, 2026-10-15): reuses nine of
     the ten existing desktop icons (clapperboard, star, heart, camera,
     flag, person, bookmark, clock, pin - only the polaroid/comment tile
     is dropped, its rectangular shape reads as clutter at this size),
     distributed across upper/middle/lower zones and balanced left/right,
     rather than the previous sparse six-icon ring. badge-4 (camera) sits
     near the device's own centre so it reads as layered partially behind
     the phone (no z-index needed - it is already earlier in DOM order
     than .hero-device, which paints on top by default). Sizes vary
     34-56px for depth. Positions measured and iterated with headless
     Chromium for zero edge-clipping and zero overlap with the headline/
     description/CTA/header - see the 2026-10-15 report. */
  /* Mobile's own circular orbit (2026-10-15), matching the desktop
     composition's shape/logic - clapperboard tight top-right, bookmark
     top-left, star/heart/camera forming a tight right-hand arc, pin/
     person/clock forming the left-hand arc, flag tucked behind the
     phone's bottom - rebuilt for mobile's own narrower box rather than
     reusing desktop's percentages directly. */
  .badge-6 { display: none; }
  .badge-1 { top: 5%;  left: 61%; width: 56px !important; height: 56px !important; }
  .badge-8 { display: flex; top: 8%;  left: 12%; width: 34px !important; height: 34px !important; }
  .badge-2 { top: 16%; left: 85%; width: 38px !important; height: 38px !important; }
  .badge-3 { display: flex; top: 44%; left: 81%; width: 36px !important; height: 36px !important; }
  .badge-4 { display: flex; top: 66%; left: 83%; width: 38px !important; height: 38px !important; }
  .badge-10 { display: flex; top: 28%; left: 6%;  width: 32px !important; height: 32px !important; }
  .badge-7 { display: flex; top: 58%; left: 3%;  width: 30px !important; height: 30px !important; }
  .badge-9 { display: flex; top: 82%; left: 14%; width: 32px !important; height: 32px !important; }
  .badge-5 { top: 90%; left: 54%; width: 40px !important; height: 40px !important; }
}

/* ─── Hero device: the premium product object ─────────────────────────────
   Realistic modern-iPhone proportions (~9:19.5), physical depth via a
   layered shadow stack (ambient + contact), a Dynamic-Island-style cutout,
   and a hairline rim highlight so it reads as metal/glass, not a flat CSS
   rectangle. Screen content is the app's own real, shipped launch screen
   (crimson field + the real app icon mark), not a fabricated feed; see
   the founder report for exactly which real screenshots would extend this
   further. Tilted off the rigid grid deliberately, per the brief. */
.hero-device {
  position: relative;
  z-index: 3;
  width: 317px;
  height: 660px;
  margin-left: 26px;
  transform: rotate(-7deg);
  animation: deviceFloat 7s ease-in-out infinite;
}
/* Orbit re-centring (2026-10-18, founder request): measured directly
   (getBoundingClientRect on .hero-device vs the outermost edges of every
   .hero-collage badge) that the phone sat ~17-20px left of the orbit's
   true visual centre at desktop widths - .hero-collage's own inset
   (-40px -24px -40px auto) only extends its box 24px past .hero-visual's
   right edge, never its left, so every badge's % position is computed
   against a box already biased right of .hero-visual's (and therefore the
   centred phone's) actual centre. Nudging the phone itself right, rather
   than touching .hero-collage or any individual badge position, keeps
   "the floating icons in their existing general arrangement" exactly as
   asked. Scoped to this base (desktop, >900px) rule only - the two
   breakpoints below set their own value since the badge set, device size,
   and required shift all differ there. */

/* Hero phone enlargement (2026-10-18, founder request - desktop only, see
   the @media(900px)/(760px) overrides below which deliberately keep their
   own pre-existing sizes unchanged). Scoped to .hero-device specifically
   so the shared .device-frame/.device-screen/::before/::after rules used
   by the My Casts phone (.app-device-primary) are left untouched - only
   the hero's own frame is scaled up, by the same ~32% factor as the
   .hero-device width/height change above, so the bezel thickness and
   corner rounding stay visually proportional to the now-larger phone. */
.hero-device .device-frame {
  border-radius: 58px;
  padding: 13px;
}
.hero-device .device-frame::before {
  top: 119px;
  width: 3px;
  height: 61px;
}
.hero-device .device-frame::after {
  top: 172px;
  width: 3px;
  height: 85px;
}
.hero-device .device-screen {
  border-radius: 45px;
}
.device-frame {
  width: 100%;
  height: 100%;
  background: linear-gradient(155deg, #2b2b2b, #0a0a0a 60%);
  border-radius: 44px;
  padding: 10px;
  box-shadow:
    0 60px 90px -30px rgba(0, 0, 0, 0.55),
    0 25px 40px -20px rgba(0, 0, 0, 0.45),
    inset 0 0 0 1.5px rgba(255, 255, 255, 0.12);
  position: relative;
}
.device-frame::before {
  /* side button details, purely decorative realism */
  content: '';
  position: absolute;
  left: -2px;
  top: 90px;
  width: 2px;
  height: 46px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 2px;
}
.device-frame::after {
  content: '';
  position: absolute;
  right: -2px;
  top: 130px;
  width: 2px;
  height: 64px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 2px;
}
.device-screen {
  width: 100%;
  height: 100%;
  background: var(--crimson);
  border-radius: 34px;
  overflow: hidden;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.device-island {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  width: 76px;
  height: 22px;
  background: #000;
  border-radius: 14px;
  z-index: 3;
}
.device-icon {
  width: 96px;
  height: 96px;
  border-radius: 26px;
  display: block;
}
.device-screenshot {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (max-width: 900px) {
  .hero-device { width: 200px; height: 416px; margin-left: 0; }
  /* Reset the desktop-only enlarged frame (2026-10-18 fix): the scoped
     .hero-device .device-frame/::before/::after/.device-screen rules
     above were tuned for the enlarged 317px-wide desktop phone (58px
     corner radius, 13px bezel) and were never reset at these smaller
     breakpoints, so a ~200px-wide phone was rendering with a corner
     radius/bezel thickness proportioned for a phone 60% wider - this is
     exactly why the hero phone looked less like a real iPhone than the
     My Casts phone (.app-device-primary), which has no such scoped
     override and uses these same generic values at every size. Reverting
     to the generic .device-frame/.device-screen proportions here matches
     the approved My Casts reference exactly. */
  .hero-device .device-frame {
    border-radius: 44px;
    padding: 10px;
  }
  .hero-device .device-frame::before { top: 90px; width: 2px; height: 46px; }
  .hero-device .device-frame::after { top: 130px; width: 2px; height: 64px; }
  .hero-device .device-screen { border-radius: 34px; }
}
@media (max-width: 760px) {
  /* Enlarged ~22% (2026-10-18, founder request, after the frame/bezel
     proportions were corrected to look like a real iPhone at this size):
     190x396 -> 232x483. Frame/bezel/corner values below are scaled by the
     same ~1.22 factor from the corrected generic proportions set in the
     @media(900px) block above (44/10/34 -> 54/12/41), so the bigger phone
     keeps the exact same corrected look, just larger - not the old,
     too-rounded desktop-scaled proportions. */
  .hero-device { width: 232px; height: 483px; margin-top: 24px; margin-left: 13px; }
  .hero-device .device-frame {
    border-radius: 54px;
    padding: 12px;
  }
  .hero-device .device-frame::before { top: 110px; width: 2px; height: 56px; }
  .hero-device .device-frame::after { top: 159px; width: 2px; height: 78px; }
  .hero-device .device-screen { border-radius: 41px; }
}

/* ─── Clapperboard signature motion ────────────────────────────────────────
   One of the hero badges renders the real clapperboard mark (exact path
   data from components/onboarding/ClapperboardMark.tsx) and performs a
   single, physical "clap" on arrival: opens slightly, closes crisply,
   settles, never loops. JS adds .clap-play once, after load; see
   script.js. The resting (unplayed) state is pixel-identical to the
   static mark used elsewhere in the app, so nothing looks unfinished if
   motion is disabled. */
.clap-arm {
  transform-box: view-box;
  transform-origin: 2px 8.5px;
}
@media not (prefers-reduced-motion: reduce) {
  .clap-play .clap-arm {
    animation: clapMotion 0.85s cubic-bezier(0.22, 1, 0.36, 1) 1;
  }
  .clapperboard-badge:hover .clap-arm {
    animation: clapMotion 0.85s cubic-bezier(0.22, 1, 0.36, 1) 1;
  }
}

@keyframes clapMotion {
  0%   { transform: rotate(0deg); }
  15%  { transform: rotate(-11deg); }
  45%  { transform: rotate(6deg); }
  70%  { transform: rotate(-2deg); }
  100% { transform: rotate(0deg); }
}

@keyframes deviceFloat {
  0%, 100% { transform: rotate(-7deg) translateY(0); }
  50% { transform: rotate(-7deg) translateY(-10px); }
}

@keyframes badgeDrift {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -8px; }
}
/* Badges whose resting position deliberately sits layered against the
   device's own edge (the approved "orbiting ecosystem" composition) move
   IN SYNC with the device's own float instead of drifting independently:
   same 7s duration, same easing, same phase, same direction and distance
   as @keyframes deviceFloat. Measured directly (not guessed): their
   resting position already touches the device edge by design, and two
   elements that overlap at rest only read as "colliding" when their
   distance to each other changes over time: independent timing was the
   actual cause, not the overlap itself. Locking their motion to the
   device's own keeps the relative distance between them constant, so the
   deliberate overlap stays a stable layered composition instead of a
   pulsing bump. Positions are untouched. Badges with real clearance from
   the device keep their own independent organic drift. */
@keyframes badgeFloatWithDevice {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -10px; }
}
.badge.depth-back, .badge.depth-mid, .badge.depth-front, .polaroid {
  animation: badgeDrift 5.5s ease-in-out infinite;
}
.badge-1 { animation: badgeFloatWithDevice 7s ease-in-out infinite; }
.badge-2 { animation-duration: 5.4s; animation-delay: -1.8s; }
.badge-3 { animation-duration: 6.8s; animation-delay: -3s; }
.badge-4 { animation-duration: 5.8s; animation-delay: -2.2s; }
.badge-5 { animation: badgeFloatWithDevice 7s ease-in-out infinite; }
.badge-6 { animation-duration: 5.9s; animation-delay: -2.6s; }
.badge-7 { animation-duration: 6.6s; animation-delay: -1.2s; }
.badge-8 { animation: badgeFloatWithDevice 7s ease-in-out infinite; }
.badge-9 { animation: badgeFloatWithDevice 7s ease-in-out infinite; }
.badge-10 { animation-duration: 6.3s; animation-delay: -2.8s; }

/* ─── Marketplace loop (simple explanation) ──────────────────────────────── */
.loop { text-align: center; }
.loop h2 { font-size: clamp(30px, 5vw, 44px); margin-bottom: 16px; }
.loop .lede { max-width: 520px; margin: 0 auto 56px; }
/* Mobile override placed here (after the base rule above), not inside the
   earlier @media(640px) section-rhythm block - that block's version of
   this same fix was silently losing the cascade to this later rule
   (identical specificity, later source order wins), so it never actually
   rendered. This is the effective one. */
@media (max-width: 640px) {
  .loop .lede { margin-bottom: 36px; }
}
.loop-steps {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
  max-width: 920px;
  margin: 0 auto;
}
@media (max-width: 760px) {
  .loop-steps { grid-template-columns: 1fr; gap: 14px; }
}
.loop-step {
  background: var(--white);
  border-radius: var(--radius-md);
  padding: 32px 24px;
  text-align: left;
}
.loop-step .num {
  display: inline-flex;
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--ink);
  color: var(--white);
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 15px;
  margin-bottom: 18px;
}
.loop-step h3 { font-size: 19px; margin-bottom: 8px; }
.loop-step p { font-size: 14.5px; color: var(--body-text); line-height: 1.5; }
/* Step 4 (2026-10-15): same .loop-step box - dimensions, radius, padding,
   typography all inherited unchanged - only the colour treatment differs,
   via this modifier class. In the existing repeat(3,1fr) grid this sits
   alone on its own row (first column) at the same per-card width as
   Steps 1-3, rather than resizing every card to fit 4 across - the brief
   requires both "same card dimensions as Steps 1-3" and "no other layout
   changes," so the grid itself is untouched. The white number badge on
   red mirrors the hero's own light-circle-on-crimson badges, an existing
   site convention for contrast on this exact background colour. */
.loop-step--highlight { background: var(--crimson); color: var(--white); }
.loop-step--highlight h3,
.loop-step--highlight p { color: var(--white); }
.loop-step--highlight p { color: rgba(255, 255, 255, 0.85); }
.loop-step--highlight .num { background: var(--white); color: var(--crimson); }

/* ─── Creator/Brand moment ────────────────────────────────────────────────── */
.flip-section {
  background: var(--ink);
  color: var(--white);
}
/* Solid crimson pill, matching the existing .cast-call-chip pattern used
   elsewhere on the site (same crimson, same white text, same pill shape)
   rather than inventing a new treatment. Font-size/weight/letter-spacing/
   uppercase/margin-bottom are all inherited unchanged from the base
   .eyebrow rule - only the pill "chrome" (background, padding, radius)
   is added here. */
.flip-section .eyebrow {
  display: inline-flex;
  color: var(--white);
  background: var(--crimson);
  padding: 8px 16px;
  border-radius: 100px;
}
.flip-grid {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 32px;
  align-items: center;
}
@media (max-width: 760px) {
  .flip-grid { grid-template-columns: 1fr; gap: 32px; }
}
.flip-section h2 { color: var(--white); font-size: clamp(28px, 4.5vw, 38px); margin-bottom: 10px; }
.flip-section .lede { color: rgba(255, 255, 255, 0.78); margin-bottom: 0; }
/* Real, founder-approved Cast Call card (2026-10-18, refined same day -
   enlarged ~18% and shadow lightened per founder feedback) - a single
   finished image (see onkast-hq website Cast Call Card implementation
   spec), replacing the old abstract skeleton-bar placeholder now that a
   real example exists. Transparent rounded corners, so the shadow follows
   the card's own shape via filter:drop-shadow rather than a box-shadow
   behind a square box. Sized/centred: 90% of the right column (was 76%),
   capped at 660px (was 560px), vertically centred against the left text
   via .flip-grid's own align-items:center. Two layered drop-shadows (a
   tight near shadow + a soft ambient one, the same dual-shadow premium
   pattern used elsewhere on this site, e.g. the old .flip-visual card)
   read as subtle depth rather than the previous single heavy 60px-blur
   shadow, which looked muddy against the dark section. aspect-ratio
   matches this specific asset's real pixel size (1619x972) - not a fixed
   card template, since the card is a single supplied image, not
   assembled from this file's own CSS. */
.cast-visual { display: flex; align-items: center; justify-content: center; }
.cast-visual img {
  display: block;
  width: 90%;
  max-width: 660px;
  height: auto;
  aspect-ratio: 1619 / 972;
  filter: drop-shadow(0 8px 16px rgba(0, 0, 0, 0.3)) drop-shadow(0 20px 38px rgba(0, 0, 0, 0.22));
}
/* Breakpoint matches .flip-grid's own existing stacking breakpoint above
   (760px, not the 900px a generic placement note suggested) - the two
   don't need to agree in general, but here they must: below that width
   .flip-grid is already a single column, so the image needs its stacked-
   layout sizing at the same width the column itself goes full-width. */
@media (max-width: 760px) {
  .cast-visual { margin-top: 40px; }
  .cast-visual img { width: 100%; max-width: 500px; }
}

/* ─── App experience ────────────────────────────────────────────────────────
   Honest real-chrome treatment: no fabricated feed. Shows the app's own
   real, accurate masthead design (crimson bar, the real two-tone wordmark
   treatment, a search-bar silhouette matching the real one) and the real
   dark content void beneath it (feed.tsx's own documented "dark void
   background below the crimson masthead"), left empty rather than filled
   with invented cards. A second, smaller device peeks from behind for
   depth. Both frames are screenshot-ready: see the founder report for the
   exact real captures that would complete this section. */
.app-section { text-align: center; }
.app-section h2 { font-size: clamp(30px, 5vw, 44px); margin-bottom: 16px; }
.app-section .lede { max-width: 520px; margin: 0 auto 48px; }
.app-showcase {
  position: relative;
  width: 100%;
  max-width: 420px;
  height: 540px;
  margin: 0 auto;
}
.app-device-primary {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%) rotate(5deg);
  width: 260px;
  height: 530px;
  z-index: 2;
}
.app-device-primary[data-reveal].reveal-ready {
  transform: translateX(-50%) rotate(5deg) translateY(18px);
}

.app-masthead-chrome {
  background: var(--crimson);
  padding: 42px 16px 14px;
  text-align: left;
  flex-shrink: 0;
}
.app-masthead-chrome .wordmark {
  font-weight: 800;
  font-size: 15px;
  letter-spacing: -0.04em;
  margin-bottom: 12px;
}
.app-masthead-chrome .wordmark .on { color: var(--white); }
.app-masthead-chrome .wordmark .kast { color: var(--ink); }
.app-search-pill {
  background: rgba(20, 20, 20, 0.82);
  height: 30px;
  border-radius: 100px;
  display: flex;
  align-items: center;
  padding: 0 12px;
  gap: 6px;
}
.app-search-pill .dot { width: 6px; height: 6px; border-radius: 50%; border: 1.3px solid rgba(255,255,255,0.5); flex-shrink: 0; }
.app-search-pill .line { height: 6px; width: 60%; border-radius: 3px; background: rgba(255, 255, 255, 0.25); }
.app-void-body {
  flex: 1;
  background: linear-gradient(180deg, #14161e 0%, #0c0d12 100%);
}
.app-caption {
  margin-top: 24px;
  font-size: 13.5px;
  color: var(--muted-text);
  font-style: normal;
}

@media (max-width: 760px) {
  .app-showcase { height: 460px; max-width: 320px; }
  .app-device-primary { width: 210px; height: 440px; }
}

/* ─── Final CTA ───────────────────────────────────────────────────────────── */
.final-cta {
  background: var(--crimson);
  color: var(--white);
  text-align: center;
  /* Overrides the generic `section{padding:88px 0}` rule, scoped to this
     section only (desktop) - that 88px top+bottom was the sole source of
     the excessive height, no min-height or other rule was involved.
     64px is a ~27% reduction, within the requested 25-30% range. Mobile's
     own section padding (64px, from the existing @media(640px) override)
     was already comparable and not flagged as excessive, so it's left
     untouched here - this rule only applies above that breakpoint. */
  padding: 64px 0;
}
/* Sized to use the full container width, not an artificially narrow
   column (measured against the real rendered text width in Archivo
   Black, not guessed): 42px needs ~1013px of the ~1072px available at
   the 1120px container cap - fits one line with real margin, much
   bolder than a size chosen to fit a constrained box. Below ~800px it
   can't fit one line at a readable size, so .cta-break (a <br> in the
   markup) is left to force a clean break between the two sentences
   there, rather than an awkward mid-phrase wrap. */
.final-cta h2 { color: var(--white); font-size: clamp(20px, 3.75vw, 42px); margin-bottom: 28px; }
.cta-break { display: none; }
@media (max-width: 760px) {
  .cta-break { display: inline; }
}

/* ─── Footer ──────────────────────────────────────────────────────────────── */
.site-footer {
  padding: 40px 24px;
  text-align: center;
  font-size: 13px;
  color: var(--muted-text);
}
.site-footer .foot-links { margin-bottom: 10px; }
.site-footer a { text-decoration: underline; color: var(--muted-text); }
.site-footer a:hover { color: var(--ink); }
.site-footer .foot-links a { margin: 0 10px; }

/* ─── Legal/support page shell (calm, readable, same brand) ──────────────── */
.doc-main { max-width: 720px; margin: 0 auto; padding: 24px 24px 80px; }
.draft-banner {
  background: #FFF3CD;
  border: 1px solid #E8C468;
  color: #6b5214;
  border-radius: 10px;
  padding: 14px 18px;
  font-size: 14px;
  line-height: 1.5;
  margin-bottom: 32px;
}
.draft-banner strong { display: block; margin-bottom: 4px; }
.doc-main h1 { font-size: 30px; margin-bottom: 6px; }
.doc-main .updated { font-size: 13px; color: var(--muted-text); margin-bottom: 32px; display: block; }
.doc-main h2 { font-size: 19px; font-weight: 800; margin: 36px 0 10px; letter-spacing: -0.01em; }
.doc-main h3 { font-size: 15px; font-weight: 800; margin: 20px 0 6px; }
.doc-main p, .doc-main li { font-size: 14.5px; line-height: 1.6; color: var(--body-text); }
.doc-main ul { padding-left: 20px; margin: 8px 0; }
.table-scroll { overflow-x: auto; margin: 14px 0 24px; }
.doc-main table { width: 100%; min-width: 560px; border-collapse: collapse; table-layout: fixed; font-size: 13.5px; margin: 0; }
.doc-main th, .doc-main td { text-align: left; padding: 8px 10px; border-bottom: 1px solid #e3ddd3; vertical-align: top; overflow-wrap: break-word; }
.doc-main th { background: var(--surface-alt); font-size: 12.5px; text-transform: uppercase; letter-spacing: 0.04em; }
.doc-main .fill { background: #fdecea; color: #a4202a; font-weight: 700; padding: 1px 5px; border-radius: 4px; }
.doc-main a { color: var(--crimson); font-weight: 600; text-decoration: none; }
.doc-main a:hover { text-decoration: underline; }

/* ─── Support page ────────────────────────────────────────────────────────── */
.email-card {
  background: var(--ink);
  color: var(--white);
  border-radius: var(--radius-md);
  padding: 24px;
  margin-bottom: 36px;
}
.email-card .label { font-size: 13px; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.7; margin-bottom: 6px; }
.email-card .email { font-size: 22px; font-weight: 800; }
.email-card .email a { color: var(--white); text-decoration: none; }
.faq { background: var(--white); border-radius: var(--radius-md); padding: 6px 22px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); margin-bottom: 24px; }
.faq h2 { font-size: 16px; margin: 20px 0 6px; }
.faq p { margin: 0 0 20px; font-size: 14.5px; color: var(--body-text); line-height: 1.55; }

/* ─── Motion: scroll reveal (progressive enhancement) ────────────────────── */
/* Default: fully visible. JS adds .reveal-ready (pre-state) then removes it
   via IntersectionObserver when the element enters the viewport. If JS
   never runs, content is simply always visible, no broken experience. */
[data-reveal].reveal-ready {
  opacity: 0;
  transform: translateY(16px);
}
[data-reveal] {
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  [data-reveal].reveal-ready { opacity: 1; transform: none; }
  [data-reveal] { transition: none; }
  * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}

/* ─── Mobile nav link hide on very small widths (keep header minimal) ────── */
@media (max-width: 480px) {
  .site-header nav { gap: 14px; }
}
@media (max-width: 420px) {
  .site-header nav { font-size: 13px; gap: 10px; }
}

/* ─── Mobile nav: hamburger toggle + dropdown menu ──────────────────────────
   Shared markup on all 5 pages: .nav-toggle (hidden on desktop, shown at
   <=760px) and its matching .mobile-menu (the reverse). Vanilla JS only
   (script.js) - no library. The dropdown is a floating card, not a full-
   width bar, so it never visually splits the red hero into sections. */
.nav-toggle {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  border-radius: 10px;
  background: transparent;
  cursor: pointer;
}
.nav-toggle-bar {
  display: block;
  width: 22px;
  height: 2.5px;
  border-radius: 2px;
  background: var(--ink);
  transition: transform 0.2s var(--ease), opacity 0.2s var(--ease);
}
.site-header--on-crimson .nav-toggle-bar { background: var(--white); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }

.mobile-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 24px;
  z-index: 20;
  display: flex;
  flex-direction: column;
  min-width: 220px;
  background: var(--white);
  border-radius: var(--radius-md);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.28), 0 4px 14px rgba(0, 0, 0, 0.14);
  padding: 8px;
}
.mobile-menu[hidden] { display: none; }
.mobile-menu a {
  display: block;
  padding: 13px 14px;
  border-radius: 8px;
  font-size: 15px;
  font-weight: 700;
  text-decoration: none;
  color: var(--ink);
}
.mobile-menu a:hover,
.mobile-menu a:focus-visible {
  background: var(--surface-alt);
}
/* Restores the site's own global focus-visible ring (see "Focus visibility"
   near the top of this file) for keyboard users here specifically - this
   rule previously set outline:none, leaving only a pale background tint
   (~1.2:1 contrast against the menu's white surface) as the sole focus
   indicator, well short of the clearly-visible ring used everywhere else
   on the site. The hover background tint above is kept unchanged for
   mouse users. */
.mobile-menu a:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: -1px;
}

/* Hamburger everywhere (2026-10-15): the same single menu system (no second,
   competing implementation) now replaces the four-link row at ALL widths,
   not just mobile - the founder's own explicit choice for a minimal header.
   Previously this pair was scoped to a `@media (max-width:760px)` block;
   removing that scoping is the only change needed, since the markup and
   script.js wiring were already shared across every width. */
.site-header nav { display: none; }
.nav-toggle { display: inline-flex; }
