/* ============================================================
   Dreams of Buttercream — styles
   Palette pulled from her cookie photos: warm cream backgrounds,
   soft pinks, and a deep cocoa brown for text. Body is Inter, the
   brand and headings use DM Serif Display for that bakery feel.
   ============================================================ */

:root {
  --cream:           #fbf6f0;
  --cream-deeper:    #f3eadf;
  --pink-soft:       #f4dadb;
  --pink:            #e6a8ac;
  --pink-strong:     #c76e72;
  --pink-strong-hov: #b25a5f;
  --cocoa:           #3a261c;
  --cocoa-muted:     #6e5448;
  --taupe:           #a89685;
  --line:            #ebd8d2;
  --success-bg:      #e3f1e0;
  --success-fg:      #2e5e2a;
  --error-bg:        #fbe2e2;
  --error-fg:        #8a2b2b;
  --warning-bg:      #fcefd6;
  --warning-fg:      #855a13;

  --serif: "DM Serif Display", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  --sans:  "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

  --radius:   10px;
  --radius-l: 16px;

  --shadow-sm: 0 1px 2px rgba(58, 38, 28, 0.06);
  --shadow:    0 4px 12px rgba(58, 38, 28, 0.08);
  --shadow-lg: 0 20px 60px rgba(58, 38, 28, 0.25);
}

/* ── Holiday themes ──────────────────────────────────────────────
   Each theme overrides the --pink-* variables for `body.theme-<slug>`
   so the whole accent palette shifts without touching individual
   selectors. The cream background, type, layout, and decorative
   pastels in the logo art stay put. See src/lib/theme.js for the
   active date windows. */

.theme-banner {
  background: var(--theme-banner-bg, var(--pink-strong));
  color: var(--theme-banner-fg, var(--cream));
  text-align: center;
  padding: 8px 16px;
  font-size: 0.92rem;
  font-weight: 500;
  letter-spacing: 0.01em;
}
.theme-banner a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Theme bunting — a horizontal strip of small American flags hanging
   from a thin rope. SVG-as-background-image tiles cleanly via
   background-repeat: repeat-x at every viewport width, so a 375 px
   phone shows ~6 flags and a 1440 px desktop shows ~24, all at
   consistent size. Each tile contains 3 identical mini flags; the
   pattern is wide enough that the seam between repeats isn't
   obvious. */
.theme-bunting {
  height: 40px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 40'><line x1='0' y1='0.8' x2='180' y2='0.8' stroke='%236d4d3a' stroke-width='1'/><g><rect x='8' y='2' width='44' height='26' fill='%23f5f0e6' stroke='%23bdbdbd' stroke-width='0.4'/><rect x='8' y='2' width='44' height='3.6' fill='%23b22234'/><rect x='8' y='9.2' width='44' height='3.6' fill='%23b22234'/><rect x='8' y='16.4' width='44' height='3.6' fill='%23b22234'/><rect x='8' y='23.6' width='44' height='4.4' fill='%23b22234'/><rect x='8' y='2' width='17' height='12' fill='%233c5b8d'/></g><g><rect x='68' y='2' width='44' height='26' fill='%23f5f0e6' stroke='%23bdbdbd' stroke-width='0.4'/><rect x='68' y='2' width='44' height='3.6' fill='%23b22234'/><rect x='68' y='9.2' width='44' height='3.6' fill='%23b22234'/><rect x='68' y='16.4' width='44' height='3.6' fill='%23b22234'/><rect x='68' y='23.6' width='44' height='4.4' fill='%23b22234'/><rect x='68' y='2' width='17' height='12' fill='%233c5b8d'/></g><g><rect x='128' y='2' width='44' height='26' fill='%23f5f0e6' stroke='%23bdbdbd' stroke-width='0.4'/><rect x='128' y='2' width='44' height='3.6' fill='%23b22234'/><rect x='128' y='9.2' width='44' height='3.6' fill='%23b22234'/><rect x='128' y='16.4' width='44' height='3.6' fill='%23b22234'/><rect x='128' y='23.6' width='44' height='4.4' fill='%23b22234'/><rect x='128' y='2' width='17' height='12' fill='%233c5b8d'/></g></svg>");
  background-repeat: repeat-x;
  background-size: 180px 40px;
  /* Subtle drop shadow so the bunting reads as floating in front of
     the page rather than glued to the banner above it. */
  box-shadow: 0 1px 3px rgba(58, 38, 28, 0.08);
}
/* Inline SVG glyphs flanking the banner text. They inherit the
   banner's foreground via fill="currentColor" in the source, so a
   theme that flips banner-fg automatically retints them too. */
/* Flag glyph is rendered slightly wider + taller than the other
   icons because at 1.1em (the default) the four stripes + canton
   blur together at typical banner font sizes. The aspect-ratio bump
   gives it room to read as a flag rather than a colored smear. */
.theme-icon--flag {
  width: 1.65em;
  height: 1.2em;
  vertical-align: -0.18em;
}
.theme-icon {
  display: inline-block;
  width: 1.1em;
  height: 1.1em;
  vertical-align: -0.18em;
  margin: 0 0.35em;
}

/* Each theme below redefines the --pink-* slots for its body class.
   The variable names still say "pink" — the theme reuses the existing
   slots so we don't have to touch every selector in the stylesheet.
   The cream background, type, and layout are unchanged. */

/* Valentine's Day — deeper rose-red, brand pink stays close */
body.theme-valentines {
  --pink-strong:     #b53f5e;
  --pink-strong-hov: #963349;
  --pink:            #e07a98;
  --pink-soft:       #f6d4dd;
  --theme-banner-bg: #b53f5e;
  --theme-banner-fg: #fbf6f0;
}

/* St. Patrick's Day — kelly green */
body.theme-stpatricks {
  --pink-strong:     #2c7e3a;
  --pink-strong-hov: #1f5f2a;
  --pink:            #5fb27e;
  --pink-soft:       #dbecdb;
  --line:            #c6d6c6;
  --theme-banner-bg: #2c7e3a;
  --theme-banner-fg: #fbf6f0;
}

/* Easter — soft lavender, gentlest shift */
body.theme-easter {
  --pink-strong:     #a47bb8;
  --pink-strong-hov: #87649a;
  --pink:            #c9b1d7;
  --pink-soft:       #ece2f0;
  --theme-banner-bg: #a47bb8;
  --theme-banner-fg: #fbf6f0;
}

/* Mother's Day — brighter floral pink */
body.theme-mothersday {
  --pink-strong:     #c44a78;
  --pink-strong-hov: #a13660;
  --pink:            #e483a8;
  --pink-soft:       #f5dbe4;
  --theme-banner-bg: #c44a78;
  --theme-banner-fg: #fbf6f0;
}

/* Memorial Day & Independence Day share the Old Glory palette;
   the date windows never overlap so a single rule is safe. */
body.theme-memorialday,
body.theme-july4 {
  --pink-strong:     #b22234;
  --pink-strong-hov: #8c1929;
  --pink:            #d35266;
  --pink-soft:       #dbe9f4;
  --line:            #d6c1cd;
  --theme-banner-bg: #b22234;
  --theme-banner-fg: #fbf6f0;
}

/* Father's Day — navy */
body.theme-fathersday {
  --pink-strong:     #29456a;
  --pink-strong-hov: #1d3551;
  --pink:            #5a7b9e;
  --pink-soft:       #d6dde6;
  --line:            #c5cdda;
  --theme-banner-bg: #29456a;
  --theme-banner-fg: #fbf6f0;
}

/* Halloween — pumpkin orange with a deep-purple banner */
body.theme-halloween {
  --pink-strong:     #d96d2a;
  --pink-strong-hov: #b3551f;
  --pink:            #e8985e;
  --pink-soft:       #f3e0c5;
  --line:            #d8c4a8;
  --theme-banner-bg: #2a1b3a;
  --theme-banner-fg: #f5b85a;
}

/* Thanksgiving — burnt orange + tan */
body.theme-thanksgiving {
  --pink-strong:     #a04826;
  --pink-strong-hov: #7d361a;
  --pink:            #c4744a;
  --pink-soft:       #ecdcbd;
  --line:            #d8c4a8;
  --theme-banner-bg: #a04826;
  --theme-banner-fg: #fbf6f0;
}

