/* ============================================================
   Viral Cards — placeholder design system
   Swap these tokens once mockups are ready; layout stays intact.
   ============================================================ */

:root {
  --bg: #101114;
  --nav-bg: #000000;
  --surface: #141824;
  --surface-2: #1c2233;
  --border: #2a3147;
  /* Control outlines on the dark card page (qty stepper, flip button) —
     ~3:1 against --bg so the boundary reads clearly. */
  --border-strong: #55628a;
  --text: #eef1f8;
  --text-muted: #9aa3b8;
  /* Now used only for the selected tier card's border (.tier-card.active) —
     the numbered badges/icons that also used to share this dropped the
     gradient for a solid color instead (see
     .card-anatomy-num, .card-anatomy-marker). Simplified to a clean 2-stop
     blue-to-pink fade — smoother than the earlier 4-stop version, and
     drops purple/lavender entirely rather than just lightening it. */
  --holo: linear-gradient(120deg, #0688c0, #d3509d);
  --accent: #a78bfa;
  /* Darker accent for text on white/light backgrounds — --accent itself is
     only ~2:1 contrast on white, well under WCAG AA's 4.5:1 minimum. */
  --accent-on-light: #6b46c1;
  --success: #4ade80;
  --radius: 14px;
  --max-width: 1280px;
  /* Outer cap for the nav and hero content on very wide screens. */
  --wide-width: 1600px;
  /* Padding scale: section top/bottom (--space-v) pairs with side padding
     (--space-h), which doubles as the page gutter for the nav, heroes,
     content sections and callouts so every left edge lines up. */
  --space-v: 5rem;
  --space-h: 4rem;
  /* Cap for running text so lines stay readable on wide screens. */
  --readable-width: 84ch;
  --font: "Helvetica Neue", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  /* Trial: section headings + CTAs only — not the Jimothy hero banner
     (Lobster), subheadings, tier cards, or body text. See .section h2 etc.
     and .btn below for where this is actually applied. */
  --font-heading: "Space Grotesk", var(--font);

  /* ---- Design system (2026-08-08 style pass) ---- */
  --cta: #B103C8;
  /* Hover state for --cta backgrounds — ~6.5:1 contrast against
     --heading-on-dark text, comfortably clears WCAG AA. */
  --cta-hover: #9C03B0;
  --heading-on-dark: #f9f9f9;
  --text-on-dark: #ddd;
  --link-on-dark: #E1B7FF;
  --heading-on-light: #101114;
  --text-on-light: #333;
  --focus-on-dark: #E1B7FF;
  --focus-on-light: #B103C8;
}

@media (max-width: 1024px) {
  :root { --space-v: 4rem; --space-h: 2.5rem; }
}

@media (max-width: 760px) {
  :root { --space-v: 3rem; --space-h: 1.5rem; }
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* ---------- Sitewide spacing standard (body copy) ----------
   Two fixed values, everywhere a <p> sits next to another <p> or a button:
     - Paragraph directly followed by another paragraph: 1rem gap
       (margin-bottom on the earlier paragraph).
     - Paragraph directly followed by a button/CTA (.btn or a custom CTA
       like .jimothy-hero-cta): 2rem gap (margin-bottom on the paragraph).
   Each component-specific rule below sets its own margin-bottom to one of
   these two values rather than a one-off number — search "paragraph-to-
   paragraph" / "paragraph-to-button" to find every place this applies. A
   paragraph's OWN trailing margin-bottom (the last one in a group, before
   something other than a paragraph or button — a heading, a form, a new
   section) is a different, untouched concern and keeps its existing,
   context-specific value. */

/* Deliberately NOT overflow-x:hidden here (only on body, below) — setting
   overflow-x on html turns both html and body into separate scroll
   containers, which breaks position: sticky on .site-header (its nearest
   scrolling ancestor resolution gets redirected and it stops tracking
   scroll). Tried that as a defensive backstop against horizontal-scroll
   edge cases; it broke the sticky header instead, so back to relying on
   body's overflow-x propagating up to the viewport. */
html { scroll-behavior: smooth; }

/* No background here on purpose — every section paints its own (dark
   sections via var(--bg)/var(--nav-bg), light ones via .light-section), so
   nothing actually depends on body's own color. It used to be var(--bg),
   which meant any gap that wasn't covered by a section's own background
   silently read as dark instead of surfacing as the bug it was — see
   .card-page below, the one spot that genuinely needed an explicit
   var(--bg) added once this was removed. */
body {
  color: var(--text);
  font-family: var(--font);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ---------- Standard heading scale (sitewide) ----------
   Base h1-h6 sizes. Any more specific selector (a class-scoped rule like
   .card-info h1 or .jimothy-hero-title) naturally wins over these via CSS
   specificity, which is how the two explicit exceptions — the homepage
   hero banner and the card-detail page's card-details section — opt out
   without needing anything special here. The blog gets its own shifted
   scale (one level down, since blog copy reads better at those sizes) —
   see .blog-post-body h2-h6 near the blog rules. */
h1, h2, h3, h4, h5, h6 { line-height: 1.15; }

h1 { font-size: 3.5rem; }
h2 { font-size: 2.75rem; margin-bottom: 1.5rem; }
h3 { font-size: 2rem; }
h4 { font-size: 1.5rem; }
h5 { font-size: 1.25rem; }
h6 { font-size: 1rem; }

@media (max-width: 760px) {
  h1 { font-size: 2.35rem; }
  h2 { font-size: 1.85rem; margin-bottom: 1.15rem; }
  h3 { font-size: 1.6rem; }
  h4 { font-size: 1.25rem; }
  h5 { font-size: 1.125rem; }
  h6 { font-size: 1rem; }
}

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

/* Best-effort deterrent against casual right-click save/copy/drag of card
   art — see js/protect-images.js. Doesn't stop a determined user (devtools,
   network tab, disabling JS), only casual copying. */
img {
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
  user-drag: none;
  -webkit-touch-callout: none;
}

/* All hyperlinks are underlined by default; navigational chrome (nav links,
   the logo, whole-block "card" links, buttons) opts back out further down
   since underlining those would look broken, not like a UI convention. */
a { color: inherit; text-decoration: underline; }

/* ---------- Promo bar ---------- */

/* Sitewide announcement strip above the header — not sticky itself (unlike
   .site-header below it), so it scrolls away normally and the header takes
   over the top of the viewport once scrolled past, same as most sites that
   use this pattern (e.g. store.google.com, which this is modeled on). */
.promo-bar {
  background: var(--cta);
  color: var(--heading-on-dark);
  text-align: center;
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 0.875rem;
  line-height: 1.5rem;
  padding: 0.5rem 1.5rem;
}

/* ---------- Header ---------- */

/* position:sticky instead of a scroll-listener-driven position:fixed toggle
   (an earlier version pinned/unpinned via JS on scroll direction) — that
   approach went through several rounds of timing fixes (debounce, transition
   vs. animation, threshold tuning) and still flashed on fast flick-scrolls,
   which are hard to fully reproduce in testing but common on phones. Native
   sticky positioning has no discrete pinned/unpinned state to flash between
   at all — the browser's compositor just keeps it at `top: 0` once its
   normal position would scroll above the viewport, with no JS involved and
   nothing to race. The one behavior change from before: the header now
   stays visible continuously once you've scrolled past it, in both
   directions, rather than hiding again on scroll-down. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 200;
  background: var(--nav-bg);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}

.site-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: var(--wide-width);
  margin: 0 auto;
  padding: 1.25rem var(--space-h);
}


.logo {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

.logo-img {
  height: 32px;
  width: auto;
  display: block;
}

.site-nav a {
  margin-left: 1.5rem;
  text-decoration: none;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 0.95rem;
  color: #ffffff;
  transition: color 0.2s;
}

.site-nav a:hover { color: var(--link-on-dark); }

/* ---------- Mobile nav (hamburger) ---------- */

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}

.nav-toggle-bar {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--text);
  border-radius: 2px;
  transition: transform 0.25s ease, opacity 0.2s ease;
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.mobile-nav {
  display: none;
  flex-direction: column;
  position: absolute;
  top: calc(100% + 1rem);
  left: 1.5rem;
  right: 1.5rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.5rem 1.25rem;
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.35);
  z-index: 50;
}

.mobile-nav.open { display: flex; }

/* Dims the rest of the page while the mobile menu is open — a plain fixed
   overlay (not scoped to .site-header) so it covers the full viewport
   regardless of scroll position. Sits below .mobile-nav's own z-index so the
   menu stays on top, above everything else on the page. Clicking it closes
   the menu (see nav.js). */
.mobile-nav-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  z-index: 40;
}

.mobile-nav-backdrop.open { display: block; }

.mobile-nav a {
  padding: 0.9rem 0;
  color: #ffffff;
  text-decoration: none;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 1rem;
  border-bottom: 1px solid var(--border);
  transition: color 0.2s;
}

.mobile-nav a:hover { color: var(--link-on-dark); }

.mobile-nav a:last-child { border-bottom: none; }

@media (max-width: 760px) {
  .site-nav { display: none; }
  .nav-toggle { display: flex; }
}

/* ---------- Hero / promo banner ---------- */

/* Plain text, not a pill/badge — about.html, blog.html, contact.html are
   all .light-section (white bg), so --accent-on-light for contrast; the
   dark-background exception (card.html) overrides via .card-info below. */
.hero-kicker {
  display: inline-block;
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: #7c288c;
  margin-bottom: 1.25rem;
}

/* Sitewide — every .hero-kicker usage (about/blog/contact page-heroes,
   card.html's .card-info, the homepage's Latest Drop) crowds its title at
   the base 0.8rem on narrow screens. */
@media (max-width: 760px) {
  .hero-kicker { font-size: 0.75rem; }
}

/* ---------- Intro hero (homepage, above the Jimothy banner) ----------
   Plain black band for now — no bolts/imagery yet, just the left-aligned
   kicker/title/description, same max-width column as every other hero.
   Sits in normal document flow, directly above the Jimothy banner — no
   breakout needed since <main>'s direct children are already full-width. */
.viral-cards-hero {
  background: var(--nav-bg);
  /* The video is scaled up past its box (below); keep the overflow out of
     the page's scroll width. */
  overflow: hidden;
}

.viral-cards-hero-inner {
  max-width: var(--wide-width);
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 3fr);
  align-items: center;
}

/* Each column carries its own padding (rather than the wrapper), so the
   video column can drop its padding on phones. */
.viral-cards-hero-text {
  position: relative;
  z-index: 1; /* above the zoomed video's overhang */
  text-align: left;
  padding: 1.5rem 1.5rem 1.5rem 6rem;
}

/* Same lavender as every other dark-background kicker sitewide — not
   blue, which we've moved away from as a kicker color entirely. */
.viral-cards-hero-text .hero-kicker { color: #cc80db; }

.viral-cards-hero-text h1 {
  color: var(--heading-on-dark);
  margin-bottom: 1rem;
}

.viral-cards-hero-desc {
  color: var(--text-on-dark);
  font-size: 1.15rem;
  line-height: 1.6;
  max-width: 60ch;
  margin-bottom: 2rem; /* paragraph-to-button, before #viral-cards-hero-cta */
}

.viral-cards-hero-media {
  padding: 1.5rem var(--space-h) 1.5rem 1.5rem;
}

/* Single-play teaser animation (js/hero-video.js) — muted autoplay, no
   controls. Always square, no rounding or overlays. */
.hero-video {
  display: block;
  width: 100%;
  /* Capped so the square doesn't keep growing on very wide screens. */
  max-width: 560px;
  margin-left: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: #000;
  /* Zooms the footage inside its square without changing the layout; the
     source has plenty of empty black around the bolt, so nothing is lost.
     Raise or lower to taste. */
  transform: scale(1.2);
}

/* Stacked (tablet and mobile): text first, square video below it. The
   side-by-side layout gets cramped below ~1024px. */
@media (max-width: 1024px) {
  .viral-cards-hero-inner { grid-template-columns: minmax(0, 1fr); }

  .viral-cards-hero-text { padding: var(--space-v) var(--space-h) 0; }

  .viral-cards-hero-media { padding: 2rem var(--space-h) var(--space-v); }

  /* Full width would make a very tall square on tablets. */
  .hero-video { margin-left: 0; }
}

/* Phones: the video container has no padding, so the video runs edge to
   edge. */
@media (max-width: 760px) {
  .viral-cards-hero-text { padding-bottom: 1.5rem; }

  .viral-cards-hero-media { padding: 0 0 1rem; }

  .hero-video { max-width: none; }
}

/* ---------- Jimothy custom banner + carousel ---------- */

.jimothy-hero {
  position: relative;
  overflow: hidden;
}

.jimothy-hero-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  z-index: 0;
  /* Entrance: simple fade in, timed together with the title/description/CTA
     fading in below (see .jimothy-hero-inner.content-in) — both triggered
     at once by js/main.js's wireHeroReveal() when the section scrolls into
     view, rather than sequenced one after the other. */
  opacity: 0;
  transition: opacity 0.9s ease;
}

