/* ═══════════════════════════════════════════════════════════════
   EPOCH 1.0 — GLOBAL STYLESHEET
   ═══════════════════════════════════════════════════════════════
   Source of truth (priority order): PTDS v1.1 · SAD · Design System
   (Step 1, superseded on colour/typography by PTDS v1.1 per this
   task's own stated priority — see accompanying chat message) ·
   published prototype (index.html) · Worker API Contract.

   This is a refactor of the existing Epoch visual language, not a
   redesign. Every token below is either lifted directly from the
   prototype's measured CSS, or an OPERATIONAL DEFAULT clearly
   marked as such where PTDS gives no exact value. Nothing here
   invents a new visual identity.

   Mobile-first. No inline styles. No duplicated rules.
   ═══════════════════════════════════════════════════════════════ */


/* ═══════════════════════════════════════════════════════════════
   1. FOUNDATION
   Fonts, design tokens, reset, base typography, and reusable motion primitives — everything later sections build on.
   ═══════════════════════════════════════════════════════════════ */

/* ───────────────────────────────────────────────────────────────
   1.1 FONTS
   Cinzel: wordmark only (PTDS 2.8). Fraunces: display/headings/
   hero/quotes/primary CTA buttons (PTDS 2.8, 7.10 — confirmed
   against the prototype's actual button font). JetBrains Mono:
   eyebrows/numerals/timestamps (PTDS 2.8, undocumented pre-v1.1
   but already in active use). Inter: UI/forms/labels/body.
   ─────────────────────────────────────────────────────────────── */
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@500;600&family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,600;1,9..144,500&family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@300;400;500;600&display=swap');


/* ───────────────────────────────────────────────────────────────
   1.2 DESIGN TOKENS (CSS custom properties)
   ─────────────────────────────────────────────────────────────── */
:root {
  /* — Colour: primary interface (PTDS 2.7/7.11 v1.1 — Violet) — */
  --ink:        #f4f0ff;  /* primary background — lavender-white */
  --panel:      #ffffff;  /* card / panel surface */
  --panel-2:    #ede8ff;  /* secondary surface, chip/input fill */
  --line:       rgba(120, 90, 200, 0.15);  /* hairline borders */
  --paper:      #1e1640;  /* primary text — deep indigo, never pure black */
  --paper-dim:  #6b5ea8;  /* secondary text / metadata */
  --violet:     #7c4dff;  /* primary interactive accent */
  --violet-soft:#b39dff;  /* secondary accent / hover tint */
  --violet-deep:#6c4ecb;  /* gradient endpoint — measured from the prototype's actual .generate-btn/.hero-cta; distinct from --violet */

  /* — Colour: gold, reserved accent (PTDS 2.7/7.11 v1.1) — */
  /* Gold is NEVER a general UI colour. Use only for: gift/payment
     buttons, premium indicators, the logo, watermark. */
  --gold:       #d4a574;
  --gold-rich:  #b8854f;
  --gold-glow:  rgba(212, 165, 116, 0.3);

  /* — Colour: rose (secondary emotional accent, measured from prototype) — */
  --rose:       #e8526a;
  --rose-tint:  rgba(232, 82, 106, 0.08);

  /* — Colour: status (PTDS 7.11) — */
  --error:      #e8526a;   /* Muted Red, matches existing rose accent */
  --success:    #6fae7c;   /* Soft Green — OPERATIONAL DEFAULT, no hex given by PTDS */

  /* — Typography — */
  --font-wordmark: 'Cinzel', serif;
  --font-display:  'Fraunces', serif;
  --font-accent:   'JetBrains Mono', monospace;
  --font-ui:       'Inter', sans-serif;

  /* Type scale — OPERATIONAL DEFAULT for the clamp() ranges; the
     rem values themselves match the prototype's real, dominant
     sizes (0.6–0.95rem for UI text, larger for hero/display). */
  --text-hero:    clamp(2.2rem, 6vw, 4rem);
  --text-h1:      clamp(1.6rem, 4vw, 2.4rem);
  --text-h2:      1.4rem;
  --text-quote:   1.1rem;
  --text-body:    0.95rem;
  --text-label:   0.82rem;
  --text-caption: 0.72rem;
  --text-eyebrow: 0.68rem;

  /* — Radius — matches the prototype's real, dominant distribution
     (measured, not invented): 50px for pills, 10–14px for
     standard cards/buttons, 8px for small controls. — */
  --radius-pill: 50px;
  --radius-lg:   18px;
  --nav-height:  96px; /* fixed nav's rendered height (80px logo + 2×1rem padding, rounded up) — used to offset content below it */
  --radius-md:   14px;
  --radius-sm:   10px;
  --radius-xs:   8px;

  /* — Elevation — matches prototype's real shadow character — */
  --shadow-sm: 0 2px 12px rgba(30, 22, 64, 0.08);
  --shadow-md: 0 6px 26px rgba(232, 82, 106, 0.25);
  --shadow-gold-glow: 0 2px 12px var(--gold-glow);

  /* — Motion — matches prototype's measured transition timing — */
  --ease-fast:   0.18s ease;
  --ease-base:   0.2s ease;
  --ease-slow:   0.3s ease;
  --ease-entry:  0.4s ease;

  /* — Breakpoints — the exact values already in use in the
     prototype's own @media queries, not invented. — */
  --bp-sm: 420px;
  --bp-md: 640px;
  --bp-lg: 760px;
  --bp-xl: 1024px;

  /* — Layout — */
  --content-width: 1140px;
  --gutter: 1.5rem;
}


/* ───────────────────────────────────────────────────────────────
   1.3 RESET & BASE
   ─────────────────────────────────────────────────────────────── */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  overflow-x: hidden;
  max-width: 100%;
}

body {
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-ui);
  font-size: var(--text-body);
  line-height: 1.6;
  min-height: 100vh;
  overflow-x: hidden;
  max-width: 100%;
  -webkit-font-smoothing: antialiased;
}

img, svg {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font-family: inherit;
  cursor: pointer;
}

ul, ol {
  list-style: none;
}


/* ───────────────────────────────────────────────────────────────
   1.4 TYPOGRAPHY
   ─────────────────────────────────────────────────────────────── */
.wordmark {
  font-family: var(--font-wordmark);
  font-weight: 600;
  letter-spacing: 0.02em;
}

h1, .h1 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-h1);
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--paper);
}

h2, .h2 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--text-h2);
  line-height: 1.2;
  color: var(--paper);
}

.hero-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-hero);
  line-height: 1.08;
  letter-spacing: -0.01em;
}

.hero-title-accent {
  font-style: italic;
  background: linear-gradient(90deg, var(--rose) 0%, var(--violet) 60%, #4a9eea 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.quote, blockquote {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: var(--text-quote);
  color: var(--paper-dim);
}

p, .body-text {
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--paper);
}

.text-dim {
  color: var(--paper-dim);
}

.eyebrow {
  font-family: var(--font-accent);
  font-size: var(--text-eyebrow);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--rose);
}

.eyebrow-note {
  display: inline-block;
  letter-spacing: 0;
  text-transform: none;
  margin-inline: 0.05em;
}

@media (max-width: 480px) {
  .eyebrow {
    letter-spacing: 0.14em;
  }
}

.caption {
  font-family: var(--font-accent);
  font-size: var(--text-caption);
  letter-spacing: 0.08em;
  color: var(--paper-dim);
}

.label {
  font-family: var(--font-ui);
  font-size: var(--text-label);
  font-weight: 500;
  color: var(--paper);
}

.numeral {
  font-family: var(--font-accent);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}


