/* ============================================================
   PURE PRINT CALENDARS — Global Stylesheet
   ============================================================ */

/* === GOOGLE FONTS === */
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700;800&family=Inter:wght@300;400;500;600;700&display=swap');

/* === CSS VARIABLES === */
:root {
  /* Brand Colors */
  --navy:        #0F1C6B;
  --navy-light:  #1E33A3;
  --navy-dark:   #081142;
  --gold:        #2851FF;
  --gold-light:  #5B7FFF;
  --gold-pale:   #EAF0FF;
  --gold-border: rgba(40,81,255,0.3);
  --cobalt:      #2851FF;
  --cobalt-dark: #0F1C6B;
  --gradient-cobalt: linear-gradient(135deg, var(--cobalt) 0%, var(--cobalt-dark) 100%);
  --accent-sky:  #AEC4FF;
  --accent-warm: #FFC857;

  /* Neutrals */
  --white:       #FFFFFF;
  --off-white:   #F8F9FF;
  --bg-light:    #EEF2FF;
  --border:      #DDE3F5;
  --border-dark: #B8C8E8;

  /* Text */
  --text-dark:   #0D0F2B;
  --text-body:   #1E2550;
  --text-muted:  #6070A0;
  --text-light:  #8697C4;

  /* Shadows */
  --shadow-sm:   0 1px 4px rgba(13,15,43,0.10);
  --shadow-md:   0 4px 16px rgba(13,15,43,0.12);
  --shadow-lg:   0 8px 32px rgba(13,15,43,0.16);
  --shadow-xl:   0 16px 48px rgba(13,15,43,0.22);

  /* Spacing */
  --section-py:  96px;
  --container:   1200px;
  --radius-sm:   6px;
  --radius-md:   12px;
  --radius-lg:   20px;
  --radius-xl:   28px;

  /* Transitions */
  --ease:        cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out:    cubic-bezier(0, 0, 0.2, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* === RESET === */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
  scroll-behavior: smooth;
  font-size: clamp(16px, 1.1111vw, 20px);
  /* The clip has to sit on the root, not on body. A visible root propagates
     body's overflow to the viewport and leaves body itself visible, so the
     same declaration on body clipped nothing — the page really did scroll 8px
     sideways. `clip` rather than `hidden`: hidden would make the viewport a
     scroll container and break every position:sticky on the site. The y axis
     stays visible because the paired value is clip. */
  overflow-x: clip;
}

/* Visible focus ring for keyboard users only (mouse clicks don't trigger
   :focus-visible, so pointer users see no change). WCAG 2.4.7. */
:focus-visible {
  outline: 3px solid var(--accent-warm);
  outline-offset: 2px;
  border-radius: 4px;
}
body {
  font-family: 'Inter', sans-serif;
  color: var(--text-body);
  background: var(--white);
  line-height: 1.6;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img { display: block; max-width: 100%; height: auto; }
a { text-decoration: none; color: inherit; }
ul { list-style: none; }
button { cursor: pointer; border: none; background: none; font-family: inherit; }

/* === TYPOGRAPHY === */
h1, h2, h3, h4 {
  font-family: 'Playfair Display', serif;
  color: var(--text-dark);
  line-height: 1.2;
}
h1 { font-size: clamp(2.2rem, 5vw, 3.8rem); font-weight: 700; }
h2 { font-size: clamp(1.8rem, 3.5vw, 2.8rem); font-weight: 700; }
h3 { font-size: clamp(1.2rem, 2vw, 1.5rem); font-weight: 600; }
h4 { font-size: 1.1rem; font-weight: 600; }
p  { line-height: 1.75; }

.text-gold  { color: var(--gold); }
.text-navy  { color: var(--navy); }
.text-muted { color: var(--text-muted); }
.text-white { color: var(--white); }

/* === LAYOUT === */
.container {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 24px;
}
.section { padding: var(--section-py) 0; }
.section-sm { padding: 64px 0; }
.section-dark { background: var(--navy); }
.section-light { background: var(--off-white); }
.section-pale  { background: var(--bg-light); }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; }
.flex   { display: flex; }
.flex-center { display: flex; align-items: center; justify-content: center; }
.flex-between { display: flex; align-items: center; justify-content: space-between; }

/* === SECTION HEADERS === */
.section-header { text-align: center; margin-bottom: 56px; }
.section-header h2 { margin-bottom: 16px; }
.section-header p  { color: var(--text-muted); max-width: 560px; margin: 0 auto; font-size: 1.05rem; }
.section-tag {
  display: inline-block;
  background: var(--gold-pale);
  color: var(--gold);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 6px 14px;
  border-radius: 100px;
  margin-bottom: 16px;
  border: 1px solid var(--gold-border);
}
.section-tag-light {
  background: rgba(255,255,255,0.12);
  color: var(--gold-light);
  border-color: rgba(40,81,255,0.4);
}

/* === BUTTONS === */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 14px 28px;
  border-radius: var(--radius-sm);
  font-family: 'Inter', sans-serif;
  font-size: 0.95rem;
  font-weight: 600;
  transition: all 0.25s var(--ease);
  white-space: nowrap;
  cursor: pointer;
}
.btn-gold {
  background: var(--white);
  color: var(--cobalt-dark);
  box-shadow: 0 4px 14px rgba(15,28,107,0.25);
}
.btn-gold:hover {
  background: var(--off-white);
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(15,28,107,0.35);
}
.btn-navy {
  background: var(--navy);
  color: var(--white);
  box-shadow: var(--shadow-md);
}
.btn-navy:hover {
  background: var(--navy-light);
  transform: translateY(-2px);
}
.btn-outline {
  background: transparent;
  color: var(--white);
  border: 2px solid rgba(255,255,255,0.5);
}
.btn-outline:hover {
  background: rgba(255,255,255,0.1);
  border-color: var(--white);
  transform: translateY(-2px);
}
.btn-outline-navy {
  background: transparent;
  color: var(--navy);
  border: 2px solid var(--navy);
}
.btn-outline-navy:hover {
  background: var(--navy);
  color: var(--white);
  transform: translateY(-2px);
}
.btn-outline-gold {
  background: transparent;
  color: var(--gold);
  border: 2px solid var(--gold);
}
.btn-outline-gold:hover {
  background: var(--gold);
  color: var(--white);
  transform: translateY(-2px);
}
.btn-lg { padding: 18px 36px; font-size: 1rem; }
.btn-sm { padding: 10px 20px; font-size: 0.85rem; }

.btn-glow {
  animation: btnGlow 3.2s ease-in-out infinite;
}
.btn-glow:hover { animation-play-state: paused; }
@keyframes btnGlow {
  0%, 100% {
    box-shadow: 0 4px 14px rgba(40,81,255,0.35);
    text-shadow: 0 0 0 rgba(255,255,255,0);
  }
  50% {
    box-shadow: 0 4px 22px rgba(40,81,255,0.6), 0 0 24px rgba(91,127,255,0.35);
    text-shadow: 0 0 10px rgba(255,255,255,0.45);
  }
}

/* === NAVIGATION === */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 1000;
  padding: 20px 0;
  background: linear-gradient(to bottom, rgba(8,17,66,0.45) 0%, rgba(8,17,66,0) 100%);
  transition: all 0.3s var(--ease);
}
.nav.scrolled {
  background: var(--navy-dark);
  padding: 14px 0;
  box-shadow: 0 4px 24px rgba(0,0,0,0.25);
}
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
}
.nav-logo {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
.nav-logo-icon {
  width: 38px;
  height: 38px;
  color: var(--accent-sky);
  animation: logoBreathe 5s ease-in-out infinite;
  transform-origin: center;
}
@keyframes logoBreathe {
  0%, 100% {
    filter: drop-shadow(0 0 0 rgba(91,127,255,0));
    transform: scale(1);
  }
  50% {
    filter: drop-shadow(0 0 6px rgba(91,127,255,0.55));
    transform: scale(1.035);
  }
}
.nav-logo-text { display: flex; flex-direction: column; line-height: 1; }
.nav-logo-primary {
  font-family: 'Playfair Display', serif;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--white);
}
.nav-logo-secondary {
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--accent-sky);
}
.nav-links {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1;
  justify-content: center;
}
.nav-links a {
  color: rgba(255,255,255,0.8);
  font-size: 0.9rem;
  font-weight: 500;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  transition: all 0.2s;
}
.nav-links a:hover, .nav-links a.active {
  color: var(--white);
  background: rgba(255,255,255,0.1);
}
.nav-cta { flex-shrink: 0; }

/* === NAV DROPDOWN (Extras) === */
.nav-dropdown { position: relative; }
.nav-dropdown-toggle {
  display: flex;
  align-items: center;
  gap: 5px;
  color: rgba(255,255,255,0.8);
  font-size: 0.9rem;
  font-weight: 500;
  font-family: 'Inter', sans-serif;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  background: none;
  border: none;
  cursor: pointer;
  transition: all 0.2s;
}
.nav-dropdown:hover .nav-dropdown-toggle,
.nav-dropdown-toggle:focus-visible {
  color: var(--white);
  background: rgba(255,255,255,0.1);
}
.nav-dropdown-arrow {
  transition: transform 0.25s var(--ease);
  flex-shrink: 0;
}
.nav-dropdown:hover .nav-dropdown-arrow { transform: rotate(180deg); }
.nav-dropdown-menu {
  position: absolute;
  top: 100%;
  left: 0;
  padding-top: 10px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.25s var(--ease-out), transform 0.25s var(--ease-out), visibility 0.25s;
  z-index: 1001;
}
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown-toggle:focus-visible + .nav-dropdown-menu,
/* :focus-within keeps the menu open once Tab moves INTO it. Without this the
   toggle lost :focus-visible on the first Tab, the menu snapped back to
   visibility:hidden, and on the pages whose footer legal links were dead
   placeholders a keyboard user had no path to those pages at all. */
.nav-dropdown:focus-within .nav-dropdown-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.nav-dropdown-menu-inner {
  min-width: 224px;
  background: var(--navy-dark);
  border: 1px solid rgba(40,81,255,0.25);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xl);
  padding: 8px;
}
.nav-dropdown-menu a {
  display: block;
  padding: 10px 14px;
  font-size: 0.88rem;
  font-weight: 500;
  color: rgba(255,255,255,0.7);
  border-radius: 6px;
  transition: all 0.18s;
}
.nav-dropdown-menu a:hover {
  background: rgba(40,81,255,0.14);
  color: var(--accent-sky);
}
.nav-mobile-label {
  color: var(--accent-sky);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  margin-top: 16px;
}
.nav-mobile a.nav-mobile-sub {
  font-size: 1rem;
  font-family: 'Inter', sans-serif;
  font-weight: 500;
  padding: 8px 32px;
}
.nav-hamburger {
  display: none;
  flex-direction: column;
  gap: 5px;
  padding: 8px;
  cursor: pointer;
}
.nav-hamburger span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--white);
  border-radius: 2px;
  transition: all 0.3s var(--ease);
}
.nav-hamburger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-hamburger.open span:nth-child(2) { opacity: 0; }
.nav-hamburger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Mobile Nav */
.nav-mobile {
  display: none;
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: var(--navy-dark);
  z-index: 999;
  flex-direction: column;
  align-items: center;
  /* flex-start + safe-centering: menu is taller than small screens, so it
     must scroll — justify-content:center would clip the first/last items */
  justify-content: flex-start;
  overflow-y: auto;
  padding: 88px 24px 40px;
  gap: 8px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s;
}
.nav-mobile.open {
  display: flex;
  opacity: 1;
  pointer-events: all;
}
.nav-mobile a {
  color: var(--white);
  font-size: 1.4rem;
  font-family: 'Playfair Display', serif;
  font-weight: 600;
  padding: 12px 32px;
  border-radius: var(--radius-sm);
  transition: color 0.2s;
}
.nav-mobile a:hover { color: var(--accent-sky); }
/* .nav-mobile a's white color outranks .btn-gold's navy — restore it so the
   CTA text isn't white-on-white */
