/* =============================================================================
   ThornBloom Wedding Websites, Card Motion Layer
   File 1 of 2 (companion: card-motion.js)

   WHAT THIS IS
   A drop-in interaction layer for the V2 wedding-website theme (EF / DR / MC / OV).
   It adds tap-parity, lift, glow, list-row nudges, a per-card scroll reveal and an
   optional desktop pointer tilt to the card-like components that already exist in
   each theme's sections.css. It does NOT add markup, sections or new selectors to
   the templates, every rule below targets class names that already ship in all
   four theme copies of sections.css (verified identical 43-selector set across
   demo-dark-romance, demo-enchanted-forest, demo-midnight-celestial and
   demo-obsidian-vow on 2026-09-27).

   LOAD ORDER (required)
   Enqueue this file AFTER design-tokens.css and sections.css on every theme.
   Nothing here uses !important, it relies on cascade order to layer transform/
   filter/box-shadow rules on top of each theme's existing color/background rules
   without touching them.

   FILE ORDER MATTERS (read this before editing)
   §1 (scroll reveal) is deliberately the FIRST rule block after :root, before
   every hover/active rule. Its resting state (.tb-cm-reveal.tb-cm-in) sets
   `transform: none` at the same specificity (0,2,0) as most of the hover/active
   transform rules below it. CSS resolves same-specificity ties by source order,
   so the reveal's resting transform must come EARLIER in the file than any rule
   that needs to override it on hover/active, or the card would scroll into view,
   settle, and then silently stop responding to hover/tap. This was caught during
   prototype testing on 2026-09-27 (computed style check on a hovered, already-
   revealed .sched-item showed no translateX until this reorder), do not move
   §1 back below the interactive sections.

   SCOPE, properties touched: transform, opacity, filter, box-shadow, background
   (only for the thin nudge bar and shimmer, both cheap compositor paints).
   Nothing here animates width, height, top/left, margin or any layout property.

   THEME TOKENS
   DR / EF / MC already define --gold, --rule, --rule-bright, --pitch. Obsidian
   Vow does not (it uses --hairline, --frame, --wine-rule, --gunmetal, --ground, see shared/visual-style-guide.md §4, no metallic gold, "cold, expensive,
   restrained"). The --cm-* custom properties below resolve per realm through a
   fallback chain so ONE file works everywhere, but each realm's own template
   should also set the four --cm-* values explicitly in its design-tokens.css for
   full art-direction control instead of relying on the fallback guess, see
   SPEC.md "Per-realm token notes" for the exact values to paste into each theme.
   ============================================================================= */

:root {
  /* Accent used for glow rings, corner ornament brighten and the button shimmer.
     Falls back: theme's own bright-rule token -> theme's own gold -> a neutral
     pewter-white so Obsidian Vow (no gold) still gets a correct, COLD glow
     instead of an incorrect warm one. */
  --cm-glow: var(--rule-bright, var(--gold, rgba(223, 225, 229, 0.45)));

  /* Elevation shadow for lifted cards, always neutral black, theme-agnostic. */
  --cm-lift-shadow: 0 22px 46px -12px rgba(0, 0, 0, 0.6), 0 8px 18px -6px rgba(0, 0, 0, 0.45);

  /* Motion constants */
  --cm-ease: cubic-bezier(0.25, 1, 0.5, 1);
  --cm-lift-y: -6px;
  --cm-lift-scale: 1.012;
  --cm-nudge-x: 6px;
}

/* =============================================================================
   1. PER-CARD SCROLL REVEAL (placed first, see "FILE ORDER MATTERS" above).
   Distinct from the theme's existing SECTION-level .reveal/.in (design-tokens.css
   / site.js), which fades in whole <section> elements. This is a second, finer
   layer added by card-motion.js that fades+lifts individual cards with a short
   stagger. Deliberately EXCLUDES .choice-card, .rstep-*, .pstep-* and anything
   inside #rsvp-app, that subtree has its own step-transition show/hide logic in
   site.js and must not be given a second, conflicting opacity/visibility state.
   The transition below is a fallback only: most cards redeclare `transition`
   later in this file, so card-motion.js applies the reveal transition and its
   stagger delay inline while the card fades in, then clears both (2026-09-27).
   ============================================================================= */