/* ───────────────────────────────────────────────────────────────
   1.5 ANIMATIONS
   Motion character matches the prototype's measured timing
   (0.18–0.4s, subtle). Never aggressive per PTDS 2.14.
   ─────────────────────────────────────────────────────────────── */
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fade-in-up {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes pulse-glow {
  0%, 100% { opacity: 0.85; filter: drop-shadow(0 0 4px var(--gold-glow)); }
  50%      { opacity: 1;    filter: drop-shadow(0 0 14px var(--gold-glow)); }
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

@keyframes skeleton-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

@keyframes float-logo-in {
  to { opacity: 1; transform: translateY(0); }
}

.animate-fade-in { animation: fade-in var(--ease-entry) both; }
.animate-fade-in-up { animation: fade-in-up var(--ease-entry) both; }


/* ═══════════════════════════════════════════════════════════════
   2. LAYOUT
   Grid/container system and the page-level structural regions (nav, footer) and responsive rules that arrange components on the page.
   ═══════════════════════════════════════════════════════════════ */

/* ───────────────────────────────────────────────────────────────
   2.1 LAYOUT / GRID
   ─────────────────────────────────────────────────────────────── */
.container {
  width: 100%;
  max-width: var(--content-width);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.grid {
  display: grid;
  gap: var(--gutter);
  grid-template-columns: repeat(12, 1fr);
}

/* Mobile-first base for .grid-md-3 — this class only ever got a
   min-width:640px rule (3 columns), so anything using it alone
   (galleryGrid, themeGrid, occasionGroup) fell through to the shared
   12-column .grid default below 640px — the same root cause behind
   several earlier "disorganized on mobile" bugs (the illustration
   gallery, the memory-type cards) fixed the same way each time: give
   the class its own real mobile column count instead of nothing. */
.grid-md-3 {
  grid-template-columns: repeat(2, 1fr);
}

.stack {
  display: flex;
  flex-direction: column;
}

.row {
  display: flex;
  align-items: center;
}

.gap-xs { gap: 0.3rem; }
.gap-sm { gap: 0.55rem; }
.gap-md { gap: 0.9rem; }
.gap-lg { gap: 1.5rem; }

@media (min-width: 640px) {
  .container { padding-inline: 2rem; }
}


/* ───────────────────────────────────────────────────────────────
   2.2 NAVIGATION
   Header nav content per PTDS 7.8 (Logo, About, Pricing, Create —
   no account menu). Floating logo pattern matches the prototype's
   .epoch-float-logo.
   ─────────────────────────────────────────────────────────────── */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 999;
  height: var(--nav-height);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding-inline: var(--gutter);
  background: var(--ink);
  border-bottom: 1px solid var(--line);
}

/* The logo link is always the nav's first child — placing it in the
   centered grid column keeps it dead-center at every viewport width,
   whether or not .nav-links is visible next to it (flex space-between
   pushed it off-center on mobile once .nav-links collapsed to
   nothing, since there was no second item left to balance against). */
.nav > a:first-child {
  grid-column: 2;
  justify-self: center;
}

.nav-logo {
  width: 80px;
  height: auto;
  opacity: 0.95;
  filter: drop-shadow(0 2px 12px var(--gold-glow));
}

/* Everything on the nav's right side lives in one flex row —
   About/Pricing (via .nav-links), the Create button, and (mobile
   only) the hamburger toggle — so "Create Your Epoch" can sit
   outside the collapsible .nav-links and stay visible on every
   screen size, while only About/Pricing tuck behind the toggle on
   mobile. Previously the Create button was INSIDE .nav-links, so it
   vanished along with About/Pricing below 640px — exactly the thing
   people are meant to do most, hidden two taps deep. */
.nav-right {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* Splits one "Create Your Epoch" / "Explore Published Epochs" CTA
   into two mutually-exclusive instances rather than one that's
   forced to work in both places. On mobile, having a full pill
   button crammed into the nav next to the hamburger was squeezing
   the logo off-center (it stopped being the centered grid column it
   was designed as, since the right-hand content grew too wide for a
   390px-ish screen). Below 640px the nav version is hidden and a
   second copy appears instead, placed naturally in the hero content
   flow where there's real room for it. At 640px+ it's the reverse —
   the hero copy hides, the nav one (which looks correct there) shows. */
.btn.nav-cta-desktop {
  display: none;
}
@media (min-width: 640px) {
  .btn.nav-cta-desktop { display: inline-flex; }
  .btn.nav-cta-mobile { display: none; }
}

/* The Create button uses .btn's default sizing, tuned for a large,
   spacious hero CTA — completely wrong for the cramped ~96px-tall
   nav bar it now always sits in on mobile (previously it was hidden
   behind the hamburger below 640px, so this size mismatch never had
   a chance to actually render and get caught). Scoped down to a
   compact size here only; the large hero buttons elsewhere on the
   page are untouched. */
.nav-right .btn {
  padding: 0.55rem 1rem;
  font-size: 0.78rem;
  white-space: nowrap;
  flex-shrink: 0;
}

@media (max-width: 380px) {
  .nav-right .btn {
    padding: 0.5rem 0.7rem;
    font-size: 0.7rem;
  }
}

.nav-links {
  display: none;
  gap: 1.5rem;
  font-size: var(--text-label);
  font-weight: 500;
}

.nav-links a:hover {
  color: var(--violet);
}

@media (min-width: 640px) {
  .nav-links { display: flex; align-items: center; }
}

/* Small, quiet "return home" link — create.html, viewer.html, and
   explore.html are all one step away from the homepage (creating,
   viewing, or browsing), and while the nav logo already links home
   by convention, this makes that path explicit and visible without
   relying on people already knowing that convention. Lives inside
   <main> (not as a sibling of the fixed nav) specifically so it
   inherits main's own padding-top and clears the fixed header —
   placed as a direct sibling once, it rendered underneath the nav
   bar, completely invisible. */
.back-home-link {
  padding-bottom: 0.5rem;
  text-align: center;
}
.back-home-link a {
  font-size: 0.8rem;
  color: var(--paper-dim);
  text-decoration: none;
}
.back-home-link a:hover {
  color: var(--violet);
  text-decoration: underline;
}

/* Mobile nav toggle — only About/Pricing hide behind this now; the
   Create button sits next to it, always visible, unaffected by
   .nav-links' own open/closed state. */
.nav-toggle {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 32px;
  height: 32px;
  padding: 7px;
  border: none;
  background: none;
  cursor: pointer;
  flex-shrink: 0;
}

.nav-toggle span {
  display: block;
  height: 2px;
  border-radius: 2px;
  background: var(--paper);
}

@media (min-width: 640px) {
  .nav-toggle { display: none; }
}

@media (max-width: 639px) {
  .nav-links {
    position: fixed;
    top: var(--nav-height);
    left: var(--gutter);
    right: var(--gutter);
    flex-direction: column;
    align-items: stretch;
    gap: 0.8rem;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 1rem;
    box-shadow: var(--shadow-md);
    /* Higher than #pwaInstallCard's z-index (1000) — both are fixed
       elements in the same top-right corner of the viewport; without
       this the open dropdown and the Install badge tied on z-index
       and the badge (added to the DOM later, at runtime) painted on
       top, overlapping "About" illegibly. */
    z-index: 1001;
  }
  .nav-links.open {
    display: flex;
  }
  .nav-links a {
    text-align: center;
    padding: 0.5rem;
  }
}


/* ───────────────────────────────────────────────────────────────
/* ───────────────────────────────────────────────────────────────
   2.24 LIVE EPOCH COUNT BADGE
   Top-left, opposite the install badge (top-right) — the two never
   collide. Used on index.html, create.html, and viewer.html.
   ─────────────────────────────────────────────────────────────── */
.epoch-count-badge {
  position: fixed;
  top: calc(var(--nav-height, 96px) + 0.8rem + env(safe-area-inset-top, 0px));
  left: 0.9rem;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  padding: 0.6rem 0.9rem;
  border-radius: 50%;
  width: 76px;
  height: 76px;
  background: linear-gradient(135deg, rgba(232,82,106,0.1), rgba(124,77,255,0.1));
  border: 1px solid var(--line);
  box-shadow: var(--shadow-md);
}
.epoch-count-num {
  font-family: var(--font-accent);
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--violet);
  line-height: 1.1;
}
.epoch-count-label {
  font-size: 0.5rem;
  text-align: center;
  line-height: 1.1;
  color: var(--paper-dim);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
@media (max-width: 480px) {
  .epoch-count-badge {
    width: 60px;
    height: 60px;
    padding: 0.4rem 0.5rem;
  }
  .epoch-count-num { font-size: 0.9rem; }
  .epoch-count-label { font-size: 0.42rem; }
}

/* ───────────────────────────────────────────────────────────────
   2.25 PWA INSTALL BADGE
   A small, permanent pill docked to the top-right corner, labeled
   so it reads as an actual button rather than a mystery icon —
   never a full-width bar across the top (an earlier version sat
   directly over the hero on mobile). Rebuilt on every page load via
   app.js's bootstrap(), same as the nav logo.
   ─────────────────────────────────────────────────────────────── */
#pwaInstallCard {
  position: fixed;
  top: calc(var(--nav-height, 96px) + 0.8rem + env(safe-area-inset-top, 0px));
  right: 0.9rem;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.5rem;
}

.pwa-badge-icon {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  height: 40px;
  padding: 0 0.9rem;
  border-radius: var(--radius-pill);
  border: none;
  background: linear-gradient(135deg, var(--rose), var(--violet));
  color: #fff;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.01em;
  white-space: nowrap;
  box-shadow: var(--shadow-md);
  cursor: pointer;
  transition: transform var(--ease-fast), box-shadow var(--ease-fast);
}

.pwa-badge-icon:hover {
  transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(232, 82, 106, 0.3);
}

.pwa-badge-icon .pwa-badge-emoji {
  font-size: 1.05rem;
  line-height: 1;
}

@media (max-width: 480px) {
  .pwa-badge-icon {
    height: 34px;
    padding: 0 0.7rem;
    font-size: 0.62rem;
    gap: 0.3rem;
  }
  .pwa-badge-icon .pwa-badge-emoji { font-size: 0.9rem; }
}

/* ───────────────────────────────────────────────────────────────
   2.26 INSTALL INSTRUCTIONS MODAL
   Replaces the previous one-line "tap Share, then Add to Home
   Screen" tooltip with clear, numbered, platform-specific steps —
   built on the existing generic .modal-backdrop/.modal/.modal-close
   components (§3.5) rather than inventing a separate dialog system.
   Uses Epoch's own violet/rose token palette throughout for the
   step numbers and tab states, for visual consistency with the rest
   of the site.
   ─────────────────────────────────────────────────────────────── */
.install-modal {
  position: relative;
  padding-top: 1.8rem;
}

.install-modal-header {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1.1rem;
}

.install-modal-icon {
  font-size: 1.4rem;
  line-height: 1;
}

.install-modal-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem;
  margin-bottom: 1.3rem;
}

.install-modal-tab {
  padding: 0.65rem 0.5rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--paper-dim);
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
  transition: all var(--ease-fast);
}