.nav-mobile a.btn-gold,
.nav-mobile a.btn-gold:hover {
  color: var(--cobalt-dark);
  font-family: 'Inter', sans-serif;
  font-size: 0.95rem;
}

/* === HERO === */
.hero {
  background: var(--gradient-cobalt);
  min-height: 100vh;
  display: flex;
  align-items: center;
  position: relative;
  overflow: hidden;
  padding: 120px 0 80px;
}
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 60% 50% at 70% 50%, rgba(255,255,255,0.10) 0%, transparent 70%),
    radial-gradient(ellipse 40% 60% at 20% 80%, rgba(15,28,107,0.5) 0%, transparent 60%);
  pointer-events: none;
}
.hero-video-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.4s ease;
}
.hero-video.is-active {
  opacity: 1;
}
.hero-video-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, rgba(40,81,255,0.72) 0%, rgba(15,28,107,0.85) 100%);
  z-index: 0;
}
.hero-grid-bg {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
  background-size: 60px 60px;
  pointer-events: none;
}
.hero-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  align-items: center;
  position: relative;
  z-index: 1;
}
.hero-content { display: flex; flex-direction: column; gap: 24px; }
.hero-tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgba(255,255,255,0.22);
  border: 1px solid rgba(255,255,255,0.4);
  box-shadow: 0 2px 10px rgba(0,0,0,0.12);
  color: var(--white);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 8px 16px;
  border-radius: 100px;
  width: fit-content;
}
.hero-tag::before {
  content: '';
  width: 6px; height: 6px;
  background: var(--accent-warm);
  border-radius: 50%;
  animation: pulse 2s infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.5; transform: scale(1.3); }
}
.hero h1 {
  color: var(--white);
  font-size: clamp(2.4rem, 5vw, 4rem);
  line-height: 1.15;
}
.hero h1 .gold-underline {
  color: var(--accent-warm);
  text-shadow: 0 2px 16px rgba(255,200,87,0.35);
  position: relative;
}
.hero-subtitle {
  color: rgba(255,255,255,0.72);
  font-size: 1.1rem;
  max-width: 480px;
  line-height: 1.75;
}
.hero-ctas {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}
.hero-mini-stats {
  display: flex;
  gap: 32px;
  padding-top: 16px;
  border-top: 1px solid rgba(255,255,255,0.1);
  flex-wrap: wrap;
}
.hero-mini-stat strong {
  display: block;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--white);
  font-family: 'Playfair Display', serif;
  text-shadow: 0 1px 8px rgba(8,17,66,0.5);
}
.hero-mini-stat span {
  font-size: 0.8rem;
  color: rgba(255,255,255,0.92);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-shadow: 0 1px 6px rgba(8,17,66,0.5);
}
.hero-visual {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.hero-calendar-stack {
  position: relative;
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
}
.hero-cal-card {
  background: var(--white);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-xl);
}
.hero-cal-card.back {
  position: absolute;
  top: -20px;
  right: -20px;
  width: 85%;
  opacity: 0.6;
  transform: rotate(4deg);
  z-index: 0;
}
.hero-cal-card.front {
  position: relative;
  z-index: 1;
}
.hero-cal-img {
  width: 100%;
  /* The covers' own proportion. At 11/9 the box was slightly squarer than the
     artwork and cover-fit shaved the top and bottom off every one. */
  aspect-ratio: 520 / 402;
  object-fit: cover;
  background: linear-gradient(135deg, var(--bg-light) 0%, #dce6f4 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
  color: var(--text-muted);
  flex-direction: column;
  gap: 8px;
  position: relative;
  overflow: hidden;
}
/* The wall photographs. No card, no border, no drop shadow of our own — each
   image already contains a framed calendar, a wall and its own cast shadow,
   and wrapping that in another frame just reads as a sticker on a page. */
.hero-mockup {
  position: relative;
  width: 100%;
  aspect-ratio: 800 / 618;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: linear-gradient(135deg, #1E33A3 0%, #0F1C6B 50%, #1E33A3 100%);
  /* A shadow and a hairline only because this sits over the hero's video, not
     a clean page — without them the darker walls dissolve into the footage.
     No card around it though: each photograph brings its own frame. */
  box-shadow: 0 30px 60px rgba(3, 8, 32, 0.42);
  outline: 1px solid rgba(255, 255, 255, 0.14);
  outline-offset: -1px;
}
.hero-mockup-fallback {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
  color: rgba(255,255,255,0.5);
}
/* Gone the moment a photograph has actually loaded — not merely covered by
   one. Left underneath it would read through any crossfade that dips, which
   is exactly how it was caught showing between two walls. Removed on load
   rather than on inject, so it still stands in if a file never arrives. */
.hero-mockup.has-art .hero-mockup-fallback { display: none; }
.hero-mockup-shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform-origin: 50% 46%;
  /* 27s for three walls: nine seconds each, the room drifting slowly closer
     the whole time it is on screen. Slow enough to notice only if you look.
     Shifted back 810ms — one fade — so the first wall is already at full
     opacity on arrival rather than fading up from an empty panel. */
  animation: heroShotFade 27s linear infinite, heroShotPush 27s ease-out infinite;
  animation-delay: calc(var(--i, 0) * 9s - 810ms);
}
/* Three images, each starting 33.33% after the last. The outgoing one must
   still be at full opacity when the next begins to rise, or their sum dips
   below one and the panel reads through. Held to 30% it was bare for 0.36s;
   held to 33% it still dipped to 0.93 at the handover, because it began
   falling before its successor had started. Holding to 34% and fading to 39%
   puts the whole crossfade inside the successor's rise: swept across the full
   cycle in 10ms steps, the combined opacity never goes below 1. */
@keyframes heroShotFade {
  0%   { opacity: 0; }
  3%   { opacity: 1; }
  34%  { opacity: 1; }
  39%  { opacity: 0; }
  100% { opacity: 0; }
}
@keyframes heroShotPush {
  0%   { transform: scale(1); }
  39%  { transform: scale(1.06); }
  100% { transform: scale(1.06); }
}
.hero-cal-bar {
  padding: 16px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-top: 1px solid var(--border);
}
.hero-cal-logo-area {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.hero-cal-logo-line {
  height: 8px;
  border-radius: 4px;
  background: var(--navy);
  opacity: 0.15;
}
.hero-cal-logo-line.wide { width: 80px; }
.hero-cal-logo-line.narrow { width: 50px; }
.hero-cal-badge {
  background: var(--gold-pale);
  color: var(--gold);
  font-size: 0.7rem;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 100px;
  letter-spacing: 0.05em;
}
.hero-float-badge {
  position: absolute;
  background: var(--white);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-dark);
  z-index: 2;
  animation: float 3s ease-in-out infinite;
}
/* Both badges straddle a corner rather than sitting inside the artwork: at
   24px in from the edge each one covered a full 56px band across nearly half
   the photograph. Hung off the edge instead, only their inner half overlaps.
   The horizontal offset stays at -24px because badge-2's right edge already
   meets the viewport at around 1024px wide — any further out and its text
   would be clipped by the root's overflow-x. */
.hero-float-badge.badge-1 { bottom: -20px; left: -24px; animation-delay: 0s; }
.hero-float-badge.badge-2 { top: -20px; right: -24px; animation-delay: 1.5s; }
/* Below roughly 1150px the container stops being capped and runs to the
   viewport, so a -24px overhang puts badge-2's right edge past the edge of
   the screen and the root clips its last few pixels. Pull both in until
   there is room again. */
@media (max-width: 1150px) {
  .hero-float-badge.badge-1 { left: -8px; }
  .hero-float-badge.badge-2 { right: -8px; }
}
.hero-float-badge .badge-icon {
  width: 32px; height: 32px;
  background: var(--gold-pale);
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gold);
}
@keyframes float {
  0%, 100% { transform: translateY(0px); }
  50% { transform: translateY(-8px); }
}

/* === STATS BAR === */
.stats-bar {
  background: var(--navy-dark);
  padding: 48px 0;
  border-top: 1px solid rgba(255,255,255,0.06);
}
.stats-bar-inner {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  text-align: center;
}
.stat-item {
  padding: 20px;
  border-right: 1px solid rgba(255,255,255,0.08);
}
.stat-item:last-child { border-right: none; }
.stat-number {
  font-family: 'Playfair Display', serif;
  font-size: 2.8rem;
  font-weight: 700;
  color: var(--accent-sky);
  line-height: 1;
  margin-bottom: 6px;
}
.stat-label {
  font-size: 0.8rem;
  font-weight: 600;
  color: rgba(255,255,255,0.5);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

/* === VALUE PROPS (WHY CALENDARS) === */
.value-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 36px 32px;
  transition: all 0.3s var(--ease);
  position: relative;
  overflow: hidden;
}
.value-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s var(--ease);
}
.value-card:hover {
  box-shadow: var(--shadow-lg);
  transform: translateY(-4px);
  border-color: var(--gold-border);
}
.value-card:hover::before { transform: scaleX(1); }
.value-icon {
  width: 52px; height: 52px;
  background: var(--gold-pale);
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gold);
  margin-bottom: 20px;
}
.value-card h3 {
  font-family: 'Inter', sans-serif;
  font-size: 1.2rem;
  font-weight: 700;
  margin-bottom: 10px;
}
.value-card p  { color: var(--text-muted); font-size: 0.95rem; }

/* === HOW IT WORKS === */
.steps-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  position: relative;
}
.steps-grid::before {
  content: '';
  position: absolute;
  top: 40px;
  left: 10%;
  right: 10%;
  height: 2px;
  background: linear-gradient(90deg, var(--gold), var(--gold-light), var(--gold));
  opacity: 0.3;
  z-index: 0;
}
.step-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 0 20px;
  position: relative;
  z-index: 1;
}
.step-number {
  width: 80px; height: 80px;
  background: var(--navy);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Playfair Display', serif;
  font-size: 1.6rem;
  font-weight: 700;
  color: var(--accent-sky);
  border: 3px solid var(--gold-border);
  margin-bottom: 24px;
  flex-shrink: 0;
  transition: all 0.3s var(--ease);
}
.step-item:hover .step-number {
  background: var(--gold);
  color: var(--white);
  border-color: var(--gold);
  transform: scale(1.1);
}
.step-icon {
  color: var(--gold);
  margin-bottom: 8px;
}
.step-item h3 { font-size: 1.1rem; margin-bottom: 10px; }
.step-item p  { font-size: 0.9rem; color: var(--text-muted); }

