:root{
  --abyss:#040912;--deep:#081626;--deep-2:#0a1d30;--water:#0e2840;
  --cyan:#7fd3ef;--cyan-bright:#aee8fb;
  /* theme-var blue defaults (no-JS / first-paint fallback) — the head snippet overrides these
     per stored theme; --line/--card and the accent-tinted rgbas resolve through --cyan-rgb. */
  --cyan-rgb:127,211,239;--cyan-bright-rgb:174,232,251;--jf:none;--bgf:none;
  --sand:#e9c79e;--sand-dim:#caa97f;
  --ink:#eef6fb;--ink-dim:#a9c0d2;--ink-faint:#7892a6;
  --line:rgba(var(--cyan-rgb),.14);--card:rgba(14,40,64,.55);
  --maxw:1120px;--read:720px;--r:22px;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{font-family:'Inter',system-ui,sans-serif;background:var(--abyss);color:var(--ink);-webkit-font-smoothing:antialiased;overflow-x:hidden}
h1,h2,h3,.display{font-family:'Hanken Grotesk',system-ui,sans-serif;font-weight:600;letter-spacing:-.01em}
a{color:inherit;text-decoration:none}
/* Site-wide keyboard focus ring (#40) — v2 shipped none; keyboard users get a visible accent
   outline on every interactive element without touching mouse-focus (:focus-visible only). */
a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--cyan);outline-offset:2px}
/* Skip-link (#13 A2) — off-screen until keyboard focus reveals it top-left. */
.skip-link{position:absolute;left:-9999px;top:auto}
.skip-link:focus{position:fixed;left:12px;top:12px;z-index:100;background:var(--deep);color:var(--ink);padding:10px 16px;border-radius:10px;outline:2px solid var(--cyan);outline-offset:2px}
/* Skip-link target (#13 P2 rework): landing on <main> via the fragment jump matches
   :focus-visible in Chrome (last input was keyboard), which would otherwise draw the
   generic [tabindex]:focus-visible ring around the entire landmark — confirmed via CDP,
   see #13 rework report. The skip-link itself already provided the visible focus cue. */
main[tabindex="-1"]:focus{outline:none}
/* Visually-hidden utility (#64 A4) — accessible-name-only content (e.g. a landmark's <h1>
   that must not visibly render) stays in the a11y tree without affecting layout. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.eyebrow{font-size:.72rem;letter-spacing:.28em;text-transform:uppercase;color:var(--cyan);font-weight:500;font-family:'Inter',sans-serif}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 26px}
.muted{color:var(--ink-dim)}.faint{color:var(--ink-faint)}

/* display:block added vs. source: source only ever used .brand on a flex-item nav <a> (block-ified
   by the flex formatting context regardless) or a block footer <div> — never a bare inline element.
   The footer normalization (div→a, plan §4 drift table) turns it into a non-flex inline <a>, whose
   margin-bottom the box model ignores; block keeps that a-tag's spacing pixel-identical to the div
   it replaces without changing anything in the nav (flex items are block-ified either way). */
.brand{display:block;font-family:'Inter',sans-serif;font-weight:600;letter-spacing:.34em;font-size:.92rem;color:var(--ink)}

/* nav */
.nav{position:sticky;top:0;z-index:50;backdrop-filter:blur(14px);background:linear-gradient(to bottom, rgba(4,9,18,.82), rgba(4,9,18,.34));border-bottom:1px solid var(--line)}
.nav__in{display:flex;align-items:center;gap:28px;height:72px}
.nav__links{display:flex;gap:26px;margin-left:auto;font-size:.9rem}
.nav__links a{color:var(--ink-dim);transition:color .2s}
.nav__links a:hover{color:var(--cyan)}

/* mobile nav toggle (issue #26) */
.nav__toggle{display:none;width:44px;height:44px;flex:0 0 auto;align-items:center;justify-content:center;background:transparent;border:1px solid var(--line);border-radius:12px;color:var(--ink);cursor:pointer;transition:border-color .2s,background .2s;-webkit-tap-highlight-color:transparent}
.nav__toggle:hover{border-color:rgba(127,211,239,.4)}
.nav__toggle:focus-visible{outline:2px solid var(--cyan);outline-offset:2px}
.nav__toggle .bars{position:relative;width:18px;height:12px}
.nav__toggle .bars i{position:absolute;left:0;right:0;height:1.5px;border-radius:2px;background:currentColor;transition:transform .28s ease,opacity .2s ease}
.nav__toggle .bars i:nth-child(1){top:0}
.nav__toggle .bars i:nth-child(2){top:5.25px}
.nav__toggle .bars i:nth-child(3){top:10.5px}

/* full-screen overlay menu (issue #26) */
.menu{position:fixed;inset:0;z-index:60;display:flex;flex-direction:column;overflow-y:auto;
  padding:calc(env(safe-area-inset-top) + 20px) 26px calc(env(safe-area-inset-bottom) + 28px);
  background:linear-gradient(180deg, rgba(4,9,18,.94), rgba(6,18,32,.97));
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  opacity:0;visibility:hidden;transform:translateY(-8px);
  transition:opacity .3s ease,transform .3s ease,visibility 0s .3s}