.install-modal-tab.active {
  border-color: var(--rose);
  background: var(--rose-tint);
  color: var(--paper);
}

.install-modal-steps {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.install-modal-step {
  display: flex;
  align-items: flex-start;
  gap: 0.8rem;
  font-size: 0.92rem;
  line-height: 1.45;
  color: var(--paper);
}

.install-modal-num {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--rose), var(--violet-deep));
  color: #fff;
  font-family: var(--font-accent);
  font-weight: 700;
  font-size: 0.78rem;
}

.install-modal-tip {
  margin-top: 1.3rem;
  padding: 0.85rem 1rem;
  border-radius: var(--radius-sm);
  background: var(--panel-2);
  border: 1px solid var(--line);
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--paper-dim);
}

/* ───────────────────────────────────────────────────────────────
   2.3 FOOTER
   Not present in the prototype — content per PTDS 7.25 (logo,
   "Every story has an Epoch.", Privacy, Terms, Contact, Copyright).
   ─────────────────────────────────────────────────────────────── */
.footer {
  border-top: 1px solid var(--line);
  padding: 2.5rem var(--gutter);
  text-align: center;
}

.footer-signature {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--text-quote);
  color: var(--paper-dim);
  margin-block: 1rem;
}

.footer-links {
  display: flex;
  justify-content: center;
  gap: 1.5rem;
  font-size: var(--text-caption);
  color: var(--paper-dim);
}

.footer-links a:hover {
  color: var(--violet);
}


/* ───────────────────────────────────────────────────────────────
   2.4 RESPONSIVE — mobile-first, breakpoints match the values
   already in use in the prototype's own media queries.
   ─────────────────────────────────────────────────────────────── */
@media (min-width: 420px) {
  .grid-sm-2 { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 640px) {
  .grid-md-2 { grid-template-columns: repeat(2, 1fr); }
  .grid-md-3 { grid-template-columns: repeat(3, 1fr); }
  .hero-title { font-size: var(--text-hero); }
}

@media (min-width: 760px) {
  .grid-lg-4 { grid-template-columns: repeat(4, 1fr); }
}

@media (min-width: 1024px) {
  .container { padding-inline: 0; }
}

/* ───────────────────────────────────────────────────────────────
   2.5 HERO & SECTION LAYOUT
   Additive — extracted from the published prototype's real,
   measured CSS (.hero, .hero::before, .showcase), not invented.
   No existing rule above is modified; this is new, reusable
   page-level composition only, per Design System §6/§10.

   Feature grids: already served by the existing .grid + .grid-md-N
   and .grid-lg-4 utilities (§2.1) — no separate "feature grid" class
   is added, since that would duplicate what's already generic.
   ─────────────────────────────────────────────────────────────── */

/* main is always the sibling of the fixed .nav (index.html, create.html
   as #wizard, viewer.html) — this is the single place that reserves
   space for it, so no page has to duplicate the offset in its own
   hero/wizard padding, and nothing can render underneath the nav. */
main {
  padding-top: var(--nav-height);
}

.hero-cover-link {
  display: block;
  position: relative;
  max-width: 720px;
  margin-inline: auto;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  text-decoration: none;
}

.hero-cover {
  display: block;
  width: 100%;
  max-width: 720px;
  height: auto;
}

/* Positioned in the one genuinely empty patch of the cover photo —
   below the "Beautiful digital memory timelines..." wordmark caption
   baked into the image, above the bottom info strip. Percentage-based
   so it tracks correctly at every rendered size, since the image's
   16:9 aspect ratio never changes. Styled as a real, solid CTA chip
   (not a translucent bar) so it reads clearly against the busy photo
   background. */
.hero-cover-badge {
  position: absolute;
  left: 5%;
  top: 61%;
  max-width: 46%;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.55rem 0.9rem;
  border-radius: var(--radius-pill, 999px);
  background: #fff;
  box-shadow: 0 4px 14px rgba(26, 10, 30, 0.28);
  color: var(--violet-deep, var(--violet));
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 0.72rem;
  line-height: 1.2;
  letter-spacing: 0.01em;
  transition: transform var(--ease-fast), box-shadow var(--ease-fast);
}

.hero-cover-badge-arrow {
  font-weight: 700;
  transition: transform var(--ease-fast);
}

.hero-cover-link:hover .hero-cover-badge,
.hero-cover-link:focus-visible .hero-cover-badge {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(26, 10, 30, 0.32);
}

.hero-cover-link:hover .hero-cover-badge-arrow,
.hero-cover-link:focus-visible .hero-cover-badge-arrow {
  transform: translateX(3px);
}

@media (max-width: 560px) {
  .hero-cover-badge {
    top: 58%;
    max-width: 50%;
    padding: 0.45rem 0.7rem;
    font-size: 0.6rem;
    gap: 0.25rem;
  }
}

/* Founder's quote — a warm, first-person aside, visually distinct
   from ordinary body copy: italic display serif (matches .quote
   above the hero image), a rose accent instead of flat grey, and
   real typographic quote marks framing it since it's spoken in the
   founder's own voice. */
.founder-quote {
  max-width: 62ch;
  margin-inline: auto;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.02rem, 2.2vw, 1.2rem);
  line-height: 1.55;
  color: var(--rose);
}