/* === GALLERY SECTIONS (rendered from theme data) === */
.gallery-section { margin-bottom: 48px; }
.gallery-section-title {
  margin-bottom: 24px;
  color: var(--text-muted);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-family: 'Inter', sans-serif;
  font-weight: 700;
}

/* === GALLERY CARDS === */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}
.cal-card {
  background: var(--white);
  /* Near-square: these cards ARE the printed product, and a large radius
     clips the artwork's corners. 6px keeps a hint of the site's soft
     language while losing almost nothing of the cover. */
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--border);
  transition: all 0.35s var(--ease);
  cursor: pointer;
}
.cal-card:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-xl);
  border-color: var(--gold-border);
}
.cal-card-img {
  position: relative;
  width: 100%;
  /* Matches the 1584x1224 cover artboard, so a real cover fills the card
     without object-fit cropping its edges. */
  aspect-ratio: 1584 / 1224;
  object-fit: cover;
  background: linear-gradient(135deg, var(--bg-light) 0%, #dce6f4 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
  color: var(--text-muted);
  flex-direction: column;
  gap: 8px;
}
.cal-card-img svg { opacity: 0.35; }

/* Real theme photo (see js/main.js themeImagePath). Hidden until it
   successfully loads, so a missing file silently keeps the existing
   icon+gradient placeholder — themes can get real photos one at a
   time with no broken-image flash. */
.cal-card-img .theme-photo {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--white); /* paper behind transparent exports */
}
.cal-card-img.has-photo .theme-photo { display: block; }
.cal-card-img.has-photo svg,
.cal-card-img.has-photo > span:last-child { display: none; }
.cal-card-body {
  padding: 18px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.cal-card-title {
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--text-dark);
}
.cal-card-size {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin-top: 2px;
}
.cal-card-arrow {
  width: 32px; height: 32px;
  background: var(--gold-pale);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gold);
  transition: all 0.25s var(--ease);
  flex-shrink: 0;
}
.cal-card:hover .cal-card-arrow {
  background: var(--gold);
  color: var(--white);
  transform: translateX(3px);
}

/* === FLIP GALLERY (calendar page-flip theme viewer) === */
.flip-gallery-wrap {
  max-width: 420px;
  margin: 0 auto;
}
.flip-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
}
.flip-nav {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--white);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--navy);
  cursor: pointer;
  flex-shrink: 0;
  transition: all 0.2s var(--ease);
  /* Lifted above the flip viewport: a turning page swings toward the viewer
     and its edge reaches past the stack, which would otherwise be painted
     straight across these buttons. */
  position: relative;
  z-index: 6;
}
.flip-nav:hover {
  background: var(--gold);
  color: var(--white);
  border-color: var(--gold);
  transform: scale(1.08);
}
.flip-nav:active { transform: scale(0.95); }
.flip-viewport {
  perspective: 1800px;
  width: 100%;
  max-width: 320px;
  /* A turning half is edge-on to the viewer at the midpoint of the flip, and
     perspective magnifies whatever is nearest — measured 39px of it reaching
     past the page's own width. Clipped to the page horizontally so nothing
     can extend beyond the calendar, with deep vertical bleed so the drop
     shadow under the stack is untouched. */
  clip-path: inset(-120px 0px -120px 0px);
}

/* --- Split page-turn: top half and bottom half flip independently around
   the center hinge line, like a real page being turned. Four stacked
   layers per page: top/bottom hold the CURRENT page (static), overlay-top/
   overlay-bottom animate to reveal the NEXT page. Each layer is a 50%-tall
   clipping window onto a double-height inner element, so any HTML content
   (not just a flat image) can be windowed into top/bottom halves. --- */
/* Sized from the 1584x1224 artboards the artwork is exported from. Open on
   a month, the calendar is two pages tall — the photo hangs above the grid.
   Closed on a cover it is a single page, so the stack shrinks to match and
   the artwork is never cropped. The transition reads as the calendar
   opening and closing. */
.flip-page-stack {
  position: relative;
  /* Cap width so the page's height always fits on screen (~220px reserved
     for the nav and the title/counter under the viewer). Without this,
     opening from the cover to a two-page month spread nearly quadruples
     the height and runs off the bottom of the viewport. */
  width: min(100%, max(280px, calc((100vh - 220px) * (1584 / 2448))));
  margin: 0 auto;
  aspect-ratio: 1584 / 2448;
  transform-style: preserve-3d;
  /* Query container for the page layers below, so each half can size its
     copy of the page against the whole stack rather than against itself. */
  container-type: size;
  /* Deliberately not transitioned. Animating aspect-ratio left the
     transition running indefinitely, freezing month pages at the cover's
     ratio — a squashed half-height calendar. The page-turn animation
     already carries the motion. */
}
/* Opacity only — the height change this carries must stay untransitioned
   (see above), and it happens while the stack is invisible. */
.flip-page-stack { transition: opacity 0.22s var(--ease); }
.flip-page-stack.is-dissolving { opacity: 0; }
.flip-page-stack.is-single-page {
  aspect-ratio: 1584 / 1224;
  width: min(100%, max(280px, calc((100vh - 220px) * (1584 / 1224))));
}
.flip-page-stack::after {
  content: '';
  position: absolute;
  left: 0; right: 0;
  top: 50%;
  height: 2px;
  margin-top: -1px;
  background: rgba(13,15,43,0.3);
  z-index: 5;
  pointer-events: none;
}
.flip-page-stack.hide-seam::after { display: none; }
.flip-half {
  position: absolute;
  left: 0;
  width: 100%;
  height: 50%;
  overflow: hidden;
  box-shadow: var(--shadow-xl);
  cursor: pointer;
}
/* Square corners, like the printed page — rounding here would clip the
   corners off the real artwork. */
.flip-half.top, .flip-half.overlay-top {
  top: 0;
  /* A hair taller than half, so subpixel rounding of the two 50% halves
     can never open a visible gap along the middle of a static page. */
  height: calc(50% + 0.6px);
  transform-origin: 50% 100%;
}
.flip-half.bottom, .flip-half.overlay-bottom {
  bottom: 0;
  transform-origin: 50% 0%;
}
.flip-half.overlay-top, .flip-half.overlay-bottom { z-index: 3; }
.flip-half.top, .flip-half.bottom { z-index: 1; }
/* At rest the page is drawn by the top layer alone, at full height. The
   halves are each rasterised as their own GPU layer, so where they meet
   they anti-alias a shared edge independently — on a stack whose height
   lands on a fractional pixel that shows as a hairline straight across the
   artwork. Splitting only while a page is genuinely turning removes it. */
.flip-page-stack.is-idle .flip-half.top { height: 100%; }
.flip-page-stack.is-idle .flip-half.bottom,
.flip-page-stack.is-idle .flip-half.overlay-top,
.flip-page-stack.is-idle .flip-half.overlay-bottom { visibility: hidden; }
.flip-half-inner {
  position: absolute;
  left: 0;
  width: 100%;
  /* Measured against the stack, never against the half that holds it. The
     top half overdraws the join by a fraction of a pixel to close the
     hairline gap; a percentage-of-half height would pass that fraction on,
     scaling its copy of the page differently from the bottom half's and
     leaving a visible seam straight down the middle of every page. */
  height: 100cqh;
  display: flex;
  flex-direction: column;
  backface-visibility: hidden;
}
.flip-half.top .flip-half-inner, .flip-half.overlay-top .flip-half-inner { top: 0; }
.flip-half.bottom .flip-half-inner, .flip-half.overlay-bottom .flip-half-inner { top: -50cqh; }