/* Christmas — classic red with a green banner and green chips */
body.theme-christmas {
  --pink-strong:     #be3034;
  --pink-strong-hov: #99262a;
  --pink:            #e07577;
  --pink-soft:       #d4e7d0;
  --line:            #c4d7c0;
  --theme-banner-bg: #2e6e3a;
  --theme-banner-fg: #fbf6f0;
}

/* ── Holiday background effects ─────────────────────────────────
   A small constellation of SVG particles drifting / rising /
   twinkling behind the main content. Pure CSS, no JS. The
   container is fixed + pointer-events: none so it never blocks
   interaction. Hidden entirely for prefers-reduced-motion. */

.theme-effect {
  position: fixed; inset: 0;
  pointer-events: none;
  overflow: hidden;
  /* High enough to float above the in-flow banner + header without
     fighting any other overlays (preview pill, bulk action bar,
     upload progress all use higher values). */
  z-index: 30;
}
.theme-effect__particle {
  position: absolute;
  display: block;
  color: var(--pink-strong);
  /* Each particle's --i (0…count-1) is set inline in the template
     and used by the per-effect rules below to vary timing/position.
     We use linear distributions + cos/sin instead of % (which is the
     percentage unit in calc, not a modulo operator) so the math
     parses correctly. */
}
.theme-effect__particle svg { display: block; width: 100%; height: 100%; }

@media (prefers-reduced-motion: reduce) {
  .theme-effect { display: none; }
}

/* Themed CTA pulse glow on hover. Only active when a holiday theme
   is in effect (gated on body[data-theme]) so the everyday cream-
   and-pink site stays calm. The halo color is the theme's accent —
   color-mix lets us use the current --pink-strong (which is red on
   July 4, green on St. Patrick's, navy on Father's Day, etc.) at
   diminishing opacity to produce a soft expanding ring. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes theme-cta-pulse {
    0%   { box-shadow: 0 0 0 0   color-mix(in srgb, var(--pink-strong) 55%, transparent); }
    100% { box-shadow: 0 0 0 16px color-mix(in srgb, var(--pink-strong) 0%,  transparent); }
  }
  body[data-theme] .btn--primary:hover,
  body[data-theme] .btn--primary:focus-visible,
  body[data-theme] .nav-cta:hover,
  body[data-theme] .nav-cta:focus-visible {
    animation: theme-cta-pulse 1.5s ease-out infinite;
  }
}

@media (prefers-reduced-motion: no-preference) {
  /* Fall: enter above the viewport, drift down past it with a gentle
     horizontal sway. The template emits THREE per-particle CSS
     variables:
       --i = sequential index 0..count-1 (drives size variation only)
       --x = random horizontal position as a literal percentage
             (e.g., "47.3%") — fully independent of --i
       --d = random delay 0..15s — applied as a negative
             animation-delay so each particle starts at an independent
             random phase of its own cycle. Range exceeds the longest
             duration (max ≈ 14.6s for count=14) so any cycle position
             is reachable from t=0; without that, the initial layout
             still reads as soft monotonic stagger.
     Confetti shares the trajectory but cycles colors per particle. */
  .theme-effect--fall .theme-effect__particle,
  .theme-effect--confetti .theme-effect__particle {
    top: -12vh;
    left: var(--x, calc(var(--i) * 7%));
    width: calc(18px + var(--i) * 1px);
    height: calc(18px + var(--i) * 1px);
    opacity: 0.55;
    animation: theme-fall calc(9s + var(--i) * 0.4s) linear infinite;
    animation-delay: calc(0s - var(--d, calc(var(--i) * 0.7s)));
  }
  @keyframes theme-fall {
    0%   { transform: translate3d(0, 0, 0) rotate(0deg);          opacity: 0; }
    8%   { opacity: 0.55; }
    50%  { transform: translate3d(18px, 55vh, 0) rotate(180deg); }
    92%  { opacity: 0.55; }
    100% { transform: translate3d(-18px, 115vh, 0) rotate(360deg); opacity: 0; }
  }

  /* Confetti color cycle. Skip pure white — would vanish against the
     cream background — and alternate red ↔ navy. The bunting strip
     carries the white. */
  .theme-effect--confetti .theme-effect__particle:nth-child(odd)  { color: #b22234; }
  .theme-effect--confetti .theme-effect__particle:nth-child(even) { color: #3c5b8d; }

  /* Rise: float up from below the viewport. Hearts on Valentine's. */
  .theme-effect--rise .theme-effect__particle {
    bottom: -10vh;
    left: calc(var(--i) * 8%);
    width: calc(16px + var(--i) * 1px);
    height: calc(16px + var(--i) * 1px);
    opacity: 0.55;
    animation: theme-rise calc(8s + var(--i) * 0.4s) linear infinite;
    animation-delay: calc(var(--i) * -0.65s);
  }
  @keyframes theme-rise {
    0%   { transform: translate3d(0, 0, 0);          opacity: 0; }
    10%  { opacity: 0.55; }
    100% { transform: translate3d(12px, -120vh, 0);  opacity: 0; }
  }

  /* Twinkle: scattered around the viewport, no movement — just
     opacity + scale pulsing. Both --x and --y come from the template
     as random percentages so particles are spread organically; the
     cos/sin fallback (the original ellipse-of-stars layout) only
     applies when the template hasn't been updated. */
  .theme-effect--twinkle .theme-effect__particle {
    left: var(--x, calc(50% + cos(var(--i) * 23deg) * 38vw));
    top:  var(--y, calc(50% + sin(var(--i) * 23deg) * 35vh));
    width: calc(16px + var(--i) * 0.6px);
    height: calc(16px + var(--i) * 0.6px);
    animation: theme-twinkle calc(2.8s + var(--i) * 0.2s) ease-in-out infinite;
    animation-delay: calc(0s - var(--d, calc(var(--i) * 0.45s)));
  }
  @keyframes theme-twinkle {
    0%, 100% { opacity: 0.18; transform: scale(0.7); }
    50%      { opacity: 0.85; transform: scale(1.15); }
  }
}

/* Theme preview pill — only renders while previewing via the
   dob_theme_preview cookie. Fixed lower-right so it survives any
   scroll position and never overlaps the main content flow. */
.theme-preview-pill {
  position: fixed;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom));
  z-index: 200;
  background: var(--cocoa);
  color: var(--cream);
  padding: 8px 14px;
  border-radius: 999px;
  font-size: 0.85rem;
  box-shadow: var(--shadow-lg);
}
.theme-preview-pill a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  color: var(--cocoa);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { font-family: var(--serif); font-weight: 400; color: var(--cocoa); line-height: 1.15; margin: 0 0 0.4em; }
h1 { font-size: clamp(2rem, 5vw, 3.25rem); }
h2 { font-size: clamp(1.5rem, 3.2vw, 2rem); }
h3 { font-size: 1.25rem; }

a { color: var(--pink-strong); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--pink-strong-hov); }

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

button { font: inherit; cursor: pointer; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; background: var(--cocoa);
  color: var(--cream); padding: 8px 12px; text-decoration: none; z-index: 100;
}
.skip-link:focus { left: 8px; top: 8px; }

/* Sticky header would otherwise overlap any in-page anchor target.
   `scroll-margin-top` reserves space above the target during scroll
   so the section heading lands BELOW the header, not under it. 100px
   gives a little breathing room across desktop + mobile (header can
   wrap to two rows on narrow screens). */
#main, #reviews, #photos {
  scroll-margin-top: 100px;
}

/* ── Header / nav ────────────────────────────────────────── */
.site-header {
  background: var(--cream);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 50;
  backdrop-filter: saturate(140%) blur(6px);
}
.site-header__inner {
  max-width: 1200px; margin: 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 24px; gap: 24px;
}
.site-header__social {
  display: flex; align-items: center; gap: 8px;
}
.site-header__social a {
  color: var(--cocoa);
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  transition: color .15s, background-color .15s;
}
.site-header__social a:hover {
  color: var(--pink-strong); background: var(--pink-soft);
}
.site-header__nav { display: flex; gap: 20px; align-items: center; flex-wrap: wrap; }
.site-header__nav a {
  color: var(--cocoa); text-decoration: none; font-weight: 500; font-size: 0.95rem;
  padding: 6px 4px;
}
.site-header__nav a:hover { color: var(--pink-strong); }
.site-header__nav .nav-cta {
  background: var(--pink-strong); color: var(--cream);
  padding: 8px 16px; border-radius: 999px;
}
.site-header__nav .nav-cta:hover { background: var(--pink-strong-hov); color: var(--cream); }

