/* =============================================================================
   SHAI — card-snap feed (Shop-app style)
   Mobile-first. A vertical feed of cards that snap to centre, each dynamically
   sized to the viewport with a uniform 22px inset (--edge) on every side
   except the top, which reserves the fixed header's height too. The header
   stays pinned/glass-blurred (gradient blur, sharp at the bottom/interior
   edge) with a logo that's large over card 1 and shrinks on scroll; the
   promo bar stays fixed/glass at the bottom. One ambient glow, anchored off
   the left edge, sits behind everything. Rebuilt from the Figma card design;
   earlier long-scroll version is on the `pre-card-feed` git branch.
   ============================================================================= */

/* ----- tokens ----- */
:root {
  --aubergine: #0D040D;
  --ivory:     #E9E8E6;
  --lavender:  #B8AACB;
  --lavender-dim: rgba(184, 170, 203, 0.2);
  --plum-cta:  #452B50;

  /* page shell. Dark by default/always — this design doesn't have a real
     light treatment yet — with an explicit override still available via the
     nav-overlay theme toggle. Cards themselves stay dark either way. */
  --bg:  var(--aubergine);
  --ink: var(--ivory);

  --col: 428px;                       /* phone-width column cap on wide screens */
  --edge: 22px;                       /* the one spacing unit: card inset, gap, content padding */
  --card-radius: calc(var(--promo-h) / 2);   /* matches the Shai Premium promo bar's corner */
  --card-gap: var(--edge);
  --header-h: 80px;                   /* constant — fits the large (58px) logo state */
  --promo-h: 78px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

:root[data-theme="light"] { --bg: var(--ivory); --ink: var(--aubergine); }

/* ----- reset ----- */
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: var(--bg); }
body {
  color: var(--ink);
  font-family: "Iosevka Charon", ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 16px;
  line-height: 1.5;
  overflow: hidden;                    /* the feed scrolls, not the body */
  -webkit-font-smoothing: antialiased;
}
img, svg, video { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }

.serif   { font-family: "Instrument Serif", Georgia, "Times New Roman", serif; font-weight: 400; }
.serif.is-italic, .serif em { font-style: italic; }
.script  { font-family: "Island Moments", "Snell Roundhand", cursive; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: fixed; left: 12px; top: -60px; z-index: 100;
  background: var(--aubergine); color: var(--ivory);
  padding: 10px 14px; border-radius: 8px; transition: top .18s;
}
.skip-link:focus { top: 12px; }

:focus-visible { outline: 2px solid var(--lavender); outline-offset: 3px; border-radius: 4px; }

/* ----- ambient glow — anchored to the left edge, half off-screen ----- */
.glow {
  position: fixed; z-index: 0; left: 0;
  /* clears the header bar (+ a buffer for the blur's own soft falloff) so no
     part of it shows in the status-bar/Dynamic-Island area above the header */
  top: calc(var(--header-h) + env(safe-area-inset-top) + 40px);
  width: 82vw; max-width: 600px; aspect-ratio: 1;
  transform: translate3d(-50%, 0, 0);
  background: radial-gradient(circle at 50% 45%,
              rgba(184,170,203,0.30), rgba(184,170,203,0.06) 44%, transparent 68%);
  filter: blur(38px);
  pointer-events: none;
  will-change: transform;
}

/* =============================================================================
   FEED + CARDS
   ============================================================================= */
.feed {
  position: relative; z-index: 1;
  height: 100svh; height: 100dvh;
  overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  /* proximity, not mandatory: cards still snap on every swipe (and
     scroll-snap-stop:always keeps it one card at a time), but the tall
     Backstories + footer tail after the last card scrolls freely instead
     of being yanked back to card 6 */
  scroll-snap-type: y proximity;
  scroll-behavior: smooth;
  overscroll-behavior-y: none;
  display: flex; flex-direction: column; align-items: center;
  gap: var(--card-gap);
  /* top: clears the fixed header + its own edge gap so cards never sit under
     it at rest; bottom: just the edge gap — the promo bar is meant to
     overlap the card, matching the Figma comps */
  padding-top: calc(var(--header-h) + env(safe-area-inset-top) + var(--edge));
  padding-bottom: var(--edge);
  /* scroll-snap-align:center otherwise centers each card in the RAW
     viewport regardless of padding — this tells it to center within the
     space below the header instead, so the padding above actually holds */
  scroll-padding-top: calc(var(--header-h) + env(safe-area-inset-top) + var(--edge));
  scroll-padding-bottom: var(--edge);
}

.card {
  position: relative;
  flex: 0 0 auto;
  /* dynamic: viewport minus the reserved header space on top and a uniform
     22px (--edge) inset everywhere else */
  width: min(calc(var(--col) - 2 * var(--edge)), calc(100vw - 2 * var(--edge)));
  height: calc(100svh - var(--header-h) - env(safe-area-inset-top) - 2 * var(--edge));
  height: calc(100dvh - var(--header-h) - env(safe-area-inset-top) - 2 * var(--edge));
  scroll-snap-align: center;
  scroll-snap-stop: always;
  /* --p : 0 when centred, →1 as the card recedes (set by the JS fallback).
     No scale() here on purpose — see .card__clip below. */
  opacity: calc(1 - 0.42 * var(--p, 1));
  transition: opacity .32s var(--ease);
}
/* every card after Slide 1 sits 20px taller with its top edge 20px higher —
   scroll-margin-bottom nudges the snapped rest position up by the same 20px
   so the extra height comes off the top gap, not pushed under the promo bar */