.founder-quote::before {
  content: '“';
}

.founder-quote::after {
  content: '”';
}

/* Hero — matches the prototype's .hero exactly: relative position
   (to anchor the glow), generous top padding, centered, contained
   overflow, hairline bottom border. */
.hero {
  position: relative;
  padding: 3rem var(--gutter) 3rem;
  text-align: center;
  border-bottom: 1px solid var(--line);
}

/* The decorative radial glow — matches the prototype's .hero::before
   exactly, using --rose and --violet-deep (see §1.2) in place of the
   prototype's raw hex, so it stays in sync with the token system. A
   true ::before pseudo-element, not a DOM node — decorative-only,
   automatically invisible to assistive tech, matching the source. */
.hero::before {
  content: '';
  position: absolute;
  top: -20%;
  left: 50%;
  width: 700px;
  height: 700px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse, rgba(232, 82, 106, 0.08) 0%, rgba(108, 78, 203, 0.06) 50%, transparent 70%);
  pointer-events: none;
}

.hero > * {
  position: relative;
  z-index: 1;
}

/* Section — the consistent vertical rhythm used for every major
   scroll-revealed block (PTDS 7.6), generalized from the
   prototype's .showcase padding pattern. */
.section {
  padding: 3rem var(--gutter);
}

.section-tight {
  padding: 1.5rem var(--gutter) 3rem;
}

/* CTA band — a closing, attention-anchoring section. No single
   literal precedent exists in the prototype (it's a one-page
   landing today, with only one hero-level CTA) — this generalizes
   the same glow treatment established in .hero above for visual
   bookending, reusing only already-established tokens, no new
   colours or fonts introduced. */
.cta-band {
  position: relative;
  overflow: hidden;
  text-align: center;
  padding: 4rem var(--gutter);
  border-top: 1px solid var(--line);
}

.cta-band::before {
  content: '';
  position: absolute;
  bottom: -30%;
  left: 50%;
  width: 600px;
  height: 600px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse, rgba(124, 77, 255, 0.07) 0%, rgba(232, 82, 106, 0.05) 50%, transparent 70%);
  pointer-events: none;
}

.cta-band > * {
  position: relative;
  z-index: 1;
}



/* ═══════════════════════════════════════════════════════════════
   3. COMPONENTS
   Reusable UI components — buttons, cards, forms, badges/chips, dialogs, toast, and the loading/empty/error states that appear across pages.
   ═══════════════════════════════════════════════════════════════ */

/* ───────────────────────────────────────────────────────────────
   3.1 BUTTONS (PTDS 7.9 v1.1 — violet-to-rose gradient primary;
   gold reserved specifically for gift/payment moments)
   ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  border: none;
  border-radius: var(--radius-md);
  padding: 1.05rem 1.5rem;
  font-size: 1.05rem;
  font-weight: 600;
  cursor: pointer;
  transition: all var(--ease-slow);
}

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

/* Primary — the main CTA on every screen (Create, Continue, etc.) */
.btn-primary {
  font-family: var(--font-display);
  font-style: italic;
  background: linear-gradient(135deg, var(--rose), var(--violet-deep));
  color: #fff;
  box-shadow: var(--shadow-md);
}

.btn-primary:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
}

/* Explore — same visual weight/treatment as .btn-primary (italic
   display font, gradient fill, same hover lift) so it reads as an
   equally important CTA, but in a distinct blue→green hue so the two
   buttons are each instantly identifiable at a glance rather than
   blending together. Reuses colors already established elsewhere in
   the site (the blue already appears in .hero-title-accent's
   gradient; green is the existing --success token) rather than
   introducing a new, ungoverned color. */
.btn-explore {
  font-family: var(--font-display);
  font-style: italic;
  background: linear-gradient(135deg, #4a9eea, var(--success));
  color: #fff;
  box-shadow: var(--shadow-md);
}

.btn-explore:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
}

/* Secondary — neutral action, e.g. "Cancel", "Back" */
.btn-secondary {
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--paper);
  font-weight: 500;
  font-size: 0.9rem;
}

.btn-secondary:hover {
  border-color: var(--violet-soft);
}

/* Gold — reserved exclusively for gift/payment/premium moments */
.btn-gold {
  font-family: var(--font-display);
  font-style: italic;
  background: linear-gradient(135deg, var(--gold), var(--gold-rich));
  color: #fff;
}

.btn-gold:hover {
  filter: brightness(1.05);
}

/* Pill — fully-rounded variant for compact actions */
.btn-pill {
  border-radius: var(--radius-pill);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}


/* ───────────────────────────────────────────────────────────────
   3.2 CARDS
   ─────────────────────────────────────────────────────────────── */
.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 1.2rem;
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--ease-entry), transform var(--ease-entry);
}

.card:hover {
  box-shadow: 0 8px 32px rgba(30, 22, 64, 0.12);
}

/* One unified card holding multiple steps/points, replacing what
   used to be several separate floating cards — same content,
   consolidated into a single cohesive shape with internal dividers
   instead of gaps between independent boxes. */
.card-unified {
  background: linear-gradient(160deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 1.6rem;
  box-shadow: var(--shadow-sm);
}
.unified-step {
  padding: 1.1rem;
  border-radius: var(--radius-sm);
  transition: background var(--ease-fast);
}
.unified-step:hover {
  background: rgba(124, 77, 255, 0.06);
}

/* ───────────────────────────────────────────────────────────────
   2.16 SWATCH GRID — compact, colour-coded mini cards used by the
   homepage "How Epoch Works" and "Everything a memory deserves"
   sections. Replaces the previous large, spread-out unified-step
   list with a tight, cute grid of small tinted cards — same
   content, far less vertical/whitespace footprint. Tints rotate
   through the existing accent tokens only (violet/rose/success +
   the blue already used in .hero-title-accent's gradient) — no new
   colours invented, per the token-only design system.
   ─────────────────────────────────────────────────────────────── */
.swatch-panel {
  background: linear-gradient(160deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 0.9rem;
  box-shadow: var(--shadow-sm);
}

.swatch-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.55rem;
}

@media (min-width: 640px) {
  .swatch-grid { grid-template-columns: repeat(3, 1fr); }
}

@media (min-width: 1024px) {
  .swatch-grid { grid-template-columns: repeat(6, 1fr); }
  .swatch-grid-features { grid-template-columns: repeat(4, 1fr); }
}

.swatch-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 0.2rem;
  text-align: center;
  padding: 0.85rem 0.6rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--line);
  transition: transform var(--ease-fast), box-shadow var(--ease-fast);
}

.swatch-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-sm);
}

.swatch-grid > .swatch-card:nth-child(4n+1) { background: rgba(124, 77, 255, 0.09); }
.swatch-grid > .swatch-card:nth-child(4n+2) { background: rgba(232, 82, 106, 0.09); }
.swatch-grid > .swatch-card:nth-child(4n+3) { background: rgba(111, 174, 124, 0.10); }
.swatch-grid > .swatch-card:nth-child(4n+4) { background: rgba(74, 158, 234, 0.09); }