/* --- "Open" month pages: photo half above grid half, each one page tall --- */
.flip-page-photo {
  position: relative;
  flex: 0 0 50%;
  background: linear-gradient(135deg, var(--bg-light) 0%, #dce6f4 100%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.flip-page-photo .theme-photo,
.flip-page-calendar .theme-photo,
.flip-page-simple .theme-photo {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 2;
  /* White "paper" behind the artwork: the Illustrator exports carry an
     alpha channel, so without this the container's tinted placeholder
     background shows through transparent areas of a page. */
  background: var(--white);
}
.flip-page-photo.has-photo .theme-photo,
.flip-page-calendar.has-photo .theme-photo,
.flip-page-simple.has-photo .theme-photo { display: block; }
/* Hide the stand-in outright rather than trusting the artwork to cover it:
   the exports carry an alpha channel, so anything left underneath shows
   through the page's white areas. */
.flip-page-photo.has-photo svg { display: none; }

/* --- Bonus spread: next year at a glance, and the ruled notes page. Both
   are drawn rather than exported, so they are sized in the same container
   units as the month grid. --- */
.flip-page-sheet {
  position: relative;
  flex: 0 0 50%;
  overflow: hidden;
  background: var(--white);
  display: flex;
  flex-direction: column;
  container-type: inline-size;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.yr-sheet {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 4cqw 6.7cqw 5cqw;
}
.yr-title {
  font-size: 3.4cqw;
  font-weight: 700;
  text-align: center;
  color: #111;
  margin-bottom: 3cqw;
}
.yr-months {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 2.2cqw;
}
.yr-month {
  border: 1px solid #b9b9b9;
  padding: 0.5cqw 0.6cqw 0.8cqw;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  /* Clip rather than bleed: if the sheet is ever laid out shorter than its
     natural height, a month must not spill over the one below it. */
  overflow: hidden;
}
.yr-month-title {
  font-size: 1.75cqw;
  text-align: center;
  color: #111;
  margin-bottom: 0.3cqw;
}
.yr-month-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  flex: 1;
  align-content: start;
}
.yr-dow,
.yr-day {
  font-size: 1.12cqw;
  line-height: 1.55;
  text-align: center;
  color: #111;
}
.yr-dow { font-weight: 700; }
.yr-day.is-red { color: #e8232a; }
.yr-day.is-sat { color: #b0b0b0; }

/* The notes page is seventeen ruled lines and nothing else. */
.notes-sheet {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: 9.2cqw 6.7cqw 0;
  gap: 3.67cqw;
}
.notes-sheet span {
  display: block;
  flex: 0 0 auto;
  border-bottom: 1px solid #1a1a1a;
}
.flip-page-calendar.has-photo .cal-sheet,
.flip-page-calendar.has-photo .flip-page-ad { display: none; }
.flip-page-simple.has-photo svg,
.flip-page-simple.has-photo .mini-cal-grid,
.flip-page-simple.has-photo .flip-tag,
.flip-page-simple.has-photo > span:last-child { display: none; }
/* Mirrors the printed grid page: flanking mini months, a large month
   title, ruled day cells, and the advertising band along the bottom. */
.flip-page-calendar {
  position: relative;
  overflow: hidden;
  flex: 1;
  background: var(--white);
  display: flex;
  flex-direction: column;
  /* Anchors the cqw units the grid below is sized in. */
  container-type: inline-size;
}
/* Every size below is a share of the page's own width (cqw), so the grid
   scales exactly like the exported artwork it replaces — thumbnail, flip
   viewer and full-screen overlay all stay in proportion. */
.cal-sheet {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 3.4cqw 6cqw 4.7cqw;
  min-height: 0;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.cal-sheet-head {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 2cqw;
  margin-bottom: 2.4cqw;
}
.flip-page-month-header {
  font-size: 5.9cqw;
  font-weight: 500;
  letter-spacing: -0.015em;
  color: #111;
  white-space: nowrap;
}
.flip-page-month-header span { font-weight: 300; }

/* The small previous/next month blocks in the top corners. These are set
   entirely in black on the printed page — only the main grid reds Sundays. */
.cal-mini { width: 11.4cqw; min-width: 0; }
.cal-mini-title {
  font-size: 1.04cqw;
  color: #111;
  text-align: center;
  margin-bottom: 0.3cqw;
  white-space: nowrap;
}
.cal-mini-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0;
}
.cal-mini-grid span {
  font-size: 0.62cqw;
  line-height: 1.68;
  text-align: center;
  color: #111;
}
.cal-mini-grid span.dim { color: #a3a3a3; }
.cal-mini.next { justify-self: end; }
.cal-mini.prev { justify-self: start; }

/* --- The month grid --- */
.cal-grid {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
.cal-grid-head {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  flex: 0 0 auto;
  padding-bottom: 0.9cqw;
}
.cal-grid-head span {
  font-size: 1.16cqw;
  text-align: center;
  color: #3a3a3a;
}
.cal-grid-row {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  flex: 1;
  min-height: 0;
  border-bottom: 1px solid #c9c9c9;
}
.cal-cell {
  display: flex;
  flex-direction: column;
  min-width: 0;
  border-right: 1px solid #c9c9c9;
}
.cal-cell:last-child { border-right: none; }
.cal-cell-main,
.cal-cell-tuck {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 0.7cqw 0.5cqw 0.4cqw 0.9cqw;
}
.cal-cell-main { flex: 1; }
/* The sixth week, tucked under row five behind a short rule. */
.cal-cell-tuck {
  flex: 0 0 44%;
  border-top: 1px solid #c9c9c9;
}
.cal-day-num {
  align-self: flex-start;
  font-size: 1.4cqw;
  line-height: 1;
  color: #111;
}
.cal-cell.is-red > .cal-cell-main > .cal-day-num,
.cal-cell-tuck.is-red > .cal-day-num { color: #ed1c24; }
.cal-day-event {
  margin-top: auto;
  align-self: stretch;
  text-align: center;
  font-size: 0.95cqw;
  line-height: 1.25;
  color: #2b2b2b;
}

/* Advertising band — the customer's logo and details, sized to match the
   printed page where it runs the full width along the bottom. */
.flip-page-ad {
  flex: 0 0 18.7%;
  background: #dbabab;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 2cqw;
  padding: 0 5cqw;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
/* Left: the customer's logo. */
.flip-page-ad-logo {
  justify-self: start;
  display: flex;
  align-items: center;
  gap: 1.2cqw;
}
.flip-page-ad-mark {
  width: 7.2cqw;
  height: 7.2cqw;
  border-radius: 1.2cqw;
  background: #7d2b2b;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.flip-page-ad-mark svg { width: 72%; height: 72%; }
.flip-page-ad-wordmark { display: flex; flex-direction: column; line-height: 1.05; }
.flip-page-ad-name {
  font-size: 3.1cqw;
  font-weight: 800;
  color: #4a1c1c;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.flip-page-ad-sub {
  font-size: 1.6cqw;
  font-weight: 700;
  letter-spacing: 0.33em;
  color: #7d2b2b;
  white-space: nowrap;
}
/* Centre: their business details. */
.flip-page-ad-text {
  justify-self: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  color: #3f1a1a;
}
.flip-page-ad-text span {
  font-size: 1.85cqw;
  line-height: 1.5;
  white-space: nowrap;
}
/* Right: a QR code to their site. */
.flip-page-ad-qr {
  justify-self: end;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4cqw;
}
.flip-page-ad-qr-box {
  width: 8.8cqw;
  height: 8.8cqw;
  background: #fff;
  border-radius: 0.5cqw;
  overflow: hidden;
  display: block;
}
.flip-page-ad-qr-box img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.flip-page-ad-qr-cap {
  font-size: 1.05cqw;
  color: #7d2b2b;
  white-space: nowrap;
}

/* --- Simple pages: Cover / Back Cover (single centered look) --- */
.flip-page-simple {
  position: relative;
  flex: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: linear-gradient(135deg, var(--bg-light) 0%, #dce6f4 100%);
  color: var(--text-muted);
  font-size: 0.85rem;
}
.flip-page-simple .flip-tag {
  position: absolute;
  top: 12px; left: 12px;
  background: var(--navy);
  color: var(--white);
  font-size: 0.7rem;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 100px;
  letter-spacing: 0.05em;
}
.flip-page-simple svg { opacity: 0.4; }
.mini-cal-grid { color: var(--border-dark); opacity: 0.7; }
/* Which page you are looking at, sat right under the calendar. It used to
   float 24px below with the counter at 12.8px in a muted blue — legible on a
   contrast checker at 4.86:1, but small, low and easy to lose at the bottom
   of a tall viewer. Pulled closer so it groups with the page it names, and
   given a rule above it so it reads as that page's caption rather than as
   loose text between two sections. */
.flip-title-label {
  text-align: center;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  max-width: 260px;
  margin-left: auto;
  margin-right: auto;
  font-family: 'Playfair Display', serif;
  font-weight: 700;
  font-size: 1.45rem;
  line-height: 1.1;
  color: var(--navy);
}
.flip-counter-label {
  text-align: center;
  margin-top: 5px;
  font-size: 0.86rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-body);
}
@media (max-width: 480px) {
  .flip-nav { width: 38px; height: 38px; }
  .flip-stage { gap: 10px; }
}

/* === VIEW ALL PAGES BUTTON + OVERLAY === */
.view-all-pages-btn {
  /* Centred over the calendar column on every theme page. */
  display: flex;
  width: fit-content;
  align-items: center;
  gap: 8px;
  background: var(--white);
  border: 1px solid var(--border);
  color: var(--navy);
  font-size: 0.85rem;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: 100px;
  cursor: pointer;
  margin: 0 auto 20px;
  box-shadow: var(--shadow-sm);
  transition: all 0.2s var(--ease);
}
.view-all-pages-btn:hover {
  border-color: var(--gold-border);
  color: var(--gold);
  box-shadow: var(--shadow-md);
}
.page-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(8,17,66,0.55);
  z-index: 2000;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.page-overlay.open { display: flex; }
.page-overlay-panel {
  background: var(--white);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-xl);
  max-width: 720px;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
  padding: 28px;
}
.page-overlay-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
}
.page-overlay-header h3 { font-size: 1.15rem; margin: 0; }
.page-overlay-close {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--off-white);
  border: none;
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: all 0.2s;
}
.page-overlay-close:hover { background: var(--gold-pale); color: var(--gold); }
.page-thumb-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
  gap: 12px;
}
.page-thumb {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 14px 8px 10px;
  background: var(--off-white);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: all 0.2s var(--ease);
}
.page-thumb:hover { border-color: var(--gold-border); }
.page-thumb.active { border-color: var(--gold); background: var(--gold-pale); }
.page-thumb-num {
  position: absolute;
  top: 6px; left: 8px;
  font-size: 0.65rem;
  font-weight: 700;
  color: var(--text-light);
}
.page-thumb-label {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-dark);
  text-align: center;
}
/* Real page artwork in the "View All Pages" grid — replaces the icon
   once it loads, keeping the number badge and label readable above it. */
.page-thumb-img {
  display: none;
  width: 100%;
  aspect-ratio: 11/9;
  object-fit: cover;
  border-radius: 4px;
  background: var(--white); /* paper behind transparent exports */
}
/* The drawn planner-page thumbnail: same sheet as the full page, shrunk by
   its own container units. */
.page-thumb-sheet {
  display: flex;
  flex-direction: column;
  width: 100%;
  aspect-ratio: 11/9;
  border-radius: 4px;
  overflow: hidden;
  background: var(--white);
  container-type: inline-size;
  pointer-events: none;
}
.page-thumb:has(.page-thumb-sheet) > svg { display: none; }
.page-thumb.has-photo .page-thumb-img { display: block; }
.page-thumb.has-photo > svg { display: none; }
.page-thumb.has-photo .page-thumb-num {
  color: var(--white);
  text-shadow: 0 1px 3px rgba(8,17,66,0.7);
}

/* === THEME PRODUCT LAYOUT (theme.html) === */
.theme-product-layout {
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 56px;
  align-items: start;
}
.theme-product-visual .flip-gallery-wrap { max-width: 100%; }
.theme-product-visual .flip-viewport { max-width: 100%; }
@media (max-width: 900px) {
  .theme-product-layout { grid-template-columns: 1fr; gap: 40px; }
}

/* === THEME DETAIL PANEL (theme.html) === */
.theme-detail-panel {
  max-width: 480px;
}
/* Without a page hero above it, this section sits directly under the fixed
   nav and needs to clear it on its own. */
.theme-product-section { padding-top: 108px; padding-bottom: 48px; }

.theme-detail-tag {
  display: block;
  width: fit-content;
  background: var(--gold-pale);
  color: var(--cobalt);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 4px 12px;
  border-radius: 100px;
  border: 1px solid var(--gold-border);
  margin: 0 auto 10px;
}
.theme-detail-tag:empty { display: none; }
/* Tag, title and page-count badge are centred as one header block; the body
   copy beneath them stays left-aligned. */
.theme-detail-title {
  font-size: clamp(1.5rem, 2.3vw, 1.9rem);
  margin-bottom: 10px;
  text-align: center;
}
.theme-detail-desc {
  color: var(--text-muted);
  font-size: 0.95rem;
  line-height: 1.65;
  margin: 10px 0 14px;
}
/* Explains the advertising band shown in the page previews. */
.theme-branding-note {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--text-muted);
  background: var(--gold-pale);
  border: 1px solid var(--gold-border);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  margin-bottom: 16px;
}
.theme-branding-note svg { color: var(--cobalt); flex-shrink: 0; margin-top: 2px; }
.theme-branding-note strong { color: var(--cobalt-dark); }
.theme-page-count {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: 8px;
  background: var(--gold-pale);
  color: var(--gold);
  font-size: 0.8rem;
  font-weight: 700;
  padding: 5px 14px;
  border-radius: 100px;
  margin: 0 auto 14px;
}
.size-pill-group {
  display: flex;
  gap: 12px;
  justify-content: flex-start;
  margin-bottom: 24px;
}
.size-pill {
  position: relative;
  flex: 1;
  max-width: 220px;
  padding: 11px 16px;
  border: 2px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--white);
  cursor: pointer;
  transition: all 0.2s var(--ease);
  text-align: left;
}
.size-pill:hover { border-color: var(--gold-border); }
.size-pill.active {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px var(--gold-pale);
}
.size-pill-name { font-weight: 700; font-size: 0.9rem; color: var(--text-dark); margin-bottom: 2px; }
.size-pill-dim { font-size: 0.8rem; color: var(--text-muted); }
/* Not yet orderable — visible so customers know it's planned, but not
   selectable until real artwork exists at this size. */
.size-pill.disabled {
  cursor: not-allowed;
  background: var(--off-white);
  opacity: 0.65;
}
.size-pill.disabled:hover { border-color: var(--border); }
.size-pill.disabled .size-pill-name,
.size-pill.disabled .size-pill-dim { color: var(--text-light); }
.size-pill-badge {
  position: absolute;
  top: -9px;
  right: 10px;
  background: var(--text-muted);
  color: var(--white);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 100px;
}
/* Button on the left, quantity on the right, in one row — keeps the CTA
   above the fold instead of pushed down by a separate quantity row. */
.theme-qty-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
}
.theme-add-btn { flex: 1; justify-content: center; }
.theme-qty-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex-shrink: 0;
}
.theme-qty-field label { font-weight: 600; font-size: 0.78rem; color: var(--text-dark); }
.theme-qty-field input.form-input {
  width: 100px;
  text-align: center;
}