.jimothy-hero-bg.bg-in {
  opacity: 1;
}

/* Black instead of the shared .hero-kicker purple — this banner's own
   light, illustrated background reads better with a plain neutral kicker
   than another brand color. */
.jimothy-hero-eyebrow { color: #000000; }

.jimothy-hero-eyebrow,
.jimothy-hero-title,
.jimothy-hero-subtitle,
.jimothy-hero-desc,
.jimothy-hero-cta,
.card-carousel,
.carousel-dots {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.jimothy-hero-inner.content-in .jimothy-hero-eyebrow,
.jimothy-hero-inner.content-in .jimothy-hero-title,
.jimothy-hero-inner.content-in .jimothy-hero-subtitle,
.jimothy-hero-inner.content-in .jimothy-hero-desc,
.jimothy-hero-inner.content-in .jimothy-hero-cta,
.jimothy-hero-inner.content-in .card-carousel,
.jimothy-hero-inner.content-in .carousel-dots {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .jimothy-hero-bg,
  .jimothy-hero-title,
  .jimothy-hero-subtitle,
  .jimothy-hero-desc,
  .jimothy-hero-cta,
  .card-carousel,
  .carousel-dots {
    transition: none !important;
    transform: none !important;
    opacity: 1 !important;
  }
}

.jimothy-hero-inner {
  position: relative;
  z-index: 1;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 5rem var(--space-h) 3rem;
  min-height: 780px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.jimothy-hero-title {
  font-family: "Lobster", cursive;
  font-weight: 400;
  font-size: 4.5rem;
  color: #000;
  line-height: 1.2;
  margin-bottom: 1.3rem;
}

@media (max-width: 760px) {
  .jimothy-hero-title { font-size: 3rem; }
}

/* Compound so it outweighs the light-section heading color (.light-section h2)
   on pages where the banner sits inside one. */
.jimothy-hero .jimothy-hero-title,
.jimothy-hero-alt .jimothy-hero-title { color: #000; }

/* Bold label line above the description — e.g. "Internet Legend #001" —
   too small a detail to carry as part of the big script .jimothy-hero-title
   itself, but still belongs above the description rather than folded into
   it. */
.jimothy-hero-subtitle {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: 0.02em;
  color: #000;
  margin-bottom: 1rem; /* paragraph-to-paragraph, before .jimothy-hero-desc */
}

.jimothy-hero-desc {
  font-family: "Raleway", sans-serif;
  font-style: italic;
  font-size: 1.125rem;
  color: #000;
  margin-bottom: 2rem; /* paragraph-to-button, before .jimothy-hero-cta */
  max-width: 60ch;
}

/* Shape/font match the sitewide .btn (Space Grotesk, 0.75rem corners,
   same padding/letter-spacing) — only the color stays its own, this is
   the one button on the site that isn't the brand purple. */
.jimothy-hero-cta {
  display: inline-block;
  background: #1c5866;
  color: #ffffff;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.125rem;
  text-decoration: none;
  padding: 0.8rem 1.6rem;
  border-radius: 0.75rem;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
  transition: transform 0.15s, background-color 0.15s;
}

.jimothy-hero-cta:hover {
  transform: translateY(-2px);
  background-color: #24707f;
}

/* ---------- Alternative single-card hero ----------
   Reuses .jimothy-hero-inner/.jimothy-hero-bg/-title/-desc/-cta as-is (same
   background, typography, button) — .bg-in/.content-in are set directly in
   the HTML rather than by the entrance-animation JS, so this renders
   immediately instead of playing the slide-up/fade-in sequence the main
   banner does. Only the layout differs: a left-text/right-card row instead
   of a centered column, with the card side using the same .flip-scene
   markup as the card detail page instead of the rotating carousel. */
/* Homepage keeps this full-width (naturally fills <main>, no width rule
   needed) — only the About/Cards instances get the boxed .nominate-section
   treatment, see .about-page .jimothy-hero-alt further down. */
.jimothy-hero-alt {
  position: relative;
  overflow: hidden;
}

/* Fades the busy background toward white behind the text (left side) while
   leaving the card's own side untouched, so the text stays readable without
   needing its own solid backdrop. */
.jimothy-hero-alt-overlay {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(to right, rgba(255, 255, 255, 0.75) 0%, rgba(255, 255, 255, 0) 75%);
}

/* Compound selector (not just .jimothy-hero-alt-inner) so this reliably
   outweighs the main banner's own mobile padding/min-height override
   further down (.jimothy-hero-inner at the 760px breakpoint) — that rule
   targets the shared .jimothy-hero-inner class this element also carries,
   at equal specificity, and it happens to come later in the file. */
.jimothy-hero-inner.jimothy-hero-alt-inner {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 3rem;
  /* Matches .page-hero-inner (about/blog/drops) instead of the tall,
     heavily-padded main banner above — no min-height either, so the
     section sizes to its (much more compact) content instead of that
     780px floor leaving text and card both adrift in empty space. */
  padding: 4rem;
  min-height: 0;
}

.jimothy-hero-alt-text {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  flex: 1 1 480px;
}

/* Soft, oversized blurred glow sitting behind the text — extends well past
   the text's own edges so it reads as a diffuse white cloud instead of a
   visible rounded rectangle, giving the text a readable backdrop against
   busy background art without needing a hard-edged panel. */
.jimothy-hero-alt-text::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -7rem;
  background: rgba(255, 255, 255, 0.8);
  filter: blur(60px);
  border-radius: 50%;
}

.jimothy-hero-alt-ctas {
  display: flex;
  align-items: center;
  /* A wrapping flex container with width:auto stretches to the full
     available width once it actually needs to wrap (narrow phones, where
     the button + link no longer fit on one line) instead of shrinking to
     its content the way it does unwrapped — so each wrapped line was
     sitting flush against the left edge of that now-full-width box instead
     of centered under the (centered) text above it. justify-content only
     matters for that wrapped case; the unwrapped box is already exactly as
     wide as its content, so this is a no-op there. */
  justify-content: center;
  flex-wrap: wrap;
  gap: 2.5rem;
}

/* Secondary, non-transactional CTA — plain link styling (not .btn/.jimothy-
   hero-cta button chrome), so it visibly reads as the lower-commitment
   option next to the primary "Get Yours Today" button. */
.jimothy-hero-secondary-cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: #1c5866;
  font-weight: 700;
  text-decoration: underline;
}

.jimothy-hero-secondary-cta:hover { color: #24707f; }

/* Mini version of .jimothy-hero-alt-text's own blob — this plain text link
   (no button chrome of its own) sits near the bottom edge of that larger
   blob, where its blur has already faded out, so it needed its own
   dedicated glow to stay legible against the background art. */
.jimothy-hero-secondary-cta::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -2rem;
  background: rgba(255, 255, 255, 0.7);
  filter: blur(18px);
  border-radius: 50%;
}

/* The flip card's own .trading-card would otherwise inherit the sitewide
   3° tilt (meant for the loose single-card display elsewhere) — cancelled
   here the same way .card-detail already cancels it for the identical
   flip-card on the card detail page. */
.jimothy-hero-alt-card .trading-card { transform: none; }
.jimothy-hero-alt-card .trading-card:hover { transform: scale(1.02); }

.jimothy-hero-alt-card {
  flex: 0 1 340px;
  width: 100%;
  max-width: 340px;
}

/* Row above each banner's title: the "Debut Drop" eyebrow. */
.jimothy-hero-eyebrow-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
}

.jimothy-hero-eyebrow-row .hero-kicker { margin-bottom: 0; }

/* Homepage only, and desktop only (About/Cards versions of this banner have
   no flip button at all — see js/jimothy-banner.js — and at mobile widths
   the row below switches to flex-direction:column, where items just stack
   in DOM order and this centering concern doesn't apply, so the button
   stays in normal flow there instead). Taken out of normal flow so it no
   longer adds to .jimothy-hero-alt-card's own height — without this, that
   extra height below the card pushed the outer row's align-items:center to
   center the text against "card + button" instead of against the card
   itself. Positioned relative to .flip-scene (already position:relative),
   so it still visually sits in the same spot just below the card. */
@media (min-width: 761px) {
  .jimothy-hero-alt-card .flip-btn {
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    margin-top: 1.25rem;
  }

  /* :hover replaces .flip-btn's own transform outright (see its base rule
     further down) — without re-adding the translateX here too, hovering
     snapped the button back to its raw left:50% position (no longer offset
     to true center), reading as a large sideways jump. */
  .jimothy-hero-alt-card .flip-btn:hover {
    transform: translateX(-50%) scale(1.06);
  }

  /* Extra clearance below the card for the now-absolutely-positioned
     button above — without this it poked out past .jimothy-hero-alt's own
     bottom edge and got clipped by that section's overflow:hidden. Only
     applies when a .flip-btn is actually present (homepage only), so the
     About/Cards versions of this banner don't get extra unneeded space. */
  .jimothy-hero-inner.jimothy-hero-alt-inner:has(.flip-btn) {
    padding-bottom: 6rem;
  }
}

@media (max-width: 760px) {
  .jimothy-hero-inner.jimothy-hero-alt-inner {
    flex-direction: column;
    padding: 3rem 1.5rem;
    min-height: 0;
    gap: 2.5rem;
  }
  .jimothy-hero-alt-text {
    align-items: center;
    text-align: center;
    /* .flex-basis:420px (set for desktop's row layout, where it controls
       width) would otherwise become a 420px MIN-HEIGHT once the container
       switches to flex-direction:column here — stretching the text block
       far past its actual content and leaving a huge gap before the card. */
    flex: 0 0 auto;
  }
  .jimothy-hero-alt-ctas {
    flex-direction: column;
    gap: 1rem;
  }
  .jimothy-hero-alt-card { max-width: 280px; }
}

.card-carousel {
  position: relative;
  margin-top: auto;
  padding-top: 3rem;
  width: 100%;
  display: flex;
  justify-content: center;
}

/* Hidden below 1024px (touch/narrower viewports use swipe + dots instead —
   there isn't room for both cards and controls at a useful size below
   that). See the min-width:1024px block below for the visible state. */
.carousel-arrow {
  display: none;
  /* top/bottom + margin:auto 0 centers the button within the track's own
     height (the region below .card-carousel's 3rem top padding) rather
     than the whole padded box — robust across the mobile/desktop track
     height difference without having to calc() the padding offset. */
  position: absolute;
  top: 3rem;
  bottom: 0;
  margin: auto 0;
  z-index: 20;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
  transition: background 0.2s, border-color 0.2s, transform 0.15s;
}

/* Dark theme — matches .flip-btn (card detail page) exactly: same icon
   color, border color, and hover treatment. */
.carousel-arrow-dark {
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
}
.carousel-arrow-dark:hover { border-color: var(--accent); transform: scale(1.06); }

/* Light theme — white background, black arrow, light grey border. */
.carousel-arrow-light {
  border: 1px solid #ececf0;
  background: #ffffff;
  color: var(--heading-on-light);
}
.carousel-arrow-light:hover { border-color: #cfcbd6; transform: scale(1.06); }

/* After the theme :hover rules so a click (:active) always wins over a
   same-specificity :hover — otherwise the press-down scale could lose to
   the hover scale while both apply during the click. */
.carousel-arrow:active { transform: scale(0.94); }

@media (min-width: 1024px) {
  .carousel-arrow { display: flex; }
  /* Negative inset — .jimothy-hero (unlike .card-carousel) has no
     max-width, so pushing the buttons out past .card-carousel's own edge
     doesn't get clipped, it just buys more gap from the cards. */
  .carousel-arrow-prev { left: -1.5rem; }
  .carousel-arrow-next { right: -1.5rem; }
}

.carousel-track {
  position: relative;
  width: 100%;
  max-width: 900px;
  height: 500px;
}

.carousel-slide {
  position: absolute;
  top: 50%;
  left: 50%;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  display: block;
  /* transform is set inline via JS (translate + per-step scale) so the slide
     can animate smoothly from one position/size to the next on rotation. */
  transition: transform 0.5s cubic-bezier(0.34, 0.2, 0.2, 1), opacity 0.4s ease;
}

.carousel-slide .trading-card {
  display: block;
  width: 280px;
  transform: none;
  border-radius: 18px;
  filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.3));
}