.tb-cm-reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s var(--cm-ease), transform 0.7s var(--cm-ease);
}
.tb-cm-reveal.tb-cm-in {
  opacity: 1;
  transform: none;
}

/* =============================================================================
   2. TAP PARITY, the highest-value, lowest-risk fix.
   sections.css (all four themes, audited 2026-09-27) ships 20 distinct :hover
   rules and ZERO :active rules. On a phone there is no :hover, so every one of
   these affordances currently gives no feedback at all on tap. Mirroring :hover
   onto :active for the existing color/border/background rules is copy-friendly
   (no new selectors), but the DECLARATIONS still need to live somewhere, this
   file supplies :active in tandem with every NEW rule below (lift, nudge, glow),
   which covers every card-like element in the brief. Website Manager: the four
   remaining non-card :hover rules that this layer does not touch (.hashtag-tag,
   .song-cta, .cal-google, .wde-cal-link, .rec-link, .faq-mailto, .rsvp-amend-toggle)
   are plain text-color links already covered by ::after underline/shimmer rules
   below wherever they share .btn-gold/.btn-ghost; the rest are low-priority and
   out of scope for this pass.
   ============================================================================= */

/* =============================================================================
   3. BUTTONS, .btn-gold, .btn-ghost, .cal-btn
   Diagonal shimmer sweep (one-shot on trigger, not looping) + lift + tap parity.
   currentColor is used for the shimmer so it auto-adapts to each theme's button
   text color (warm bone/gold on DR-EF-MC, cool pewter on OV) with no per-realm
   override needed.
   ============================================================================= */
.btn-gold,
.btn-ghost,
.cal-btn {
  position: relative;
  overflow: hidden;
  transform: translateY(0) scale(1);
  transition: transform 0.4s var(--cm-ease), box-shadow 0.4s var(--cm-ease);
}

.btn-gold::after,
.btn-ghost::after,
.cal-btn::after {
  content: '';
  position: absolute;
  top: -60%;
  left: -60%;
  width: 60%;
  height: 220%;
  background: linear-gradient(60deg, transparent 30%, currentColor 50%, transparent 70%);
  opacity: 0.22;
  transform: rotate(20deg) translateX(-220%);
  transition: transform 0.75s ease;
  pointer-events: none;
}

.btn-gold:hover,
.btn-gold:active,
.btn-ghost:hover,
.btn-ghost:active,
.cal-btn:hover,
.cal-btn:active {
  transform: translateY(-2px) scale(1.015);
  box-shadow: var(--cm-lift-shadow);
}

.btn-gold:hover::after,
.btn-gold:active::after,
.btn-ghost:hover::after,
.btn-ghost:active::after,
.cal-btn:hover::after,
.cal-btn:active::after {
  transform: rotate(20deg) translateX(420%);
}

/* =============================================================================
   4. FREESTANDING BOXED CARDS, full lift + glow, hover AND active (tap).
   These already sit as independent bordered/isolated units in every theme
   (not sharing a hairline with a neighbour), so a vertical lift reads cleanly.
   .choice-card, .registry-card, .party-person, .pstep-num (the step numeral only).
   ============================================================================= */
.choice-card,
.registry-card,
.party-person .pp-portrait,
.rsvp-pstep .pstep-num {
  transform: translateY(0) scale(1);
  transition: transform 0.5s var(--cm-ease), box-shadow 0.5s var(--cm-ease), filter 0.4s ease;
  will-change: transform;
}

.choice-card:hover,
.choice-card:active,
.registry-card:hover,
.registry-card:active {
  transform: translateY(var(--cm-lift-y)) scale(var(--cm-lift-scale));
  box-shadow: var(--cm-lift-shadow);
}

/* choice-card.selected keeps its existing inset glow from sections.css; we only
   add the lift, not a second background, so the two rules layer instead of fight. */
.choice-card.selected:hover,
.choice-card.selected:active {
  transform: translateY(calc(var(--cm-lift-y) * 0.6)) scale(1.006);
}

.party-person:hover .pp-portrait,
.party-person:active .pp-portrait {
  transform: translateY(-4px) scale(1.03);
}

.party-person:hover .pp-ring,
.party-person:active .pp-ring {
  filter: drop-shadow(0 0 8px var(--cm-glow));
}