/* === QUOTE BADGE + TOAST === */
.quote-badge {
  display: none;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 100px;
  background: var(--navy);
  color: var(--white);
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 1;
  margin-left: 4px;
}
.quote-toast {
  position: fixed;
  top: 20px;
  left: 50%;
  transform: translateX(-50%) translateY(-16px);
  z-index: 9999;
  background: var(--navy);
  color: var(--white);
  padding: 14px 22px;
  border-radius: 100px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.9rem;
  font-weight: 600;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transition: opacity 0.3s ease, transform 0.3s ease;
  pointer-events: none;
  white-space: nowrap;
}
.quote-toast svg { color: var(--accent-sky); flex-shrink: 0; }
.quote-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* === QUOTE LIST (order.html) === */
.quote-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: var(--off-white);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-md);
  padding: 18px 20px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
.quote-item-title { font-weight: 700; font-size: 0.95rem; color: var(--text-dark); }
.quote-item-meta { font-size: 0.82rem; color: var(--text-muted); margin-top: 2px; }
.quote-item-controls { display: flex; align-items: center; gap: 10px; }
.quote-qty-input { width: 90px; padding: 8px 10px; }
.quote-empty {
  text-align: center;
  padding: 32px 20px;
  background: var(--off-white);
  border: 1.5px dashed var(--border-dark);
  border-radius: var(--radius-md);
  margin-bottom: 20px;
}
.quote-empty p { color: var(--text-muted); margin-bottom: 16px; }
@media (max-width: 480px) {
  .theme-qty-row { flex-direction: column; align-items: stretch; }
  .theme-add-btn { width: 100%; }
  .theme-qty-field { align-items: center; }
  .theme-qty-field input.form-input { width: 100%; }
  .size-pill-group { flex-direction: column; align-items: center; }
  .size-pill { max-width: 100%; width: 100%; }
}

/* === SIZE COMPARISON === */
/* Two-card comparison — still used by the homepage. The gallery uses the
   compact strip below instead. */
.size-compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  align-items: start;
}
.size-card {
  background: var(--white);
  border: 2px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 36px;
  text-align: center;
  transition: all 0.3s var(--ease);
  position: relative;
}
.size-card.featured {
  border-color: var(--gold);
  box-shadow: 0 0 0 4px var(--gold-pale);
}
.size-badge {
  position: absolute;
  top: -14px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--gold);
  color: var(--white);
  font-size: 0.7rem;
  font-weight: 700;
  padding: 4px 14px;
  border-radius: 100px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}
.size-visual {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 20px;
  margin: 24px 0;
}

/* One horizontal strip: the scale drawing on the left, what it means on the
   right. Left-aligned on purpose — the centred cards this replaced were the
   page's strongest template tell. */
.size-section { padding-top: 52px; padding-bottom: 44px; }
/* The grid is the page. Full section rhythm above it just pushes it down. */
.gallery-main { padding-top: 52px; }
.size-strip {
  display: flex;
  align-items: center;
  gap: 44px;
  background: var(--white);
  border: 1px solid var(--border);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius-lg);
  padding: 26px 32px;
}
.size-strip-visual {
  display: flex;
  align-items: flex-end;
  gap: 26px;
  flex-shrink: 0;
}
.size-fig { margin: 0; }
/* Lift the format being pointed at. The rectangle moves, never the box that
   sets the baseline, so the scale comparison holds while it animates. */
.size-fig .size-calendar-rect {
  transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.size-fig:hover .size-calendar-rect {
  transform: translateY(-5px);
  box-shadow: 0 14px 26px rgba(8,17,66,0.28);
}
.size-fig:hover figcaption { color: var(--navy); }
/* Fixed box so both formats and the mug sit on one baseline — otherwise the
   drawing stops being an honest comparison. */
.size-fig-rect {
  height: 102px;
  display: flex;
  align-items: flex-end;
}
.size-fig figcaption {
  margin-top: 10px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--text-body);
  white-space: nowrap;
}
.size-fig.is-muted .size-calendar-rect { opacity: 0.4; }
.size-fig.is-muted figcaption { color: var(--text-muted); font-weight: 500; }
.size-fig-ref svg { color: var(--text-muted); opacity: 0.55; }
.size-fig-ref figcaption { color: var(--text-muted); font-weight: 500; }
.size-strip-copy { min-width: 0; }
.size-strip .size-label { margin-bottom: 10px; }
.size-strip .size-desc { max-width: 46ch; margin-bottom: 10px; }
.size-note {
  font-size: 0.82rem;
  color: var(--text-muted);
  margin: 0;
}
.size-calendar-rect {
  background: linear-gradient(135deg, var(--navy) 0%, var(--navy-light) 100%);
  /* Square, like the trimmed page. A printed calendar has cut corners, not
     rounded ones, and rounding a drawing that exists to show real dimensions
     misstates the product. */
  border-radius: 0;
  position: relative;
  flex-shrink: 0;
  box-shadow: var(--shadow-md);
}
.size-calendar-rect::after {
  content: '';
  position: absolute;
  inset: 6px;
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 0;
}
.size-ref-object {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 500;
}
.size-ref-object svg { color: var(--text-muted); opacity: 0.6; }
.size-dimensions {
  font-family: 'Playfair Display', serif;
  font-size: 1.8rem;
  font-weight: 700;
  color: var(--navy);
  margin-bottom: 6px;
}
.size-label {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--gold);
  margin-bottom: 12px;
}
.size-desc { font-size: 0.9rem; color: var(--text-muted); }

/* === ABOUT PANEL (about.html) === */
/* Three covers where the generic icon sat, middle one forward. */
.about-covers {
  position: relative;
  width: 100%;
  height: 128px;
}
.about-cover {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 132px;
  border-radius: 5px;
  overflow: hidden;
  box-shadow: 0 10px 24px rgba(0,0,0,0.35);
}
.about-cover img { display: block; width: 100%; height: auto; }
.about-cover-0 { transform: translate(-92%, -46%) rotate(-7deg); }
.about-cover-1 { transform: translate(-50%, -54%); z-index: 1; }
.about-cover-2 { transform: translate(-8%, -46%) rotate(7deg); }

/* === PROCESS STEP VISUALS (how-it-works.html) === */
/* The frames keep .process-visual's box; only the contents changed. */
.process-visual.has-art { padding: 28px; gap: 20px; overflow: hidden; }

/* Step 1 — three covers fanned like samples on a counter. */
.process-fan {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
}
.fan-card {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 46%;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 10px 24px rgba(8,17,66,0.22);
  transition: transform 0.35s var(--ease-out);
}
.fan-card img { display: block; width: 100%; height: auto; }
.fan-0 { transform: translate(-88%, -46%) rotate(-9deg); }
.fan-1 { transform: translate(-50%, -54%); z-index: 1; }
.fan-2 { transform: translate(-12%, -46%) rotate(9deg); }
/* The fan opens a little further for whoever is looking at it. */
.process-visual:hover .fan-0 { transform: translate(-98%, -48%) rotate(-12deg); }
.process-visual:hover .fan-1 { transform: translate(-50%, -58%); }
.process-visual:hover .fan-2 { transform: translate(-2%, -48%) rotate(12deg); }

/* Step 2 — the bottom of a real month page, grid + branded band. The crop
   shows the band and the last grid rows: the placement, not the whole page.
   The inner page uses the flip viewer's own classes untouched; this frame
   only sizes and crops them. */
.process-page-demo {
  width: 100%;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: flex-end;
}
.process-page-crop {
  width: 100%;
  aspect-ratio: 1584 / 760;
  overflow: hidden;
  border-radius: 8px;
  box-shadow: 0 10px 26px rgba(8,17,66,0.2);
  display: flex;
  align-items: flex-end;
  background: var(--white);
}
.process-page-crop .flip-page-calendar {
  width: 100%;
  aspect-ratio: 1584 / 1224;
  flex: none;
  margin-bottom: -0.5%;
}

/* Step 3 — the sheet feeding out of the press. The sheet is clipped by the
   demo box and slides down behind the roller bar on a long loop; transform
   only, so nothing reflows. */
.process-press-demo {
  position: relative;
  width: 78%;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  border-radius: 8px;
}
.press-roller {
  position: absolute;
  top: 0; left: -4%; right: -4%;
  height: 26px;
  background: linear-gradient(180deg, var(--navy) 0%, var(--navy-light) 100%);
  border-radius: 4px;
  z-index: 2;
  box-shadow: 0 6px 14px rgba(8,17,66,0.3);
}
.press-sheet {
  position: absolute;
  top: 12px;
  left: 4%; right: 4%;
  animation: pressFeed 14s var(--ease) infinite;
  will-change: transform;
}
.press-sheet .flip-page-calendar {
  aspect-ratio: 1584 / 1224;
  flex: none;
  box-shadow: 0 8px 20px rgba(8,17,66,0.18);
  border-radius: 0 0 6px 6px;
}
/* Feed, rest so the sheet can be read, withdraw, repeat. */
@keyframes pressFeed {
  0%       { transform: translateY(-96%); }
  38%, 78% { transform: translateY(0); }
  100%     { transform: translateY(-96%); }
}

/* Step 4 — the finished pile. Offsets only, no rotation: calendars come out
   of the box squared up, not fanned. */
.process-stack {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
}
.stack-card {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 58%;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 12px 28px rgba(8,17,66,0.24);
}
.stack-card img { display: block; width: 100%; height: auto; }
.stack-0 { transform: translate(-58%, -42%); }
.stack-1 { transform: translate(-52%, -50%); }
.stack-2 { transform: translate(-46%, -58%); z-index: 1; }
.stack-count {
  position: absolute;
  right: 8%;
  bottom: 10%;
  z-index: 2;
  background: var(--gold);
  color: var(--white);
  font-weight: 800;
  font-size: 1.05rem;
  padding: 10px 16px;
  border-radius: 100px;
  box-shadow: 0 8px 18px rgba(8,17,66,0.25);
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1.15;
}
.stack-count small {
  font-size: 0.58rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.85;
}

/* === PRICING === */
.pricing-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
  align-items: start;
}
/* Size switch above the pricing cards. */
/* Pricing headings drop the display serif for Inter. Playfair is a display
   face — lovely at "Born from a Simple Idea", less so above a table of
   figures. The numbers in these sections are already Inter, so the heading
   now matches what it introduces, and reads plainly at a glance. */
.pricing-heading {
  font-family: 'Inter', sans-serif;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.18;
}

/* The run-up above the price cards, trimmed so a whole card clears the fold.
   Every value here is spacing only — nothing is hidden or shrunk. */