.swatch-num {
  font-family: var(--font-accent);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
}

.swatch-icon {
  font-size: 1.25rem;
  line-height: 1;
}

.swatch-title {
  font-family: var(--font-ui);
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--paper);
  line-height: 1.25;
}

.swatch-caption {
  font-family: var(--font-accent);
  font-size: 0.65rem;
  letter-spacing: 0.02em;
  color: var(--paper-dim);
  line-height: 1.3;
}

/* Selectable card, e.g. subscription plan */
.card-select {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.9rem 1rem;
  cursor: pointer;
  transition: all var(--ease-fast);
  position: relative;
}

.card-select:hover {
  border-color: var(--violet-soft);
}

.card-select.active {
  border-color: var(--rose);
  background: var(--rose-tint);
}

/* Built-in illustration gallery — the shared .grid utility defaults
   to 12 equal columns until .grid-md-3 takes over at 640px+; below
   that breakpoint this grid was falling through to that 12-column
   base with no override, squeezing every thumbnail into a sliver a
   few pixels wide. Explicit mobile-first sizing fixes it without
   touching .grid itself (used generically elsewhere on the page). */
#backgroundGrid.grid {
  grid-template-columns: repeat(3, 1fr);
  gap: 0.7rem;
}

@media (max-width: 419px) {
  #backgroundGrid.grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Memory-type option cards (Upload a Photo / Built-in Illustration) —
   same root cause as the gallery grid above: .grid-md-2 only takes
   over at 640px+, so below that this was falling through to the
   shared 12-column .grid base with no override, packing both cards
   to the left with a large dead zone on the right instead of an
   even 2-up layout. .grid-md-2 is used in exactly this one place
   site-wide, so it's safe to give it its own mobile-first base
   directly rather than scoping to a container. */
.grid-md-2 {
  grid-template-columns: repeat(2, 1fr);
}
#backgroundGrid.grid > .card-select {
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  padding: 0;
  overflow: hidden;
  position: relative;
  aspect-ratio: 3 / 4;
}
#backgroundGrid.grid > .card-select img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
#backgroundGrid.grid > .card-select .caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0;
  padding: 0.6rem 0.5rem 0.5rem;
  background: linear-gradient(180deg, transparent 0%, rgba(20, 14, 40, 0.85) 100%);
  color: #fff;
  text-align: center;
}

/* Premium/gift card — the one place a deeper gradient background
   is used, matching the prototype's gift-card treatment */
.card-premium {
  position: relative;
  overflow: hidden;
  background: linear-gradient(135deg, #1a0a30 0%, #2a1020 50%, #1a0a18 100%);
  border: 1px solid var(--gold-glow);
  border-radius: var(--radius-lg);
  padding: 1.2rem;
  color: #fff;
}

/* Lead-in copy above the gift card — colourful, inviting, matches the
   same gradient-text technique used by .hero-title-accent so the
   brand's one gradient-text treatment stays consistent site-wide. */
.gift-lead-in {
  text-align: center;
  margin-bottom: 1.4rem;
}

.gift-lead-text {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 3.4vw, 1.8rem);
  font-weight: 600;
  line-height: 1.3;
  color: var(--paper);
}

.gift-lead-accent {
  font-style: italic;
  background: linear-gradient(90deg, var(--rose) 0%, var(--violet) 60%, #4a9eea 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.gift-lead-tagline {
  margin-top: 0.5rem;
  font-family: var(--font-accent);
  font-size: var(--text-eyebrow);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--paper-dim);
}

.gift-lead-gold {
  color: var(--gold);
  font-weight: 700;
}

/* Rebuilt against the corrected, genuinely-transparent logo file
   (see epoch-logo-transparent.png — replaced in place, same R2 key,
   opaque grey backing baked in, which is why it always looked like
   an awkward grey box no matter how it was positioned. A light,
   warm card background instead of the old dark gradient: the logo's
   wordmark is dark ink, so it only reads clearly on a light surface
   — the same reason it works fine in the nav. Box is sized to the
   logo's own ~2:1 proportions and capped narrow, so it reads as one
   snug unit instead of a wide bar with the mark lost in the middle.
   The CTA sits in its own clear strip at the bottom, below the
   mark's live area — never overlapping it. */
.card-premium--branded {
  max-width: 380px;
  margin-inline: auto;
  min-height: 280px;
  padding: 1.6rem 1.4rem 1.6rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  background: linear-gradient(160deg, #fffaf1 0%, #f7ecd8 100%);
  background-image:
    url('https://assets.epoch.veeanta.com/logos:epoch-logo-transparent.png?v=2'),
    linear-gradient(160deg, #fffaf1 0%, #f7ecd8 100%);
  background-repeat: no-repeat, no-repeat;
  background-position: top 1.4rem center, center;
  background-size: 68% auto, cover;
  border: 1px solid var(--gold-glow);
}


/* ───────────────────────────────────────────────────────────────
   3.3 FORMS / INPUTS
   ─────────────────────────────────────────────────────────────── */
.field {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}

.field-label {
  font-family: var(--font-ui);
  font-size: var(--text-label);
  font-weight: 500;
  color: var(--paper);
}

.field-hint {
  font-size: var(--text-caption);
  color: var(--paper-dim);
}

input[type="text"],
input[type="email"],
input[type="date"],
input[type="search"],
textarea,
select {
  width: 100%;
  font-family: var(--font-ui);
  font-size: var(--text-body);
  color: var(--paper);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.75rem 1rem;
  transition: border-color var(--ease-fast), box-shadow var(--ease-fast);
}

input::placeholder,
textarea::placeholder {
  color: var(--paper-dim);
  opacity: 0.7;
}

input:focus,
textarea:focus,
select:focus {
  outline: none;
  border-color: var(--violet);
  box-shadow: 0 0 0 3px rgba(124, 77, 255, 0.15);
}

textarea {
  resize: vertical;
  min-height: 6rem;
}

/* Choice/occasion button — matches the prototype's .occ-btn exactly */
.choice-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: 0.7rem 0.4rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--line);
  background: var(--panel-2);
  cursor: pointer;
  transition: all var(--ease-fast);
  text-align: center;
}

.choice-btn:hover {
  border-color: rgba(232, 82, 106, 0.35);
}

.choice-btn.active {
  border-color: var(--rose);
  background: var(--rose-tint);
}


/* ───────────────────────────────────────────────────────────────
   3.4 BADGES & CHIPS
   Badge pattern matches the prototype's .sub-card-badge exactly.
   ─────────────────────────────────────────────────────────────── */
.badge {
  display: inline-block;
  background: var(--violet);
  color: #fff;
  font-size: 0.55rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.18rem 0.6rem;
  border-radius: 0 0 6px 6px;
}

.badge-gold {
  background: linear-gradient(135deg, var(--gold), var(--gold-rich));
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 0.35rem 0.85rem;
  font-size: var(--text-caption);
  font-weight: 500;
  color: var(--paper);
  transition: all var(--ease-fast);
}

.chip.active {
  border-color: var(--rose);
  background: var(--rose-tint);
  color: var(--rose);
}


/* ───────────────────────────────────────────────────────────────
   3.5 DIALOGS / MODALS
   Not present in the prototype (only a landing page exists today)
   — designed as a consistent extension using the same token
   language (radius, shadow, colour) established above.
   ─────────────────────────────────────────────────────────────── */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(30, 22, 64, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--gutter);
  z-index: 1000;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--ease-slow);
}

.modal-backdrop.open {
  opacity: 1;
  pointer-events: auto;
}