.party-person .pp-photo {
  transition: transform 1s var(--cm-ease);
}

.party-person:hover .pp-photo,
.party-person:active .pp-photo {
  transform: scale(1.06);
}

.rsvp-pstep.active .pstep-num,
.rsvp-pstep.done .pstep-num {
  animation: cm-pstep-pop 0.4s var(--cm-ease);
}

@keyframes cm-pstep-pop {
  0% { transform: scale(0.85); }
  60% { transform: scale(1.08); }
  100% { transform: scale(1); }
}

/* =============================================================================
   5. TESSELLATED / MOSAIC COMPONENTS, glow only, deliberately no lift.
   .detail-tile and .g-tile are laid out edge-to-edge so a translateY lift would
   visually overlap the neighbouring tile's hairline (sections.css already sets
   "transform: none" on both of their :hover rules on purpose, see the inline
   comment on .detail-tile in every theme's sections.css re: the mosaic gaps).
   We respect that and add glow/brighten only, plus tap parity for the photo
   zoom that DR/EF/MC already wire on :hover but not :active.
   ============================================================================= */
.detail-tile {
  transition: background 0.6s ease, box-shadow 0.5s ease;
}

.detail-tile:hover,
.detail-tile:active {
  box-shadow: inset 0 0 0 1px var(--cm-glow), inset 0 0 32px -8px var(--cm-glow);
}

.detail-tile .dt-ornament {
  transition: filter 0.4s ease, opacity 0.4s ease;
}

.detail-tile:hover .dt-ornament,
.detail-tile:active .dt-ornament {
  opacity: 0.9;
  filter: drop-shadow(0 0 6px var(--cm-glow));
}

/* Tap parity for the gallery photo zoom (sections.css already has the :hover
   version of these two rules on every theme; phones have no :hover, so without
   this the gallery has zero tap feedback). Declarations mirror the theme's own
   .g-tile:hover rule exactly, just extended to :active. */
.g-tile:active .g-photo img {
  transform: scale(1.06);
}
.g-tile:active .g-photo-tint {
  opacity: 0.85;
}
.g-tile:active .g-cap {
  opacity: 1;
}

/* =============================================================================
   6. LIST-ROW COMPONENTS, horizontal nudge, never a vertical lift.
   These share a hairline top-border with the row above/below (a real list, like
   a table), so lifting one would visually tear the shared rule line. A small
   translateX nudge plus a thin accent bar reads as "responsive" without
   disturbing vertical rhythm. .sched-item, .stay-card, .rec-card, .song-item,
   .access-item.
   ============================================================================= */
.sched-item,
.stay-card,
.rec-card,
.song-item,
.access-item {
  position: relative;
  transform: translateX(0);
  transition: transform 0.4s var(--cm-ease), background 0.4s ease;
}

.sched-item::before,
.stay-card::before,
.rec-card::before,
.song-item::before,
.access-item::before {
  content: '';
  position: absolute;
  left: -14px;
  top: 8px;
  bottom: 8px;
  width: 2px;
  background: var(--cm-glow);
  opacity: 0;
  transform: scaleY(0.4);
  transform-origin: center;
  transition: opacity 0.35s ease, transform 0.35s var(--cm-ease);
  pointer-events: none;
}

.sched-item:hover,
.sched-item:active,
.stay-card:hover,
.stay-card:active,
.rec-card:hover,
.rec-card:active,
.song-item:hover,
.song-item:active,
.access-item:hover,
.access-item:active {
  transform: translateX(var(--cm-nudge-x));
}

.sched-item:hover::before, .sched-item:active::before,
.stay-card:hover::before, .stay-card:active::before,
.rec-card:hover::before, .rec-card:active::before,
.song-item:hover::before, .song-item:active::before,
.access-item:hover::before, .access-item:active::before {
  opacity: 0.85;
  transform: scaleY(1);
}

.access-item .access-mark {
  transition: transform 0.4s var(--cm-ease);
}
.access-item:hover .access-mark,
.access-item:active .access-mark {
  transform: scale(1.12);
}

/* =============================================================================
   7. FAQ ACCORDION ROW, same nudge language as list-rows, on the closed
   question row only. Does not touch the existing open/close (.faq-a max-height)
   logic or the caret rotate, purely additive hover/tap affordance.
   ============================================================================= */