.pricing-top { padding-top: 12px; }
.pricing-top .season-strip { padding: 10px 24px; margin-bottom: 14px; }
.pricing-top .price-size-toggle { margin-bottom: 16px; }
.pricing-top .price-size-note {
  margin: -8px auto 8px;
  max-width: 68ch;
  font-size: 0.84rem;
}
/* The Most Popular badge is absolutely placed at top:-14px and so stands 13px
   proud of its card, outside the grid's box entirely. With nothing reserved
   for it, it overlapped the line above by 5px. The grid holds that room
   itself now, so the badge cannot collide with whatever precedes it. */
.pricing-top .pricing-grid { padding-top: 20px; }

.price-size-toggle {
  display: flex;
  justify-content: center;
  gap: 8px;
  /* The featured card's Most Popular badge rises above the grid, so the
     toggle needs real clearance, not card-to-card spacing. */
  margin: 0 auto 36px;
  width: fit-content;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 5px;
  box-shadow: var(--shadow-sm);
}
.price-size-btn {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 7px;
  border: none;
  background: transparent;
  color: var(--text-body);
  font-family: 'Inter', sans-serif;
  font-size: 0.88rem;
  font-weight: 700;
  padding: 8px 18px;
  border-radius: 100px;
  cursor: pointer;
  transition: all 0.2s var(--ease);
}
.price-size-btn span { font-size: 0.78rem; font-weight: 500; color: var(--text-muted); }
.price-size-btn.active { background: var(--navy); color: var(--white); }
.price-size-btn.active span { color: rgba(255,255,255,0.65); }
.price-size-btn em {
  position: absolute;
  top: -9px; right: 8px;
  font-style: normal;
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--gold);
  color: var(--white);
  padding: 2px 8px;
  border-radius: 100px;
}
.price-size-note {
  text-align: center;
  font-size: 0.88rem;
  color: var(--text-muted);
  margin: -26px auto 44px;
  max-width: 560px;
}
.price-size-note[hidden] { display: none; }

.price-card {
  background: var(--white);
  border: 2px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 26px 24px;
  position: relative;
  transition: all 0.3s var(--ease);
}
.price-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-xl);
}
.price-card.featured {
  border-color: var(--gold);
  box-shadow: 0 8px 32px rgba(40,81,255,0.15);
  background: var(--navy);
}
.price-popular {
  position: absolute;
  top: -14px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--gold);
  color: var(--white);
  font-size: 0.7rem;
  font-weight: 700;
  padding: 4px 16px;
  border-radius: 100px;
  white-space: nowrap;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.price-tier {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--gold);
  margin-bottom: 12px;
}
.price-name {
  font-family: 'Inter', sans-serif;
  font-variant-numeric: tabular-nums;
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--text-dark);
  margin-bottom: 8px;
}
.price-card.featured .price-name { color: var(--white); }
.price-qty {
  font-size: 0.85rem;
  color: var(--text-muted);
  margin-bottom: 12px;
}
.price-card.featured .price-qty { color: rgba(255,255,255,0.6); }
/* The published price: per-unit figure leads, order total beneath it. */
.price-amount {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-bottom: 4px;
}
.price-amount b {
  font-family: 'Inter', sans-serif;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  font-size: 2rem;
  font-weight: 700;
  line-height: 1;
  color: var(--text-dark);
}
.price-amount span {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text-muted);
}
.price-total {
  font-size: 0.85rem;
  color: var(--text-muted);
  margin-bottom: 16px;
}
.price-total strong { color: var(--text-body); font-weight: 700; }
.price-card.featured .price-amount b { color: var(--white); }
.price-card.featured .price-amount span,
.price-card.featured .price-total { color: rgba(255,255,255,0.72); }
.price-card.featured .price-total strong { color: var(--white); }
.price-divider {
  height: 1px;
  background: var(--border);
  margin-bottom: 16px;
}
.price-card.featured .price-divider { background: rgba(255,255,255,0.12); }
.price-features { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; }
.price-feature {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 0.85rem;
  color: var(--text-body);
}
.price-card.featured .price-feature { color: rgba(255,255,255,0.8); }
.price-feature-icon {
  width: 18px; height: 18px;
  background: var(--gold-pale);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gold);
  flex-shrink: 0;
  margin-top: 1px;
}
.price-card.featured .price-tier {
  color: var(--accent-sky);
}
.price-card.featured .price-feature-icon {
  background: rgba(40,81,255,0.2);
  color: var(--accent-sky);
}

/* === PARTNERS === */
.partners-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 32px;
}
.partner-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 36px;
  display: flex;
  gap: 20px;
  align-items: flex-start;
  transition: all 0.3s var(--ease);
}
.partner-card:hover {
  border-color: var(--gold-border);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}
.partner-logo {
  width: 60px; height: 60px;
  background: var(--navy);
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gold);
  flex-shrink: 0;
}
.partner-info h4 { color: var(--text-dark); margin-bottom: 6px; }
.partner-info p  { font-size: 0.9rem; color: var(--text-muted); }

/* === BLOG === */
.blog-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}
.blog-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: all 0.3s var(--ease);
}
/* Real cover art in the card head. Absolute so the flex fallback (icon +
   label) never reflows, cover-fit so any thumb crops to the 16:9 head. */
.blog-card-img img,
.blog-hero-img img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.blog-card-img img { transition: transform 0.4s var(--ease-out); }
.blog-card:hover .blog-card-img img { transform: scale(1.04); }
.blog-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: var(--gold-border);
}
.blog-card-img {
  width: 100%;
  /* The covers' own proportion, not 16/9. At 16/9 the card was a third wider
     than the artwork and cover-fit ate 27% of its height — enough to take the
     title clean off the top of every card. Matching the shape crops nothing. */
  aspect-ratio: 520 / 402;
  object-fit: cover;
  background: linear-gradient(135deg, var(--bg-light) 0%, #dce6f4 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 0.85rem;
  flex-direction: column;
  position: relative;
  overflow: hidden;
  gap: 8px;
}
.blog-card-body { padding: 24px; }
.blog-cat {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--gold);
  margin-bottom: 10px;
}
.blog-card h3 {
  font-size: 1.05rem;
  margin-bottom: 10px;
  line-height: 1.35;
  transition: color 0.2s;
}
.blog-card:hover h3 { color: var(--gold); }
.blog-card p  { font-size: 0.88rem; color: var(--text-muted); margin-bottom: 16px; }
.blog-read-more {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--navy);
  display: flex;
  align-items: center;
  gap: 6px;
  transition: gap 0.2s;
}
.blog-card:hover .blog-read-more { gap: 10px; color: var(--gold); }

/* === CTA BANNER === */
.cta-banner {
  background: linear-gradient(135deg, var(--navy) 0%, var(--navy-light) 50%, var(--navy) 100%);
  position: relative;
  overflow: hidden;
  padding: 96px 0;
  text-align: center;
}
.cta-banner::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 70% 80% at 50% 50%, rgba(40,81,255,0.12) 0%, transparent 70%);
}
/* A shelf of real covers standing along the banner's bottom edge, fading up
   into the navy. Absolutely placed and pointer-inert, so it can never move
   the buttons, change the banner's height, or catch a click. The banner's
   own overflow:hidden clips it. */
.cta-shelf {
  position: absolute;
  left: -2%; right: -2%;
  bottom: -6px;
  height: 88px;
  opacity: 0.3;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 55%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 55%);
}
.cta-shelf-row {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  width: max-content;
  height: 100%;
  animation: ctaShelfDrift 110s linear infinite;
  will-change: transform;
}
.cta-shelf-tile {
  flex: 0 0 auto;
  width: 150px;
  border-radius: 4px 4px 0 0;
  overflow: hidden;
}
.cta-shelf-tile img { display: block; width: 100%; height: auto; }
/* One copy of the doubled row, so the restart lands on an identical frame. */
@keyframes ctaShelfDrift { to { transform: translateX(calc(-50% - 7px)); } }

/* Faint cover texture behind the full-height page heroes — the gallery
   band's mobile treatment generalized. Same tiles and drift keyframes as the
   gallery wall; only the framing differs: no mask, low opacity, and a tilt.
   The hero's h1/p/tag sit in .page-hero-inner (position:relative, z-index:1),
   so they paint above it. */
.hero-texture {
  position: absolute;
  inset: -14% -8%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 16px;
  transform: rotate(-3deg);
  opacity: 0.13;
  pointer-events: none;
  /* Thinned where the title and tag sit, so the type reads on calm navy and
     the covers register at the edges. */
  -webkit-mask-image: radial-gradient(ellipse 62% 88% at 50% 50%, rgba(0,0,0,0.25) 30%, #000 78%);
  mask-image: radial-gradient(ellipse 62% 88% at 50% 50%, rgba(0,0,0,0.25) 30%, #000 78%);
}
.hero-texture .hero-wall-tile { width: 148px; box-shadow: none; }
@media (max-width: 768px) {
  /* Copy fills the band at phone widths; no clear centre can be cut wide
     enough, so thin the whole texture instead — same call as the gallery. */
  .hero-texture {
    opacity: 0.09;
    -webkit-mask-image: none;
    mask-image: none;
  }
}

.cta-banner h2 { color: var(--white); margin-bottom: 16px; position: relative; }
.cta-banner p  { color: rgba(255,255,255,0.7); max-width: 520px; margin: 0 auto 36px; position: relative; font-size: 1.05rem; }
.cta-banner .btn { position: relative; }
.cta-banner-btns {
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
  position: relative;
}

/* === FOOTER === */
.footer {
  background: var(--navy-dark);
  padding: 72px 0 0;
}
.footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1.5fr;
  gap: 48px;
  padding-bottom: 56px;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}
.footer-brand p {
  color: rgba(255,255,255,0.55);
  font-size: 0.9rem;
  margin: 16px 0 24px;
  line-height: 1.7;
  max-width: 280px;
}
.footer-col h5 {
  font-family: 'Inter', sans-serif;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent-sky);
  margin-bottom: 16px;
}
.footer-col ul { display: flex; flex-direction: column; gap: 10px; }
.footer-col ul li a {
  color: rgba(255,255,255,0.55);
  font-size: 0.9rem;
  transition: color 0.2s;
}
.footer-col ul li a:hover { color: var(--white); }
.footer-contact-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  color: rgba(255,255,255,0.55);
  font-size: 0.88rem;
  margin-bottom: 12px;
}
.footer-contact-item svg { color: var(--accent-sky); flex-shrink: 0; margin-top: 2px; }
.footer-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 0;
  flex-wrap: wrap;
  gap: 12px;
}
.footer-bottom p { color: rgba(255,255,255,0.35); font-size: 0.82rem; }
.footer-bottom-links {
  display: flex;
  gap: 20px;
}
.footer-bottom-links a {
  color: rgba(255,255,255,0.35);
  font-size: 0.82rem;
  transition: color 0.2s;
}
.footer-bottom-links a:hover { color: rgba(255,255,255,0.7); }
.footer-social {
  display: flex;
  gap: 10px;
  margin-top: 4px;
}
.footer-social a {
  width: 36px; height: 36px;
  background: rgba(255,255,255,0.07);
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255,255,255,0.55);
  transition: all 0.2s;
}
.footer-social a:hover {
  background: var(--gold);
  color: var(--white);
}

/* === FORM ELEMENTS === */
.form-group { display: flex; flex-direction: column; gap: 6px; }
.form-label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-dark);
}
/* Persistent helper under a field, for the ones where the consequence of the
   answer is not obvious from the label alone. */