.carousel-slide .trading-card:hover { transform: none; }

.carousel-slide-overlay {
  position: absolute;
  inset: 0;
  border-radius: 18px;
  background: rgba(11, 13, 18, 0.5);
  transition: opacity 0.4s ease;
}

.carousel-slide.active .carousel-slide-overlay { opacity: 0; }

/* Color/width/offset come from the sitewide focus rule below — this just
   keeps the outline following the slide's own rounded shape. */
.carousel-slide:focus-visible { border-radius: 18px; }

/* Hover/focus reveal: tier name + blurb near the top, "Get This Card" CTA
   pinned to the bottom. Sits above both the image and the dim overlay. */
.carousel-slide-info {
  position: absolute;
  inset: 0;
  border-radius: 18px;
  background: rgba(11, 13, 18, 0.85);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: stretch;
  text-align: left;
  padding: 1.5rem 1.25rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}

/* Mouse/trackpad: hover reveals immediately. Scoped to hover-capable,
   fine-pointer devices so touch doesn't get a flaky synthetic-hover state —
   a slide's click now navigates straight to its page (see main.js), so
   touch users don't get a preview step at all, just this hover preview on
   desktop. */
@media (hover: hover) and (pointer: fine) {
  .carousel-slide.active:hover .carousel-slide-info {
    opacity: 1;
    pointer-events: auto;
  }
}

/* Keyboard: any slide reveals its own overlay as soon as focus lands on it
   (not just the centered one — a tabbing user needs to see what they're
   about to activate regardless of which slide that is), and stays revealed
   while focus moves on into the "Get This Card" link inside it. Mouse hover
   stays scoped to the active slide only (see above), that's unchanged. */
.carousel-slide:focus-within .carousel-slide-info {
  opacity: 1;
  pointer-events: auto;
}

/* While a slide is still animating into the center position, it may briefly
   sit under the cursor that just clicked it — force the overlay hidden for
   that window so it doesn't flash on before sliding away from the pointer. */
.carousel-slide.just-activated .carousel-slide-info {
  opacity: 0 !important;
  pointer-events: none !important;
}

.carousel-slide-info-title {
  color: #ffffff;
  font-weight: 800;
  font-size: 1.15rem;
  margin-bottom: 0.5rem;
}

.carousel-slide-info-desc {
  color: rgba(255, 255, 255, 0.8);
  font-size: 0.85rem;
  line-height: 1.45;
}

.carousel-slide-info-cta {
  display: block;
  text-align: center;
  background: var(--cta);
  color: var(--heading-on-dark);
  font-family: var(--font-heading);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.125rem;
  font-size: 0.75rem;
  text-decoration: none;
  padding: 0.7rem 1rem;
  border-radius: 0.75rem;
  transition: transform 0.15s;
}

.carousel-slide-info-cta:hover { transform: translateY(-2px); background: var(--cta-hover); }

.carousel-dots {
  display: flex;
  justify-content: center;
  gap: 0.6rem;
  margin-top: 1.5rem;
  padding-bottom: 3rem;
}

.carousel-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: none;
  padding: 0;
  background: rgba(255, 255, 255, 0.6);
  cursor: pointer;
  transition: transform 0.2s, background 0.2s;
}

.carousel-dot.active {
  background: #ffffff;
  transform: scale(1.3);
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-block;
  padding: 0.8rem 1.6rem;
  border-radius: 0.75rem;
  font-family: var(--font-heading);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.125rem;
  font-size: 0.85rem;
  text-decoration: none;
  transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;
  cursor: pointer;
  border: none;
}

.btn:hover { transform: translateY(-2px); }

.btn-primary {
  background: var(--cta);
  color: var(--heading-on-dark);
}

.btn-primary:hover { background: var(--cta-hover); }

/* Buttons on a white background (the homepage banner's own CTA is custom
   and untouched — see .jimothy-hero-cta). */
.btn-secondary {
  background: transparent;
  color: #000000;
  border: 1px solid #101114;
  transition: transform 0.15s, background-color 0.15s, color 0.15s;
}

.btn-secondary:hover {
  background: #101114;
  color: #f9f9f9;
}

.btn-disabled {
  background: var(--surface-2);
  color: var(--text-muted);
  cursor: not-allowed;
  pointer-events: none;
}

/* ---------- The card visual ---------- */

.hero-card { display: flex; justify-content: center; }

.trading-card {
  width: min(320px, 80vw);
  border-radius: 18px;
  transition: transform 0.3s ease;
  transform: rotate(3deg);
  filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.5));
}

.trading-card:hover { transform: rotate(0deg) scale(1.03); }

/* ---------- Sections ---------- */

.section {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--space-v) var(--space-h);
}

/* #story sits directly after .gallery-section (which keeps its own
   padding) — top halved on desktop, dropped entirely on mobile (760px
   block below) so it doesn't stack excess empty space against it. */
#story { padding-top: 2.25rem; }

@media (max-width: 760px) {
  #story { padding-top: 0; }
}

/* Full-width pink-to-white fade, same as the card
   detail page's .card-anatomy-block. */
.about-block {
  position: relative;
  background: linear-gradient(to bottom, #fcf5fd 0%, #ffffff 100%);
}

.about-block-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  /* Bottom halved — .packaging-block (Shipped Like a Collectible) right
     after it keeps its own full top padding, and this section's gradient
     background already fades to the same white by the time it ends, so an
     unhalved bottom here just doubled up into an oversized gap. */
  padding: var(--space-v) var(--space-h) 2rem;
}

@media (max-width: 760px) {
  .about-block-inner { padding-top: 3rem; padding-bottom: 0; }
}

/* Space Grotesk trial — section headings and page-level h1s. Grouped here
   instead of repeating font-family on each of these rules individually
   (they're scattered across the file, one per section/page). Explicitly
   NOT applied: the Jimothy hero banner title (Lobster), subheadings/
   section-labels, tier cards, or body copy. */
.section h2,
.about-block h2,
.drops-showcase-text h2,
.story-block h2,
.packaging-block h2,
.faq-section h2,
.urgency-section h2,
.card-anatomy-block h2,
.reviews-block h2,
.about-story h2,
.about-vision h2,
.about-why h2,
.nominate-section h2,
.blog-post-body h2,
.gallery-title,
.timeline-heading,
.blog-card-title,
.card-info h1,
.contact-page h1,
.about-page h1,
.blog-page h1,
.blog-post h1,
.viral-cards-hero-text h1 {
  font-family: var(--font-heading);
}

/* Full-bleed white background on constrained-width sections: the box-shadow
   spread paints edge-to-edge while the element itself stays centered/max-width. */
.light-section {
  background: #ffffff;
  display: flow-root;
}

/* Centered content column used inside full-width bands. */
.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding-inline: var(--space-h);
}


.light-section h2 { color: var(--heading-on-light); }

.light-section .section-story p { color: var(--text-on-light); }

@media (min-width: 761px) {
  .about-block h2 { margin-bottom: 2.5rem; }
}

.about-teaser-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2.5rem;
}

.about-teaser-col p {
  color: var(--text-on-light);
  font-size: 1.05rem;
  line-height: 1.6;
}

.about-teaser-col p strong { color: var(--heading-on-light); }

@media (max-width: 760px) {
  .about-teaser-grid { grid-template-columns: 1fr; gap: 1.5rem; }
}

.section-story p {
  color: var(--text-on-light);
  font-size: 1.1rem;
  max-width: 64ch;
  margin-bottom: 1rem; /* paragraph-to-paragraph */
}

/* Last paragraph in the section sits right above .story-callout instead of
   another paragraph — paragraph-to-button gets the larger gap instead. */
.section-story p:last-of-type {
  margin-bottom: 2rem;
}

/* ---------- Drops showcase ----------
   Full-width dark band — like .page-hero (About/Blog/Drops) — sitting
   between the light #about and #story sections with its own dark
   background. Left-text/right-card layout mirrors .jimothy-hero-alt-inner. */
.drops-showcase {
  position: relative;
  background: var(--bg);
}

.drops-showcase-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--space-v) var(--space-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4.5rem;
  /* Faded decorative graphic, sized to sit behind the text column on
     desktop; recentered (and left at its default size) on mobile once the
     layout stacks below. */
  background: url("../img/graphics/faded-bolt-graphic.svg") no-repeat left;
  background-size: 50%;
}

.drops-showcase-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  flex: 1 1 420px;
}

/* Compound selector (not just .drops-showcase-text h2) so this reliably
   outweighs .light-section h2 — this section sits nested inside
   .light-section (safe for its own background per the note above), and
   both selectors would otherwise tie at equal specificity. */
.light-section .drops-showcase-text h2 { color: var(--heading-on-dark); }

.drops-tagline {
  color: var(--text-on-dark);
  font-size: 1.1rem;
  max-width: 64ch;
  margin-bottom: 2rem; /* paragraph-to-button, before .drops-callout */
}

/* Dark-background kicker color, same reasoning as .page-hero .hero-kicker
   and .card-info .hero-kicker — the base .hero-kicker color is tuned for
   the light-background pages that use it elsewhere. */
.drops-showcase-text .hero-kicker {
  color: #cc80db;
  text-decoration: none;
}
.drops-showcase-text .hero-kicker:hover { text-decoration: underline; }

.drops-showcase-card {
  flex: 0 1 340px;
  width: 100%;
  max-width: 340px;
}

/* No glow/shadow at all here (removed) — tilt still cancelled, the same
   way .jimothy-hero-alt-card already cancels it. */
.drops-showcase-card .trading-card {
  transform: none;
  filter: none;
}
.drops-showcase-card .trading-card:hover { transform: scale(1.03); }

@media (max-width: 760px) {
  .drops-showcase-inner {
    flex-direction: column;
    padding: var(--space-v) var(--space-h);
    gap: 3rem;
    background-position: center;
    background-size: cover;
  }
  .drops-showcase-text {
    align-items: center;
    text-align: center;
    /* Avoids the same column-direction flex-basis-as-height bug fixed on
       .jimothy-hero-alt-text — flex-basis:420px is fine as a WIDTH in the
       desktop row layout, but becomes a min-HEIGHT once stacked here. */
    flex: 0 0 auto;
  }
  /* flex-basis:340px is a WIDTH in the desktop row but becomes a min-HEIGHT
     once stacked, leaving dead space under the image — same fix as the
     text block above. */
  .drops-showcase-card { max-width: 280px; flex: 0 0 auto; }
}