.faq-item {
  position: relative;
  transition: background 0.4s ease;
}
.faq-item::before {
  content: '';
  position: absolute;
  left: -14px;
  top: 10px;
  bottom: 10px;
  width: 2px;
  background: var(--cm-glow);
  opacity: 0;
  transform: scaleY(0.4);
  transition: opacity 0.35s ease, transform 0.35s var(--cm-ease);
  pointer-events: none;
}
.faq-item:hover::before,
.faq-item:has(.faq-q:active)::before {
  opacity: 0.85;
  transform: scaleY(1);
}

/* =============================================================================
   8. GUESTBOOK QUOTE ENTRIES, .gb-entry
   Border-left accent brighten + tiny nudge, dynamically-inserted-safe (see
   card-motion.js §MutationObserver, new entries posted during the session get
   the same treatment without a page reload).
   ============================================================================= */
.gb-entry {
  transform: translateX(0);
  transition: transform 0.4s var(--cm-ease), filter 0.4s ease;
}
.gb-entry:hover,
.gb-entry:active {
  transform: translateX(4px);
  filter: brightness(1.08);
}

/* =============================================================================
   9. POINTER TILT (desktop only, applied by card-motion.js via inline custom
   properties --cm-tx / --cm-ty; both default to 0deg here so the page is correct
   even if JS fails to load or is disabled, pure progressive enhancement).
   ============================================================================= */
.choice-card,
.registry-card,
.party-person {
  --cm-tx: 0deg;
  --cm-ty: 0deg;
}
.choice-card:hover,
.choice-card:active,
.registry-card:hover,
.registry-card:active {
  transform: translateY(var(--cm-lift-y, 0)) scale(var(--cm-lift-scale, 1)) rotateX(var(--cm-tx)) rotateY(var(--cm-ty));
  transform-style: preserve-3d;
}
/* .party-person itself has no lift rule in §4 (only its .pp-portrait child does),
   so give the outer element the tilt-only transform without re-declaring lift. */
.party-person:hover,
.party-person:active {
  transform: rotateX(var(--cm-tx)) rotateY(var(--cm-ty));
}

.cm-sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(320px circle at var(--cm-mx, 50%) var(--cm-my, 50%), var(--cm-glow), transparent 60%);
  mix-blend-mode: soft-light;
  transition: opacity 0.3s ease;
}
.choice-card:hover .cm-sheen,
.choice-card:active .cm-sheen,
.registry-card:hover .cm-sheen,
.registry-card:active .cm-sheen {
  opacity: 0.5;
}

/* =============================================================================
   10. REDUCED MOTION, mirrors the idiom already used in envelope.css / hero.css
   / nav.css on this site (forcing durations to ~0 rather than deleting rules).
   Content stays fully present: reveal starts at opacity 1 / no transform, lift
   and tilt are neutralised, shimmer sweep does not travel.
   ============================================================================= */
@media (prefers-reduced-motion: reduce) {
  .btn-gold, .btn-ghost, .cal-btn,
  .btn-gold::after, .btn-ghost::after, .cal-btn::after,
  .choice-card, .registry-card, .party-person, .party-person .pp-portrait,
  .party-person .pp-photo, .rsvp-pstep .pstep-num,
  .detail-tile, .detail-tile .dt-ornament,
  .sched-item, .stay-card, .rec-card, .song-item, .access-item, .access-item .access-mark,
  .sched-item::before, .stay-card::before, .rec-card::before, .song-item::before, .access-item::before,
  .faq-item, .faq-item::before,
  .gb-entry,
  .tb-cm-reveal,
  .cm-sheen {
    transition-duration: 0.01s !important;
    animation-duration: 0.01s !important;
  }

  .tb-cm-reveal {
    opacity: 1;
    transform: none;
  }

  .choice-card:hover, .choice-card:active,
  .registry-card:hover, .registry-card:active,
  .party-person:hover .pp-portrait, .party-person:active .pp-portrait,
  .party-person:hover, .party-person:active {
    transform: none;
  }

  .rsvp-pstep.active .pstep-num,
  .rsvp-pstep.done .pstep-num {
    animation: none;
  }
}