.form-hint {
  margin-top: 6px;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--text-muted);
}
.form-input, .form-select, .form-textarea {
  width: 100%;
  padding: 12px 16px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: 'Inter', sans-serif;
  font-size: 0.95rem;
  color: var(--text-dark);
  background: var(--white);
  transition: border-color 0.2s, box-shadow 0.2s;
  outline: none;
}
.form-input:focus, .form-select:focus, .form-textarea:focus {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(40,81,255,0.12);
}
.form-textarea { resize: vertical; min-height: 120px; }
.form-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.form-row { display: flex; flex-direction: column; gap: 20px; }

/* === PAGE HERO (inner pages) === */
.page-hero {
  background: var(--navy);
  padding: 140px 0 80px;
}
/* Slim variant: pages whose content should be visible on arrival. */
.page-hero.compact { padding: 96px 0 30px; }
.page-hero.compact h1 { font-size: clamp(1.6rem, 3vw, 2.2rem); margin: 0; }
/* The gallery band carries the size-reference copy as well as the page title,
   so the white section below can open straight onto the two format cards. The
   h2 is deliberately set below the h1 — inheriting the section-header size
   would leave it larger than the title it sits under. */
.page-hero.gallery-hero { padding-bottom: 48px; }
/* Two class names, to outrank .page-hero.compact h1 { margin: 0 } — without
   the extra weight the title sits flush on the tag below it and the band reads
   as one jammed block. The title and the size note are separate thoughts and
   need the gap to say so. */
/* The wall sits inside the band, absolutely placed, so it cannot change the
   band's height. Tilted a few degrees and inset past the edges so the tilt
   never exposes a corner. */