/* ---------- Card detail page ---------- */

/* Horizontal padding lives on .breadcrumb/.card-detail (not here) so the
   light-section content below (story/packaging/gallery/faq) isn't inset
   twice — once by this container and again by its own padding. Every
   section's content should sit at the same 1.5rem margin site-wide. */

.card-page {
  /* Same margin-collapse risk as #blog-post-page (see its comment) — not
     visibly broken here since the color on both sides of the collapse
     happens to be the same dark background, but flow-root keeps the
     underlying structure correct regardless. */
  display: flow-root;
}

/* Full-width dark band behind the card detail hero; .card-hero-inner holds
   the width-limited content. */
.card-hero {
  position: relative;
  background: var(--bg);
  /* Without this, .breadcrumb's margin-top collapses straight through this
     div (no border/padding of its own to stop it) and pushes the whole
     box — background included — down below where the breadcrumb actually
     starts, leaving a non-dark gap above it. Same fix as .card-page/
     #blog-post-page use for the same reason. */
  display: flow-root;
}

.card-hero-inner {
  max-width: 1080px;
  margin: 0 auto;
}

.card-detail {
  display: grid;
  grid-template-columns: minmax(280px, 400px) 1fr;
  gap: 3.5rem;
  align-items: start;
  padding: 0 var(--space-h) 4rem;
}

.card-detail .trading-card { transform: none; width: 100%; }
.card-detail .trading-card:hover { transform: scale(1.02); }

/* ---------- Card flip ---------- */

.flip-scene {
  position: relative;
  width: 100%;
  perspective: 1800px;
}

.flip-inner {
  position: relative;
  width: 100%;
  aspect-ratio: 750 / 1050;
  transform-style: preserve-3d;
  transition: transform 0.6s cubic-bezier(0.4, 0.2, 0.2, 1);
}

.flip-inner.flipped { transform: rotateY(180deg); }

.flip-face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.flip-face .trading-card { width: 100%; height: 100%; display: block; }

.flip-back {
  transform: rotateY(180deg);
}

.flip-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  margin: 1.25rem auto 0;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
  transition: border-color 0.2s, transform 0.2s;
}

.flip-btn:hover { border-color: var(--accent); transform: scale(1.06); }

/* Round to match the button's own shape — color/width/offset come from
   the sitewide :focus-visible rule. */
.flip-btn:focus-visible { border-radius: 999px; }

/* ---------- Tier cards ---------- */

.tier-selection {
  margin-bottom: 1.5rem;
}

.tier-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.tier-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  background: var(--surface);
  border: 2px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
  cursor: pointer;
  font-family: inherit;
  transition: border-color 0.2s, transform 0.15s;
}

.tier-card:hover { border-color: var(--accent); }

.tier-card.active {
  border-color: transparent;
  background:
    linear-gradient(var(--surface), var(--surface)) padding-box,
    var(--holo) border-box;
}

.tier-card-label {
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: 0.5rem;
}

.tier-card.active .tier-card-label { color: var(--accent); }

.tier-card-price {
  font-size: 1.7rem;
  font-weight: 800;
  color: var(--text);
  margin-bottom: 0.5rem;
}

.tier-card:not(.active) .tier-card-price { opacity: 0.6; }

/* Bundle card ("collect all 3") uses .bundle-discounted for its price
   instead of .tier-card-price, so it didn't pick up the rule above even
   though it's also a .tier-card. */
.tier-card:not(.active) .bundle-discounted { opacity: 0.6; }