#card-why ~ .card {
  height: calc(100svh - var(--header-h) - env(safe-area-inset-top) - 2 * var(--edge) + 20px);
  height: calc(100dvh - var(--header-h) - env(safe-area-inset-top) - 2 * var(--edge) + 20px);
  scroll-margin-bottom: 20px;
}
/* Backstories: not a card. Full-bleed, no rounding, snaps its top under the
   header when you arrive from card 6, then free-scrolls straight down
   through the posts and into the footer as one continuous stretch. */
.backstories {
  flex: 0 0 auto;
  width: 100%;
  /* no snap — card 6 is the last snap point; from there it's a free scroll
     down through the posts and the footer to the bottom of the page */
  scroll-snap-align: none;
}
/* The rounded/clipped "look" of a card lives on this separate inner wrapper.
   Isolated on-device testing (test-video-radius.html box B vs A) proved the
   bright edge seam on video cards is caused by `isolation: isolate` combined
   with an inset box-shadow on a rounded overflow:hidden element containing a
   <video> — neither property alone (nor the video/scroll-snap/settle-
   animation machinery tested separately) reproduced it. Both are dropped
   here; see .orb below for where the isolation was actually load-bearing. */
.card__clip {
  position: relative;
  width: 100%; height: 100%;
  border-radius: var(--card-radius);
  overflow: hidden;
  background: var(--aubergine);
}
/* narrator card (3): no static fallback still behind the video — any gap
   before a freshly-swapped clip has decoded shows plain black instead, so
   an arrow tap never flashes the old narrator's frame back into view */