/* ── Mobile hamburger menu ───────────────────────────────────────── */
/* Visually-hidden checkbox carries the open/closed state. The label
   below is the button users see; CSS sibling selectors light up the
   menu when the checkbox is checked. No JS required. */
.site-header__menu-state {
  /* Standard visually-hidden technique, with -webkit-appearance:none
     and opacity:0 added because iOS Safari otherwise renders the
     native checkbox glyph regardless of clip-path. */
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  -webkit-appearance: none;
  appearance: none;
  opacity: 0;
}
.site-header__menu-button { display: none; }
/* Default icon visibility: hamburger shown, X hidden. The :checked
   swap below flips both. Declared by class-suffix (not by the shared
   .site-header__menu-icon) so a later rule on the shared class can't
   accidentally show the X. */
.site-header__menu-icon--hamburger { display: block; }
.site-header__menu-icon--close { display: none; }

@media (max-width: 720px) {
  .site-header__menu-button {
    display: inline-flex;
    align-items: center; justify-content: center;
    width: 44px; height: 44px;
    color: var(--cocoa);
    cursor: pointer;
    border-radius: 10px;
    -webkit-tap-highlight-color: transparent;
    transition: background-color .15s ease;
  }
  .site-header__menu-button:hover {
    background-color: var(--pink-soft);
  }
  .site-header__menu-button:active {
    background-color: var(--pink-soft);
    transform: scale(0.96);
  }

  /* Hide nav by default on mobile — revealed when checkbox is checked. */
  .site-header__nav {
    display: none;
    position: absolute;
    top: 100%; left: 0; right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 8px 16px 16px;
    background: var(--cream);
    border-bottom: 1px solid var(--line);
    box-shadow: 0 12px 24px rgba(58, 38, 28, 0.08);
  }
  .site-header__nav a {
    padding: 14px 12px;
    font-size: 1.05rem;
    border-bottom: 1px solid rgba(58, 38, 28, 0.06);
    border-radius: 0;
  }
  .site-header__nav a:last-child {
    border-bottom: 0;
  }

  /* The Contact CTA stays visually distinct in the dropdown — pink
     pill, with margin so it doesn't crowd the divider above. */
  .site-header__nav .nav-cta {
    margin-top: 10px;
    text-align: center;
    border-radius: 999px;
    padding: 12px 16px;
  }

  /* Checkbox checked → swap icon, reveal nav. */
  .site-header__menu-state:checked ~ .site-header__menu-button .site-header__menu-icon--hamburger {
    display: none;
  }
  .site-header__menu-state:checked ~ .site-header__menu-button .site-header__menu-icon--close {
    display: block;
  }
  .site-header__menu-state:checked ~ .site-header__nav {
    display: flex;
  }

  /* Keyboard focus ring on the visible button, since the checkbox
     itself is sr-only. */
  .site-header__menu-state:focus-visible ~ .site-header__menu-button {
    outline: 2px solid var(--pink-strong);
    outline-offset: 2px;
  }
}

/* ── Page layout ─────────────────────────────────────────── */
main { min-height: 60vh; }

.page-header {
  max-width: 900px; margin: 0 auto; padding: 56px 24px 24px;
  text-align: center;
}
.page-header__lede {
  color: var(--cocoa-muted);
  font-size: 1.1rem; max-width: 60ch; margin: 0 auto;
}
.page-header__crumb {
  margin: 0 0 6px;
  font-size: 0.9rem;
}
.page-header__crumb a {
  color: var(--cocoa-muted);
  text-decoration: none;
}
.page-header__crumb a:hover { color: var(--pink-strong); text-decoration: underline; }

/* ── Album grid (browse-by-album landing) ───────────────────────
   Each card: square cover thumbnail + name + count. Tap to drill
   into /gallery/:slug. */
.album-grid {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: 24px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  max-width: 1200px; margin: 0 auto; padding: 16px 24px 64px;
}
.album-grid__item { display: flex; }
.album-card {
  display: flex; flex-direction: column;
  width: 100%;
  background: white;
  border-radius: var(--radius-l);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  color: var(--cocoa);
  text-decoration: none;
  transition: transform .2s, box-shadow .2s;
}
.album-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow);
}
.album-card__cover {
  aspect-ratio: 4 / 3;
  background: var(--cream-deeper);
  overflow: hidden;
  position: relative;
}
.album-card__cover img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .25s ease;
}
.album-card:hover .album-card__cover img { transform: scale(1.03); }
.album-card__cover--blank {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%;
  color: var(--cocoa-muted);
  font-size: 0.9rem;
}
.album-card__body {
  padding: 14px 18px 18px;
}
.album-card__name {
  font-family: var(--serif);
  font-size: 1.35rem;
  margin: 0 0 4px;
  color: var(--cocoa);
  line-height: 1.2;
}
.album-card__count {
  margin: 0;
  font-size: 0.85rem;
  color: var(--cocoa-muted);
}

.prose {
  max-width: 800px; margin: 0 auto; padding: 16px 24px 64px;
}
.prose h2 { margin-top: 2.2em; }
.prose ol, .prose ul { padding-left: 1.2em; }
.prose ol li, .prose ul li { margin-bottom: 0.4em; }

/* ── Hero ────────────────────────────────────────────────── */
.hero {
  max-width: 1200px; margin: 0 auto;
  display: grid; grid-template-columns: 1fr;
  gap: 32px; padding: 24px 24px 32px;
  align-items: center;
}
@media (min-width: 880px) {
  .hero { grid-template-columns: 1.1fr 1fr; padding-top: 36px; padding-bottom: 56px; gap: 56px; }
}
.hero__logo {
  display: block; width: 100%; height: auto;
  max-width: 460px; margin: 0 auto 8px;
}
@media (min-width: 880px) {
  .hero__logo { max-width: 540px; margin-left: -8px; margin-right: 0; }
}
.hero__cta { display: flex; gap: 12px; margin-top: 20px; flex-wrap: wrap; justify-content: center; }
@media (min-width: 880px) {
  .hero__cta { justify-content: flex-start; }
}

.hero__collage {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 120px;
  gap: 10px;
}
@media (min-width: 880px) {
  .hero__collage { grid-auto-rows: 150px; }
}
.hero__collage-img {
  width: 100%; height: 100%; object-fit: cover;
  border-radius: var(--radius-l);
  box-shadow: var(--shadow);
}
.hero__collage-img--0 { grid-column: 1 / span 2; grid-row: 1 / span 2; }
.hero__collage-img--3 { grid-column: 3 / span 1; grid-row: 2 / span 2; }
.hero__collage-img--5 { display: none; }
@media (max-width: 600px) {
  .hero__collage-img--4 { display: none; }
}