.tier-card-price .sold-label { color: #f87171; }

.tier-card-blurb {
  font-size: 0.85rem;
  color: var(--text-muted);
  line-height: 1.5;
}

.section-label {
  font-size: 0.85rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  margin-bottom: 0.75rem;
}

.or-divider {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: 1.25rem 0;
  color: var(--text-muted);
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.or-divider::before,
.or-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.bundle-card {
  width: 100%;
}

.bundle-card .bundle-price {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
}

/* Standard breadcrumb: 2rem margin above/below (1.5rem on mobile, see the
   760px breakpoint), no horizontal padding of its own — pages differ in
   whether their container already provides that inset (.blog-page does,
   .card-page doesn't), so double-padding is avoided by adding it per
   context below instead of unconditionally here. */
.breadcrumb {
  font-size: 0.9rem;
  color: var(--text-muted);
  margin: 2rem 0;
}

.card-page .breadcrumb { padding: 0 var(--space-h); }

.breadcrumb a {
  color: var(--link-on-dark);
  font-family: var(--font-heading);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

/* card.html sits on a dark background — pink by default, white on hover. */
.card-page .breadcrumb a:hover { color: #ffffff; }

/* blog-post.html is .light-section (white bg) — needs a dark color instead
   of the pink --link-on-dark, which was made for dark backgrounds. */
.blog-page .breadcrumb a { color: var(--heading-on-light); }
.blog-page .breadcrumb a:hover { color: var(--cta-hover); }

.icon-arrow { flex-shrink: 0; }

.card-info .hero-kicker {
  margin-bottom: 1rem;
  /* card.html sits on a dark background, unlike the other .hero-kicker
     usages (about/blog/contact, all .light-section) — needs the raw
     (brighter) brand blue instead of the darkened light-background one. */
  color: #cc80db;
}

.card-info h1 {
  font-size: clamp(1.9rem, 4vw, 2.6rem);
  letter-spacing: -0.02em;
  color: var(--heading-on-dark);
  margin-bottom: 0.5rem;
}

.card-tagline {
  color: var(--text-on-dark);
  font-size: 1.05rem;
  margin-bottom: 1rem; /* paragraph-to-paragraph, before .v-price */
}

.v-price {
  color: var(--heading-on-dark);
  font-size: 1.7rem;
  font-weight: 800;
  margin-bottom: 1.25rem;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.price-badge {
  display: inline-block;
  background: var(--link-on-dark);
  color: #000;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 0.75rem;
  line-height: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
}

.v-price .sold-label { color: #f87171; }

.shipping-note {
  margin: 1.5rem 0 2rem;
  font-size: 0.85rem;
  color: var(--text-on-dark);
  text-align: center;
}

.shipping-note a { color: var(--link-on-dark); }

.buy-row {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 1rem;
  margin-bottom: 1rem;
}

/* Default (desktop): label sits above the stepper. Overridden to a single
   row (label left, stepper right) at mobile — see the 760px breakpoint. */
.qty-row {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.qty-label {
  font-size: 0.85rem;
  font-weight: 400;
  letter-spacing: 0.05rem;
  color: var(--text-muted);
}

.btn-buy-now {
  flex: 1;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.buy-row .btn-buy-now { font-size: 1rem; }

.qty-stepper {
  display: inline-flex;
  align-items: center;
  gap: 0;
  border: 1px solid var(--border-strong);
  border-radius: 0.75rem;
  flex-shrink: 0;
  /* No overflow: hidden — that clipped the focus outline on .qty-btn.
     Each end button rounds its own outer corner instead, below. */
}

.qty-btn {
  width: 48px;
  height: 48px;
  border: none;
  background: var(--surface-2);
  color: var(--text);
  font-size: 1.1rem;
  cursor: pointer;
  transition: background 0.2s;
}

.qty-btn:first-child { border-top-left-radius: 0.75rem; border-bottom-left-radius: 0.75rem; }
.qty-btn:last-child { border-top-right-radius: 0.75rem; border-bottom-right-radius: 0.75rem; }

.qty-btn:hover:not(:disabled) { background: var(--border); }
.qty-btn:disabled { color: var(--text-muted); cursor: not-allowed; opacity: 0.5; }

.qty-value {
  min-width: 44px;
  text-align: center;
  font-weight: 700;
  font-size: 1rem;
}

.bundle-original {
  color: var(--text-muted);
  text-decoration: line-through;
  font-size: 1rem;
}

.bundle-discounted {
  color: var(--text);
  font-size: 1.7rem;
  font-weight: 800;
}

.detail-table { width: 100%; border-collapse: collapse; font-size: 0.95rem; }

.detail-table td {
  padding: 0.65rem 0;
  border-bottom: 1px solid var(--border);
}

.detail-table td:first-child { color: var(--text-muted); width: 40%; }

.loading { color: var(--text-muted); padding: 3rem 0; text-align: center; }
.light-section .loading { color: #555555; }

/* ---------- Story block (card detail page) ---------- */
/* White strip below the dark banner — sits inside a .light-section band. */

.story-block {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--space-v) var(--space-h);
}

.story-block h2 {
  max-width: 620px;
}

.story-grid {
  display: grid;
  align-items: start;
}

.story-copy {
  color: var(--text-on-light);
  font-size: 1.05rem;
  line-height: 1.7;
  /* Was constrained to a 1.3fr column alongside the (now-removed) why-love
     list; widened now that it's the section's only content, but still
     short of the full container width for readable line length. */
  max-width: 760px;
}

.story-copy p + p { margin-top: 1rem; }

/* ---------- Packaging block (card detail page) ---------- */

.packaging-block {
  /* max-width/margin make this portable to pages where it isn't already
     nested in a max-width-constrained ancestor (card.html's .card-page
     already provides this, so it's a no-op there) — used standalone on the
     homepage and cards.html too. */
  max-width: var(--max-width);
  margin: 0 auto;
  /* Not halved against the next section: on card.html this used to chain
     into .reviews-block/.gallery-section, but both are placeholder/hidden
     for now (REVIEWS_LIVE/GALLERY_LIVE), so this is effectively always the
     last visible thing in its light-section on every page that uses it —
     full, generous bottom padding everywhere instead of a halved value
     tuned for a chain that no longer renders. */
  padding: var(--space-v) var(--space-h);
  scroll-margin-top: 2rem;
}

@media (max-width: 760px) {
  .packaging-block { padding-bottom: 3rem; }
}

/* card.html only: .story-block follows right after and keeps its own full
   top padding, so the generous bottom padding above doubled up into an
   oversized gap between the two — same fix as .drops-page .about-page. */
.card-page .packaging-block { padding-bottom: 2.25rem; }

@media (max-width: 760px) {
  .card-page .packaging-block { padding-bottom: 0; }
  .card-page .story-block { padding-top: 3rem; }
}

.packaging-intro {
  color: var(--text-on-light);
  margin-bottom: 2rem;
}

.packaging-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: stretch;
  gap: 0.75rem;
}

/* Same dark fill + pink-to-blue gradient border as .nominate-section, at
   2px instead of 6px so the three cards read lighter. */
.packaging-step {
  text-align: center;
  padding: 2rem 1.5rem;
  border: 2px solid transparent;
  border-radius: 24px;
  background-image:
    linear-gradient(var(--surface-2), var(--surface-2)),
    linear-gradient(135deg, #d3509d, #0688c0);
  background-repeat: no-repeat, no-repeat;
  background-origin: padding-box, border-box;
  background-clip: padding-box, border-box;
}

.packaging-icon {
  display: block;
  width: 96px;
  height: 96px;
  margin: 0 auto 1rem;
}

.packaging-step h3 { color: var(--heading-on-dark); font-size: 1.05rem; margin-bottom: 0.5rem; }
.packaging-step p { color: var(--text-on-dark); font-size: 0.9rem; }

.packaging-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #2a3147;
}

@media (max-width: 760px) {
  .packaging-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.5rem;
  }

  .packaging-step {
    padding: 1.5rem 1.25rem;
    border-radius: 16px;
  }

  .packaging-arrow svg { transform: rotate(90deg); }
}

/* ---------- Contact page ---------- */

.contact-page {
  max-width: 800px;
  margin: 0 auto;
  padding: 4rem var(--space-h) var(--space-v);
  min-height: 55vh;
}

.contact-kicker { margin-bottom: 1.25rem; }

.contact-page h1 {
  letter-spacing: -0.02em;
  color: var(--heading-on-light);
  margin-bottom: 1rem;
}

.contact-intro {
  color: var(--text-on-light);
  font-size: 1.05rem;
  margin-bottom: 1.5rem;
  max-width: 56ch;
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  margin-bottom: 4rem;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--text-on-light);
}

.form-field-label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
}

.form-field-required {
  font-weight: 400;
}

.form-field input,
.form-field textarea {
  font-family: inherit;
  font-size: 1rem;
  font-weight: 400;
  padding: 0.75rem 1rem;
  border: 1px solid #dcd9e0;
  border-radius: 0.75rem;
  background: #ffffff;
  color: #1a1a1a;
  resize: vertical;
}

/* Focus ring comes from the sitewide :focus-visible rule further down. */

/* Client-side required-field validation (contact.js) — light-background
   red, matching .form-status.error's existing text color for consistency. */
.form-field-error {
  display: none;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.35rem;
  color: #a3312f;
  font-size: 0.85rem;
  font-weight: 400;
}

.form-field-error .icon-error { flex-shrink: 0; }

.form-field.invalid .form-field-label-text { color: #a3312f; }
.form-field.invalid input,
.form-field.invalid textarea { border-color: #a3312f; }
.form-field.invalid .form-field-error { display: flex; }

.contact-submit {
  align-self: flex-start;
  background: var(--cta);
  color: var(--heading-on-dark);
  margin-top: 1rem;
}

.contact-submit:hover { background: var(--cta-hover); }

.form-status {
  position: relative;
  font-size: 0.95rem;
  padding: 1rem 2.75rem 1rem 1.25rem;
  border-radius: 10px;
  margin-bottom: 2rem;
}

.form-status.success { background: #e6f7ec; color: #1c6b3a; }
.form-status.error { background: #fbe9e9; color: #a3312f; }

.form-status-close {
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 999px;
  background: none;
  color: inherit;
  cursor: pointer;
  opacity: 0.7;
  transition: opacity 0.15s, background 0.15s;
}

.form-status-close:hover { opacity: 1; background: rgba(0, 0, 0, 0.06); }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---------- Auto-scrolling gallery track (shared across pages) ----------
   card.html keeps the original centered "Show us your cards!" heading with
   no header wrapper; the homepage's #gallery (.drops-gallery) uses the
   .gallery-header row below instead — a left-aligned title + right-aligned
   "View All Cards" button, and its items link out to cards.html on hover
   (see .gallery-item-overlay and js/gallery.js). */

.gallery-section[hidden] { display: none; }

.gallery-section {
  position: relative;
  padding: 3.5rem 0;
  background: #ffffff;
}

.gallery-title {
  text-align: center;
  max-width: var(--max-width);
  margin: 0 auto 1.5rem;
  padding: 0 var(--space-h);
  color: var(--heading-on-light);
}

/* Left-aligned title + right-aligned button row — homepage-only (card.html
   keeps the plain centered .gallery-title above, untouched). Takes over the
   max-width/centering/padding that .gallery-title normally does on its own,
   so the override below just resets those for this context. */
.gallery-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1.5rem;
  max-width: var(--max-width);
  margin: 0 auto 1.5rem;
  padding: 0 var(--space-h);
}

.gallery-header .gallery-title {
  text-align: left;
  max-width: none;
  margin: 0;
  padding: 0;
}

.gallery-track-wrap {
  overflow: hidden;
  width: 100%;
}

.gallery-track {
  display: flex;
  gap: 1.25rem;
  width: max-content;
  margin-top: 1.5rem;
  animation: gallery-scroll 28s linear infinite;
}

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

.gallery-item {
  position: relative;
  flex-shrink: 0;
  width: 250px;
  aspect-ratio: 750 / 1050;
  border-radius: 14px;
  overflow: hidden;
}

/* Hover/focus reveal for the homepage's cards gallery only (see
   js/gallery.js) — a dim tint plus a link through to cards.html, in place
   of the customer-photo captions this track doesn't have here. Darker than
   the 0.6 alpha this started at, for stronger contrast against the white
   .gallery-item-btn text/border sitting on top of it. */
.gallery-item-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(11, 13, 18, 0.8);
  text-decoration: none;
  opacity: 0;
  transition: opacity 0.25s ease;
}

@media (hover: hover) and (pointer: fine) {
  .gallery-item-overlay:hover { opacity: 1; }
}
.gallery-item-overlay:focus-visible { opacity: 1; }

/* The actual "View Cards" pill inside the overlay — white outline by
   default, filling solid white (with dark text) on hover/focus so the
   button itself has a visible reaction, not just the overlay it sits in. */
.gallery-item-btn {
  display: inline-block;
  border: 1.5px solid #ffffff;
  border-radius: 0.75rem;
  padding: 0.6rem 1.25rem;
  color: #ffffff;
  font-family: var(--font-heading);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1rem;
  font-size: 0.75rem;
  transition: background-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
}

.gallery-item-overlay:hover .gallery-item-btn,
.gallery-item-overlay:focus-visible .gallery-item-btn {
  background: #ffffff;
  color: var(--bg);
  transform: translateY(-2px);
}

.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

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

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

/* ---------- FAQ accordion (shared across pages) ---------- */

/* Full-width dark band (like .light-section, but --bg). .faq-inner holds the
   width-limited content; the band's top border is a real border so it
   snaps to the pixel grid. */
.faq-section {
  background: var(--bg);
  border-top: 1px solid var(--border);
}

.faq-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--space-v) var(--space-h);
}


.faq-section h2 { color: var(--heading-on-dark); }

.faq-list {
  display: flex;
  flex-direction: column;
}

.faq-item {
  border-bottom: 1px solid var(--border);
}

.faq-item:last-child { border-bottom: none; }

.faq-question {
  cursor: pointer;
  padding: 1.25rem 0.25rem;
  color: var(--heading-on-dark);
  font-size: 1.05rem;
  font-weight: 600;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.faq-question::-webkit-details-marker { display: none; }

.faq-chevron {
  flex-shrink: 0;
  color: var(--heading-on-dark);
  transition: transform 0.2s ease;
}

.faq-item[open] .faq-chevron { transform: rotate(180deg); }

.faq-answer { padding: 0 0.25rem 1.5rem; }
.faq-answer p { color: var(--text-on-dark); font-size: 0.95rem; line-height: 1.6; }

/* Standard inline text-link + icon treatment (see blog.html's "Read more"
   links, .blog-card-link) — reused anywhere a plain arrow-text link shows
   up on the site, e.g. "Read Jimothy's story" here and in the card-detail
   story copy. .faq-answer sits on a dark background on every page (see
   .faq-section's own comment), so it needs the lighter link color instead
   of .link-arrow's own light-background default — same fix as the
   breadcrumb's dark-bg link color. */
.link-arrow {
  color: var(--cta);
  font-weight: 700;
  font-size: 1rem;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.link-arrow:hover { color: var(--cta-hover); }

.faq-answer .link-arrow { color: var(--link-on-dark); margin-top: 1rem; }
.faq-answer .link-arrow:hover { color: #ffffff; }

/* ---------- Footer ---------- */

.site-footer {
  /* Matches the header — same var(--nav-bg) black on every page now,
     regardless of what's above it. A plain full-width block, so a normal
     border-top spans edge to edge. */
  background: var(--nav-bg);
  padding: 2rem var(--space-h);
  color: var(--text-muted);
  font-size: 0.85rem;
  border-top: 1px solid var(--border);
}

.footer-social {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  max-width: calc(var(--max-width) - 2 * var(--space-h));
  margin: 0 auto 1.5rem;
  padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--border);
}

.footer-social-text { margin: 0; }

.footer-social-icons {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-shrink: 0;
}

.footer-social-icons a {
  display: inline-flex;
  color: var(--text-muted);
  transition: color 0.2s;
}

.footer-social-icons a:hover { color: var(--text); }

.footer-social-icons svg {
  width: 20px;
  height: 20px;
  display: block;
}

.footer-copyright {
  text-align: center;
  max-width: calc(var(--max-width) - 2 * var(--space-h));
  margin: 0 auto;
}

.footer-legal-links {
  text-align: center;
  max-width: calc(var(--max-width) - 2 * var(--space-h));
  margin: 0.5rem auto 0;
  font-size: 0.8rem;
}

.footer-legal-links a {
  color: var(--text-muted);
  text-decoration: underline;
}

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

@media (max-width: 768px) {
  .footer-social {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 1rem;
  }
}

/* ---------- Rating badge (card detail page — Senja placeholder) ---------- */

.rating-badge {
  display: inline-block;
  color: #ffd166;
  font-size: 0.95rem;
  letter-spacing: 0.05em;
  margin-bottom: 1rem;
  text-decoration: none;
}

.rating-badge span {
  color: var(--link-on-dark);
  font-weight: 400;
  letter-spacing: normal;
  margin-left: 0.4rem;
  text-decoration: underline;
  transition: color 0.15s;
}

.rating-badge:hover span { color: var(--heading-on-dark); }

/* ---------- Urgency-style dark section (homepage "internet forgets" banner,
   and reused for the "Never Miss a Drop" email capture on both the homepage
   and the card detail page). A full-width band. ---------- */

.urgency-section {
  max-width: none;
  position: relative;
  padding: var(--space-v) var(--space-h);
  background: var(--bg);
  text-align: center;
}

.urgency-inner {
  max-width: 720px;
  margin: 0 auto;
}

.urgency-section h2 { color: var(--heading-on-dark); }

.urgency-copy {
  color: var(--text-on-dark);
  font-size: 1.15rem;
  line-height: 1.6;
  margin-bottom: 0.75rem;
}

/* ---------- Story callout button ---------- */
/* margin-bottom lives on .section-story p instead (paragraphs above a
   button get 1.5rem spacing), not a margin-top here. */

/* ---------- Anatomy of a card (card detail page) ----------
   Explains what's actually printed on the card, with a numbered list
   matched to numbered markers overlaid on an image of the card itself —
   marker positions (inline style="top/left" in the card.js template) are
   hand-measured against img/cards/jimothy-standard.svg's own 750×1050
   viewBox, so they'd need re-measuring against a different reference image. */

.card-anatomy-block {
  /* Own background (not just the
     ambient .light-section white the sibling sections rely on) — a
     distinct panel, so no halved bottom padding needed the way same-
     background chained sections use. */
  position: relative;
  background: linear-gradient(to bottom, #fcf5fd 0%, #ffffff 100%);
  /* Bottom matches the top: the next section (Never Miss a Drop) is a
     distinct dark panel, so nothing chains into this one's bottom edge. */
  padding: 4.5rem 0;
}

.card-anatomy-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 var(--space-h);
}

.card-anatomy-intro {
  color: var(--text-on-light);
  font-size: 1.05rem;
  line-height: 1.6;
  max-width: 64ch;
  margin-bottom: 2.5rem;
}

.card-anatomy-grid {
  display: grid;
  grid-template-columns: 3fr 2fr;
  gap: 5rem;
  align-items: center;
}

.card-anatomy-list {
  list-style: none;
  display: grid;
  gap: 1.5rem;
}

.card-anatomy-list li {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
}

.card-anatomy-list h3 {
  color: var(--heading-on-light);
  font-size: 1.05rem;
  margin-bottom: 0.3rem;
}

.card-anatomy-list p {
  color: var(--text-on-light);
  font-size: 0.95rem;
  line-height: 1.5;
}

.card-anatomy-num {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: var(--cta);
  color: var(--heading-on-dark);
  font-size: 0.85rem;
  font-weight: 800;
  font-family: var(--font-heading);
}

.card-anatomy-visual {
  position: relative;
}

.card-anatomy-img {
  display: block;
  width: 100%;
  border-radius: 18px;
  filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.25));
}

.card-anatomy-marker {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: var(--cta);
  color: var(--heading-on-dark);
  font-size: 0.85rem;
  font-weight: 800;
  font-family: var(--font-heading);
  border: 2px solid #ffffff;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
}

@media (max-width: 760px) {
  .card-anatomy-block { padding-top: 3rem; padding-bottom: 3rem; }

  .card-anatomy-grid {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }
}

/* ---------- Timeline (card detail page) — native horizontal scroller ----------
   .timeline-track scrolls natively (overflow-x + scroll-snap) at every width —
   vertical page scroll is never hijacked, so scrolling down always continues
   straight past the section. The wavy line is a repeating background-image
   tile (always fully drawn, not a progress indicator — see .timeline-track),
   same technique at every width; only the dot row (desktop only) tracks the
   track's own scrollLeft (see wireTimeline in card.js), lighting up as the
   user scrolls the row horizontally (wheel/trackpad/touch/drag), and
   clicking a dot scrolls the track itself to that card. */

.timeline-block {
  position: relative;
  /* Vertical fade instead of a flat fill — the top/bottom edges ease into
     white so the seam with the neighboring .light-section (pure white)
     reads as a soft transition instead of a hard color change. */
  background: linear-gradient(to bottom, #ffffff 0%, #F5FFFF 15%, #F5FFFF 85%, #ffffff 100%);
}

.timeline-sticky {
  /* Left edge lines up with the centered content column; the right side is
     deliberately left open so the cards run off the screen. The percentage
     is the width of the full-width .timeline-block. */
  padding: 3rem 0 4rem max(var(--space-h), calc((100% - var(--max-width)) / 2 + var(--space-h)));
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.timeline-heading {
  padding: 0;
  color: #101114;
}

.timeline-track {
  position: relative;
  display: flex;
  gap: 4vw;
  /* Top padding clears room for the wavy background-image line below. */
  padding: 3.5rem 1.5rem 2rem 0;
  width: 100%;
  align-items: center;
  overflow-x: auto;
  /* Explicit, not left to default: setting only overflow-x leaves overflow-y
     at its initial "visible", which the spec then computes to "auto" too —
     so without this, the oversized decorative shapes bleeding a bit past
     their own card's bottom edge (intentional, see .timeline-graphic) turn
     into a second, unwanted vertical scrollbar on the track itself. */
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  /* The browser's own scrollbar would be a second, redundant strip right
     under the dot row — native scroll (wheel/trackpad/touch/drag) works
     exactly the same with it hidden. */
  scrollbar-width: none;
  /* A small wavy-line tile repeated with background-repeat — because it
     paints across this element's own scrollable content, not just the
     visible viewport, it automatically spans the full scrollable width with
     no JS measurement needed. Always fully drawn (not a progress fill) —
     see .timeline-dots below for the thing that actually tracks position. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 44 24'%3E%3Cpath d='M0,12 Q11,2 22,12 T44,12' fill='none' stroke='%238DC295' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: repeat-x;
  background-position: top left;
  background-size: 44px 24px;
}

.timeline-track::-webkit-scrollbar { display: none; }

/* No card box, no side-by-side layout — the graphic sits centered behind
   its own entry's text as a large, pale watermark (see .timeline-graphic
   below) rather than a discrete icon next to it. Sized so ~2 entries are
   visible with the next one peeking in from the right edge of the native
   horizontal scroller. */
.timeline-card {
  position: relative;
  flex-shrink: 0;
  scroll-snap-align: start;
  width: 42vw;
  max-width: 520px;
  padding: 3rem 0;
}

.timeline-card-text {
  position: relative;
  z-index: 1;
}

.timeline-date {
  display: block;
  color: #000000;
  font-size: 0.9rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 0.85rem;
}

.timeline-event {
  color: #101114;
  font-size: 2.25rem;
  line-height: 1.4;
  font-weight: 400;
}

.timeline-detail {
  color: var(--text-on-light);
  font-size: 1rem;
  line-height: 1.6;
  margin-top: 0.75rem;
}

/* Faint decorative blobs instead of a discrete icon: 1-2 generic brand-
   colored shapes (see TIMELINE_SHAPES in card.js) scattered behind the
   entry's own text, low-opacity so they read as texture, not content — the
   text needs to stand out over them, not the other way around. */
.timeline-graphic {
  position: absolute;
  z-index: 0;
  inset: 0;
  pointer-events: none;
}

.timeline-shape {
  position: absolute;
  display: block;
  opacity: 0.05;
}

.timeline-shape svg { width: 100%; height: 100%; display: block; }

.timeline-dots {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 0;
}

.timeline-dot {
  width: 10px;
  height: 10px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid #CDDEDE;
  background: #CDDEDE;
  cursor: pointer;
  transition: background-color 0.2s, border-color 0.2s, transform 0.2s;
}

.timeline-dot:hover { border-color: #6B7979; }

.timeline-dot.passed {
  background: #6B7979;
  border-color: #6B7979;
  transform: scale(1.15);
}

/* Positions the prev/next arrows relative to the track itself, not the dot
   row below — same as store.google.com/product/pixel_11_pro's carousel,
   where the arrows float on top of the sliding content rather than sitting
   in a separate control row underneath it. Works at every width, which
   matters most on mobile where there's no dot row to click and a swipe
   isn't always obvious as the way to move the track (see the dots' own
   desktop-only rule further down). */
.timeline-track-wrap { position: relative; }

/* Plain floating circle + shadow (no border ring) — matches the carousel
   arrows on store.google.com/product/pixel_11_pro, which use the same
   solid-white-circle-with-shadow treatment instead of an outlined button,
   overlaid on the content instead of sitting in a row below it. */
.timeline-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  border: none;
  background: #ffffff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  color: #101114;
  cursor: pointer;
  transition: box-shadow 0.2s, transform 0.15s;
}

.timeline-arrow-prev { left: 1rem; }

/* Author CSS's own display:flex above otherwise wins over the UA
   stylesheet's [hidden]{display:none} — needed for the prev arrow's
   hide-at-the-start behavior (see wireTimeline's setActiveDots). */
.timeline-arrow[hidden] { display: none; }
.timeline-arrow-next { right: 1rem; }

.timeline-arrow:hover { box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25); transform: translateY(-50%) scale(1.06); }
.timeline-arrow:focus-visible { border-radius: 999px; }

@media (max-width: 760px) {
  .timeline-sticky {
    padding: 0;
    gap: 0.75rem;
  }
  /* The sticky box has no side padding on phones, so the heading carries the
     gutter itself. */
  .timeline-heading { padding: 0 var(--space-h); }
  .timeline-track {
    /* Base rule's width: 100% is of the parent, so adding margin-left on
       top of that (unlike padding, which the base width already accounts
       for) would push the box 2rem past the viewport edge — width has to
       give up that same 2rem for the two to actually agree.
       margin (not padding) for the left inset here — the wavy background-
       image line paints from this box's own edge, so margin keeps it (and
       the cards) clear of the screen edge without needing a matching
       scroll-padding fix. */
    width: calc(100% - var(--space-h));
    margin-left: var(--space-h);
    padding-left: 0;
    padding-right: 1.5rem;
    gap: 1rem;
  }
  .timeline-card {
    width: 84vw;
    max-width: none;
    padding: 2rem 2rem 2rem 0;
  }
  .timeline-dots { display: none; }

  /* Arrows move out of the cards' way: a centered row under the track
     instead of floating over it. Still real buttons, so they stay usable
     for keyboard/screen-reader users. */
  .timeline-track-wrap {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem;
    padding-bottom: 2rem;
  }
  .timeline-track { flex: none; }
  .timeline-arrow {
    position: static;
    transform: none;
  }
  .timeline-arrow:hover { transform: scale(1.06); }
}

/* ---------- Customer reviews (card detail page — Senja placeholder) ---------- */

/* Bottom halved — same light background as the next section
   (.gallery-section), see the comment on .packaging-block's padding. */
.reviews-block { padding: var(--space-v) var(--space-h) 2.25rem; }

/* Same-background bottom padding removed entirely on mobile (halved on
   desktop, see the rule above) — .gallery-title's own margin-bottom
   still keeps a visible gap before .gallery-section's content. Doesn't
   include .packaging-block: that no longer chains into a visible section
   here (see its own rule for why), so it keeps its own full mobile
   bottom padding instead. */
@media (max-width: 760px) {
  .reviews-block { padding-bottom: 0; }
}

.review-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1.25rem;
}

.review-card {
  background: #f8f8fa;
  border: 1px solid #ececf0;
  border-radius: var(--radius);
  padding: 1.5rem;
  margin-top: 0.5rem;
}

.review-stars { color: #f5a524; margin-bottom: 0.5rem; letter-spacing: 0.05em; }
.review-quote { color: var(--text-on-light); font-size: 0.98rem; }

/* ---------- Email signup ("Never Miss a Drop" — homepage above FAQ, card page above FAQ) ----------
   Styled to match .urgency-section (dark, centered, holo heading) — both sections
   share that class so this only needs to add the form-specific bits. */

.email-signup-section .urgency-inner {
  max-width: 600px;
}

.email-signup-form {
  display: flex;
  gap: 0.75rem;
  justify-content: center;
  flex-wrap: wrap;
  align-items: flex-start;
  margin-top: 2rem;
}

.email-signup-field {
  flex: 1;
  min-width: 220px;
  text-align: left;
}

.email-signup-form input[type="email"] {
  width: 100%;
  padding: 0.8rem 1.1rem;
  border-radius: 0.75rem;
  /* #56648F instead of var(--border) — the latter is too close in
     luminance to the field's own dark background for reliable contrast. */
  border: 1px solid #56648F;
  background: var(--surface-2);
  color: var(--text);
  font-size: 0.95rem;
}

.email-signup-form input[type="email"]::placeholder { color: var(--text-muted); }

/* Focus ring comes from the sitewide :focus-visible rule further down. */

/* Client-side required-field validation (email-signup.js) — dark-background
   red, matching .tile-status.sold's existing dark-bg red for consistency. */
.email-signup-field .form-field-error {
  display: none;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.5rem;
  color: #f87171;
  font-size: 0.85rem;
  font-weight: 400;
}

.email-signup-field.invalid input[type="email"] { border-color: #f87171; }
.email-signup-field.invalid .form-field-error { display: flex; }

/* Tighter than the shared .form-status's 4rem — this message sits inside a
   compact email-capture box, not a full page section, so it needs less
   trailing space. Applies to both the success and error state below, since
   both share this id. */
#email-signup-status { margin-bottom: 1.5rem; }

/* Purple instead of the shared .form-status.success green — this is the
   only success message on a dark background, so it also needs its own
   (dark-appropriate) border rather than reusing the light-page green. */
#email-signup-status.success {
  background: #f1e6fb;
  color: #000000;
  border: 1px solid #c9a0e8;
  margin-top: 1.5rem;
}

/* ---------- Page hero (About / Blog / Cards) ----------
   Full-bleed dark band — same background as the card detail page (--bg) —
   shared by about.html/blog.html/cards.html above their own (light-section)
   content. Title/description reuse each page's existing .hero-kicker/h1/
   .about-intro or .blog-intro classes (dark-context overrides below,
   following the same pattern as .card-info's own dark-background kicker
   override); only the surrounding layout and bolt graphics are new. */
.page-hero {
  position: relative;
  background: var(--bg);
}

.page-hero-inner {
  max-width: var(--wide-width);
  margin: 0 auto;
  padding: 4rem;
  display: flex;
  align-items: center;
  /* justify-content: center kept the bolts+text clustered in the middle
     regardless of how wide this box actually got — the box itself was full
     width, but nothing was using that width. space-between pushes the
     bolts out to the (padded) edges instead, with the text filling the
     remaining middle so the whole hero actually reads as full-width. */
  justify-content: space-between;
  gap: 4rem;
}

/* aspect-ratio (matches left/right-bolt.svg's own 42.05x105.47 viewBox) lets
   the browser reserve the right-sized box before the image has actually
   loaded — without it, width:auto has nothing to go on until the SVG
   arrives, so the bolts (and everything after them) visibly snap into their
   final layout a beat late instead of just being there from first paint. */
.page-hero-bolt {
  flex-shrink: 0;
  height: 250px;
  width: auto;
  aspect-ratio: 42.05 / 105.47;
  display: block;
}

.page-hero-text { text-align: center; }

.page-hero .hero-kicker { color: #cc80db; }

.page-hero h1 {
  color: var(--heading-on-dark);
  margin-bottom: 1rem;
}

.page-hero .about-intro,
.page-hero .blog-intro {
  color: var(--text-on-dark);
  font-size: 1rem;
  margin: 0 auto;
  /* Overrides the base .about-intro's 56ch cap — .page-hero-text (its
     parent) is already sized to its widest child, the h1, so this is
     relative to that width instead of an independent ch-based cap. */
  max-width: 80%;
}

/* Bolts start shrinking a bit earlier than the rest of the hero's mobile
   layout below (768px vs. 760px) — at full 250px height they start
   crowding the title on tablet-ish widths well before the other mobile
   adjustments are otherwise needed. */
@media (max-width: 768px) {
  .page-hero-bolt { height: 64px; }
}

@media (max-width: 760px) {
  .page-hero-inner {
    position: relative;
    padding: 2rem 1rem;
  }

  /* Mobile only: bolts come out of the flex flow (position:absolute) so
     the description text can stretch into the same space they occupy
     instead of being boxed into whatever's left over between them —
     desktop keeps the original flex-row layout above, where the text
     stays in its own narrower column. Inset (1rem) matches this
     container's own mobile padding, so the bolts land in the same spot
     they did as flex items with that padding. */
  .page-hero-bolt {
    position: absolute;
    top: 2rem;
    left: 1rem;
  }
  .page-hero-bolt:last-of-type { left: auto; right: 1rem; }

  /* Side padding keeps centered title/description lines clear of the bolts'
     own column (bolt width + 1rem inset ≈ 42px) even when a line runs the
     full width of this now-unconstrained flex child — without it, a wide
     first line (e.g. a two-word h1 that fits on one line at this width)
     renders directly under/behind the absolutely-positioned bolts. */
  .page-hero-text {
    flex: 1;
    padding: 0 2rem;
  }

  .page-hero .about-intro,
  .page-hero .blog-intro {
    max-width: none;
  }
}

/* ---------- About page ---------- */

/* Top padding kept modest (not the usual larger top padding other pages'
   own top-level container gets) — .page-hero (above, in the HTML) already
   ends with its own bottom padding, so this only needs to add a bit more
   breathing room at the seam, not a full second block of spacing. */
.about-page {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 3rem var(--space-h) var(--space-v);
}

@media (max-width: 760px) {
  .about-page { padding-bottom: 3rem; }
}

/* cards.html only: .packaging-block (Shipped Like a Collectible) follows
   right after this and keeps its own full top padding, so the generous
   bottom padding above — tuned for about.html, where this is followed by
   a dark, differently-styled section — doubled up into an oversized gap
   here instead. */
.drops-page .about-page {
  padding-bottom: 2rem;
}

@media (max-width: 760px) {
  .drops-page .about-page { padding-bottom: 0; }
}

.about-kicker { margin-bottom: 1.25rem; }

.about-page h1 {
  letter-spacing: -0.02em;
  color: var(--heading-on-light);
  margin-bottom: 1rem;
  line-height: 1.15;
}

.about-intro {
  color: var(--text-on-light);
  font-size: 1.15rem;
  margin-bottom: 1.5rem;
  max-width: 56ch;
}

.about-story {
  margin-bottom: 2.5rem;
}

/* One paragraph style for every light-background paragraph on the page
   (intro copy, the lead lines, and the "Why" steps). */
.about-story p,
.about-vision p,
.about-why p {
  color: var(--text-on-light);
  font-size: 1.02rem;
  line-height: 1.6;
}

.about-story p,
.about-vision p {
  /* Trailing value (spacing before the next section/heading, not another
     paragraph) — the interior paragraph-to-paragraph gap is overridden to
     1rem below. */
  margin-bottom: 1.5rem;
}

.about-story p:not(:last-of-type),
.about-vision p:not(:last-of-type) {
  margin-bottom: 1rem; /* paragraph-to-paragraph */
}

/* One-line lead under an H2, before the body paragraphs proper — same size
   and color as the paragraphs, set apart by weight only. */
.about-lead {
  font-weight: 600;
  margin-bottom: 1.25rem;
}

/* Light grey rule marking where "One card. One moment. Forever." used to
   sit as its own pull-quote — same treatment as .about-why below it. */
.about-vision {
  border-top: 1px solid #e4e4ea;
  padding-top: 2.5rem;
}

.about-why {
  border-top: 1px solid #e4e4ea;
  padding-top: 2.5rem;
}

/* Not .about-why too — it's the last section in .about-page, which already
   has its own generous bottom padding before the dark Nominate section. */
.about-vision { margin-bottom: 2.5rem; }

.about-why-grid {
  display: flex;
  flex-direction: column;
  margin: 2rem 0 2.5rem;
}

.about-why-step { text-align: left; padding: 1.5rem 0; }
.about-why-step:first-child { padding-top: 0; }
.about-why-step:last-child { padding-bottom: 0; }
.about-why-step + .about-why-step { border-top: 1px solid #e4e4ea; }
.about-why-step h3 { color: var(--heading-on-light); margin-bottom: 0.5rem; }

/* ---------- Nominate a Legend (About page) ----------
   Same dark background as the page-hero above it, but inset as a rounded
   card inside a .container rather than full-bleed. The faded bolt graphic
   (same one as the homepage's Latest Drop banner) sits on the right
   instead of the left; text stays left-aligned instead of that section's
   centered treatment. */
.nominate-section {
  /* No margin above — .about-why already has its own bottom padding before
     this. Below, .urgency-section is edge-to-edge with no padding of its
     own to lean on, so this section keeps its standard bottom margin
     instead of sitting flush against it. */
  margin-top: 0;
  margin-bottom: 64px;
  border: 6px solid transparent;
  border-radius: 24px;
  overflow: hidden;
  /* Three layers: the decorative bolt graphic on top, --surface-2 (the
     dark blue from the card detail page's quantity stepper/inputs) as the
     actual fill, and the same pink-to-blue gradient as .about-pull-quote
     for the border — same padding-box/border-box split that uses. */
  background-image:
    url("../img/graphics/faded-bolt-graphic.svg"),
    linear-gradient(var(--surface-2), var(--surface-2)),
    linear-gradient(135deg, #d3509d, #0688c0);
  background-repeat: no-repeat, no-repeat, no-repeat;
  background-position: right, 0 0, 0 0;
  background-size: 50%, auto, auto;
  background-origin: padding-box, padding-box, border-box;
  background-clip: padding-box, padding-box, border-box;
  padding: var(--space-v) var(--space-h);
}

.nominate-inner {
  width: 65%;
  text-align: left;
}

/* Below this the 65% column (and the form inside it) gets too narrow for
   the input + button, so the text takes the full width of the box. */
@media (max-width: 1200px) {
  .nominate-inner { width: 100%; }
}

/* cards.html only page with two .nominate-section instances back to back
   ("The Archive Starts Here" then "Who should become collectible next?")
   — the shared 64px margin-bottom reads as the same gradient-bordered box
   doubled/overlapping itself with that little room between, so this one
   gets extra breathing room. Scoped to the ID since it's only ever used
   on this one page. */
#dont-miss-002 { margin-bottom: 6rem; }

@media (max-width: 760px) {
  #dont-miss-002 { margin-bottom: 3rem; }
}

/* "Who belongs in the collection?" only — a real graphic on the right
   instead of the shared .nominate-section bolt background (still used by
   "The Archive Starts Here"/#dont-miss-002), so this needs its own layout
   (flex row) and its own 2-layer background (fill + border, no bolt). */
#nominate-a-legend {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 3rem;
  background-image:
    linear-gradient(var(--surface-2), var(--surface-2)),
    linear-gradient(135deg, #d3509d, #0688c0);
  background-repeat: no-repeat, no-repeat;
  background-position: 0 0, 0 0;
  background-size: auto, auto;
  background-origin: padding-box, border-box;
  background-clip: padding-box, border-box;
}

#nominate-a-legend .nominate-inner {
  width: 60%;
  flex: none;
}

.nominate-graphic {
  position: relative;
  flex-shrink: 0;
  width: 260px;
}

.nominate-graphic img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 24px;
}

/* Dashed border, gradient-colored — border-image can't do dashed, and
   border-color can't take a gradient, so this is a separate SVG rect
   (same gradient/radius as the graphic itself) laid over the image
   instead of a CSS border. */
.nominate-graphic-border {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

@media (max-width: 760px) {
  #nominate-a-legend {
    flex-direction: column;
    background-size: auto, auto;
  }

  .nominate-graphic { width: 140px; }
}

.nominate-section h2 { color: var(--heading-on-dark); }

.nominate-copy {
  color: var(--text-on-dark);
  font-size: 1.15rem;
  line-height: 1.6;
  margin-bottom: 1rem; /* paragraph-to-paragraph */
}

/* Last paragraph sits right above the section's own CTA (a plain button
   in "Who should become collectible next?", or the email-signup form in
   "The Archive Starts Here"/#dont-miss-002) — paragraph-to-button gets the
   larger gap instead. The email-signup-form's own button sits in a flex
   row with the input rather than stacked below this paragraph, so this
   margin only ever pushes the form itself down, never the button alone. */
.nominate-copy:last-of-type {
  margin-bottom: 2rem;
}

@media (max-width: 760px) {
  .nominate-copy,
  .urgency-copy { font-size: 1rem; }
}

/* #dont-miss-002 only — the embedded email form there is sized down from
   the callout's full width so it doesn't stretch edge to edge like the
   copy above it. */
#dont-miss-002 .email-signup-form { width: 100%; }

@media (max-width: 760px) {
  #dont-miss-002 .email-signup-form { width: 100%; }
}

@media (max-width: 760px) {
  .nominate-section {
    margin-top: 0;
    margin-bottom: 32px;
    border-radius: 16px;
    background-size: 80%, auto, auto;
  }

  /* 55% (see base rule) is a desktop value, sized for the wider card —
     at mobile width that would leave barely any room for the text. */
  .nominate-inner {
    width: 100%;
  }

  /* #nominate-a-legend's own 60% (see base rule) is an ID selector, so it
     otherwise beats the plain-class rule above regardless of this being a
     later, more specific media query — needs its own explicit override. */
  #nominate-a-legend .nominate-inner {
    width: 100%;
  }
}

/* ---------- Drops page ---------- */

/* Top padding kept modest — .page-hero (above, in the HTML) already ends
   with its own bottom padding, so this only needs to add a bit more
   breathing room before the first section, not a full second block of
   spacing. */
/* No padding here — .about-page (its only child) already supplies its own
   top/bottom padding; stacking both doubled the gap above "Internet
   Legends" and below the featured card, worst on mobile where that extra
   space eats a big share of the viewport. */
.drops-page { padding: 0; }

/* About/Cards pages only: space above the Jimothy promo banner (#hero-alt)
   — both pages nest it inside .about-page, right after the section before
   it, which otherwise left it sitting flush against that section. Also
   where it gets the same boxed width as .nominate-section ("The Archive
   Starts Here") instead of the homepage's full-bleed treatment — same
   left:50%/translateX(-50%) centering technique, which centers correctly
   here too even nested inside a narrower centered ancestor (.about-page
   itself is centered via margin:0 auto). */
.about-page .jimothy-hero-alt {
  margin-top: 3rem;
}


@media (max-width: 760px) {
  /* Full-bleed on phones: cancel the container's side padding. */
  .about-page .jimothy-hero-alt { margin-inline: calc(-1 * var(--space-h)); }
}

/* ---------- Order confirmation page (post-checkout redirect) ---------- */

.order-success-page {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 4rem var(--space-h) var(--space-v);
  min-height: 55vh;
}

.order-success-page h1 {
  letter-spacing: -0.02em;
  color: var(--heading-on-light);
  margin-bottom: 1rem;
}

.order-summary {
  background: #f8f8fa;
  border: 1px solid #ececf0;
  border-radius: var(--radius);
  padding: 1.5rem;
  margin: 2rem 0 0.75rem;
}

.order-summary-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid #ececf0;
  font-size: 0.95rem;
  color: var(--text-on-light);
}

.order-summary-row:last-child { border-bottom: none; }

.order-summary-total {
  font-weight: 800;
  color: var(--heading-on-light);
}

.order-meta {
  color: #555555;
  font-size: 0.85rem;
  margin-bottom: 2.5rem;
}

.order-success-next h2 { margin-bottom: 0.75rem; }

.order-success-next p {
  color: var(--text-on-light);
  font-size: 1rem;
  line-height: 1.6;
  margin-bottom: 1rem; /* paragraph-to-paragraph */
  max-width: 56ch;
}

/* Last paragraph sits right above the "Contact Us" button — paragraph-to-
   button gets the larger gap instead. */
.order-success-next p:last-of-type {
  margin-bottom: 2rem;
}

/* ---------- Contact form thank-you page (post-submit redirect) ---------- */

.message-sent-page {
  max-width: 800px;
  margin: 0 auto;
  padding: 4rem var(--space-h) var(--space-v);
  min-height: 55vh;
}

/* Quick stopgap for the gap this page otherwise leaves above the footer —
   see the reverted body/main flex approach above for why the "real" sticky-
   footer fix isn't in yet. Desktop only: on mobile the page is already
   taller relative to the viewport, so this isn't needed there. */
@media (min-width: 761px) {
  .message-sent-page { margin-bottom: 10rem; }
}

.message-sent-page h1 {
  letter-spacing: -0.02em;
  color: var(--heading-on-light);
  margin-bottom: 1rem;
}

.message-sent-page .about-intro {
  margin-bottom: 2rem;
}

/* Nomination-only "Follow our socials" callout (see js/thank-you.js) — same
   text+icons shape as the footer's own .footer-social, but toned for this
   light background instead of the footer's dark one. */
.thank-you-socials {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  margin-top: 2.5rem;
  padding: 1.5rem;
  background: #f8f8fa;
  border: 1px solid #ececf0;
  border-radius: var(--radius);
}

/* Author CSS always beats the UA stylesheet's [hidden]{display:none} —
   setting display:flex above otherwise cancels the hidden attribute out
   entirely, so this restores it with higher specificity. */
.thank-you-socials[hidden] { display: none; }

.thank-you-socials-text {
  margin: 0;
  font-weight: 700;
  color: var(--heading-on-light);
}

.thank-you-socials-icons {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-shrink: 0;
}

.thank-you-socials-icons a {
  display: inline-flex;
  color: var(--text-on-light);
  transition: color 0.2s;
}

.thank-you-socials-icons a:hover { color: var(--heading-on-light); }

.thank-you-socials-icons svg {
  width: 20px;
  height: 20px;
  display: block;
}

@media (max-width: 600px) {
  .thank-you-socials {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* ---------- Blog ---------- */

/* Top padding kept modest for the listing page — .page-hero (above, in the
   HTML) already ends with its own bottom padding. blog-post.html shares
   this class but overrides padding-top itself (see #blog-post-page) for its
   own breadcrumb-driven spacing. */
.blog-page {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 3rem var(--space-h) var(--space-v);
}

/* blog-post.html only (shares .blog-page with the listing page, which has
   no breadcrumb) — its own top padding would double up with .breadcrumb's
   margin-top, so it's zeroed here and left entirely to the breadcrumb.
   display: flow-root is required, not optional: with padding-top at 0 and
   no border, the breadcrumb's margin-top (being the first child) would
   otherwise collapse straight through this element and push its entire
   box — including the .light-section white background painted off of
   that box — down with it, leaving a gap of the page's dark background
   showing above where the white was supposed to start. flow-root gives
   this its own block formatting context so the child's margin stays
   inside it instead of escaping. */
#blog-post-page {
  padding-top: 0;
  display: flow-root;
}

.blog-page h1 {
  letter-spacing: -0.02em;
  color: var(--heading-on-light);
  margin-bottom: 1rem;
}

.blog-intro {
  color: var(--text-on-light);
  font-size: 1.05rem;
  margin-bottom: 2.5rem;
  max-width: 56ch;
}

.blog-list {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.blog-card {
  display: block;
  text-decoration: none;
  border: 1px solid #ececf0;
  border-radius: var(--radius);
  padding: 1.5rem;
  transition: border-color 0.2s, transform 0.2s;
}

.blog-card:hover { border-color: var(--cta-hover); transform: translateY(-2px); }
.blog-card:hover .blog-card-link { color: var(--cta-hover); }

.blog-card-date {
  color: #555555;
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 0.5rem;
}

.blog-card-title {
  color: var(--heading-on-light);
  font-size: 1.2rem;
  letter-spacing: -0.01em;
  margin-bottom: 0.5rem;
}

.blog-card-excerpt { color: var(--text-on-light); font-size: 0.95rem; margin-bottom: 0.75rem; }
.blog-card-link {
  color: var(--cta);
  font-weight: 700;
  font-size: 1rem;
  margin-top: 0.5rem;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.story-callout,
.drops-callout,
.gallery-callout,
.nominate-callout,
#viral-cards-hero-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.blog-post h1 {
  letter-spacing: -0.02em;
  color: var(--heading-on-light);
  margin: 0.5rem 0 1.75rem;
}

.blog-post-body {
  color: var(--text-on-light);
  font-size: 1.05rem;
  line-height: 1.7;
  max-width: 68ch;
  margin-bottom: 1.5rem;
}

/* .btn is inline-block, so its icon-arrow (a plain inline SVG, not part of
   a flex layout) can wrap onto its own line below the label text once the
   label+icon run wider than the shrink-to-fit box — inline-flex keeps the
   two glued to a single line regardless of the button's own width. */
.blog-post .btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.blog-post-body a { color: var(--cta); }
.blog-post-body a:hover { color: var(--cta-hover); }

.blog-post-body p + p { margin-top: 1rem; } /* paragraph-to-paragraph */
.blog-post-body h2,
.blog-post-body h3,
.blog-post-body h4,
.blog-post-body h5,
.blog-post-body h6 { margin-top: 1.5rem; }

/* The sitewide * { padding: 0 } reset otherwise strips ul/ol's own default
   indent along with everything else's — restored explicitly here, since
   this is the first place on the site with real list content (the Terms/
   Privacy pages). */
.blog-post-body ul,
.blog-post-body ol {
  margin-top: 0.75rem;
  margin-bottom: 1rem;
  padding-left: 1.5rem;
}

.blog-post-body li { margin-bottom: 0.5rem; }
.blog-post-body li:last-child { margin-bottom: 0; }

/* Blog heading scale — shifted one level down from the standard scale (H2
   reads at standard H3 size, H3 at H4, H4 at H5), since blog copy is
   denser/narrower and the standard sizes ran too large here. H5/H6 don't
   have a "next level down" to borrow from, so they're their own fixed
   values, same on mobile and desktop. */
.blog-post-body h2 { color: var(--heading-on-light); font-size: 2rem; margin-bottom: 0.75rem; }
.blog-post-body h3 { color: var(--heading-on-light); font-size: 1.5rem; margin-bottom: 0.75rem; }
.blog-post-body h4 { color: var(--heading-on-light); font-size: 1.25rem; margin-bottom: 0.75rem; }
.blog-post-body h5 { color: var(--heading-on-light); font-size: 1.125rem; margin-bottom: 0.75rem; }
.blog-post-body h6 { color: var(--heading-on-light); font-size: 1rem; margin-bottom: 0.75rem; }

@media (max-width: 760px) {
  .blog-post-body h2 { font-size: 1.6rem; }
  .blog-post-body h3 { font-size: 1.25rem; }
  .blog-post-body h4 { font-size: 1.125rem; }
}

/* Slightly more breathing room around h2s/h3s, desktop only — mobile keeps
   the tighter base spacing above. */
@media (min-width: 761px) {
  .blog-post-body h2,
  .blog-post-body h3 { margin-top: 2rem; margin-bottom: 1rem; }
}

/* ---------- Floating "back to top" button (card detail page) ----------
   Minimal replacement for an earlier, heavier floating bar that duplicated
   the name/tier/qty/buy controls (see git history if that's ever worth
   reviving) — just a round up-arrow back to the buy area. Shown/hidden by
   wireScrollTopButton in card.js. */
.scroll-top-btn {
  position: fixed;
  right: 1.5rem;
  bottom: calc(1.5rem + env(safe-area-inset-bottom));
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
  cursor: pointer;
  transform: translateY(calc(100% + 1.5rem));
  opacity: 0;
  pointer-events: none;
  transition: transform 0.3s ease, opacity 0.3s ease, border-color 0.2s;
}

.scroll-top-btn.visible {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}

.scroll-top-btn:hover { border-color: var(--accent); }

@media (max-width: 760px) {
  .scroll-top-btn {
    right: 1rem;
    bottom: calc(1rem + env(safe-area-inset-bottom));
  }
}

/* ---------- Focus states (sitewide) ----------
   Universal :focus-visible ring on every focusable element — links,
   buttons, form fields, the carousel's div[role=button] slides, FAQ
   <summary> elements, everything. Defaults to the dark-background color;
   .light-section covers every light page/section, and .jimothy-hero is
   the one light-background area that isn't wrapped in .light-section. */
:focus-visible {
  outline: 2px solid var(--focus-on-dark);
  outline-offset: 2px;
}

.light-section :focus-visible,
.jimothy-hero :focus-visible {
  outline-color: var(--focus-on-light);
}

/* ---------- Responsive ---------- */

@media (max-width: 760px) {
  .jimothy-hero-inner { min-height: 600px; padding-top: 3rem; }
  .carousel-track { height: 340px; }
  .carousel-slide .trading-card { width: 190px; }
  .breadcrumb { margin: 1.5rem 0; }
  .card-detail { grid-template-columns: 1fr; gap: 2rem; }
  .site-nav a { margin-left: 1rem; font-size: 0.85rem; }
  .tier-cards { grid-template-columns: 1fr; }
  /* Full-width qty row + buy button, stacked, on the main card-detail buy
     row. Scoped to .buy-row/.qty-row specifically — .qty-stepper/.qty-value
     are shared classes with the floating sticky bar's controls, which has
     its own (different) mobile layout below and shouldn't inherit this. */
  .buy-row {
    /* Desktop's align-items: flex-end only matters when qty-row and the
       button sit side by side — stacked here, so it needs stretch instead
       so .btn-buy-now (which only has flex:1, a main-axis/vertical property
       in this column layout) actually fills the row's width instead of
       just centering at its own size. */
    flex-direction: column;
    align-items: stretch;
    gap: 1.25rem;
  }
  /* "Quantity" label left, stepper right, on one row — overrides the
     desktop default of label-above-stepper. */
  .qty-row { flex-direction: row; align-items: center; justify-content: space-between; }
  .qty-label { font-size: 1.1rem; }
  .email-signup-form { flex-direction: column; align-items: stretch; }
  .email-signup-field { min-width: 0; }
}

/* About page only: the dark-background paragraphs (hero intro, nominate
   callout, email signup) match the 1.02rem used everywhere else on the
   page. Colors stay on-dark since they sit on dark backgrounds. */
.about-body .page-hero .about-intro,
.about-body .nominate-copy,
.about-body .urgency-copy {
  font-size: 1.02rem;
}

/* Readable line length: text-heavy sections cap at --readable-width instead
   of running the full --max-width. */
.about-story p,
.about-vision p,
.about-why p,
.packaging-intro,
.faq-answer p,
.blog-card-excerpt {
  max-width: var(--readable-width);
}

/* FAQ rows, dividers and chevrons span the full container; only the
   expanded answer text is capped. */