.menu__top{display:flex;align-items:center;justify-content:space-between;height:32px;margin-bottom:8px}
.menu__close{width:44px;height:44px;margin-inline-end:-10px;display:grid;place-items:center;background:transparent;border:0;color:var(--ink-dim);font-size:1.6rem;line-height:1;cursor:pointer;transition:color .2s}
.menu__close:hover{color:var(--cyan)}
.menu__close:focus-visible{outline:2px solid var(--cyan);outline-offset:2px;border-radius:10px}
.menu__links{display:flex;flex-direction:column;margin-top:26px}
.menu__links a{font-family:'Hanken Grotesk',system-ui,sans-serif;font-weight:600;font-size:2rem;line-height:1;color:var(--ink);padding:20px 0;border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;transition:color .2s}
.menu__links a .go{font-family:'Inter',sans-serif;font-size:.9rem;color:var(--cyan);opacity:0;transform:translateX(-6px);transition:.24s}
.menu__links a:hover,.menu__links a:focus-visible{color:var(--cyan-bright);outline:none}
.menu__links a:hover .go,.menu__links a:focus-visible .go{opacity:1;transform:none}
.menu__cta{margin-top:auto;padding-top:30px;text-align:center}
.menu__cta .appstore{justify-content:center}
.menu__cta .appstore img{height:54px}
.menu__note{font-size:.78rem;color:var(--ink-faint);text-align:center;margin-top:14px}

/* open state (JS toggles .menu-open on <body>) */
body.menu-open{overflow:hidden}
body.menu-open .menu{opacity:1;visibility:visible;transform:none;transition:opacity .3s ease,transform .3s ease}
body.menu-open .nav__toggle .bars i:nth-child(1){transform:translateY(5.25px) rotate(45deg)}
body.menu-open .nav__toggle .bars i:nth-child(2){opacity:0}
body.menu-open .nav__toggle .bars i:nth-child(3){transform:translateY(-5.25px) rotate(-45deg)}

/* no-JS fallback: :target reveals the menu, links stay reachable */
.menu:target{opacity:1;visibility:visible;transform:none;transition:opacity .3s ease}

@media(max-width:780px){
  .nav__links{display:none}
  .nav__in{gap:12px}
  .brand{letter-spacing:.2em;margin-inline-end:auto}
  .nav .appstore{margin-inline-start:0}
  .nav__toggle{display:inline-flex}
}
@media(min-width:781px){
  .menu{display:none}
}

@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .menu,body.menu-open .menu,.nav__toggle .bars i{transition:opacity .001s,visibility 0s!important}
}

/* Official Apple "Download on the App Store" badge (#33). Fixed-aspect artwork: size by height only,
   never distort/animate (Apple guidelines). Min 40px onscreen; clear space ≥¼ height via layout gaps. */
.appstore{display:inline-flex;line-height:0;border-radius:8px;transition:opacity .2s}
.appstore img{display:block;height:42px;width:auto}
.appstore:hover{opacity:.85}
.appstore:focus-visible{outline:2px solid var(--cyan);outline-offset:3px}
.appstore--lg img{height:54px}

/* #28: per-theme COLOURED medusa assets (jelly-<theme>-v1.mp4) carry the hue → --jf hue-rotate
   retired (filter:none). The videos are NON-cutout: their own dark-NAVY water fills the 560x824
   frame, which is DELIBERATE — navy ≈ the site water, so where the mask feathers the medusa out the
   surround blends into the water almost invisibly. (A baked pure-BLACK surround was tried and
   reverted: mix-blend:screen composites against the PAGE bg, not the fixed water layer at z-index:-3,
   so black is NOT screened away — it just reads as a dark halo. Navy-that-matches-the-water is what
   makes the feather disappear.) The mask does the real compositing: it must reach FULL transparency
   BEFORE the video-box edge (else the straight box edge shows as a "paste seam") and hug the medusa
   so little surround remains — opaque through the bell, a gentle navy→water feather at the rim,
   transparent by ~the bell+glow radius. Same % mask serves every placement (hero 400px + 150px
   mockups: same video, same fractions). */
.jelly-vid{width:100%;height:auto;aspect-ratio:560/824;display:block;mix-blend-mode:screen;filter:none;
  -webkit-mask-image:radial-gradient(50% 66% at 50% 42%,#000 20%,transparent 90%),linear-gradient(180deg,transparent 2%,#000 22%);
  -webkit-mask-composite:source-in;
  mask-image:radial-gradient(50% 66% at 50% 42%,#000 20%,transparent 90%),linear-gradient(180deg,transparent 2%,#000 22%);
  mask-composite:intersect;
  /* #46 FIX: reserve the box height. All jelly-*-v1.mp4 are 560x824; without an explicit ratio the
     <video> has height:auto with NO reserved size, so during load() (theme swap) it loses its
     intrinsic dimensions, the box collapses to ~0, and the hero content below JUMPS UP into its place
     then back down — that vertical reflow IS the "blink" (worst on iOS WebKit). aspect-ratio gives the
     box a definite height independent of the replaced content, so it can never collapse. */}

.footer__in{display:flex;flex-wrap:wrap;gap:30px;justify-content:space-between;align-items:flex-start}
.footer__links{display:flex;gap:26px;flex-wrap:wrap;font-size:.88rem}
.footer__links a{color:var(--ink-dim)}.footer__links a:hover{color:var(--cyan)}
.footer small{color:var(--ink-faint);font-size:.8rem;display:block;margin-top:14px;max-width:44ch}

.q{border-bottom:1px solid var(--line);padding:22px 0;cursor:pointer}
.q summary::-webkit-details-marker{display:none}
.q summary::after{content:"+";color:var(--cyan);font-size:1.3rem;transition:.2s}
.q[open] summary::after{transform:rotate(45deg)}

/* texture */
.grain{position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.05;mix-blend-mode:soft-light;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}

/* v2 pass: per-theme backdrop hue filter (--bgf; blue default = none). The .bg/.rays/.caustic
   positioning lives in the page-type sheets (landing/article) + home's page CSS. */
.bg,.rays,.caustic{filter:var(--bgf,none)}