.gallery-hero-wall {
  position: absolute;
  inset: -14% -8%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 16px;
  transform: rotate(-3deg);
  opacity: 0.38;
  pointer-events: none;
  z-index: 0;
  /* Cleared out of the middle so the headline sits on flat navy, and back to
     full strength before the edge so the covers actually read rather than
     staying a grey suggestion. The clear radius is set past the longest line
     of copy, which is what decides how wide it has to be. */
  -webkit-mask-image: radial-gradient(ellipse 66% 90% at 50% 50%, transparent 44%, #000 78%);
  mask-image: radial-gradient(ellipse 66% 90% at 50% 50%, transparent 44%, #000 78%);
}
.hero-wall-row {
  display: flex;
  gap: 16px;
  width: max-content;
  will-change: transform;
}
.hero-wall-row[data-row="0"] { animation: heroWallDrift 96s linear infinite; }
.hero-wall-row[data-row="1"] { animation: heroWallDriftBack 124s linear infinite; }
.hero-wall-tile {
  flex: 0 0 auto;
  width: 168px;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 8px 20px rgba(0,0,0,0.28);
}
.hero-wall-tile img { display: block; width: 100%; height: auto; }
/* Travels exactly one copy of the row, so the restart lands on an identical
   frame. */
@keyframes heroWallDrift     { to   { transform: translateX(calc(-50% - 8px)); } }
@keyframes heroWallDriftBack { from { transform: translateX(calc(-50% - 8px)); } }

.page-hero.gallery-hero h1 { margin-bottom: 38px; }
.gallery-hero .section-tag { margin-bottom: 18px; }
.gallery-hero h2 {
  color: var(--white);
  font-size: clamp(1.25rem, 2.2vw, 1.7rem);
  margin-bottom: 14px;
}
.gallery-hero p { font-size: 0.98rem; }
/* When the Maps API fails to authorize, it marks the field it was attached to
   by tiling an error icon across it as a background-image, set inline on the
   input. The address stays typeable underneath but is completely unreadable,
   so the field reads as broken. Address autocomplete is a convenience; it must
   never be able to deface a required field on the quote form. */
#deliveryAddress { background-image: none !important; }

/* === ESTIMATE PANEL (order.html) === */
.estimate-card {
  background: var(--navy);
  border-radius: var(--radius-lg);
  padding: 22px 24px;
  color: var(--white);
  position: sticky;
  top: 96px;
  /* Sticking pins this card while its siblings keep scrolling. Without a
     stacking order they win on document order and ride over it, so the
     cards below were covering the total. They pass behind it instead. */
  z-index: 5;
  /* A long quote would otherwise grow the card past the viewport and carry
     the total off the bottom, where sticky can't bring it back. */
  max-height: calc(100vh - 120px);
  overflow-y: auto;
  box-shadow: 0 12px 30px rgba(8,17,66,0.25);
}
.estimate-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding-bottom: 14px;
  margin-bottom: 14px;
  border-bottom: 1px solid rgba(255,255,255,0.14);
}
.estimate-head span { font-weight: 700; font-size: 1rem; }
.estimate-head em {
  font-style: normal;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #FFD469;
  white-space: nowrap;
}
.estimate-lines { display: flex; flex-direction: column; gap: 10px; }
.estimate-line { display: flex; justify-content: space-between; gap: 12px; font-size: 0.88rem; }
.estimate-line-name { color: rgba(255,255,255,0.9); min-width: 0; }
.estimate-line-name small {
  display: block;
  color: rgba(255,255,255,0.55);
  font-size: 0.76rem;
  margin-top: 2px;
}
.estimate-line-value {
  font-variant-numeric: tabular-nums;
  color: var(--white);
  white-space: nowrap;
}
.estimate-line.is-short .estimate-line-value { color: #FFB4A8; }
.estimate-foot {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,0.14);
}
.estimate-foot-row {
  display: flex;
  justify-content: space-between;
  font-size: 0.8rem;
  color: rgba(255,255,255,0.65);
  margin-bottom: 10px;
  font-variant-numeric: tabular-nums;
}
.estimate-total-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.estimate-total-row span { font-size: 0.9rem; color: rgba(255,255,255,0.8); }
.estimate-total-row strong {
  font-family: 'Inter', sans-serif;
  font-variant-numeric: tabular-nums;
  font-size: 1.7rem;
  font-weight: 800;
  color: #FFD469;
  line-height: 1;
}
.estimate-note {
  margin: 14px 0 0;
  font-size: 0.74rem;
  line-height: 1.5;
  color: rgba(255,255,255,0.6);
}
/* Matches the width at which order.html drops to a single column. The card
   keeps its full desktop detail and simply takes its place in the stack,
   between the season strip and the form, rather than shrinking to a bar
   floating over the page. Static because there is no sidebar left to travel
   alongside — pinned, it would sit on top of the fields being filled in. */
@media (max-width: 1024px) {
  .estimate-card {
    position: static;
    max-height: none;
    overflow-y: visible;
  }
}

/* === THEME PAGE ESTIMATE === */
.theme-estimate {
  margin-top: 14px;
  padding: 12px 16px;
  background: var(--off-white);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.theme-estimate.is-below-min { background: var(--gold-pale); border-color: var(--gold-border); }
.theme-estimate-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.theme-estimate-label { font-size: 0.88rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.theme-estimate-value {
  font-family: 'Inter', sans-serif;
  font-variant-numeric: tabular-nums;
  font-size: 1.25rem;
  font-weight: 800;
  color: var(--text-dark);
}
.theme-estimate-note { margin: 4px 0 0; font-size: 0.75rem; color: var(--text-muted); line-height: 1.45; }
/* Tier-cliff prompt: more calendars for less money. */
.theme-upsell {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--text-body);
}
.theme-upsell[hidden] { display: none; }
.theme-upsell svg { color: var(--gold); flex-shrink: 0; }
.theme-upsell span { flex: 1; min-width: 0; }
.theme-upsell button {
  flex-shrink: 0;
  border: 1px solid var(--gold-border);
  background: var(--white);
  color: var(--gold);
  font-family: 'Inter', sans-serif;
  font-size: 0.76rem;
  font-weight: 700;
  padding: 5px 12px;
  border-radius: 100px;
  cursor: pointer;
  transition: all 0.2s var(--ease);
}
.theme-upsell button:hover { background: var(--gold); color: var(--white); border-color: var(--gold); }
.estimate-upsell {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px dashed rgba(255,255,255,0.2);
  font-size: 0.8rem;
  line-height: 1.45;
  color: #FFD469;
}
.estimate-upsell[hidden] { display: none; }
.estimate-upsell svg { flex-shrink: 0; margin-top: 2px; }

/* Seasonal deadline strip — the deadline drawn as the product itself: a
   top-stapled mini calendar leaf that flips between the two dates, the way
   the real calendar turns. */
.season-strip {
  display: flex;
  align-items: center;
  gap: 22px;
  background: linear-gradient(120deg, var(--navy-dark) 0%, var(--navy) 55%, #16247e 100%);
  border-radius: var(--radius-lg);
  padding: 18px 26px;
  margin: 0 auto 34px;
  max-width: 780px;
  position: relative;
  overflow: hidden;
  box-shadow: 0 12px 32px rgba(8,17,66,0.28);
}
/* faint year watermark, echoing the cover art language */
.season-strip::after {
  content: '2027';
  position: absolute;
  right: -8px;
  bottom: -30px;
  font-family: 'Playfair Display', serif;
  font-size: 6.2rem;
  font-weight: 700;
  color: rgba(255,255,255,0.05);
  pointer-events: none;
  line-height: 1;
}
/* The flipping leaf */
.season-leaf {
  flex-shrink: 0;
  width: 74px;
  height: 82px;
  perspective: 500px;
}
.season-leaf-stack {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  /* Rotates about its own centre. Hinging at the staples (origin near the
     top edge) swings the whole leaf a full height above its box, so it
     escaped the strip and sat over the copy — the flip has to stay put and
     turn the sheet over, not lift it away. Both faces keep their staples at
     the top, which is what carries the binding. */
  transform-origin: 50% 50%;
  transition: transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}
.season-leaf.is-flipped .season-leaf-stack { transform: rotateX(-180deg); }
.season-leaf-face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  background: var(--white);
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  box-shadow: 0 3px 10px rgba(8,17,66,0.35);
}
.season-leaf-face.back { transform: rotateX(180deg); }
/* the two staples on the top edge — the real binding */
.season-leaf-face::before, .season-leaf-face::after {
  content: '';
  position: absolute;
  top: 3px;
  width: 10px;
  height: 3px;
  border-radius: 2px;
  background: linear-gradient(180deg, #d8dce8, #9aa2b8);
}
.season-leaf-face::before { left: 16px; }
.season-leaf-face::after  { right: 16px; }
.season-leaf-month {
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  color: #C0392B;
}
.season-leaf-day {
  font-family: 'Inter', sans-serif;
  font-variant-numeric: tabular-nums;
  font-size: 1.9rem;
  font-weight: 800;
  line-height: 1;
  color: var(--navy-dark);
}
.season-leaf-tag {
  font-size: 0.5rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
/* Copy */
.season-copy { position: relative; z-index: 1; min-width: 0; }
.season-copy strong { color: var(--white); font-size: 1rem; display: block; margin-bottom: 3px; }
.season-copy span { color: rgba(255,255,255,0.75); font-size: 0.88rem; line-height: 1.5; display: block; }
.season-copy b { color: #FFD469; font-weight: 700; }
/* Days-remaining counter */
.season-count {
  margin-left: auto;
  flex-shrink: 0;
  text-align: center;
  padding: 10px 18px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--radius-md);
  background: rgba(255,255,255,0.06);
}
.season-count b {
  display: block;
  font-family: 'Inter', sans-serif;
  font-variant-numeric: tabular-nums;
  font-size: 1.7rem;
  font-weight: 800;
  line-height: 1.1;
  color: #FFD469;
}
.season-count span {
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.65);
  white-space: nowrap;
}
@media (max-width: 640px) {
  .season-strip { flex-wrap: wrap; justify-content: center; text-align: center; }
  .season-count { margin-left: 0; }
  .season-strip::after { font-size: 4rem; }
}
@media (prefers-reduced-motion: reduce) {
  .season-leaf-stack { transition: none; }
}

.page-hero {
  text-align: center;
  position: relative;
  overflow: hidden;
}
.page-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 60% 70% at 50% 50%, rgba(40,81,255,0.08) 0%, transparent 70%);
}
.page-hero-inner { position: relative; z-index: 1; }
.page-hero h1 { color: var(--white); margin-bottom: 16px; }
.page-hero p  { color: rgba(255,255,255,0.68); max-width: 560px; margin: 0 auto; font-size: 1.05rem; }

/* === ANIMATIONS === */
/* Everything below is gated on .js-anim, which the script sets on <html>
   only once it has an IntersectionObserver to reveal things again. Ungated,
   opacity:0 is the default state of the page: anything the observer misses
   stays invisible forever, and a whole section of the homepage did. The
   failure now leaves content on screen rather than erasing it. */
.js-anim .animate-on-scroll {
  opacity: 0;
  transform: translateY(32px);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}
.js-anim .animate-on-scroll.from-left  { transform: translateX(-32px); }
.js-anim .animate-on-scroll.from-right { transform: translateX(32px); }
.js-anim .animate-on-scroll.scale      { transform: scale(0.92); }
@media (max-width: 768px) {
  /* Sideways entrances park an element 32px outside the container while it
     waits to be revealed, which at phone widths is past the edge of the
     screen — every page carrying one scrolled horizontally by 8px until the
     reveal fired. They come up from below here instead. */
  .js-anim .animate-on-scroll.from-left,
  .js-anim .animate-on-scroll.from-right { transform: translateY(32px); }
}
.js-anim .animate-on-scroll.visible {
  opacity: 1;
  transform: translateY(0) translateX(0) scale(1);
}
/* The Coming Soon size card is dimmed to read as unavailable. That used to
   be an inline opacity:0.75, which beat every one of the rules above — the
   card sat fully visible while parked 32px past the viewport edge waiting
   for its reveal, and never faded in. As a class the dimming composes: the
   pre-reveal opacity:0 above still applies, and this rule wins the final
   state only because it comes after .visible (equal specificity). */
.js-anim .animate-on-scroll.is-coming-soon.visible,
html:not(.js-anim) .animate-on-scroll.is-coming-soon {
  opacity: 0.75;
}
.delay-1 { transition-delay: 0.1s; }
.delay-2 { transition-delay: 0.2s; }
.delay-3 { transition-delay: 0.3s; }
.delay-4 { transition-delay: 0.4s; }
.delay-5 { transition-delay: 0.5s; }
.delay-6 { transition-delay: 0.6s; }

/* Hero animation */
.hero-animate {
  opacity: 0;
  transform: translateY(24px);
  animation: heroFadeIn 0.8s var(--ease-out) forwards;
}
.hero-animate.d1 { animation-delay: 0.1s; }
.hero-animate.d2 { animation-delay: 0.25s; }
.hero-animate.d3 { animation-delay: 0.4s; }
.hero-animate.d4 { animation-delay: 0.55s; }
.hero-animate.d5 { animation-delay: 0.7s; }
.hero-animate.visual { animation: heroFadeRight 0.9s var(--ease-out) 0.3s forwards; }
@keyframes heroFadeIn {
  to { opacity: 1; transform: translateY(0); }
}
@keyframes heroFadeRight {
  from { opacity: 0; transform: translateX(32px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* Divider wave */
.wave-divider {
  display: block;
  width: 100%;
  overflow: hidden;
  line-height: 0;
}
.wave-divider svg { display: block; }

/* === UTILITIES === */
.text-center { text-align: center; }
.mb-0 { margin-bottom: 0; }
.mb-8 { margin-bottom: 8px; }
.mb-16 { margin-bottom: 16px; }
.mb-24 { margin-bottom: 24px; }
.mb-32 { margin-bottom: 32px; }
.mb-48 { margin-bottom: 48px; }
.mt-24 { margin-top: 24px; }
.mt-32 { margin-top: 32px; }
.mt-48 { margin-top: 48px; }
.view-all {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--navy);
  transition: gap 0.2s, color 0.2s;
}
.view-all:hover { gap: 10px; color: var(--gold); }

/* === LARGE SCREEN SCALING === */
@media (min-width: 1440px) {
  :root { --container: 1360px; }
}
@media (min-width: 1920px) {
  :root { --container: 1560px; }
}

/* === RESPONSIVE === */
@media (max-width: 1024px) {
  :root { --section-py: 72px; }
  .grid-4        { grid-template-columns: repeat(2, 1fr); }
  .footer-grid   { grid-template-columns: 1fr 1fr; }
  .steps-grid    { grid-template-columns: repeat(2, 1fr); gap: 40px; }
  .steps-grid::before { display: none; }
}
@media (max-width: 768px) {
  :root { --section-py: 56px; }
  .hero-inner    { grid-template-columns: 1fr; }
  .hero-visual   { display: none; }
  .grid-2        { grid-template-columns: 1fr; }
  .grid-3        { grid-template-columns: 1fr; }
  .gallery-grid  { grid-template-columns: repeat(2, 1fr); }
  .pricing-grid  { grid-template-columns: 1fr; }
  .partners-grid { grid-template-columns: 1fr; }
  .blog-grid     { grid-template-columns: 1fr; }
  .size-compare  { grid-template-columns: 1fr; }
  /* At this width the copy fills the band, so no clear centre can be cut wide
     enough to keep it off the artwork. The wall drops back to a texture —
     still the real covers, still moving, but no longer competing with the
     words in front of it. */
  .gallery-hero-wall {
    opacity: 0.15;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .hero-wall-tile { width: 124px; box-shadow: none; }
  /* The strip's two halves stop fitting side by side; stack them and let the
     scale drawing scroll rather than shrink, since shrinking it would make it
     lie about the sizes it exists to show. */
  .size-strip { flex-direction: column; align-items: flex-start; gap: 24px; padding: 24px; }
  .size-strip-visual { gap: 20px; max-width: 100%; overflow-x: auto; padding-bottom: 4px; }
  .stats-bar-inner { grid-template-columns: repeat(2, 1fr); }
  .stat-item { border-right: none; border-bottom: 1px solid rgba(255,255,255,0.08); }
  .nav-links, .nav-cta { display: none; }
  .nav-dropdown { display: none; }
  .nav-hamburger { display: flex; }
  .footer-grid   { grid-template-columns: 1fr; gap: 32px; }
  .form-grid-2   { grid-template-columns: 1fr; }
  .steps-grid    { grid-template-columns: 1fr; }
}
@media (max-width: 480px) {
  .gallery-grid  { grid-template-columns: 1fr; }
  .hero-ctas     { flex-direction: column; }
  .hero-mini-stats { gap: 20px; }
  .stats-bar-inner { grid-template-columns: 1fr 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  /* The blanket rule above shortens durations but leaves iteration counts
     alone, which would leave the drifting wall looping thousands of times a
     second instead of stopping. Stop them outright — the imagery stays. */
  .hero-wall-row { animation: none !important; }
  .press-sheet { animation: none !important; transform: translateY(0); }
  .cta-shelf-row { animation: none !important; }
  /* The hero covers stop cycling and the first one simply stays. Without the
     explicit stop the blanket rule leaves them looping at 0.01ms forever. */
  /* The walls stop cycling and the first one simply stays. Without the
     explicit stop the blanket rule leaves them looping at 0.01ms forever. */
  .hero-mockup-shot { animation: none !important; opacity: 0; transform: none; }
  .hero-mockup-shot:first-of-type { opacity: 1; }
  /* The four that predate the marquees and were never covered: a glowing
     button, the breathing logo, the pulsing dot on the hero tag, and the
     floating badges. Each is infinite, so the blanket rule above leaves them
     running thousands of cycles a second rather than stopping them. */
  .btn-glow,
  .nav-logo-icon,
  .hero-tag::before,
  .hero-float-badge { animation: none !important; }
}

/* ===== WALL SHOWCASE =========================================================
   Real pages from the flip viewer, hung on a wall. Dark ground on purpose: the
   pages are almost entirely white, so anything lighter than this flattens them.
   ========================================================================== */
.wallshow {
  background: linear-gradient(160deg, var(--navy-dark) 0%, var(--navy) 55%, #142a8f 100%);
  color: #fff;
  padding: 96px 0;
  position: relative;
  overflow: hidden;
}
.wallshow::after {
  /* A wash of light off the top-left, so the band is not a flat rectangle. */
  content: '';
  position: absolute;
  top: -30%; left: -10%;
  width: 60%; height: 120%;
  background: radial-gradient(ellipse at center, rgba(255, 200, 87, 0.10), transparent 68%);
  pointer-events: none;
}
.wallshow > .container { position: relative; z-index: 1; }
.wallshow .section-header h2 { color: #fff; }
.wallshow .section-header p { color: rgba(255, 255, 255, 0.76); }

.wallshow-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
  margin-top: 8px;
}
.wallshow-card {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.13);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: transform 0.35s var(--ease-out), border-color 0.35s var(--ease-out);
}
.wallshow-card:hover {
  transform: translateY(-5px);
  border-color: rgba(255, 200, 87, 0.5);
}
.wallshow-card img {
  display: block;
  width: 100%;
  /* The mockups' own proportion. Declared so the row reserves its height
     before the images arrive and nothing jumps. */
  aspect-ratio: 1400 / 1767;
  object-fit: cover;
}
.wallshow-cap {
  padding: 16px 20px 18px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.wallshow-cap strong {
  font-size: 1rem;
  font-weight: 600;
  color: #fff;
}
.wallshow-cap span {
  font-size: 0.8rem;
  color: rgba(255, 255, 255, 0.62);
  white-space: nowrap;
}

/* The point of the whole section: the strip along the foot of every page. */
.wallshow-note {
  margin-top: 40px;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 22px 26px;
  border-radius: var(--radius-lg);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
}
.wallshow-note svg { flex-shrink: 0; color: var(--accent-warm); }
.wallshow-note p {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.84);
}
.wallshow-note strong { color: #fff; font-weight: 600; }

@media (max-width: 900px) {
  .wallshow-grid { grid-template-columns: repeat(2, 1fr); gap: 20px; }
  /* Third card would sit alone in a half-width row. Centre it across both
     columns, but hold it to one column's width (half the grid, less half the
     20px gap) so it does not read as larger than the two above it. */
  .wallshow-card:last-child {
    grid-column: 1 / -1;
    max-width: calc(50% - 10px);
    margin-inline: auto;
  }
}
@media (max-width: 600px) {
  .wallshow { padding: 72px 0; }
  .wallshow-grid { grid-template-columns: 1fr; }
  .wallshow-card:last-child { max-width: none; margin-inline: 0; }
  .wallshow-note { flex-direction: column; align-items: flex-start; gap: 12px; }
}