.modal {
  background: var(--panel);
  border-radius: var(--radius-lg);
  box-shadow: 0 20px 60px rgba(30, 22, 64, 0.25);
  padding: 1.5rem;
  width: 100%;
  max-width: 480px;
  max-height: 90vh;
  overflow-y: auto;
  transform: translateY(12px);
  transition: transform var(--ease-slow);
}

.modal-backdrop.open .modal {
  transform: translateY(0);
}

.modal-close {
  position: absolute;
  top: 1rem;
  right: 1rem;
  background: none;
  border: none;
  color: var(--paper-dim);
  font-size: 1.2rem;
}


/* ───────────────────────────────────────────────────────────────
   3.6 TOAST
   Matches the prototype's .toast exactly.
   ─────────────────────────────────────────────────────────────── */
.toast {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--panel);
  border: 1px solid var(--rose);
  color: var(--paper);
  padding: 0.85rem 1.4rem;
  border-radius: var(--radius-md);
  font-size: var(--text-label);
  opacity: 0;
  pointer-events: none;
  transition: all var(--ease-slow);
  z-index: 999;
  max-width: 90vw;
  text-align: center;
}

.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}


/* ───────────────────────────────────────────────────────────────
   3.7 LOADING STATES (PTDS 7.22 — logo, soft gold glow, simple
   progress animation; avoid long loading screens)
   ─────────────────────────────────────────────────────────────── */
.loading-screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  min-height: 40vh;
}

.loading-logo {
  width: 64px;
  animation: pulse-glow 3s ease-in-out infinite;
}

.spinner {
  width: 28px;
  height: 28px;
  border: 3px solid var(--line);
  border-top-color: var(--violet);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

.skeleton {
  background: linear-gradient(90deg, var(--panel-2) 25%, var(--line) 50%, var(--panel-2) 75%);
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.5s ease-in-out infinite;
  border-radius: var(--radius-sm);
}


/* ───────────────────────────────────────────────────────────────
   3.8 EMPTY STATES (PTDS 7.23 — encouraging, never technical)
   ─────────────────────────────────────────────────────────────── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.75rem;
  padding: 2.5rem 1.5rem;
  color: var(--paper-dim);
}

.empty-state-title {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--text-quote);
  color: var(--paper);
}


/* ───────────────────────────────────────────────────────────────
   3.9 ERROR STATES (PTDS 7.24 — explain clearly, suggest next
   step, never expose technical detail)
   ─────────────────────────────────────────────────────────────── */
.error-message {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  background: var(--rose-tint);
  border: 1px solid var(--error);
  border-radius: var(--radius-sm);
  padding: 0.85rem 1rem;
  font-size: var(--text-label);
  color: var(--paper);
}

.success-message {
  background: rgba(111, 174, 124, 0.1);
  border: 1px solid var(--success);
  border-radius: var(--radius-sm);
  padding: 0.85rem 1rem;
  font-size: var(--text-label);
  color: var(--paper);
}

.field-error {
  font-size: var(--text-caption);
  color: var(--error);
}

input.invalid,
textarea.invalid {
  border-color: var(--error);
}

/* ───────────────────────────────────────────────────────────────
   3.10 PREVIEW CARDS
   Static marketing showcase for index.html only — restores the
   "sample Epoch" preview from the original prototype's carousel.
   Illustrative sample content, not live per-request data, so fixed
   colour-variant classes are used directly (real hex values from
   the Design System's Epoch Theme Presets) rather than the dynamic
   style-injection pattern viewer.html uses for actual per-epoch
   theming — that mechanism exists specifically for genuinely
   unknown-until-request-time data, which this isn't.
   ─────────────────────────────────────────────────────────────── */
/* Marquee — an auto-scrolling, self-looping strip of sample cards.
   The track is rendered twice in the HTML (two identical sets of
   cards back to back); animating exactly -50% of the track's total
   width moves through the first copy and lands perfectly on the
   start of the second, so the loop has no visible seam or jump. */
.marquee {
  width: 100%;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, black 6%, black 94%, transparent);
          mask-image: linear-gradient(to right, transparent, black 6%, black 94%, transparent);
}

.marquee-track {
  display: flex;
  width: max-content;
  gap: 1.1rem;
  animation: marquee-scroll 45s linear infinite;
}

.marquee:hover .marquee-track {
  animation-play-state: paused;
}

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .marquee-track {
    animation: none;
  }
}

.preview-card {
  position: relative;
  flex: 0 0 auto;
  width: 190px;
  height: 280px;
  border-radius: var(--radius-lg);
  padding: 1.2rem;
  color: #fff;
  text-align: center;
  box-shadow: var(--shadow-md);
  background-size: cover;
  background-position: center;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
}

/* Gradient scrim so white text stays legible over any photo,
   independent of that photo's own brightness. */
.preview-card::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(26,19,48,0.05) 0%, rgba(20,14,40,0.55) 55%, rgba(15,10,32,0.92) 100%);
  z-index: 0;
}

.preview-card > * {
  position: relative;
  z-index: 1;
}

.preview-card .numeral {
  font-size: 2rem;
  display: block;
}

.preview-card-tag {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 0.82rem;
  color: rgba(255, 255, 255, 0.85);
  min-height: 2.4em;
}

.preview-card .caption {
  color: rgba(255, 255, 255, 0.7);
}

.preview-card-occasion {
  font-size: var(--text-caption);
  color: rgba(255, 255, 255, 0.75);
  margin-top: 0.5rem;
}

/* Featured/Sample badges — top-left corner of each preview card,
   distinguishing real live Epochs (linked, clickable) from the
   decorative sample cards (not real data, never linked) sharing the
   same carousel. */
.preview-card-badge {
  position: absolute;
  top: 0.7rem;
  left: 0.7rem;
  padding: 0.25rem 0.6rem;
  border-radius: var(--radius-pill, 999px);
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 0.62rem;
  letter-spacing: 0.02em;
  z-index: 2;
}

.preview-card-badge-featured {
  background: linear-gradient(135deg, var(--gold), var(--gold-rich));
  color: #fff;
}

.preview-card-badge-sample {
  background: rgba(255, 255, 255, 0.18);
  color: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

/* Real Featured cards render as <a> tags (they link to the actual
   Epoch) rather than <div>s — reset link defaults so they keep
   looking identical to the sample cards next to them. */
.preview-card-live {
  cursor: pointer;
  text-decoration: none;
}

/* Small persistent label on real Featured cards only (sample cards
   never get one, since they aren't real links) — reinforces that
   the card is clickable and leads to the full live Epoch, not just
   a static preview. */
.preview-card-cta {
  margin-top: 0.5rem;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 0.66rem;
  color: #fff;
  opacity: 0.9;
}

@media (min-width: 640px) {
  .preview-card { width: 220px; height: 310px; }
}


/* ═══════════════════════════════════════════════════════════════
   4. UTILITIES
   Small single-purpose helper classes.
   ═══════════════════════════════════════════════════════════════ */

/* ───────────────────────────────────────────────────────────────
   4.1 UTILITIES
   ─────────────────────────────────────────────────────────────── */
.text-center { text-align: center; }
.text-right  { text-align: right; }
.hidden      { display: none !important; }
.flex-1      { flex: 1; }
.icon-lg     { font-size: 1.5rem; line-height: 1; }
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.mt-1 { margin-top: 0.5rem; }
.mt-2 { margin-top: 1rem; }
.mt-3 { margin-top: 1.5rem; }
.mt-4 { margin-top: 2rem; }
.mb-1 { margin-bottom: 0.5rem; }
.mb-2 { margin-bottom: 1rem; }
.mb-3 { margin-bottom: 1.5rem; }
.mb-4 { margin-bottom: 2rem; }


/* ═══════════════════════════════════════════════════════════════
   5. ACCESSIBILITY
   Focus handling and reduced-motion support — applies globally across every section above.
   ═══════════════════════════════════════════════════════════════ */

/* ───────────────────────────────────────────────────────────────
   5.1 ACCESSIBILITY (PTDS 2.17, 7.21 — non-negotiable)
   ─────────────────────────────────────────────────────────────── */
:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}