.card__clip--black { background: #000; }

/* Preferred: drive the settle off the scroll timeline — no JS, off the main thread */
@supports (animation-timeline: view()) {
  .card {
    transform: none; opacity: 1; transition: none;
    animation: card-settle linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }
  @keyframes card-settle {
    0%   { opacity: 0.58; }
    50%  { opacity: 1;    }
    100% { opacity: 0.58; }
  }
}

/* ----- card backgrounds + scrims ----- */
.card__bg {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
  /* A poster image and its <video> can disagree on intrinsic aspect ratio
     (confirmed: slide_1_bg.png is 770×1574 vs its .mp4's 720×1280 — a real
     mismatch, not just rounding), and a video's own `poster` attribute frame
     doesn't always get object-fit:cover applied to it as reliably as a real
     decoded frame does. A small uniform overscan gives every element here
     (img or video, poster-phase or playing) a safety margin so any of those
     ever falls a hair short of the card's edge, cropped by .card__clip's
     overflow:hidden, instead of a gap or seam. */
  transform: scale(1.03);
}
.card__bg--low   { object-position: center 26%; }
.card__bg--video { opacity: 0; transition: opacity .6s ease; }
.card__bg--video.is-live { opacity: 1; }

.card__scrim { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.card__scrim--why {
  background:
    linear-gradient(180deg, rgba(13,4,13,0.72) 0%, rgba(13,4,13,0) 34%),
    linear-gradient(0deg,   rgba(13,4,13,0.86) 0%, rgba(13,4,13,0) 42%);
}
.card__scrim--top    { background: linear-gradient(180deg, rgba(16,8,18,0.86) 0%, rgba(16,8,18,0.1) 44%, rgba(16,8,18,0) 60%); }
.card__scrim--bottom { background: linear-gradient(0deg,   rgba(12,6,16,0.92) 0%, rgba(12,6,16,0.25) 34%, rgba(12,6,16,0) 55%); }
.card__scrim--silk   { background:
    radial-gradient(130% 80% at 50% 38%, rgba(0,0,0,0.2), rgba(0,0,0,0.5) 90%),
    linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 24%, rgba(0,0,0,0) 72%, rgba(0,0,0,0.45) 100%); }
/* full-black wipe used to cross-fade the narrator background on arrow taps */
.card__scrim--fade { background: #000; opacity: 0; transition: opacity .35s ease; }
.card__scrim--fade.is-active { opacity: 1; }

.card--ink .card__clip { background: linear-gradient(180deg, #14091b 0%, #0d040d 100%); }
.card--transparent .card__clip { background: transparent; }

/* ----- card content ----- */
.card__inner {
  position: relative; z-index: 2;
  height: 100%;
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
  color: var(--lavender);
  padding: clamp(28px, 5svh, 44px) var(--edge);
}
.card__inner--between   { justify-content: space-between; align-items: flex-start; text-align: left; }
.card__inner--makers    { align-items: flex-start; text-align: left; }
/* Slides 1 & 2: reserve the strip the fixed promo bar overlaps (its own
   height + the bottom safe area) plus an --edge gap, so their lower text
   block always lands above the bar instead of behind it */
#card-why .card__inner,
#card-mornings .card__inner {
  padding-bottom: calc(env(safe-area-inset-bottom) + var(--promo-h) + var(--edge));
}
.card__inner--stories   {
  justify-content: flex-start; gap: clamp(12px, 2.2svh, 20px);
  /* keep the bottom copy clear of the fixed promo bar */
  padding-bottom: calc(env(safe-area-inset-bottom) + var(--promo-h) + var(--edge));
}
.card__inner--premium   { justify-content: center; gap: clamp(12px, 2.2svh, 22px); padding-block: clamp(22px, 4svh, 40px); }
.card__inner--narrators { justify-content: flex-start; }
/* ----- Backstories (section 7) ----- */
.backstories__inner {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center;
  gap: clamp(12px, 2svh, 18px);
  width: min(var(--col), 100vw);
  margin: 0 auto;
  padding: clamp(4px, 1svh, 10px) var(--edge) clamp(28px, 6svh, 56px);
  text-align: center;
  color: var(--lavender);
}
.back__title {
  margin: 0;
  font-size: clamp(3.4rem, 23vw, 6rem);
  line-height: .92;
  color: var(--lavender);
}
.back__intro {
  margin: 0 auto;
  max-width: 44ch;
  font-size: clamp(.86rem, 3.6vw, .95rem);
  line-height: 1.4;
  color: rgba(184,170,203,0.82);
}
.back__list {
  list-style: none; margin: clamp(6px, 1.4svh, 14px) 0 0; padding: 0;
  width: 100%;
  display: flex; flex-direction: column; gap: var(--edge);
}
/* Row border only — the post PNGs already carry their own rounded corners
   and 1px stroke, so the image sits inside at its natural aspect ratio with
   NOTHING added on top of it (no second border, no clip, no blend layer —
   any of those doubled the stroke or squared off the baked right-hand
   radius). */
.back__post {
  display: flex; align-items: center;
  gap: clamp(12px, 3.5vw, 20px);
  border: 1px solid rgba(184,170,203,0.28);
  border-radius: var(--card-radius);
  background: var(--aubergine);
  padding: clamp(12px, 3.4vw, 18px);
}
.back__media {
  flex: 0 0 39%;
}
.back__media img {
  display: block;
  width: 100%; height: auto;
}
.back__text {
  flex: 1;
  display: flex; flex-direction: column; justify-content: center;
  gap: 10px;
  padding-right: clamp(4px, 2vw, 10px);
  text-align: left;
}
.back__post-title {
  margin: 0;
  font-size: clamp(1.35rem, 6vw, 1.5rem);
  line-height: 1.16;
  color: var(--lavender);
}
.back__post-body {
  margin: 0;
  font-size: clamp(.85rem, 3.7vw, .95rem);
  line-height: 1.32;
  color: rgba(184,170,203,0.82);
}
.back__more {
  margin-top: clamp(6px, 1.6svh, 14px);
  padding: 12px 26px;
  border: 1px solid rgba(184,170,203,0.4);
  border-radius: 100px;
  color: var(--lavender);
  font-size: .92rem; letter-spacing: .02em;
  transition: background .15s, border-color .15s;
}
.back__more:hover { background: rgba(184,170,203,0.1); border-color: rgba(184,170,203,0.6); }

.card__title   { margin: 0; font-size: clamp(2rem, 8.6vw, 2.5rem); line-height: 1.08; letter-spacing: .004em; }
.card__kicker  { margin: 0; font-size: clamp(2rem, 8.6vw, 2.5rem); line-height: 1.1; }
.card__gap     { flex: 1 1 auto; min-height: 24px; }
/* .card__gap (the flex-grow spacer) drops the Discover group to the bottom,
   where .card__inner's own bottom padding sits it the same distance off the
   card bottom as "Introducing," is off the top */
.card__lead-xl { margin: 0 0 2px; font-size: clamp(2rem, 8.6vw, 2.5rem); line-height: 1.1; }
.card__lead    { margin: 0; font-size: clamp(1.55rem, 6.4vw, 1.9rem); line-height: 1.2; }
.card__body    { margin: 0; font-size: clamp(1.7rem, 7vw, 2.05rem); line-height: 1.12; max-width: 15ch; }
.card__body--right { align-self: flex-end; text-align: right; max-width: 18ch; }
.card__desc    { margin: 18px 0 auto; font-size: clamp(1.3rem, 5.4vw, 1.55rem); }
.card__quote   { margin: 20px 0 0; align-self: flex-end; max-width: 22ch; text-align: right;
                 font-size: clamp(1.25rem, 5vw, 1.45rem); line-height: 1.28;
                 text-shadow: 0 2px 16px rgba(8,4,12,0.7); }
.card__foot    { margin: auto 0 0; font-size: clamp(1.15rem, 4.8vw, 1.35rem); line-height: 1.24; }
.card__sign    { margin: 8px 0 0; align-self: flex-end; font-size: clamp(2.1rem, 9vw, 2.7rem);
                 line-height: 1; color: var(--lavender); text-shadow: 0 2px 18px rgba(8,4,12,0.85); }

/* legibility for text sitting directly on photography */
.card--photo .card__title,
.card--photo .card__kicker,
.card--photo .card__lead,
.card--photo .card__lead-xl,
.card--photo .card__body { text-shadow: 0 2px 20px rgba(8,4,12,0.72); }

.uline { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 4px;
         text-decoration-color: rgba(184,170,203,0.7); }

/* frosted note pinned to the bottom of card 5 — white text/glass, distinct
   from the lavender treatment everywhere else, per the Figma update */
.ai-note {
  margin-top: auto; margin-bottom: 50px; width: 100%;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 26px;
  padding: 18px 22px 20px;
  backdrop-filter: blur(16px) saturate(1.1);
  -webkit-backdrop-filter: blur(16px) saturate(1.1);
  box-shadow: 0 10px 30px rgba(0,0,0,0.35);
}
.ai-note__title { margin: 0 0 8px; font-size: 1.15rem; color: #fff; }
.ai-note__body  { margin: 0; font-size: .74rem; line-height: 1.5; color: rgba(255,255,255,0.86); }
.ai-note__link  { color: #fff; text-decoration: underline; text-underline-offset: 2px; }

/* =============================================================================
   NARRATOR carousel (card 3)
   ============================================================================= */
/* mute/unmute pill — sits directly under the title with the feed's one
   spacing unit (--edge) as breathing room, so the gap reads as deliberate
   rather than tacked on */
.mutebtn {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: var(--edge);
  padding: 8px 18px;
  border: 1px solid var(--lavender);
  border-radius: 100px;
  color: var(--lavender);
  font-size: .82rem; letter-spacing: .02em;
  transition: background .15s, border-color .15s, transform .15s var(--ease);
}
.mutebtn:hover  { background: rgba(184,170,203,0.12); }
.mutebtn:active { transform: scale(0.96); }
.mutebtn__icon {
  width: 16px; height: 16px;
  background-color: var(--lavender);
  mask-image: url("https://krffvljsetckdicebcsw.supabase.co/storage/v1/object/public/website_video/volume-down.svg");
  -webkit-mask-image: url("https://krffvljsetckdicebcsw.supabase.co/storage/v1/object/public/website_video/volume-down.svg");
  mask-size: contain; -webkit-mask-size: contain;
  mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat;
  mask-position: center; -webkit-mask-position: center;
}
.mutebtn.is-unmuted .mutebtn__icon {
  mask-image: url("https://krffvljsetckdicebcsw.supabase.co/storage/v1/object/public/website_video/volume-mute.svg");
  -webkit-mask-image: url("https://krffvljsetckdicebcsw.supabase.co/storage/v1/object/public/website_video/volume-mute.svg");
}
.narrator {
  margin-top: auto; width: 100%;
  display: flex; align-items: center; justify-content: center;
}
/* Arrows align to the centre of the orb+numeral baked into the narrator
   video — that sits at ~47% of the card height (the video is height-fitted
   so nothing crops it vertically). Positioned against .card__inner, which
   is the card's own box. */
.narrator__arrow {
  position: absolute; top: 47%; transform: translateY(-50%);
  z-index: 3;
}
.narrator__arrow--prev { left: var(--edge); }
.narrator__arrow--next { right: var(--edge); }
.iconbtn {
  display: grid; place-items: center;
  width: 44px; height: 44px; border-radius: 50%;
  color: var(--lavender);
  filter: drop-shadow(0 4px 8px rgba(0,0,0,0.5));
  transition: transform .15s var(--ease), background .15s;
}
.iconbtn:hover  { background: rgba(184,170,203,0.12); }
.iconbtn:active { transform: scale(0.92); }
.iconbtn svg    { width: 24px; height: 24px; }
/* narrator arrows: no circle / selected state, just the chevron (declared
   after .iconbtn:hover so it wins the equal-specificity tie) */
.narrator__arrow,
.narrator__arrow:hover,
.narrator__arrow:focus,
.narrator__arrow:focus-visible,
.narrator__arrow:active { background: none; }

.orb {
  position: relative;
  width: var(--orb-size, 172px); aspect-ratio: 1;
  display: grid; place-items: center;
  --orb-tint: var(--lavender);
  /* .orb__chroma below uses mix-blend-mode:screen — this used to be
     contained by the parent .card__clip's isolation:isolate, which was
     dropped (see .card__clip) because it combined with an inset box-shadow
     to trigger a Safari video-layer rendering bug. Isolating here instead
     keeps the blend scoped to the orb itself. */
  isolation: isolate;
}
/* narrator orb (card 3): purely an invisible hit-target for the prev/next
   arrows now — each narrator's background video (see .card__scrim--fade /
   NARRATORS in main.js) is itself a recording of this exact circle+numeral
   composition, so the CSS numeral is hidden and nothing is drawn here. */
.orb--narrator {
  --orb-size: 176px;
}
.orb--narrator .orb__numeral { display: none; }
.orb__halo {
  position: absolute; inset: -12%; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--orb-tint) 40%, transparent), transparent 68%);
  filter: blur(14px); opacity: .7;
  animation: orb-breathe 6.5s ease-in-out infinite;
}
.orb__media {
  position: absolute; inset: 0; border-radius: 50%; overflow: hidden;
  background: rgba(184,170,203,0.15);
  box-shadow: inset 0 0 30px 6px rgba(6,3,10,0.7), 0 4px 18px rgba(0,0,0,0.5);
}
.orb__media img {
  width: 132%; height: 132%; margin: -16%; object-fit: cover;
  filter: url(#orb-glass) brightness(0.62) contrast(0.86) saturate(0.82) blur(1px);
  animation: orb-drift 22s linear infinite;
}
.orb--story .orb__media img { filter: url(#orb-glass) brightness(0.78) contrast(0.9) saturate(1) blur(0.8px); }
.orb__chroma {
  position: absolute; inset: -2%; border-radius: 50%;
  padding: 2px;
  background: conic-gradient(from .12turn,
    rgba(255,170,200,0.16), rgba(170,190,255,0.14), rgba(190,240,215,0.12), rgba(255,170,200,0.16));
  -webkit-mask: radial-gradient(closest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
          mask: radial-gradient(closest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
  mix-blend-mode: screen; filter: blur(1.5px); opacity: .5;
  animation: orb-spin 30s linear infinite;
}
.orb__rim {
  position: absolute; inset: 0; border-radius: 50%;
  border: 1px solid rgba(184,170,203,0.32);
  box-shadow: inset 0 0 14px rgba(184,170,203,0.22);
}
.orb__numeral {
  position: relative; z-index: 2;
  font-size: clamp(1.7rem, 7vw, 2rem); color: var(--lavender);
  text-shadow: 0 2px 14px rgba(0,0,0,0.65);
}
@keyframes orb-breathe { 0%,100% { transform: scale(1); opacity: .6; } 50% { transform: scale(1.05); opacity: .82; } }
@keyframes orb-drift   { 0% { transform: translate3d(-1.5%,1%,0) rotate(0); } 50% { transform: translate3d(1.5%,-1%,0) rotate(1.4deg); } 100% { transform: translate3d(-1.5%,1%,0) rotate(0); } }
@keyframes orb-spin    { to { transform: rotate(1turn); } }

/* =============================================================================
   STORIES picker (card 4)
   ============================================================================= */
.picker { width: 100%; }
.picker__label { margin: 10px 0 8px; font-size: .78rem; letter-spacing: .06em; color: var(--lavender); }
.pills { display: flex; gap: 8px; justify-content: center; }
.pills button {
  flex: 1 1 0; min-width: 0;
  padding: 6px 4px; border-radius: 100px;
  background: var(--lavender-dim); color: var(--lavender);
  font-size: .8rem; font-weight: 500; letter-spacing: .04em;
  transition: background .18s, color .18s, transform .12s;
}
.pills button:active { transform: scale(0.96); }
.pills button.is-on  { background: var(--lavender); color: var(--aubergine); }

.story { width: 100%; margin-top: 6px; flex: 1 1 auto; min-height: 0; display: flex; }
.story__media {
  position: relative; width: 100%;
  border-radius: 26px; overflow: hidden; background: #0c0710;
}
.story__img, .story__video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.story__video { opacity: 0; }
.story__video.is-live { opacity: 1; }
.story__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(8,4,12,0.5) 0%, rgba(8,4,12,0) 30%, rgba(8,4,12,0) 62%, rgba(8,4,12,0.78) 100%);
}
.story .orb { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); --orb-size: 150px; }
.story__head { position: absolute; left: 0; right: 0; top: 16px; text-align: center; padding: 0 16px; }
.story__cat  { margin: 0; font-size: .68rem; letter-spacing: .07em; color: rgba(184,170,203,0.8); }
.story__name { margin: 4px 0 0; font-size: clamp(1.2rem, 5vw, 1.4rem); color: var(--lavender); }
.story__len  { position: absolute; left: 0; right: 0; bottom: 14px; text-align: center; color: var(--lavender); }
.story__len-line { display: block; width: 72px; height: 2px; margin: 0 auto 8px; position: relative;
                   background: rgba(184,170,203,0.35); border-radius: 2px; }
.story__len-line i { position: absolute; left: 42%; top: 50%; width: 30px; height: 2px; transform: translateY(-50%);
                     background: var(--lavender); border-radius: 2px; }
.story__len-a { display: block; font-size: .82rem; }
.story__len-b { display: block; font-size: .66rem; color: rgba(184,170,203,0.7); margin-top: 2px; }
.story.is-empty .story__name { color: rgba(184,170,203,0.85); }
.story.is-empty .story__img  { filter: grayscale(0.4) brightness(0.5); }

/* =============================================================================
   PREMIUM (card 6)
   ============================================================================= */
/* the combined "Shai Premium" lockup — one flat SVG (assets/brand/shai-premium-lockup.svg) */
.lockup-wrap { margin: 0; }
.lockup { display: block; height: 26px; width: auto; }
.lockup--xl { height: 64px; }
.card__inner--premium .rotator {
  display: inline-flex; align-items: center; gap: 10px;
  margin: 0; min-height: 1.6em; font-size: clamp(1.2rem, 5vw, 1.4rem);
}
.rotator__mark { width: 22px; height: 22px; flex: none; opacity: .9; }
.rotator span { transition: opacity .4s ease; }
.rotator.is-swapping span { opacity: 0; }

.testi {
  margin: 2px 0 0; width: 100%;
  background: rgba(217,217,217,0.1);
  border: 1px solid rgba(184,170,203,0.14);
  border-radius: 22px;
  padding: 22px 20px 18px;
  box-shadow: 0 4px 22px rgba(0,0,0,0.45);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  transition: opacity .4s ease;
}
.testi.is-swapping { opacity: 0; }
.testi__stars { width: 88px; height: 16px; margin: 0 auto 12px; }
.testi blockquote { margin: 0; font-size: 1.1rem; line-height: 1.32; color: var(--lavender); }
.testi figcaption { margin: 10px 0 0; font-size: .9rem; color: var(--lavender); }
.testi__dots { display: flex; gap: 4px; justify-content: center; margin-top: 12px; }
.testi__dots i { width: 10px; height: 2px; border-radius: 2px; background: rgba(184,170,203,0.4); transition: width .25s, background .25s; }
.testi__dots i.is-on { width: 26px; background: var(--lavender); }

.laurels { position: relative; display: grid; place-items: center; margin: 4px 0 0; color: var(--lavender); }
.laurels img { width: 168px; height: auto; opacity: .85; grid-area: 1 / 1; }
.laurels span { grid-area: 1 / 1; max-width: 116px; font-size: .58rem; line-height: 1.25; text-align: center; }
.price {
  margin: 2px 0 0;
  padding: 16px 32px; border-radius: 1000px;
  background: var(--lavender-dim); color: var(--lavender); font-size: 1.1rem;
}
.launch { margin: 10px 0 0; font-size: .62rem; letter-spacing: .04em; color: rgba(184,170,203,0.8); }

/* =============================================================================
   CHROME — header (fixed, gradient-blur glass) + promo bar (fixed, glass)
   ============================================================================= */
.chrome { display: flex; align-items: center; }

/* Fixed at the top, height constant regardless of the logo's own animated
   size (see .wordmark img). No solid fill — just a backdrop-blur layer
   (::before) masked to fade from full blur at the very top down to none at
   the header's own bottom edge, so it reads as "glass" without a hard line. */
.chrome--top {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  height: calc(var(--header-h) + env(safe-area-inset-top));
  padding: env(safe-area-inset-top) 20px 0;
  justify-content: center;
  background: none;
}
.chrome--top::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  backdrop-filter: blur(20px) saturate(1.3);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 100%);
  pointer-events: none;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .chrome--top::before {
    background: linear-gradient(to bottom, rgba(13,4,13,0.75) 0%, rgba(13,4,13,0.75) 45%, rgba(13,4,13,0) 100%);
  }
}
/* the strip directly behind the OS status bar/Dynamic Island — solid, not
   blurred, so it reads as part of the system chrome rather than translucent
   glass over whatever card is scrolled underneath. 0-height (invisible) on
   devices with no safe-area inset. */
.chrome--top::after {
  content: ""; position: absolute; top: 0; left: 0; right: 0;
  height: env(safe-area-inset-top);
  background: var(--aubergine);
  pointer-events: none;
}
.wordmark { position: relative; z-index: 1; display: inline-flex; }
.wordmark img { height: 30px; width: auto; transition: height .1s linear; }
.menu-btn {
  position: absolute; z-index: 1; right: 16px; top: 50%; transform: translateY(-50%);
  width: 40px; height: 40px; display: grid; place-content: center; gap: 6px;
}
.menu-btn span { display: block; width: 30px; height: 1.5px; background: rgba(184,170,203,0.6); border-radius: 2px; }

/* floats above the bottom edge, inset --edge (22px) inside the card's own
   edges on both sides — same centering as .card, just 2*--edge narrower on
   each side so a strip of card shows all the way around. bottom matches the
   card's own bottom edge exactly (env(safe-area-inset-bottom) + --edge, same
   as .feed's padding-bottom) so the bar meets the card rather than floating
   above it. */
.promo {
  position: fixed; z-index: 50;
  left: 50%; transform: translateX(-50%);
  bottom: calc(var(--edge) + env(safe-area-inset-bottom));
  /* back to matching the card's full width (no visible side strip) — the
     logo (native 142x26) and a properly-sized button don't both fit in the
     card-minus-44px version; see chat for the trade-off */
  width: min(calc(var(--col) - 2 * var(--edge)), calc(100vw - 2 * var(--edge)));
  height: var(--promo-h);
  /* left padding and the brand/cta gap stay equal (the earlier "equal gap"
     fix) — both shrank from 30px to fit the button's wider min-width */
  padding: 0 9px 0 14px;
  border-radius: 100px;
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  background: linear-gradient(0deg, #000000 0%, #05000c 100%);
  box-shadow: 0 10px 20px rgba(0,0,0,0.55), inset 0 1px 1px rgba(184,170,203,0.2);
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
/* hidden once the footer is in view — the waitlist CTA is reachable there */
.promo.is-hidden {
  opacity: 0;
  transform: translate(-50%, 140%);
  pointer-events: none;
}
.promo__brand-wrap { flex: 1; min-width: 0; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.promo__brand { flex: none; height: 26px; width: auto; }
/* mobile: no room for a tagline next to the logo — shown from the 768px
   breakpoint on, once the promo bar has grown wide enough to hold it
   (see the RESPONSIVE section below) */
.promo__tagline { display: none; }
.promo__cta {
  flex: none; height: 60px; min-width: 174px;
  display: flex; align-items: center; justify-content: center;
  padding: 0 10px; border-radius: 100px;
  background: var(--plum-cta); color: var(--lavender);
  font-size: .82rem; letter-spacing: .02em; white-space: nowrap;
  transition: filter .15s, transform .12s;
}
.promo__cta:hover  { filter: brightness(1.18); }
.promo__cta:active { transform: scale(0.97); }

/* =============================================================================
   FOOTER  — last panel in the feed, after card 6
   ============================================================================= */
.site-footer {
  position: relative;
  flex: 0 0 auto;
  margin-top: calc(-1 * var(--card-gap));   /* butt straight up under Backstories, no feed gap */
  /* full viewport width — NOT the phone-width column — so the glow below
     can wash edge-to-edge on wide screens; the column cap moves to
     .site-footer__inner, which holds the actual nav/legal content */
  width: 100%;
  min-height: calc(100svh - var(--header-h) - env(safe-area-inset-top) - 2 * var(--edge));
  min-height: calc(100dvh - var(--header-h) - env(safe-area-inset-top) - 2 * var(--edge));
  /* no snap — it's the tail end of the Backstories scroll, one continuous
     stretch from the last post down to the bottom of the page */
  scroll-snap-align: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  color: var(--lavender);
  overflow: hidden;                    /* contains the glow — no border-radius, so no card edges */
}
/* the gradiated, blurred wash behind the footer content — sized off the
   now-full-width .site-footer, so it reaches the real page edges instead
   of the narrower phone-width column */
.site-footer__glow {
  position: absolute; left: -30%; right: -30%; bottom: -35%;
  height: 105%;
  background:
    radial-gradient(62% 70% at 50% 92%,
      rgba(184,170,203,0.42), rgba(184,170,203,0.12) 48%, transparent 76%),
    linear-gradient(180deg, transparent 0%, rgba(120,96,150,0.18) 60%, rgba(150,120,185,0.26) 100%);
  filter: blur(56px);
  pointer-events: none;
}
.site-footer__inner {
  position: relative;
  width: min(var(--col), 100%);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(28px, 6svh, 52px);
  text-align: center;
  padding: clamp(40px, 9svh, 80px) var(--edge)
           calc(env(safe-area-inset-bottom) + var(--edge));
}
.site-footer__nav {
  position: relative;
  display: flex; flex-direction: column; align-items: center;
  gap: clamp(20px, 4.4svh, 40px);
}
.site-footer__nav a {
  font-size: clamp(1rem, 4.4vw, 1.15rem);
  letter-spacing: .01em;
  color: rgba(184,170,203,0.92);
  transition: color .15s;
}
.site-footer__nav a:hover { color: #fff; }
.site-footer__premium {
  font-family: "Luxurious Script", "Snell Roundhand", cursive;
  font-size: clamp(2.6rem, 12vw, 3.4rem) !important;
  line-height: 1; letter-spacing: 0;
  margin-top: clamp(4px, 1.5svh, 12px);
}
.site-footer__legal {
  position: relative; margin: 0;
  font-size: clamp(.82rem, 3.4vw, .95rem);
  color: rgba(184,170,203,0.5);
}
.site-footer__legal a { color: inherit; transition: color .15s; }
.site-footer__legal a:hover { color: rgba(184,170,203,0.9); }
.site-footer__legal span { margin: 0 .45em; opacity: .55; }

/* =============================================================================
   LEGAL PAGES (Privacy Policy / Terms of Service) — static reading pages,
   not part of the card feed. Reuse the same chrome/footer/tokens as
   index.html, but a normal scrolling document instead of the snap feed.
   ============================================================================= */
body.legal { overflow-y: auto; overflow-x: hidden; height: auto; min-height: 100%; }
.legal-main {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: center;
  padding-top: calc(var(--header-h) + env(safe-area-inset-top) + clamp(28px, 6svh, 48px));
}
.legal__title {
  margin: 0 0 clamp(28px, 6svh, 44px);
  padding: 0 var(--edge);
  max-width: min(620px, calc(100% - 2 * var(--edge)));
  text-align: center;
  font-size: clamp(2.1rem, 9vw, 2.75rem);
  line-height: 1.08;
  color: var(--lavender);
}
.legal__body {
  width: min(620px, calc(100% - 2 * var(--edge)));
  display: flex; flex-direction: column; gap: 1.1em;
  font-size: .95rem;
  line-height: 1.55;
  color: var(--lavender);
}
.legal__body h2 {
  margin: .6em 0 0;
  font-weight: 500;
  font-size: 1.2rem;
  line-height: 1.3;
  color: var(--lavender);
}
.legal__body h3 {
  margin: .4em 0 0;
  font-weight: 500;
  font-size: 1.02rem;
  line-height: 1.3;
  color: var(--lavender);
}
.legal__body p { margin: 0; }
.legal__body ul { margin: 0; padding-left: 1.3em; display: flex; flex-direction: column; gap: .5em; }
.legal__body li { padding-left: .1em; }
.legal__body strong { font-weight: 700; color: var(--lavender); }
.legal__body a { color: var(--lavender); text-decoration: underline; text-decoration-color: rgba(184,170,203,0.45); text-underline-offset: 2px; }
.legal__body a:hover { text-decoration-color: var(--lavender); }
.legal__body hr { width: 100%; height: 1px; margin: .4em 0; border: 0; background: rgba(184,170,203,0.2); }
.legal__table-wrap { width: 100%; overflow-x: auto; }
.legal__body table { width: 100%; min-width: 480px; border-collapse: collapse; font-size: .88rem; }
.legal__body th, .legal__body td {
  border: 1px solid rgba(184,170,203,0.25);
  padding: .6em .7em;
  text-align: left;
  vertical-align: top;
  color: var(--lavender);
}
.legal__body th { font-weight: 700; }
.legal__disclaimer { font-style: italic; color: var(--lavender); }
.legal__footer-nav {
  margin-top: clamp(32px, 7svh, 56px);
  padding: 0 var(--edge);
  width: min(620px, 100%);
  display: flex; flex-wrap: wrap; justify-content: center; gap: .4em 1.4em;
  font-size: .85rem;
}
.legal__footer-nav a { color: var(--lavender); text-decoration: underline; text-decoration-color: transparent; text-underline-offset: 2px; transition: text-decoration-color .15s; }
.legal__footer-nav a:hover { text-decoration-color: var(--lavender); }

/* =============================================================================
   NAV OVERLAY
   ============================================================================= */
.nav-overlay {
  position: fixed; inset: 0; z-index: 60;
  background: var(--aubergine); color: var(--lavender);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(6px, 1.5svh, 16px);
  overflow: hidden;
  /* whole overlay (dark-purple field + glow blobs) fades in over the page
     and fades back out — the page behind is near-black, so this reads as a
     fade in from / out to black. JS holds the element in the DOM through
     the fade-out (navCloseTimer) so the close animation is visible. */
  opacity: 0;
  transition: opacity .28s var(--ease);
}
.nav-overlay[hidden] { display: none; }
.nav-overlay.is-open { opacity: 1; }
/* menu contents lag the field by a beat so they rise in rather than
   snapping on with it */
.nav-overlay__close,
.nav-overlay__list,
.nav-overlay__brand {
  opacity: 0;
  transition: opacity .24s var(--ease);
}
.nav-overlay.is-open .nav-overlay__close,
.nav-overlay.is-open .nav-overlay__list,
.nav-overlay.is-open .nav-overlay__brand {
  opacity: 1;
  transition-delay: .14s;
}
.nav-overlay::before, .nav-overlay::after {
  content: ""; position: absolute; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(184,170,203,0.16), transparent 70%);
  filter: blur(20px);
}
.nav-overlay::before { width: 560px; height: 560px; left: -46%; top: 30%; }
.nav-overlay::after  { width: 440px; height: 440px; right: -34%; bottom: 8%;
  background: radial-gradient(circle, rgba(184,170,203,0.12), transparent 70%); }
.nav-overlay__close {
  position: absolute; top: calc(env(safe-area-inset-top) + 14px); right: 18px;
  width: 44px; height: 44px; display: grid; place-items: center; color: var(--lavender);
}
.nav-overlay__close img { width: 26px; height: 26px; display: block; }
.nav-overlay__list { display: flex; flex-direction: column; align-items: center; }
.nav-overlay__list a {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: clamp(1.9rem, 8.4vw, 2.5rem);
  line-height: 2.02; color: var(--lavender);
}
/* .is-current is still tracked in JS (nav highlight) but carries no visual
   treatment here by request — no underline on the active link */
.nav-overlay__brand { margin-top: 14px; }
.nav-overlay__brand img { height: 42px; width: auto; }

/* =============================================================================
   WAITLIST DIALOG
   ============================================================================= */
.signup {
  width: min(400px, calc(100vw - 32px));
  padding: 0; border-radius: 20px;
  background: #140A17; color: var(--lavender);
  border: 1px solid rgba(184,170,203,0.16);
  box-shadow: 0 40px 90px -20px rgba(0,0,0,0.7);
}
.signup::backdrop { background: rgba(5,2,10,0.62); backdrop-filter: blur(3px); }
.signup__form { position: relative; padding: 30px 26px 26px; display: flex; flex-direction: column; gap: 12px; }
.signup__close { position: absolute; top: 10px; right: 14px; font-size: 1.5rem; line-height: 1; color: rgba(184,170,203,0.7); }
.signup__title { margin: 0; font-size: 1.6rem; }
.signup__body  { margin: 0; font-size: .9rem; color: rgba(184,170,203,0.8); line-height: 1.45; }
.signup__field { display: flex; flex-direction: column; gap: 6px; font-size: .8rem; }
.signup__field input {
  padding: 12px 14px; border-radius: 10px;
  background: rgba(184,170,203,0.08); border: 1px solid rgba(184,170,203,0.2);
  color: var(--ivory); font-size: 1rem;
}
.signup__hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.signup__submit { width: 100%; text-align: center; }
.signup__status { margin: 2px 0 0; font-size: .82rem; min-height: 1.2em; }
.signup__status[data-state="ok"]  { color: #9ad6b0; }
.signup__status[data-state="err"] { color: #e6a3a3; }

/* =============================================================================
   RESPONSIVE — tablet/desktop
   Same feed/card layout and content as mobile, just resized up: one
   breakpoint stands in for both tablet and desktop for now (no separate
   multi-column desktop layout yet). Bumping --col/--edge/--header-h grows
   the card itself; bumping the root font-size scales every rem-based type
   size along with it, since every clamp() in this file is already pinned to
   its rem max well below this width (mobile design tuned for phone
   viewports) — so raising the root size is equivalent to raising all of
   those maxes at once, in the same proportions as the mobile design.
   ============================================================================= */
@media (min-width: 700px) {
  .glow { max-width: 780px; }
}

@media (min-width: 768px) {
  :root {
    --col: 820px;
    --edge: 40px;
    --header-h: 108px;
    --promo-h: 92px;
  }
  html { font-size: 23px; }

  .orb { --orb-size: 220px; }
  .orb--narrator { --orb-size: 230px; }
  .story .orb { --orb-size: 190px; }

  .lockup { height: 34px; }
  .lockup--xl { height: 84px; }
  .laurels img { width: 210px; }
  .testi__stars { width: 110px; height: 20px; }
  .promo__brand { height: 32px; }
  .nav-overlay__brand img { height: 52px; }

  .signup { width: min(460px, calc(100vw - 32px)); }

  .promo__brand-wrap { justify-content: flex-start; padding-left: 50px; gap: 10px; }
  .promo__tagline {
    display: inline-block; flex: 1 1 auto; min-width: 0;
    color: var(--lavender); font-size: .82rem; letter-spacing: .02em;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .promo__cta { min-width: 224px; }
}

/* =============================================================================
   REDUCED MOTION
   ============================================================================= */
@media (prefers-reduced-motion: reduce) {
  .feed { scroll-behavior: auto; }
  .card { transform: none !important; opacity: 1 !important; animation: none !important; transition: none !important; }
  .orb__halo, .orb__media img, .orb__chroma { animation: none !important; }
  .card__bg--video, .story__video { display: none !important; }
  .rotator span, .testi { transition: none !important; }
  .nav-overlay,
  .nav-overlay__close, .nav-overlay__list, .nav-overlay__brand,
  .nav-overlay::before, .nav-overlay::after { transition: none !important; }
  .wordmark img { transition: none; }         /* JS skips the scroll-driven resize too — stays at 30px */
}