/* ── Buttons ─────────────────────────────────────────────── */
.btn {
  display: inline-block; padding: 12px 22px; border-radius: 999px;
  font-weight: 600; font-size: 1rem; text-decoration: none;
  border: 1.5px solid transparent; cursor: pointer; transition: background .15s, color .15s, border-color .15s;
  line-height: 1.2;
}
.btn--primary { background: var(--pink-strong); color: var(--cream); border-color: var(--pink-strong); }
.btn--primary:hover { background: var(--pink-strong-hov); color: var(--cream); border-color: var(--pink-strong-hov); }
.btn--ghost { background: transparent; color: var(--cocoa); border-color: var(--cocoa); }
.btn--ghost:hover { background: var(--cocoa); color: var(--cream); }
.btn--small { padding: 6px 12px; font-size: 0.85rem; }
.btn--danger { background: transparent; color: #8a2b2b; border-color: #d9b0b0; }
.btn--danger:hover { background: #8a2b2b; color: white; }

.cta-row { display: flex; gap: 12px; margin-top: 32px; flex-wrap: wrap; }

/* ── Home strip & info cards ─────────────────────────────── */
.home-strip {
  background: var(--cream-deeper);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 48px 24px;
}
.home-strip__inner {
  max-width: 1100px; margin: 0 auto;
  display: grid; gap: 32px; grid-template-columns: 1fr;
}
@media (min-width: 760px) { .home-strip__inner { grid-template-columns: repeat(3, 1fr); } }
.home-strip__col h2 { font-size: 1.4rem; }

.home-recent {
  max-width: 1200px; margin: 0 auto; padding: 64px 24px 48px;
}
.home-recent__head {
  display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 24px;
}
.home-recent__more { font-weight: 600; text-decoration: none; }

/* ── Gallery grid ────────────────────────────────────────── */
.gallery-grid {
  list-style: none; padding: 0 24px 80px; margin: 0;
  max-width: 1200px; margin: 0 auto;
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.gallery-grid--teaser { padding: 0; }
.gallery-grid__item { margin: 0; }
.gallery-grid__link {
  display: block; padding: 0; border: 0; background: transparent;
  border-radius: var(--radius-l); overflow: hidden; cursor: pointer;
  box-shadow: var(--shadow-sm); transition: transform .2s, box-shadow .2s;
  width: 100%; aspect-ratio: 1 / 1;
}
.gallery-grid__link:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.gallery-grid__link img { width: 100%; height: 100%; object-fit: cover; display: block; }

.empty-state {
  max-width: 600px; margin: 24px auto 80px; text-align: center;
  color: var(--cocoa-muted);
}

/* ── Lightbox ────────────────────────────────────────────── */
.lightbox {
  position: fixed; inset: 0; background: rgba(20, 12, 8, 0.92);
  display: flex; align-items: center; justify-content: center;
  z-index: 200; padding: 24px;
  flex-direction: column;
}
.lightbox[hidden] { display: none; }
.lightbox__img {
  max-width: min(1200px, 92vw); max-height: 80vh;
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
/* Lightbox controls — high-contrast so they don't get lost in light
   or busy photo areas. Solid dark fill + thin white ring + drop
   shadow means they pop against any photo content. */
.lightbox__close, .lightbox__prev, .lightbox__next {
  position: absolute;
  display: flex; align-items: center; justify-content: center;
  background: rgba(20, 12, 8, 0.78);
  color: var(--cream);
  border: 0;
  width: 52px; height: 52px;
  border-radius: 999px;
  box-shadow:
    0 4px 14px rgba(0, 0, 0, 0.5),
    0 0 0 1.5px rgba(255, 255, 255, 0.25);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color .15s ease, box-shadow .15s ease, transform .1s ease;
}
.lightbox__close { top: 16px; right: 16px; }
.lightbox__prev  { left: 12px; top: 50%; transform: translateY(-50%); }
.lightbox__next  { right: 12px; top: 50%; transform: translateY(-50%); }

.lightbox__close:hover,
.lightbox__prev:hover,
.lightbox__next:hover {
  background: rgba(20, 12, 8, 0.92);
  box-shadow:
    0 6px 20px rgba(0, 0, 0, 0.6),
    0 0 0 1.5px rgba(255, 255, 255, 0.4);
}

/* Press feedback. The prev/next buttons already have translateY for
   vertical centering, so the scale has to be composed alongside it. */
.lightbox__close:active { transform: scale(0.92); }
.lightbox__prev:active  { transform: translateY(-50%) scale(0.92); }
.lightbox__next:active  { transform: translateY(-50%) scale(0.92); }

.lightbox__close svg,
.lightbox__prev svg,
.lightbox__next svg {
  display: block;
}

/* Mobile: bigger tap targets and pinned closer to the viewport edges
   so the photo isn't competing with them as much. */
@media (max-width: 720px) {
  .lightbox__close { width: 48px; height: 48px; top: 12px; right: 12px; }
  .lightbox__prev,
  .lightbox__next { width: 56px; height: 56px; }
  .lightbox__prev { left: 6px; }
  .lightbox__next { right: 6px; }
}

/* ── Info cards on /order ────────────────────────────────── */
.info-cards {
  display: grid; gap: 16px; grid-template-columns: 1fr; margin: 24px 0 16px;
}
@media (min-width: 700px) { .info-cards { grid-template-columns: repeat(2, 1fr); } }
.info-card {
  background: white; padding: 24px; border-radius: var(--radius-l);
  border: 1px solid var(--line); box-shadow: var(--shadow-sm);
}
.info-card h2 { font-size: 1rem; color: var(--cocoa-muted); margin: 0; font-family: var(--sans); font-weight: 500; letter-spacing: 0.05em; text-transform: uppercase; }
.info-card__big {
  font-family: var(--serif); font-size: 2.2rem; color: var(--cocoa); margin: 8px 0 12px;
}
.info-card__unit { font-size: 1rem; color: var(--cocoa-muted); }

/* ── FAQ ─────────────────────────────────────────────────── */
.faq__item {
  border-bottom: 1px solid var(--line); padding: 18px 0;
}
.faq__item summary {
  cursor: pointer; font-weight: 600; font-size: 1.05rem; list-style: none;
  display: flex; justify-content: space-between; align-items: center;
}
.faq__item summary::after { content: "+"; font-size: 1.5rem; color: var(--pink-strong); margin-left: 12px; }
.faq__item[open] summary::after { content: "−"; }
.faq__item p { margin: 12px 0 0; color: var(--cocoa-muted); }

/* ── Contact form ────────────────────────────────────────── */
.contact {
  max-width: 640px; margin: 0 auto; padding: 16px 24px 80px;
}
.field { margin-bottom: 20px; }
.field label { display: block; font-weight: 600; margin-bottom: 6px; font-size: 0.95rem; }
.field input[type=text],
.field input[type=email],
.field textarea {
  width: 100%; padding: 12px 14px; border-radius: var(--radius);
  border: 1.5px solid var(--line); background: white; color: var(--cocoa);
  font: inherit; transition: border-color .15s, box-shadow .15s;
}
.field input:focus, .field textarea:focus {
  outline: none; border-color: var(--pink);
  box-shadow: 0 0 0 3px rgba(199, 110, 114, 0.15);
}
.field__help { font-size: 0.85rem; color: var(--cocoa-muted); margin: 6px 0 0; }
.field--submit { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.field--turnstile { display: flex; justify-content: flex-start; }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ── Field legend (the "Inspiration photos" label) ─────────────
   Looks like a normal field label but isn't a <label> because the
   real <label> sits inside the picker on the drop-zone itself. */
.field__legend {
  display: block;
  font-weight: 600;
  margin-bottom: 6px;
  font-size: 0.95rem;
}
.field__legend-soft {
  color: var(--cocoa-muted);
  font-weight: 500;
  font-size: 0.85rem;
}

/* ── Photo picker (contact form) ───────────────────────────────
   A styled drop zone + thumbnail grid that replaces the default
   browser file UI. The hidden <input> stays focusable for
   keyboard users; the visible label is the actual click target. */
.photo-picker { position: relative; }
.photo-picker__zone {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 28px 20px;
  background: var(--cream);
  border: 2px dashed var(--line);
  border-radius: var(--radius-l);
  cursor: pointer;
  text-align: center;
  transition: border-color .15s, background-color .15s, transform .1s;
}
.photo-picker__zone:hover {
  border-color: var(--pink);
  background-color: var(--pink-soft);
}
.photo-picker__zone--dragover {
  border-color: var(--pink-strong);
  background-color: var(--pink-soft);
  transform: scale(1.005);
}
.photo-picker__input:focus-visible + .photo-picker__zone {
  outline: 2px solid var(--pink-strong);
  outline-offset: 3px;
}
.photo-picker__icon {
  width: 36px; height: 36px; color: var(--pink-strong);
  display: block;
}
.photo-picker__title {
  font-weight: 600; font-size: 1rem; color: var(--cocoa);
}
.photo-picker__hint {
  font-size: 0.82rem; color: var(--cocoa-muted);
  max-width: 38ch;
}
.photo-picker--full .photo-picker__zone {
  cursor: not-allowed;
  opacity: 0.6;
}
.photo-picker__grid[hidden] { display: none; }
.photo-picker__grid {
  list-style: none; padding: 0; margin: 14px 0 0;
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}
.photo-picker__item {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--cream-deeper);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.photo-picker__item img {
  width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.photo-picker__name {
  position: absolute; left: 6px; right: 32px; bottom: 6px;
  background: rgba(58, 38, 28, 0.7);
  color: var(--cream);
  font-size: 0.7rem;
  padding: 2px 6px;
  border-radius: 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  pointer-events: none;
  /* Only show the name when the image preview fell back to a
     placeholder (HEIC on a non-Safari desktop, etc.). */
  display: none;
}
.photo-picker__item--placeholder {
  display: flex; align-items: center; justify-content: center;
  color: var(--cocoa-muted);
  font-size: 0.85rem;
}
.photo-picker__item--placeholder::before {
  content: "📷";
  font-size: 1.8rem;
  position: absolute;
  top: 24%; left: 0; right: 0;
  text-align: center;
  opacity: 0.6;
}
.photo-picker__item--placeholder .photo-picker__name {
  display: block;
  left: 4px; right: 4px; bottom: 4px;
  text-align: center;
  white-space: normal;
}
.photo-picker__remove {
  position: absolute;
  top: 6px; right: 6px;
  width: 24px; height: 24px;
  background: rgba(255, 255, 255, 0.95);
  color: var(--cocoa);
  border: 1px solid var(--line);
  border-radius: 50%;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  padding: 0;
  transition: background-color .15s, color .15s, transform .1s;
}
.photo-picker__remove:hover {
  background: var(--pink-strong);
  color: var(--cream);
  border-color: var(--pink-strong);
  transform: scale(1.05);
}
.photo-picker__status {
  margin: 8px 0 0;
  font-size: 0.82rem;
  color: var(--cocoa-muted);
  min-height: 1.2em;
}
.photo-picker__status[data-kind="error"] {
  color: var(--pink-strong);
}

/* ── Inline upload progress for the contact form ──────────────
   Shown while client-side photo resizing runs, then upload
   bytes, then while the server processes + sends the email. */
.contact-progress {
  margin: 14px 0 0;
  padding: 14px 16px;
  background: var(--cream);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.contact-progress[hidden] { display: none; }
.contact-progress__title {
  margin: 0 0 8px;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--cocoa);
}
.contact-progress__bar {
  height: 10px;
  background: var(--pink-soft);
  border-radius: 999px;
  overflow: hidden;
  border: 1px solid var(--line);
}
.contact-progress__fill {
  height: 100%; width: 0%;
  background: var(--pink-strong);
  border-radius: inherit;
  transition: width .2s ease-out;
}
.contact-progress--indeterminate .contact-progress__fill {
  width: 100% !important;
  background-image: linear-gradient(
    90deg,
    var(--pink-strong) 0%,
    var(--pink) 50%,
    var(--pink-strong) 100%
  );
  background-size: 200% 100%;
  animation: contact-progress-stripe 1.2s linear infinite;
}
@keyframes contact-progress-stripe {
  from { background-position:   0% 0%; }
  to   { background-position: 200% 0%; }
}
.contact-progress__sub {
  margin: 6px 0 0;
  font-size: 0.82rem;
  color: var(--cocoa-muted);
  min-height: 1.2em;
}
@media (prefers-reduced-motion: reduce) {
  .contact-progress__fill { transition: none; }
  .contact-progress--indeterminate .contact-progress__fill { animation: none; }
}

/* ── Sent-confirmation modal ──────────────────────────────────
   Pops up on JS submit success so the customer sees the
   confirmation right where they were tapping, instead of having
   to scroll up past a long form on mobile. Uses the same brand
   green as the inline banner so it still reads as "success." */
.success-modal {
  position: fixed; inset: 0; z-index: 500;
  background: rgba(58, 38, 28, 0.55);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  animation: success-fade-in 0.22s ease-out;
}
.success-modal[hidden] { display: none; }
@keyframes success-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.success-modal__card {
  background: white;
  border-radius: var(--radius-l);
  padding: 32px 28px 24px;
  text-align: center;
  width: min(380px, 100%);
  box-shadow: var(--shadow-lg);
  animation: success-pop-in 0.42s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes success-pop-in {
  from { transform: scale(0.85); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}

.success-modal__check {
  width: 96px; height: 96px;
  margin: 0 auto 18px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--success-bg);
}
.success-modal__check svg { width: 76px; height: 76px; }

/* The circle and tick are drawn via stroke-dashoffset animation
   so the user sees them sketch themselves in — circle first,
   then the check mark over the top. The dasharray values match
   the path lengths (circle = 2π·36 ≈ 226, tick ≈ 60). */
.success-modal__circle,
.success-modal__tick {
  fill: none;
  stroke: var(--success-fg);
  stroke-linecap: round;
  stroke-linejoin: round;
}
.success-modal__circle {
  stroke-width: 4;
  stroke-dasharray: 226;
  stroke-dashoffset: 226;
  animation: success-draw-circle 0.5s ease-out 0.1s forwards;
  transform-origin: center;
  transform: rotate(-90deg);
}
.success-modal__tick {
  stroke-width: 6;
  stroke-dasharray: 60;
  stroke-dashoffset: 60;
  animation: success-draw-tick 0.35s ease-out 0.55s forwards;
}
@keyframes success-draw-circle {
  to { stroke-dashoffset: 0; }
}
@keyframes success-draw-tick {
  to { stroke-dashoffset: 0; }
}

.success-modal__title {
  margin: 0 0 6px;
  color: var(--cocoa);
  font-family: var(--serif);
  font-size: 1.5rem;
  line-height: 1.15;
}
.success-modal__body {
  margin: 0 0 14px;
  color: var(--cocoa-muted);
  font-size: 0.95rem;
}
.success-modal__warnings {
  margin: 0 0 14px;
  color: var(--cocoa-muted);
  font-size: 0.82rem;
  padding: 8px 12px;
  background: var(--cream);
  border-radius: var(--radius);
}
.success-modal__warnings[hidden] { display: none; }
.success-modal__close {
  background: var(--success-fg);
  color: var(--cream);
  border-color: var(--success-fg);
  padding: 8px 22px;
}
.success-modal__close:hover {
  background: #234820;
  border-color: #234820;
  color: var(--cream);
}

@media (prefers-reduced-motion: reduce) {
  .success-modal,
  .success-modal__card { animation: none; }
  .success-modal__circle,
  .success-modal__tick { stroke-dashoffset: 0; animation: none; }
}

/* ── Banners ─────────────────────────────────────────────── */
.banner {
  border-radius: var(--radius); padding: 16px 20px; margin: 0 auto 24px;
  max-width: 800px;
}
.banner ul { margin: 8px 0 0; padding-left: 1.2em; }
.banner--success { background: var(--success-bg); color: var(--success-fg); }
.banner--error   { background: var(--error-bg);   color: var(--error-fg); }
.banner--warning { background: var(--warning-bg); color: var(--warning-fg); }

/* ── Admin ───────────────────────────────────────────────── */
.admin-upload, .admin-list {
  max-width: 1100px; margin: 0 auto; padding: 16px 24px 32px;
}
.admin-upload__form {
  background: white; padding: 24px; border-radius: var(--radius-l);
  border: 1px solid var(--line);
}

/* ── Photo upload drop-zone ─────────────────────────────────────── */
.upload-control { margin-bottom: 20px; }
.upload-control__input {
  /* Visually hidden but keyboard-focusable for accessibility. The
     label below is the actual visible/clickable target. */
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.upload-control__label {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 36px 24px;
  background: var(--cream);
  border: 2px dashed var(--line);
  border-radius: var(--radius-l);
  cursor: pointer;
  text-align: center;
  transition: border-color .15s ease, background-color .15s ease, transform .1s ease;
}
.upload-control__label:hover {
  border-color: var(--pink);
  background-color: var(--pink-soft);
}
.upload-control__label--dragover {
  border-color: var(--pink-strong);
  background-color: var(--pink-soft);
  transform: scale(1.01);
}
.upload-control__input:focus-visible + .upload-control__label {
  outline: 2px solid var(--pink-strong);
  outline-offset: 3px;
}
.upload-control__icon {
  width: 44px; height: 44px;
  color: var(--pink-strong);
  display: block;
}
.upload-control__title {
  font-weight: 600; font-size: 1.05rem; color: var(--cocoa);
  font-family: var(--sans);
}
.upload-control__hint {
  font-size: 0.85rem; color: var(--cocoa-muted);
  max-width: 36ch;
}
.upload-control__status {
  display: block;
  margin-top: 12px; padding: 10px 14px;
  background: var(--cream);
  border-radius: var(--radius);
  font-size: 0.9rem; color: var(--cocoa-muted);
  text-align: center;
  word-break: break-word;
  min-height: 1.5em;
  transition: background-color .15s ease, color .15s ease;
}
.upload-control--has-files .upload-control__status {
  background: #e9f4e6;
  color: #2e5e2a;
  font-weight: 500;
}

/* ── Pre-upload album picker ────────────────────────────────────
   Lets her choose which albums the whole batch lands in before
   submitting. Empty selection = unassigned (hidden from /gallery
   until she tags them). */
.upload-control__albums {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin: 0 0 16px;
  background: var(--cream);
}
.upload-control__albums legend {
  padding: 0 6px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--cocoa);
}
.upload-control__albums-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 6px 14px;
  margin: 6px 0;
}
.upload-control__albums-hint {
  margin: 8px 0 0;
  font-size: 0.78rem;
  color: var(--cocoa-muted);
}

/* ── Upload progress overlay ────────────────────────────────────
   Shown by upload-files.js while a multipart POST is in flight.
   Covers the viewport so the user can't accidentally navigate
   away mid-upload (especially on mobile, where the only other
   feedback is the tiny browser progress hairline). */
.upload-progress {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(58, 38, 28, 0.55); /* --cocoa @ 55% */
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.upload-progress[hidden] { display: none; }
.upload-progress__card {
  width: min(440px, 100%);
  background: var(--cream);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-lg);
  padding: 28px 24px;
  text-align: center;
}
.upload-progress__title {
  font-family: var(--serif);
  font-size: 1.4rem;
  color: var(--cocoa);
  margin: 0 0 18px;
}
.upload-progress__bar {
  height: 14px;
  background: var(--pink-soft);
  border-radius: 999px;
  overflow: hidden;
  border: 1px solid var(--line);
}
.upload-progress__fill {
  height: 100%; width: 0%;
  background: var(--pink-strong);
  border-radius: inherit;
  transition: width .2s ease-out;
}
/* Indeterminate: bytes are uploaded but the server is still
   processing (Sharp resize, hashing, writes). Animate a moving
   stripe so it's clearly still "working" rather than stalled. */
.upload-progress--indeterminate .upload-progress__fill {
  width: 100% !important;
  background-image: linear-gradient(
    90deg,
    var(--pink-strong) 0%,
    var(--pink) 50%,
    var(--pink-strong) 100%
  );
  background-size: 200% 100%;
  animation: upload-progress-stripe 1.2s linear infinite;
}
@keyframes upload-progress-stripe {
  from { background-position:   0% 0%; }
  to   { background-position: 200% 0%; }
}
.upload-progress__status {
  margin: 14px 0 0;
  font-size: 0.95rem;
  color: var(--cocoa);
  font-weight: 500;
  min-height: 1.3em;
}
.upload-progress__hint {
  margin: 6px 0 0;
  font-size: 0.85rem;
  color: var(--cocoa-muted);
}
.upload-progress--error .upload-progress__title { color: var(--pink-strong); }
.upload-progress--error .upload-progress__fill  { background: var(--pink); animation: none; }
@media (prefers-reduced-motion: reduce) {
  .upload-progress__fill { transition: none; }
  .upload-progress--indeterminate .upload-progress__fill { animation: none; }
}
.admin-grid {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: 20px; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.admin-grid__item {
  background: white; border-radius: var(--radius); border: 1px solid var(--line);
  padding: 12px; display: flex; flex-direction: column; gap: 8px;
  transition: opacity .18s ease, transform .25s ease;
}
.admin-grid__item img {
  width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: var(--radius);
}
.admin-grid__delete { text-align: right; }
.admin-grid__meta { font-size: 0.8rem; color: var(--cocoa-muted); margin: 0; }

/* ── Inline (async) delete states ───────────────────────────────
   The admin.js progressive enhancement removes photos in place so
   the page doesn't reload mid-prune. While the fetch is in flight
   the item dims and ignores clicks; once the server says it's
   gone we fade+shrink it out before yanking it from the DOM. */
.admin-grid__item--deleting {
  opacity: .55;
  pointer-events: none;
}
.admin-grid__item--gone {
  opacity: 0;
  transform: scale(.94);
}
.admin-grid__delete-error {
  margin: 4px 0 0;
  font-size: 0.8rem;
  color: var(--pink-strong);
  text-align: right;
}

/* ── Album chips on a photo card ─────────────────────────────────
   The chips show the current memberships at a glance; the <details>
   below opens a checkbox list to edit them. */
.album-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--pink-soft);
  color: var(--cocoa);
  font-size: 0.72rem;
  font-weight: 500;
  padding: 2px 8px;
  border-radius: 999px;
  margin: 0 4px 4px 0;
  line-height: 1.4;
}
/* Button-shaped chips need a button reset + a cursor + a touch of
   feedback on focus/hover so the click affordance reads. */
button.album-chip {
  border: 1px solid transparent;
  font-family: inherit;
  cursor: pointer;
}
button.album-chip:hover {
  border-color: var(--pink);
}
button.album-chip:focus-visible {
  outline: 2px solid var(--pink-strong);
  outline-offset: 1px;
}
.album-chip__star {
  font-size: 0.7rem;
  color: var(--cocoa-muted);
  opacity: 0.4;
  transition: color .15s, opacity .15s;
}
.album-chip--cover {
  background: var(--pink);
  color: var(--cocoa);
}
.album-chip--cover .album-chip__star {
  color: #b8860b; /* warm gold so the "cover" state reads at a glance */
  opacity: 1;
}
.admin-grid__chips {
  margin: 0;
  display: flex; flex-wrap: wrap; gap: 0;
  min-height: 1.2em;
}
.admin-grid__chips--empty {
  font-size: 0.78rem;
  color: var(--cocoa-muted);
  font-style: italic;
}
.admin-grid__albums-edit > summary {
  cursor: pointer;
  font-size: 0.8rem;
  color: var(--pink-strong);
  list-style: none; /* Safari */
  padding: 4px 0;
  user-select: none;
}
.admin-grid__albums-edit > summary::-webkit-details-marker { display: none; }
.admin-grid__albums-edit > summary::before {
  content: "+ ";
  font-weight: 600;
}
.admin-grid__albums-edit[open] > summary::before { content: "− "; }
.admin-grid__albums-form {
  display: flex; flex-direction: column; gap: 4px;
  padding: 8px 10px;
  background: var(--cream);
  border-radius: var(--radius);
  margin-top: 4px;
}
.album-check {
  display: flex; align-items: center; gap: 6px;
  font-size: 0.85rem;
  color: var(--cocoa);
}
.admin-grid__albums-actions {
  display: flex; align-items: center; gap: 8px; margin-top: 6px;
}
.admin-grid__albums-status {
  font-size: 0.75rem;
  min-width: 1ch;
}
.admin-grid__albums-status[data-kind="pending"] { color: var(--cocoa-muted); }
.admin-grid__albums-status[data-kind="success"] { color: #2e5e2a; font-weight: 500; }
.admin-grid__albums-status[data-kind="error"]   { color: var(--pink-strong); }

/* Auto-album cover toggles inside the per-photo editor. The chip
   styling is shared with the user-album chips, but they sit in a
   separate row beneath the save button with a small hint. */
.admin-grid__auto-covers {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px dashed var(--line);
}
.admin-grid__auto-covers-hint {
  margin: 0 0 4px;
  font-size: 0.75rem;
  color: var(--cocoa-muted);
}

/* ── Albums admin section ────────────────────────────────────── */
.admin-albums {
  max-width: 1100px; margin: 0 auto; padding: 16px 24px 24px;
}
.admin-albums__hint {
  color: var(--cocoa-muted);
  font-size: 0.9rem;
  margin: 0 0 14px;
}
.admin-albums__create {
  display: flex; gap: 8px; flex-wrap: wrap;
  background: white;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin-bottom: 16px;
}
.admin-albums__create input[type="text"] {
  flex: 1; min-width: 200px;
  font: inherit; padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--cocoa);
}
.admin-albums__create input[type="text"]:focus-visible {
  outline: 2px solid var(--pink-strong); outline-offset: 1px;
}
.admin-albums__list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.admin-album {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  background: white;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 14px;
}
.admin-album__rename {
  display: inline-flex; align-items: center; gap: 6px; margin: 0;
}
.admin-album__rename input[type="text"] {
  font: inherit; padding: 4px 8px;
  border: 1px solid var(--line); border-radius: 6px;
  color: var(--cocoa); min-width: 160px;
}
.admin-album__rename input[type="text"]:focus-visible {
  outline: 2px solid var(--pink-strong); outline-offset: 1px;
}
.admin-album__count {
  font-size: 0.82rem; color: var(--cocoa-muted);
}
.admin-album__badge {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--cream-deeper);
  color: var(--cocoa-muted);
  padding: 2px 8px;
  border-radius: 999px;
  cursor: help;
}
.admin-album--auto { background: var(--cream); }
.admin-album__slug {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.78rem;
  color: var(--cocoa-muted);
  text-decoration: none;
}
.admin-album__slug:hover { color: var(--pink-strong); text-decoration: underline; }
.admin-album__delete { margin-left: auto; }

/* ── Admin: theme preview ───────────────────────────────────── */
.admin-theme {
  max-width: 1100px; margin: 0 auto; padding: 16px 24px 24px;
}
.admin-theme__hint {
  color: var(--cocoa-muted);
  font-size: 0.9rem;
  margin: 0 0 12px;
  max-width: 70ch;
}
.admin-theme__status {
  background: white;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin: 0 0 12px;
  font-size: 0.92rem;
  color: var(--cocoa);
}
.admin-theme__status--preview {
  background: var(--cream-deeper);
  border-color: var(--pink-strong);
}
.admin-theme__list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-wrap: wrap; gap: 8px;
}
.admin-theme__list li { margin: 0; }

/* ── Bulk select mode on the photo grid ────────────────────────
   .select-mode on <body> activates an invisible label overlay on
   each photo card so taps select instead of triggering inline
   chip/edit/delete actions. */
.admin-list__select-toggle {
  margin-left: 12px;
  font-size: 0.8rem;
  font-weight: 500;
  vertical-align: middle;
}
body.select-mode .admin-list__select-toggle {
  background: var(--pink-strong);
  color: var(--cream);
  border-color: var(--pink-strong);
}
/* Reserve space below the fold so the fixed action bar doesn't sit
   on top of the last row of photos. Includes the iOS safe area so
   the bar clears the home-indicator strip. */
body.select-mode {
  padding-bottom: calc(80px + env(safe-area-inset-bottom));
}
.admin-grid__item { position: relative; }
.admin-grid__select { display: none; }
body.select-mode .admin-grid__select {
  display: block;
  position: absolute; inset: 0;
  z-index: 5;
  cursor: pointer;
}
.admin-grid__select-indicator {
  position: absolute;
  top: 10px; left: 10px;
  width: 28px; height: 28px;
  border-radius: 50%;
  background: rgba(255,255,255,0.92);
  border: 2px solid var(--pink);
  display: flex; align-items: center; justify-content: center;
  color: transparent;
  font-size: 1rem; font-weight: 700;
  transition: background-color .15s, color .15s, transform .12s;
}
.admin-grid__select-checkbox:checked + .admin-grid__select-indicator {
  background: var(--pink-strong);
  border-color: var(--pink-strong);
  color: var(--cream);
  transform: scale(1.05);
}
.admin-grid__item--selected {
  outline: 3px solid var(--pink-strong);
  outline-offset: -2px;
}
/* In select mode, suppress the inline controls so taps go to the
   label overlay instead of the chips/edit/delete forms. */
body.select-mode .admin-grid__chips,
body.select-mode .admin-grid__albums-edit,
body.select-mode .admin-grid__delete,
body.select-mode .admin-grid__meta {
  opacity: 0.5;
  pointer-events: none;
}

/* ── Bulk action bar + album picker overlay ───────────────────── */
.bulk-actions {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  background: white;
  border-top: 1px solid var(--line);
  box-shadow: 0 -6px 18px rgba(58, 38, 28, 0.08);
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  display: flex; align-items: center; gap: 10px;
  z-index: 100;
}
.bulk-actions[hidden] { display: none; }
.bulk-actions__count {
  font-weight: 600;
  color: var(--cocoa);
  margin-right: auto;
}

.bulk-picker {
  position: fixed; inset: 0; z-index: 110;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  background: rgba(58, 38, 28, 0.55);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.bulk-picker[hidden] { display: none; }
.bulk-picker__card {
  background: var(--cream);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-lg);
  padding: 22px 22px 18px;
  width: min(500px, 100%);
  max-height: 90vh;
  overflow-y: auto;
}
.bulk-picker__title {
  font-family: var(--serif);
  font-size: 1.3rem;
  margin: 0 0 14px;
  color: var(--cocoa);
}
.bulk-picker__fieldset {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin: 0 0 12px;
  background: white;
}
.bulk-picker__fieldset legend {
  padding: 0 6px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--cocoa);
}
.bulk-picker__mode {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 4px 0;
  font-size: 0.9rem;
  color: var(--cocoa);
}
.bulk-picker__actions {
  display: flex; gap: 10px; justify-content: flex-end;
  margin-top: 6px;
}

.admin-album__move {
  display: inline-flex; flex-direction: column; gap: 2px;
}
.admin-album__move form { margin: 0; line-height: 0; }
.btn--icon {
  padding: 2px 8px;
  font-size: 0.85rem;
  background: white;
  color: var(--cocoa);
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
  line-height: 1.1;
  min-width: 28px;
}
.btn--icon:hover:not(:disabled) {
  background: var(--pink-soft);
  border-color: var(--pink);
}
.btn--icon:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
  .admin-grid__item { transition: opacity .12s ease; }
  .admin-grid__item--gone { transform: none; }
}

/* ── Stars (display) ─────────────────────────────────────── */
.stars {
  color: #f5b800;            /* saturated gold; reads on both cream and white */
  font-size: 1.1rem;
  letter-spacing: 1px;
  line-height: 1;
  display: inline-block;
  white-space: nowrap;
}
.stars--inline { font-size: 1rem; vertical-align: -1px; }
.reviews-summary { color: var(--cocoa-muted); margin-left: 6px; }

/* ── Star rating widget (form) ───────────────────────────────────── */
/* Real radios for keyboard + screen-reader + no-JS support, hidden via
   the visually-hidden pattern (clip-path) so they can't leak through
   any mobile browser's native rendering. Labels carry inline SVG
   stars — consistent across iOS/Android/desktop, no glyph/emoji
   surprises.

   DOM order is 5→1 so the CSS general-sibling combinator (~) can
   light up "this star and every star visually before it" when one is
   hovered or checked. */
.star-rating {
  border: 0; padding: 0; margin: 0;
  display: inline-flex; flex-direction: row-reverse;
  gap: 4px;
  justify-content: flex-end;
}
.star-rating input {
  -webkit-appearance: none;
  appearance: none;
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.star-rating__star {
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px;
  border-radius: 14px;
  -webkit-tap-highlight-color: transparent;
  transition: background-color .15s ease;
}
.star-rating__star svg {
  display: block;            /* kills inline-SVG baseline alignment so the
                                star centers in the label instead of
                                sitting in the upper-left */
  width: 44px; height: 44px;
  fill: #ecdec6;            /* soft beige — empty state */
  stroke: #d4be9f;
  stroke-width: 0.75;
  stroke-linejoin: round;
  transition: fill .15s ease, stroke .15s ease, transform .12s ease;
  filter: drop-shadow(0 1px 1px rgba(58, 38, 28, 0.04));
}

/* Hover: fill this star + every later one in DOM (= every earlier
   one visually, since we're row-reverse). */
.star-rating__star:hover svg,
.star-rating__star:hover ~ .star-rating__star svg {
  fill: #fbc02d;            /* bright gold */
  stroke: #e0a800;
  filter: drop-shadow(0 2px 4px rgba(245, 184, 0, 0.4));
}
.star-rating__star:hover {
  background-color: rgba(251, 192, 45, 0.12);
}
.star-rating__star:active svg {
  transform: scale(0.88);
}

/* Checked state — persists when not hovering. */
.star-rating input:checked ~ .star-rating__star svg {
  fill: #f5b800;            /* rich saturated gold */
  stroke: #c79200;          /* gold-amber stroke, not brown */
  filter: drop-shadow(0 2px 4px rgba(245, 184, 0, 0.35));
}

/* Keyboard focus ring on the label of whichever radio is focused. */
.star-rating input:focus-visible + .star-rating__star {
  outline: 2px solid var(--pink-strong);
  outline-offset: 2px;
}

/* Mobile: even bigger tap targets, slightly tighter gap. */
@media (max-width: 520px) {
  .star-rating { gap: 2px; }
  .star-rating__star { width: 60px; height: 60px; border-radius: 16px; }
  .star-rating__star svg { width: 50px; height: 50px; }
}

.field__label-text {
  display: block; font-weight: 600; margin-bottom: 10px; font-size: 0.95rem;
}

/* ── Review cards (shared between /reviews and home) ─────── */
.review-card {
  background: white;
  border: 1px solid var(--line);
  border-radius: var(--radius-l);
  padding: 20px 22px;
  box-shadow: var(--shadow-sm);
  list-style: none;
}
.review-card__top {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 10px;
}
.review-card__occasion {
  background: var(--pink-soft); color: var(--cocoa);
  font-size: 0.8rem; padding: 2px 10px; border-radius: 999px;
  font-weight: 500;
}
.review-card__text {
  margin: 0 0 12px; color: var(--cocoa); line-height: 1.55;
}
.review-card__meta {
  margin: 0; color: var(--cocoa-muted); font-size: 0.9rem;
}
.review-card__date { margin-left: 8px; color: var(--taupe); font-size: 0.85rem; }

/* Line-clamp the home-page version so cards line up visually. */
.review-card--clamp .review-card__text {
  display: -webkit-box;
  -webkit-line-clamp: 5;
  line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ── Reviews list (full /reviews page) ───────────────────── */
.reviews-list {
  max-width: 900px; margin: 0 auto; padding: 0 24px 48px;
  display: grid; gap: 18px;
}

/* ── Reviews form section ────────────────────────────────── */
.reviews-form {
  max-width: 640px; margin: 0 auto; padding: 32px 24px 80px;
}
.reviews-form__lede {
  color: var(--cocoa-muted); margin-bottom: 24px;
}

/* ── Home page reviews section ───────────────────────────── */
.home-reviews {
  background: var(--cream-deeper);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 56px 24px;
}
.home-reviews__head {
  max-width: 1100px; margin: 0 auto 28px;
  display: flex; justify-content: space-between; align-items: baseline;
  flex-wrap: wrap; gap: 12px;
}
.home-reviews__head h2 { margin: 0; }
.home-reviews__summary { margin: 0; color: var(--cocoa-muted); }
.home-reviews__list {
  list-style: none; padding: 0; margin: 0 auto;
  max-width: 1100px;
  display: grid; gap: 16px; grid-template-columns: 1fr;
}
@media (min-width: 760px) {
  .home-reviews__list { grid-template-columns: repeat(3, 1fr); }
}
.home-reviews__cta { text-align: center; margin: 32px 0 0; }

/* ── Admin: jump nav + review queue ──────────────────────── */
.admin-jump {
  margin-top: 8px; display: flex; gap: 16px; justify-content: center;
  flex-wrap: wrap;
}
.admin-jump a {
  color: var(--cocoa); text-decoration: none; font-weight: 600;
  padding: 6px 14px; border: 1px solid var(--line); border-radius: 999px;
  background: white;
}
.admin-jump a:hover { background: var(--pink-soft); }
.admin-jump__badge {
  display: inline-block; background: var(--pink-strong); color: var(--cream);
  font-size: 0.75rem; padding: 1px 8px; border-radius: 999px;
  margin-left: 4px; font-weight: 700; vertical-align: 1px;
}

.admin-reviews, .admin-photos {
  max-width: 1100px; margin: 0 auto; padding: 16px 24px 32px;
}
.admin-reviews h3, .admin-photos h3 {
  margin-top: 24px; font-family: var(--sans); font-size: 1rem;
  color: var(--cocoa-muted); font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.05em;
}

.admin-review-list {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: 12px;
}
.admin-review {
  background: white; border: 1px solid var(--line);
  border-radius: var(--radius); padding: 16px 18px;
}
.admin-review--approved { background: #f8f5ef; }
.admin-review__top {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  font-size: 0.9rem; color: var(--cocoa-muted); margin-bottom: 10px;
}
.admin-review__top strong { color: var(--cocoa); }
.admin-review__occasion {
  background: var(--pink-soft); color: var(--cocoa);
  font-size: 0.75rem; padding: 1px 8px; border-radius: 999px;
}
.admin-review__date, .admin-review__ip { color: var(--taupe); font-size: 0.8rem; }
.admin-review__ip { margin-left: auto; }

/* ── Approved-review date editor (inline) ────────────────────────
   Sits inside .admin-review__top alongside the name + occasion.
   Used to backdate reviews ported from the old site so they sort
   into the right spot on /reviews. */
.admin-review__date-form {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 0; /* form default */
  font-size: 0.8rem;
}
.admin-review__date-label { color: var(--cocoa-muted); }
.admin-review__date-input {
  font: inherit;
  padding: 2px 6px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: white;
  color: var(--cocoa);
  min-height: 28px;
}
.admin-review__date-input:focus-visible {
  outline: 2px solid var(--pink-strong);
  outline-offset: 1px;
}
.admin-review__date-save {
  /* Tighter than the default btn--small for the inline row. */
  padding: 2px 10px;
  font-size: 0.75rem;
}
.admin-review__date-status {
  font-size: 0.75rem;
  min-width: 1ch;
}
.admin-review__date-status[data-kind="pending"] { color: var(--cocoa-muted); }
.admin-review__date-status[data-kind="success"] { color: #2e5e2a; font-weight: 500; }
.admin-review__date-status[data-kind="error"]   { color: var(--pink-strong); }
.admin-review__text {
  margin: 0 0 12px; color: var(--cocoa); white-space: pre-wrap;
  line-height: 1.5;
}
.admin-review__actions {
  display: flex; gap: 8px;
}
.admin-review__actions form { margin: 0; }

.empty-state--inline {
  text-align: left; margin: 8px 0 16px; padding: 12px 16px;
  background: white; border: 1px dashed var(--line); border-radius: var(--radius);
}

/* ── Footer ──────────────────────────────────────────────── */
.site-footer {
  background: var(--cocoa); color: var(--cream); padding: 48px 24px;
  margin-top: 64px;
}
.site-footer__inner { max-width: 1000px; margin: 0 auto; text-align: center; }
.site-footer__brand-link {
  display: inline-block; margin: 0 auto 12px; text-decoration: none;
  /* Subtle light "card" behind the logo so the pastel illustration
     reads clearly against the dark footer background. */
  background: var(--cream);
  padding: 18px 24px;
  border-radius: var(--radius-l);
}
.site-footer__logo {
  display: block; width: 100%; max-width: 220px; height: auto;
}
.site-footer__tagline { color: rgba(251, 246, 240, 0.7); margin: 4px 0 24px; }
.site-footer__social {
  list-style: none; padding: 0; margin: 0 0 24px;
  display: flex; gap: 24px; justify-content: center; flex-wrap: wrap;
}
.site-footer__social a { color: var(--cream); text-decoration: none; font-weight: 500; }
.site-footer__social a:hover { color: var(--pink-soft); }
.site-footer__legal { color: rgba(251, 246, 240, 0.5); font-size: 0.85rem; margin: 0; }
.site-footer__legal-link { color: rgba(251, 246, 240, 0.75); text-decoration: underline; text-underline-offset: 2px; }
.site-footer__legal-link:hover { color: var(--pink-soft); }