/* ═══════════════════════════════════════════════════════════════
   "CHOOSING YOU" LIVE EMBED — the founder's actual real, live Epoch,
   lifted verbatim from choosingyou.veeanta.com's own source (colors,
   fonts, ticking logic, and the final approved photo crop/overlay),
   embedded natively in the homepage hero — not a static image, not
   an iframe. Classes are prefixed cy- so they never collide with
   unrelated sitewide classes (.card, .footer, .bg) used elsewhere
   on this site. index.html ONLY — do not add this block or its
   script to create.html / explore.html.
   ═══════════════════════════════════════════════════════════════ */

.cy-embed-wrap {
  position: relative;
  width: 100%;
  max-width: 440px;
  margin: 2.5rem auto 0;
  border-radius: 28px;
  overflow: hidden;
  box-shadow: 0 8px 50px rgba(0, 0, 0, 0.3);
  cursor: pointer; /* the whole card is tap-to-play, same as the original page */

  background: radial-gradient(ellipse at 60% 100%, #3d0020 0%, #1a000f 40%, #0a0005 100%);
  background-image: url('https://assets.epoch.veeanta.com/choosingyou_bg.png?v=1');
  background-size: cover;
  background-position: center top;
  background-repeat: no-repeat;

  min-height: 620px;
  display: flex;
  align-items: flex-end;
  padding: 0 1.2rem 1.6rem;
}
.cy-embed-wrap::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at center, transparent 50%, rgba(10, 0, 5, 0.6) 100%);
}
@media (max-width: 480px) {
  .cy-embed-wrap { min-height: 520px; border-radius: 22px; }
}

.cy-card {
  position: relative;
  z-index: 1;
  width: 100%;
  background: rgba(10, 0, 20, 0.08);
  backdrop-filter: blur(1px);
  -webkit-backdrop-filter: blur(1px);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 28px;
  padding: 2.4rem 2rem 1.8rem;
  text-align: center;
  color: #fff;
  box-shadow: 0 8px 60px rgba(0, 0, 0, 0.3);
}
.cy-card::before {
  content: '';
  position: absolute; top: 0; left: 0; right: 0; height: 3px;
  border-radius: 28px 28px 0 0;
  background: linear-gradient(90deg, #0891b2, #5eead4, #a5f3fc);
}

.cy-label-top {
  font-family: 'Playfair Display', Georgia, serif;
  font-style: italic;
  font-size: 0.95rem;
  color: #5eead4;
  margin-bottom: 1.6rem;
  letter-spacing: 0.02em;
  line-height: 1.4;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.5);
}
.cy-pulse-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: #5eead4; margin-right: 6px; vertical-align: middle;
  animation: cy-pulse 2s ease-in-out infinite;
}
@keyframes cy-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.3; transform: scale(0.6); } }

.cy-days-number {
  font-family: 'Space Mono', monospace;
  font-size: clamp(3.2rem, 14vw, 5.5rem);
  font-weight: 700;
  line-height: 1;
  background: linear-gradient(135deg, #ffffff 0%, #5eead4 45%, #0891b2 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  letter-spacing: -0.02em;
  filter: drop-shadow(0 2px 20px rgba(94, 234, 212, 0.6));
  margin-bottom: 0.3rem;
}
.cy-days-unit {
  font-size: 0.82rem; font-weight: 600; letter-spacing: 0.14em;
  color: #5eead4; text-transform: uppercase; margin-bottom: 1.6rem;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
}
.cy-since-line {
  font-size: 0.8rem; color: rgba(255, 255, 255, 0.65);
  margin-bottom: 1.8rem; line-height: 1.6;
}
.cy-since-line strong { color: #fff; font-weight: 600; }

.cy-time-bar {
  background: rgba(255, 255, 255, 0.14); border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 12px; padding: 0.7rem 1.2rem; margin-bottom: 1.5rem;
  display: flex; align-items: center; justify-content: space-between;
}
.cy-time-label { font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.12em; color: rgba(255, 255, 255, 0.85); text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85); }
.cy-time-value { font-family: 'Space Mono', monospace; font-size: 0.9rem; color: #a5f3fc; font-weight: 700; text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85); }

.cy-breakdown { display: flex; gap: 1rem; margin-bottom: 1.5rem; }
.cy-breakdown-item {
  background: rgba(255, 255, 255, 0.14); border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 10px; padding: 0.6rem 0.8rem; text-align: center; flex: 1;
}
.cy-breakdown-num { font-family: 'Space Mono', monospace; font-size: 1.05rem; font-weight: 700; color: #a5f3fc; display: block; text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85); }
.cy-breakdown-lbl { font-size: 0.58rem; text-transform: uppercase; letter-spacing: 0.1em; color: rgba(255, 255, 255, 0.85); margin-top: 0.2rem; display: block; text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85); }

.cy-music-btn {
  display: flex; align-items: center; justify-content: center; gap: 0.6rem;
  width: 100%;
  background: linear-gradient(135deg, rgba(8, 145, 178, 0.45), rgba(94, 234, 212, 0.3));
  border: 1px solid rgba(94, 234, 212, 0.4);
  border-radius: 50px; padding: 0.75rem 1.4rem;
  color: #f0fdfa;
  font-family: 'Playfair Display', Georgia, serif; font-style: italic; font-size: 0.88rem;
  letter-spacing: 0.04em; cursor: pointer; margin-bottom: 1rem;
  transition: all 0.3s; box-shadow: 0 0 18px rgba(94, 234, 212, 0.12);
}
.cy-music-btn:hover, .cy-music-btn:active {
  background: linear-gradient(135deg, rgba(8, 145, 178, 0.6), rgba(94, 234, 212, 0.42));
  box-shadow: 0 0 30px rgba(94, 234, 212, 0.28);
}
.cy-music-icon { font-size: 1rem; }

.cy-today-date {
  font-size: 0.82rem; color: rgba(255, 255, 255, 0.92);
  letter-spacing: 0.06em; margin-bottom: 0.5rem;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.9), 0 0 10px rgba(0, 0, 0, 0.6);
}
.cy-footer-note {
  font-size: 0.62rem; color: rgba(255, 255, 255, 0.55); letter-spacing: 0.08em;
  text-transform: uppercase; text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85), 0 0 8px rgba(0, 0, 0, 0.6);
}

/* Logo sitting below the embed, above the quote */
.cy-embed-logo {
  display: block;
  width: 200px;
  max-width: 55%;
  height: auto;
  margin: 1.8rem auto 0;
}

/* ═══════════════════════════════════════════════════════════════
   LAYOUT REFINEMENT — matching choosingyou.veeanta.com's own
   composition. The previous version's wrapper was much taller and
   narrower than the source photo's natural aspect ratio, which
   forced background-size:cover to crop in tightly ("zoomed in").
   This version widens the wrapper (especially on desktop) so its
   aspect ratio sits close to the photo's own near-square shape,
   letting the full bouquet and more of the background show
   naturally. The card itself is scaled down as a single unit
   (transform: scale) — not by touching any individual font-size,
   padding, or blur value — and nudged right + down so it clears
   the face, matching the reference screenshot. Nothing about the
   counter logic, music playback, or asset URLs changes here — this
   file only touches .cy-embed-wrap and .cy-card positioning/sizing.
   ═══════════════════════════════════════════════════════════════ */

.cy-embed-wrap {
  display: block;
  width: 100%;
  max-width: 460px;
  height: 700px;
  min-height: 0;
  padding: 0;
  align-items: unset;
  background-position: center 8%;
}

.cy-card {
  position: absolute;
  left: 50%;
  right: auto;
  top: 142px;
  width: 330px;
  max-width: 84%;
  box-sizing: border-box;
  transform: translate(-53%, 0) scale(0.85);
  transform-origin: top center;
}

@media (min-width: 768px) {
  .cy-embed-wrap {
    max-width: 760px;
    height: 740px;
    background-position: center 12%;
  }
  .cy-card {
    top: 150px;
    width: 380px;
    max-width: 88%;
    transform: translate(-55%, 0) scale(0.85);
  }
}

/* ═══════════════════════════════════════════════════════════════
   FINE NUDGE — measured against the latest deployed screenshot:
   card top sat at 18.2% down the frame vs. the reference's 20.3%,
   a gap of roughly half a centimeter at typical desktop card sizes.
   This just increases the top offset to close that gap. Nothing
   else (width, scale, horizontal position) changes.
   ═══════════════════════════════════════════════════════════════ */

.cy-card {
  top: 158px;
}

@media (min-width: 768px) {
  .cy-card {
    top: 168px;
  }
}

/* ═══════════════════════════════════════════════════════════════
   Label line fix — "Every sunrise, my heart choosing you" wraps to
   two lines on narrow mobile widths at the desktop font-size. This
   only shrinks that one line's font-size on mobile and forces
   nowrap so it matches desktop's single-line look. Nothing about
   card position, width, or scale changes.
   ═══════════════════════════════════════════════════════════════ */

@media (max-width: 767px) {
  .cy-label-top {
    font-size: 0.72rem;
    letter-spacing: 0.01em;
    white-space: nowrap;
  }
}

/* ═══════════════════════════════════════════════════════════════
   MOBILE MARQUEE FIX — the carousel appearing, vanishing, and
   freezing on mobile (fixed by tapping) traces to two separate
   mobile-only issues:

   1. `.marquee:hover { animation-play-state: paused }` was meant
      for desktop (hover to pause and read a card). Touch devices
      have no real hover, but iOS Safari fakes one on tap and can
      get stuck in that state with nothing to trigger a hover-out —
      freezing the animation exactly as described. Scoped below to
      `@media (hover: hover)` so touch devices never engage it at
      all.

   2. `-webkit-mask-image` (used for the fade-out edges) combined
      with an animating flex child is a known WebKit bug: Safari can
      drop the compositing layer and fail to repaint until something
      forces a redraw — which is exactly why tapping the screen
      makes it "reappear". Forcing the track onto its own stable
      compositing layer (`translate3d` + `will-change`) keeps Safari
      from dropping it in the first place.
   ═══════════════════════════════════════════════════════════════ */

.marquee-track {
  -webkit-transform: translate3d(0, 0, 0);
  transform: translate3d(0, 0, 0);
  will-change: transform;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.marquee:hover .marquee-track {
  animation-play-state: running;
}

@media (hover: hover) {
  .marquee:hover .marquee-track {
    animation-play-state: paused;
  }
}

/* ═══════════════════════════════════════════════════════════════
   MARQUEE — SWITCHED FROM CSS ANIMATION TO A JS-DRIVEN SCROLL.
   The previous fix (forcing a stable compositing layer) didn't
   resolve it — on real mobile Safari the marquee still froze
   entirely. Rather than keep patching the CSS animation, this
   removes it completely: the corresponding <script> change (see
   the JS patch file) now moves the track continuously via
   requestAnimationFrame instead of a CSS @keyframes animation.
   There is no longer any CSS animation running on this element at
   all, which removes the entire class of WebKit "animation + mask
   compositing" bugs this looked like — not just this specific
   symptom of it.
   ═══════════════════════════════════════════════════════════════ */

.marquee-track {
  animation: none;
}

.marquee:hover .marquee-track {
  animation-play-state: initial;
}

/* ═══════════════════════════════════════════════════════════════
   VIEWER HOME LABEL — makes the existing logo-link read as an
   obvious "Home" button (it already linked to / — this just adds
   a visible label so shared-link visitors recognize it as one,
   matching create.html / explore.html's clearer nav).
   ═══════════════════════════════════════════════════════════════ */
.viewer-home-link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
}
.viewer-home-label {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--paper);
}

/* ═══════════════════════════════════════════════════════════════
   DELETE-REQUEST PANEL — collapsed by default (a rare, serious
   action, kept visually secondary to Renew/Gift/Share), expands
   into a small confirmation form matching the backend's actual
   contract for POST /delete-request: the visitor re-types the
   Epoch's own URL (a deliberate "type to confirm" anti-mistake
   step), a contact email, a reason, and an explicit ownership +
   irreversibility checkbox. Nothing here deletes anything by
   itself — it only ever submits a pending request for admin
   review, exactly like the backend already enforces.
   ═══════════════════════════════════════════════════════════════ */
.delete-request-toggle {
  background: none;
  border: none;
  color: var(--paper-dim);
  font-family: var(--font-ui);
  font-size: 0.78rem;
  text-decoration: underline;
  cursor: pointer;
  margin-top: 2rem;
}
.delete-request-panel {
  max-width: 420px;
  margin: 1rem auto 0;
  padding: 1.4rem;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg, 16px);
  text-align: left;
}
.delete-request-panel label {
  display: block;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 0.78rem;
  color: var(--paper);
  margin: 0.9rem 0 0.3rem;
}
.delete-request-panel input[type="text"],
.delete-request-panel input[type="email"],
.delete-request-panel select {
  width: 100%;
  box-sizing: border-box;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  font-family: var(--font-ui);
  font-size: 0.85rem;
  background: var(--panel);
  color: var(--paper);
}
.delete-request-checkbox-row {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin-top: 1rem;
}
.delete-request-checkbox-row input[type="checkbox"] {
  margin-top: 0.2rem;
  flex-shrink: 0;
}
.delete-request-checkbox-row label {
  margin: 0;
  font-weight: 400;
  font-size: 0.78rem;
  color: var(--paper-dim);
  line-height: 1.4;
}
.delete-request-submit {
  margin-top: 1.2rem;
  width: 100%;
}
.plan-toggle {
  display: inline-flex;
  gap: 0.4rem;
  margin: 0.8rem 0 1rem;
  padding: 0.25rem;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 999px;
}
.plan-toggle-btn {
  border: none;
  background: none;
  padding: 0.45rem 1.1rem;
  border-radius: 999px;
  font-family: var(--font-ui);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--paper-dim);
  cursor: pointer;
  transition: background 0.2s, color 0.2s;
}
.plan-toggle-btn.is-active {
  background: var(--accent, #7c4dff);
  color: #fff;
}

/* ═══════════════════════════════════════════════════════════════
   THUMBNAIL WATERMARK — a faint Epoch logo overlaid on every
   gallery/marquee card's own photo, like a subtle shadow sitting on
   top of the image itself. Pure CSS, no image processing: the logo
   is layered in via ::after using a background-image pointed at the
   same asset already used everywhere else on the site, positioned
   bottom-right, low opacity so it never fights with the photo or
   the card's own text for attention.
   ═══════════════════════════════════════════════════════════════ */

.gallery-card-image,
.preview-card {
  position: relative;
}
.gallery-card-image::after,
.preview-card::after {
  content: '';
  position: absolute;
  right: 0.6rem;
  bottom: 0.6rem;
  width: 34px;
  height: 34px;
  background-image: url('https://assets.epoch.veeanta.com/logos:epoch-logo-transparent.png');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  opacity: 0.35;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.4));
  pointer-events: none;
}
@media (max-width: 480px) {
  .gallery-card-image::after,
  .preview-card::after {
    width: 26px;
    height: 26px;
    right: 0.5rem;
    bottom: 0.5rem;
  }
}
