/* ============================================================
   KEEPSAKES — cinematic scroll-jacked scrapbook
   Pull-up-a-chair memory book · horizontal reels · journey thread
   Builds on styles.css tokens (--clay, --parch, --espresso, fonts)
   ============================================================ */

.ks{
  --paper:        oklch(0.962 0.010 86);
  --paper-deep:   oklch(0.930 0.014 82);
  --thread:       var(--clay);
  --ink:          var(--espresso-dk);
  background:var(--paper);
  color:var(--espresso);
  overflow-x:hidden;
}
.ks *{ box-sizing:border-box; }

/* paper grain over everything */
.ks::before{
  content:""; position:fixed; inset:0; z-index:1; pointer-events:none; opacity:.5;
  mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.045'/%3E%3C/svg%3E");
}

/* hide the decor symbol library */
.ks-defs{ position:absolute; width:0; height:0; overflow:hidden; }

/* ---------- shared decor primitives ---------- */
.decor{ position:absolute; pointer-events:none; z-index:6; color:var(--thread); }
.decor svg, svg.decor{ width:100%; height:100%; display:block; overflow:visible; }

/* washi / masking tape — real torn ends, fibres, sheen.
   The span itself only carries position + drop-shadow (shadow must sit on the
   parent so it follows the torn mask, which lives on the ::before layer). */
.tape{ position:absolute; z-index:8; width:96px; height:30px; pointer-events:none;
  filter:drop-shadow(0 2px 3px rgba(20,17,15,.22)); }
.tape::before{ content:""; position:absolute; inset:0;
  /* styles.css also styles .tape::before (polaroid tape on light pages) —
     neutralise its transform/size or the tape paints 52px off its span */
  transform:none; width:auto; height:auto;
  background:
    /* sheen band */
    linear-gradient(105deg, rgba(255,255,255,.36), rgba(255,255,255,.08) 34%, rgba(255,255,255,0) 55%, rgba(255,255,255,.16) 82%, rgba(255,255,255,.02)),
    /* vertical paper fibres */
    repeating-linear-gradient(90deg, rgba(255,255,255,.13) 0 1px, rgba(255,255,255,0) 1px 3px),
    repeating-linear-gradient(90deg, rgba(20,17,15,.05) 0 6px, rgba(20,17,15,0) 6px 13px),
    /* edge shade top/bottom */
    linear-gradient(180deg, rgba(20,17,15,.12), rgba(20,17,15,0) 26% 74%, rgba(20,17,15,.14)),
    var(--tape-c, oklch(0.86 0.04 78 / .8));
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 32' preserveAspectRatio='none'%3E%3Cpath fill='%23000' d='M7 0 L113 0 L118 4 L112 7 L117 11 L111 15 L118 19 L113 23 L117 26 L112 29 L116 32 L4 32 L8 28 L3 25 L7 21 L1 18 L6 14 L2 10 L8 6 L3 3 Z'/%3E%3C/svg%3E");
          mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 32' preserveAspectRatio='none'%3E%3Cpath fill='%23000' d='M7 0 L113 0 L118 4 L112 7 L117 11 L111 15 L118 19 L113 23 L117 26 L112 29 L116 32 L4 32 L8 28 L3 25 L7 21 L1 18 L6 14 L2 10 L8 6 L3 3 Z'/%3E%3C/svg%3E");
  -webkit-mask-size:100% 100%; mask-size:100% 100%; }
.tape--paper{ --tape-c:oklch(0.93 0.012 84 / .88); }
.tape--sage{  --tape-c:oklch(0.84 0.03 140 / .78); }
.tape--blue{  --tape-c:oklch(0.82 0.03 250 / .72); }
.tape--clay{  --tape-c:oklch(0.78 0.06 44 / .7); }
.tape--gold{  --tape-c:oklch(0.85 0.07 84 / .75); }
/* styles.css sets these vars at ::before level — re-assert ours (same
   specificity, later file wins) so the book keeps its own palette */
.tape--sage::before{ --tape-c:oklch(0.84 0.03 140 / .78); }
.tape--blue::before{ --tape-c:oklch(0.82 0.03 250 / .72); }

/* paperclip wrapper (clips over the top edge) */
.clip{ position:absolute; top:-16px; left:22px; width:26px; height:58px; z-index:9; color:var(--taupe);
  filter:drop-shadow(0 2px 2px rgba(20,17,15,.28)); }

/* wax seal / round stamp */
.ks-seal{ display:inline-flex; flex-direction:column; align-items:center; justify-content:center; gap:.12em;
  width:88px; height:88px; border-radius:50%; border:1px dashed rgba(166,96,60,.6);
  background:radial-gradient(circle at 50% 36%, rgba(202,140,80,.16), transparent 70%);
  color:var(--clay); text-align:center; }
.ks-seal i{ font-family:var(--serif); font-style:normal; font-size:1.25rem; letter-spacing:.05em; line-height:1; }
.ks-seal b{ font-family:var(--mono); font-weight:400; font-size:.46rem; letter-spacing:.2em; text-transform:uppercase; color:var(--taupe); }

/* handwritten + typed caption styles */
.hand{ font-family:var(--hand); line-height:1.15; color:var(--clay); }
.typed{ font-family:var(--mono); font-size:.62rem; letter-spacing:.18em; text-transform:uppercase; color:var(--taupe); }
.script{ font-family:var(--script); }

/* =========================================================
   PHOTO OBJECTS
   ========================================================= */
.photo{ position:relative; background:#fdfaf3; padding:10px; box-shadow:0 18px 36px -16px rgba(20,17,15,.5), 0 3px 10px rgba(20,17,15,.12);
  border:1px solid rgba(20,17,15,.05);
  display:flex; flex-direction:column; }
.photo img{ width:100%; height:auto; flex:1 1 auto; min-height:0; object-fit:cover; display:block; filter:saturate(.96) contrast(1.02);
  outline:1px solid rgba(20,17,15,.08); outline-offset:-1px; }
.photo figcaption{ flex:0 0 auto; font-family:var(--hand); font-size:1.15rem; color:var(--ink); text-align:center; padding:.5rem .2rem .55rem; line-height:1; }
.photo--polaroid{ padding-bottom:0; }
.photo--polaroid figcaption{ padding:.7rem .2rem .9rem; }
/* faint print grain over the whole frame — reads as real photo paper */
.photo::after{ content:""; position:absolute; inset:0; pointer-events:none; z-index:2; mix-blend-mode:multiply; opacity:.55;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)' opacity='0.05'/%3E%3C/svg%3E"); }

/* torn-edge print — deckled on all four sides, like a page pulled from an album */
.print{ position:relative; display:flex; flex-direction:column; box-shadow:0 18px 40px -18px rgba(20,17,15,.55); }
.print img{ width:100%; height:auto; flex:1 1 auto; min-height:0; object-fit:cover; display:block;
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500' preserveAspectRatio='none'%3E%3Cpath fill='%23000' d='M10 12 Q45 4 82 10 T156 8 T228 12 T302 7 T390 12 L392 58 Q398 92 391 132 T393 212 T390 292 T394 372 T391 446 L390 488 Q348 496 300 489 T208 493 T118 488 T42 494 L10 488 Q3 442 9 392 T7 302 T10 212 T6 122 L8 58 Z'/%3E%3C/svg%3E");
          mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500' preserveAspectRatio='none'%3E%3Cpath fill='%23000' d='M10 12 Q45 4 82 10 T156 8 T228 12 T302 7 T390 12 L392 58 Q398 92 391 132 T393 212 T390 292 T394 372 T391 446 L390 488 Q348 496 300 489 T208 493 T118 488 T42 494 L10 488 Q3 442 9 392 T7 302 T10 212 T6 122 L8 58 Z'/%3E%3C/svg%3E");
  -webkit-mask-size:100% 100%; mask-size:100% 100%; }

/* vintage album photo-corner mounts — overlay so the photo looks slipped in */
.corners::after{ content:""; position:absolute; inset:0; pointer-events:none; z-index:7;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cpath d='M0 0 H30 L0 30 Z' fill='%23d9c9a8'/%3E%3Cpath d='M30 0 L0 30' stroke='rgba(20,17,15,.22)' stroke-width='1.4'/%3E%3Cpath d='M0 0 H30 L0 30 Z' fill='none' stroke='rgba(20,17,15,.12)'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cpath d='M40 0 H10 L40 30 Z' fill='%23d9c9a8'/%3E%3Cpath d='M10 0 L40 30' stroke='rgba(20,17,15,.22)' stroke-width='1.4'/%3E%3Cpath d='M40 0 H10 L40 30 Z' fill='none' stroke='rgba(20,17,15,.12)'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cpath d='M0 40 V10 L30 40 Z' fill='%23d9c9a8'/%3E%3Cpath d='M0 10 L30 40' stroke='rgba(20,17,15,.22)' stroke-width='1.4'/%3E%3Cpath d='M0 40 V10 L30 40 Z' fill='none' stroke='rgba(20,17,15,.12)'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cpath d='M40 40 V10 L10 40 Z' fill='%23d9c9a8'/%3E%3Cpath d='M40 10 L10 40' stroke='rgba(20,17,15,.22)' stroke-width='1.4'/%3E%3Cpath d='M40 40 V10 L10 40 Z' fill='none' stroke='rgba(20,17,15,.12)'/%3E%3C/svg%3E");
  background-position:top left, top right, bottom left, bottom right;
  background-repeat:no-repeat;
  background-size:clamp(22px,14%,34px) clamp(22px,14%,34px);
  filter:drop-shadow(0 2px 2px rgba(20,17,15,.14)); }

/* film frame (sprocket holes) */
.filmframe{ position:relative; background:#1c1815; padding:26px 10px; box-shadow:0 18px 40px -16px rgba(20,17,15,.6); }
.filmframe::before, .filmframe::after{ content:""; position:absolute; left:0; right:0; height:14px;
  background-image:repeating-linear-gradient(90deg, #1c1815 0 8px, #d8cfbf 8px 17px); background-size:auto 100%;
  -webkit-mask:repeating-linear-gradient(90deg, transparent 0 4px, #000 4px 13px); mask:repeating-linear-gradient(90deg, transparent 0 4px, #000 4px 13px); }
.filmframe::before{ top:6px; } .filmframe::after{ bottom:6px; }
.filmframe img{ width:100%; height:100%; object-fit:cover; }

/* angles */
.rot-1{ transform:rotate(-3deg); } .rot-2{ transform:rotate(2.4deg); }
.rot-3{ transform:rotate(-1.6deg); } .rot-4{ transform:rotate(3.2deg); }
.rot-5{ transform:rotate(-4.4deg); } .rot-6{ transform:rotate(1.2deg); }

/* =========================================================
   NAV offset + COVER
   ========================================================= */
.ks-cover{ position:relative; z-index:2; min-height:100svh; display:grid; place-items:center; text-align:center;
  padding:7rem 1.4rem 3rem; overflow:hidden; }
.ks-cover__deco{ position:absolute; inset:0; z-index:0; pointer-events:none; }
.ks-cover__inner{ position:relative; z-index:3; max-width:46rem; }
.ks-cover__kicker{ font-family:var(--mono); font-size:.66rem; letter-spacing:.42em; text-transform:uppercase; color:var(--taupe); }
.ks-cover__title{ font-family:var(--serif); font-weight:400; line-height:.86; color:var(--ink);
  font-size:clamp(4rem,13.5vw,12rem); letter-spacing:-.01em; margin:.1em 0 .15em; }
.ks-cover__title em{ font-style:italic; color:var(--clay); }
.ks-cover__sub{ font-family:var(--serif); font-style:italic; font-size:clamp(1.1rem,2.4vw,1.7rem); color:var(--taupe); max-width:34ch; margin:0 auto; }
.ks-cover__hand{ font-family:var(--hand); font-size:clamp(1.6rem,3vw,2.3rem); color:var(--clay); transform:rotate(-4deg); display:inline-block; margin-bottom:.4rem; }

.ks-cover__cluster{ position:absolute; inset:0; z-index:1; pointer-events:none; }
.ks-cover__ph{ position:absolute; width:clamp(110px,13vw,200px); }
.cph-1{ top:11%; left:7%; }   .cph-2{ bottom:10%; left:13%; }
.cph-3{ top:13%; right:8%; }  .cph-4{ bottom:9%; right:10%; }

.ks-scrollcue{ position:absolute; left:50%; bottom:2rem; transform:translateX(-50%); z-index:4; display:flex; flex-direction:column; align-items:center; gap:.5rem; }
.ks-scrollcue span{ font-family:var(--mono); font-size:.56rem; letter-spacing:.3em; text-transform:uppercase; color:var(--taupe); }
.ks-scrollcue i{ width:1px; height:42px; background:linear-gradient(var(--taupe), transparent); position:relative; overflow:hidden; }
.ks-scrollcue i::after{ content:""; position:absolute; top:-50%; left:0; width:100%; height:50%; background:var(--clay); animation:kscue 1.8s var(--ease) infinite; }
@keyframes kscue{ 0%{ transform:translateY(0); } 100%{ transform:translateY(300%); } }

/* =========================================================
   JOURNEY THREAD — wavy map trail rail
   ========================================================= */
.ks-rail{ position:fixed; left:max(1.1rem,2.2vw); top:50%; transform:translateY(-50%); z-index:40;
  display:flex; flex-direction:column; align-items:center; gap:0; pointer-events:none; }

/* the SVG trail */
.ks-trail{ display:block; overflow:visible; }
.ks-trail__bg{ fill:none; stroke:var(--sand); stroke-width:2; stroke-dasharray:4 7; stroke-linecap:round; }
.ks-trail__fill{ fill:none; stroke:var(--clay); stroke-width:2.5; stroke-linecap:round;
  stroke-dasharray:1; stroke-dashoffset:1;
  transition:stroke-dashoffset 0.25s ease; }

/* station dots */
.ks-trail .ks-bead{ fill:var(--paper); stroke:var(--sand); stroke-width:1.5;
  transition:fill .4s var(--ease), stroke .4s var(--ease); }
.ks-trail .ks-bead.on{ fill:var(--clay); stroke:var(--clay); transform:scale(1.3); transform-box:fill-box; transform-origin:center; }
.ks-trail .ks-bead.past{ fill:var(--sand); stroke:var(--sand); }
.ks-trail .ks-bead.on + .ks-bead-ring { opacity: 1; } /* fallback, real toggle done in JS */

/* station ring pulse — appears only when bead is active */
.ks-trail .ks-bead-ring{ fill:none; stroke:var(--clay); stroke-width:1.2; opacity:0; transition:opacity .4s var(--ease); }
.ks-trail .ks-bead-ring.on{ opacity:1; animation:ksRingPulse 2.2s ease-out infinite; }
@keyframes ksRingPulse{
  0%  { transform:scale(1);   opacity:.7; transform-box:fill-box; transform-origin:center; }
  100%{ transform:scale(2.6); opacity:0;  transform-box:fill-box; transform-origin:center; }
}

/* station label */
.ks-rail__label{ writing-mode:vertical-rl; margin-top:1rem; font-family:var(--mono); font-size:.54rem; letter-spacing:.34em; text-transform:uppercase; color:var(--taupe); }
@media (max-width:900px){ .ks-rail{ display:none; } }

/* mobile top progress */
.ks-topbar{ position:fixed; top:0; left:0; height:3px; width:100%; z-index:40; background:transparent; display:none; }
.ks-topbar i{ display:block; height:100%; width:var(--rail,0%); background:var(--clay); transition:width .15s linear; }
@media (max-width:900px){ .ks-topbar{ display:block; } }

/* =========================================================
   PAGE-TURN INTERSTITIAL (the vertical beats between reels)
   ========================================================= */
.ks-turn{ position:relative; z-index:2; min-height:62svh; display:grid; place-items:center; text-align:center; padding:4rem 1.4rem; overflow:hidden; }
.ks-turn__no{ font-family:var(--serif); font-style:italic; font-size:clamp(5rem,16vw,13rem); line-height:.8; color:var(--accent,var(--clay)); opacity:.22; }
.ks-turn__inner{ position:relative; z-index:3; max-width:40rem; margin-top:-2.5rem; }
.ks-turn__couple{ font-family:var(--serif); font-size:clamp(2.4rem,6vw,5rem); line-height:1; color:var(--ink); }
.ks-turn__couple em{ font-style:italic; color:var(--accent,var(--clay)); }
.ks-turn__meta{ font-family:var(--mono); font-size:.66rem; letter-spacing:.26em; text-transform:uppercase; color:var(--taupe); margin-top:1.1rem; }
.ks-turn__hand{ font-family:var(--hand); font-size:clamp(1.4rem,2.6vw,2rem); color:var(--accent,var(--clay)); transform:rotate(-2.5deg); display:inline-block; margin-top:1.4rem; }
.ks-turn__cue{ font-family:var(--mono); font-size:.58rem; letter-spacing:.28em; text-transform:uppercase; color:var(--taupe); margin-top:1.8rem; display:inline-flex; gap:.6rem; align-items:center; }
.ks-turn__cue::after{ content:"→"; font-size:1.1rem; color:var(--accent,var(--clay)); animation:ksnudge 1.6s var(--ease) infinite; }
@keyframes ksnudge{ 0%,100%{ transform:translateX(0); } 50%{ transform:translateX(6px); } }

/* =========================================================
   REEL — horizontal scroll-jacked spread
   ========================================================= */
.ks-reel{ position:relative; z-index:2; }
.ks-reel__sticky{ position:sticky; top:0; height:100svh; overflow:hidden; display:flex; align-items:center;
  background:var(--bg-tint, transparent); }
.ks-reel__track{ display:flex; align-items:center; gap:clamp(2.5rem,6vw,7rem); height:100%; padding:0 12vw;
  will-change:transform; }
.ks-reel__hint{ position:absolute; right:1.4rem; bottom:1.2rem; z-index:12; font-family:var(--mono); font-size:.54rem; letter-spacing:.22em; text-transform:uppercase; color:var(--taupe); opacity:.7; }

/* a panel = one beat inside the reel */
.ks-panel{ position:relative; flex:0 0 auto; display:flex; align-items:center; justify-content:center; }
.ks-panel--intro{ flex-basis:min(78vw,640px); }
.ks-panel--cluster{ flex-basis:min(92vw,860px); }
.ks-panel--single{ flex-basis:min(60vw,460px); }
.ks-panel--video{ flex-basis:min(60vw,420px); }
.ks-panel--quote{ flex-basis:min(80vw,560px); }
.ks-panel--end{ flex-basis:min(50vw,360px); }

/* chapter intro card */
.ks-intro{ position:relative; padding:2rem; }
.ks-intro__name{ font-family:var(--serif); font-size:clamp(2.6rem,6vw,4.6rem); line-height:.96; color:var(--ink); }
.ks-intro__name em{ font-style:italic; color:var(--accent,var(--clay)); }
.ks-intro__rule{ width:64px; height:1px; background:var(--accent,var(--clay)); margin:1.3rem 0; }
.ks-intro__meta{ font-family:var(--mono); font-size:.66rem; letter-spacing:.22em; text-transform:uppercase; color:var(--taupe); line-height:2; }
.ks-intro__note{ font-family:var(--hand); font-size:1.5rem; color:var(--accent,var(--clay)); transform:rotate(-2deg); margin-top:1.4rem; max-width:26ch; }
.ks-intro__seal{ position:absolute; right:-1rem; bottom:-1rem; }

/* photo clusters — overlapping arrangement */
.ks-cluster{ position:relative; width:100%; height:min(74vh,640px); }
.ks-cluster .obj{ position:absolute; }
/* legacy free placements — kept for safety; engineered variants below are
   the source of truth (every cluster in the book now uses a variant) */
.pos-a{ top:2%;  left:2%;   width:40%; }
.pos-b{ top:14%; left:36%;  width:46%; z-index:3; }
.pos-c{ top:40%; left:6%;   width:34%; z-index:4; }
.pos-d{ bottom:2%; right:3%; width:30%; z-index:5; }
.pos-e{ top:6%;  right:1%;  width:26%; }

/* single hero photo */
.ks-single{ width:100%; max-width:440px; }

/* vertical video reel */
.ks-vreel{ position:relative; width:min(58vw,360px); aspect-ratio:9/16; background:#15110e;
  padding:12px; box-shadow:0 26px 60px -22px rgba(20,17,15,.7); border:1px solid rgba(20,17,15,.06); }
.ks-vreel video{ width:100%; height:100%; object-fit:cover; display:block; background:#0c0a08; }
.ks-vreel__label{ position:absolute; left:50%; bottom:-1.7rem; transform:translateX(-50%); white-space:nowrap;
  font-family:var(--mono); font-size:.56rem; letter-spacing:.2em; text-transform:uppercase; color:var(--taupe); }
.ks-vreel__live{ position:absolute; top:1.3rem; left:1.3rem; z-index:4; display:inline-flex; align-items:center; gap:.4rem;
  font-family:var(--mono); font-size:.5rem; letter-spacing:.2em; text-transform:uppercase; color:#fff; opacity:.9; }
.ks-vreel__live::before{ content:""; width:7px; height:7px; border-radius:50%; background:#e0654a; box-shadow:0 0 0 0 rgba(224,101,74,.7); animation:kslive 1.6s infinite; }
@keyframes kslive{ 0%{ box-shadow:0 0 0 0 rgba(224,101,74,.6); } 100%{ box-shadow:0 0 0 9px rgba(224,101,74,0); } }
.ks-vreel__btn{ position:absolute; inset:0; z-index:5; display:grid; place-items:center; cursor:pointer; }
.ks-vreel__btn span{ width:60px; height:60px; border-radius:50%; background:rgba(253,250,243,.9); color:var(--ink); display:grid; place-items:center; font-size:1.1rem; padding-left:4px; box-shadow:0 8px 24px rgba(20,17,15,.4); transition:.4s var(--ease); }
.ks-vreel.playing .ks-vreel__btn{ opacity:0; pointer-events:none; }

/* big handwritten quote / torn note */
.ks-quote{ position:relative; }
.ks-quote__note{ position:relative; background:#f6efe1; padding:2.4rem 2.6rem; box-shadow:0 18px 40px -18px rgba(20,17,15,.45);
  transform:rotate(-1.4deg); }
.ks-quote__note::after{ content:""; position:absolute; inset:0; background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E"); pointer-events:none; }
.ks-quote__text{ font-family:var(--serif); font-style:italic; font-size:clamp(1.5rem,3vw,2.4rem); line-height:1.22; color:var(--ink); }
.ks-quote__by{ font-family:var(--hand); font-size:1.4rem; color:var(--accent,var(--clay)); margin-top:1rem; }

/* chapter end card */
.ks-end{ text-align:center; }
.ks-end__line{ font-family:var(--serif); font-style:italic; font-size:clamp(1.4rem,3vw,2.2rem); color:var(--taupe); }
.ks-end__arrow{ font-family:var(--mono); font-size:.6rem; letter-spacing:.26em; text-transform:uppercase; color:var(--clay); margin-top:1rem; }

/* =========================================================
   CLOSING — guestbook CTA
   ========================================================= */
.ks-close{ position:relative; z-index:2; min-height:100svh; display:grid; place-items:center; text-align:center; padding:7rem 1.4rem; overflow:hidden;
  background:var(--espresso-dk); color:var(--parch); }
.ks-close .ks-grain{ position:absolute; inset:0; z-index:0; opacity:.5; mix-blend-mode:overlay; pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.06'/%3E%3C/svg%3E"); }
.ks-close__inner{ position:relative; z-index:3; max-width:42rem; }
.ks-close__hand{ font-family:var(--hand); font-size:clamp(1.7rem,3.4vw,2.6rem); color:var(--clay); transform:rotate(-3deg); display:inline-block; }
.ks-close__title{ font-family:var(--serif); font-weight:400; line-height:.92; color:var(--parch); font-size:clamp(2.6rem,7vw,6rem); margin:.6rem 0; }
.ks-close__title em{ font-style:italic; color:#e9c9a0; }
.ks-close__sub{ font-family:var(--serif); font-style:italic; color:rgba(244,239,230,.72); font-size:clamp(1.1rem,2.2vw,1.5rem); max-width:34ch; margin:0 auto 2.4rem; }
.ks-btn{ display:inline-flex; align-items:center; gap:.7rem; font-family:var(--mono); font-size:.66rem; letter-spacing:.24em; text-transform:uppercase;
  background:var(--parch); color:var(--espresso-dk); padding:1.1em 2em; border-radius:40px; transition:.4s var(--ease); }
.ks-btn:hover{ background:#e9c9a0; transform:translateY(-2px); }
.ks-close__seal{ margin-top:2.6rem; border-color:rgba(244,239,230,.4); color:var(--parch); }
.ks-close__seal b{ color:rgba(244,239,230,.6); }

/* reveal helper (used outside reels) */
.ks-rv{ opacity:0; transform:translateY(26px); transition:opacity 1s var(--ease), transform 1s var(--ease); }
.ks-rv.in{ opacity:1; transform:none; }
.ks-rv[data-d="1"]{ transition-delay:.12s; } .ks-rv[data-d="2"]{ transition-delay:.24s; } .ks-rv[data-d="3"]{ transition-delay:.36s; }

/* in-reel objects get a soft settle as the reel enters */
.ks-reel.in .obj, .ks-reel.in .ks-intro, .ks-reel.in .ks-vreel, .ks-reel.in .ks-quote, .ks-reel.in .ks-end, .ks-reel.in .ks-single{
  animation:kssettle .9s var(--ease) both; }
.ks-reel.in .obj:nth-child(2){ animation-delay:.06s; }
.ks-reel.in .obj:nth-child(3){ animation-delay:.12s; }
.ks-reel.in .obj:nth-child(4){ animation-delay:.18s; }
@keyframes kssettle{ from{ opacity:0; transform:translateY(22px) var(--rot,rotate(0)); } }

/* =========================================================
   RESPONSIVE
   ========================================================= */
@media (max-width:760px){
  .ks-reel__track{ padding:0 8vw; gap:2.2rem; }
  .ks-panel--cluster{ flex-basis:88vw; }
  .ks-panel--intro{ flex-basis:82vw; }
  .ks-panel--single{ flex-basis:74vw; }
  .ks-panel--video{ flex-basis:76vw; }
  .ks-panel--quote{ flex-basis:84vw; }
  .ks-cluster{ height:64vh; }
  .ks-cover__cluster{ opacity:.5; }
  .ks-cover__ph{ width:clamp(86px,26vw,120px); }
}

/* =========================================================
   REDUCED MOTION / NO-JS FALLBACK
   reels become vertical stacks; no scroll-jack
   ========================================================= */
.ks-static .ks-reel__sticky{ position:static; height:auto; display:block; padding:3rem 0; }
.ks-static .ks-reel__track{ flex-direction:column; height:auto; padding:0 6vw; gap:3rem; transform:none !important; }
.ks-static .ks-panel{ flex-basis:auto !important; width:100%; max-width:560px; margin-inline:auto; }
.ks-static .ks-cluster{ height:auto; min-height:340px; }
.ks-static .ks-rail, .ks-static .ks-topbar{ display:none; }
@media (prefers-reduced-motion:reduce){
  .ks-reel__sticky{ position:static; height:auto; display:block; padding:3rem 0; }
  .ks-reel__track{ flex-direction:column; height:auto; padding:0 6vw; gap:3rem; transform:none !important; }
  .ks-panel{ flex-basis:auto !important; width:100%; max-width:560px; margin-inline:auto; }
  .ks-cluster{ height:auto; min-height:340px; }
  .ks-reel.in .obj, .ks-reel.in *{ animation:none !important; }
}

/* =========================================================
   MICRO-ANIMATIONS
   ========================================================= */

/* --- 1. Photo float (uses standalone 'translate' — composes with transform:rotate) --- */
@keyframes ksFloat{ from{ translate:0 0; } to{ translate:0 -5px; } }
.ks-reel .obj{ animation:ksFloat 5s ease-in-out infinite alternate; }
.ks-reel .obj:nth-child(2){ animation-duration:6.8s; animation-delay:-2.1s; }
.ks-reel .obj:nth-child(3){ animation-duration:4.3s; animation-delay:-3.5s; }
.ks-reel .obj:nth-child(4){ animation-duration:7.2s; animation-delay:-1s; }
.ks-reel .obj:nth-child(5){ animation-duration:5.6s; animation-delay:-4.2s; }

/* --- 2. SVG decor sway (uses standalone 'rotate' — composes with transform) --- */
@keyframes ksSway{ from{ rotate:-3.5deg; } to{ rotate:4deg; } }
.ks-reel .decor{ transform-origin:center bottom; animation:ksSway 8s ease-in-out infinite alternate; }
.ks-reel .decor:nth-of-type(even){ animation-duration:11s; animation-delay:-4s; }

/* --- 3. Chapter turn — stamp / wipe-in entrance --- */
.ks-turn__no{ opacity:.22; }
@keyframes ksStamp{
  0%  { opacity:0; transform:scale(1.6) rotate(5deg); filter:blur(4px); }
  55% { opacity:.28; transform:scale(.96) rotate(-1.5deg); filter:blur(0); }
  100%{ opacity:.22; transform:scale(1) rotate(0); filter:blur(0); }
}
@keyframes ksWipe{ from{ clip-path:inset(0 100% 0 0); } to{ clip-path:inset(0 0% 0 0); } }

.ks-turn.in .ks-turn__no{     animation:ksStamp .85s var(--ease) forwards; }
.ks-turn.in .ks-turn__couple{ animation:ksWipe .9s var(--ease) .18s both; }
.ks-turn.in .ks-turn__meta{   animation:ksWipe .6s var(--ease) .38s both; }
.ks-turn.in .ks-turn__hand{   animation:ksWipe .7s var(--ease) .5s both; }
.ks-turn.in .ks-turn__cue{    animation:ksWipe .5s var(--ease) .66s both; }

/* clip-path needs baseline hidden state */
.ks-turn__couple,.ks-turn__meta,.ks-turn__hand,.ks-turn__cue{
  clip-path:inset(0 100% 0 0);
}
.ks-turn.in .ks-turn__couple,.ks-turn.in .ks-turn__meta,
.ks-turn.in .ks-turn__hand,.ks-turn.in .ks-turn__cue{
  clip-path:inset(0 0% 0 0);
}

/* --- 4. Wax seal slow wobble --- */
@keyframes ksSealWobble{ from{ rotate:-3deg; } to{ rotate:3deg; } }
.ks-seal{ animation:ksSealWobble 6s ease-in-out infinite alternate; transform-origin:center; }

/* --- 5. Cover scroll cue already has kscue (defined above) --- */

/* --- 6. Panel 3D perspective — set on track, JS drives rotateY per panel --- */
.ks-reel__track{ perspective:1000px; }
.ks-panel{ transform-style:preserve-3d; will-change:transform; }

/* --- 7. Photo hover lift --- */
.ks-reel .photo,.ks-reel .print,.ks-reel .filmframe{ transition:box-shadow .4s var(--ease), filter .4s var(--ease); }
.ks-reel .photo:hover,.ks-reel .print:hover{
  box-shadow:0 28px 56px -20px rgba(20,17,15,.6), 0 6px 16px rgba(20,17,15,.18);
  filter:saturate(1.04) contrast(1.03);
  z-index:9;
}

/* --- 8. Closing CTA background shimmer --- */
@keyframes ksShimmer{ 0%,100%{ opacity:.5; } 50%{ opacity:.7; } }
.ks-close .ks-grain{ animation:ksShimmer 7s ease-in-out infinite; }

/* --- 9. Reduced motion: kill everything --- */
@media (prefers-reduced-motion:reduce){
  .ks-reel .obj, .ks-reel .decor, .ks-seal, .ks-turn__no,
  .ks-trail .ks-bead-ring.on, .ks-close .ks-grain,
  .ks-turn.in .ks-turn__no{ animation:none !important; }
  .ks-turn__couple,.ks-turn__meta,.ks-turn__hand,.ks-turn__cue{ clip-path:none !important; }
}

/* ============================================================
   v2 ADDITIONS — canvas trail · scatter · front-pop · 3D tilt
   ============================================================ */

/* #ks-maptrail removed — trail is the side SVG rail */
#ks-maptrail{ display:none; }

/* ─── PANEL 3D TILT (slight rotateY as panel drifts off-center) ─── */
.ks-panel{
  transform:perspective(1400px) rotateY(calc(var(--ptilt,0) * 7deg));
  transition:transform 0.35s ease;
}

/* ─── PHOTO SCATTER ───
   Uses standalone CSS translate + scale properties — compose cleanly
   with the transform:rotate() on .rot-N classes.
   Photos start collapsed (stacked) and scatter to their target positions.
*/
.ks-cluster .obj{
  cursor:pointer;
  transition:
    translate 0.9s cubic-bezier(0.34,1.56,0.64,1),
    scale     0.85s cubic-bezier(0.34,1.56,0.64,1),
    opacity   0.5s ease,
    box-shadow 0.4s ease;
}

/* Initial "stacked pile" state (before scatter fires) */
.ks-cluster .obj:not(.scatter-in){
  opacity:0;
  scale:0.65;
  translate:var(--scx,28px) var(--scy,22px);
  transition:none !important;
}
/* Per-child start offsets — creates the scattered pile effect */
.ks-cluster .obj:nth-child(1):not(.scatter-in){ --scx:22px;  --scy:36px; }
.ks-cluster .obj:nth-child(2):not(.scatter-in){ --scx:-32px; --scy:18px; }
.ks-cluster .obj:nth-child(3):not(.scatter-in){ --scx:14px;  --scy:-24px; }
.ks-cluster .obj:nth-child(4):not(.scatter-in){ --scx:-18px; --scy:30px; }
.ks-cluster .obj:nth-child(5):not(.scatter-in){ --scx:26px;  --scy:-16px; }

/* Scattered (landed) — spring to natural position */
.ks-cluster .obj.scatter-in{
  opacity:1;
  scale:1;
  translate:0px 0px;
}

/* ─── HOVER: subtle lift when already scattered, not front ─── */
.ks-cluster .obj.scatter-in:not(.ks-front):hover{
  scale:1.04 !important;
  translate:0px -6px !important;
  z-index:10;
  box-shadow:0 28px 56px -18px rgba(20,17,15,.58),0 6px 16px rgba(20,17,15,.16) !important;
  transition:
    scale 0.28s cubic-bezier(0.34,1.56,0.64,1),
    translate 0.28s cubic-bezier(0.34,1.56,0.64,1),
    box-shadow 0.28s ease !important;
}

/* ─── FRONT-POP: click brings a back photo to front with spring bounce ─── */
.ks-cluster .obj.ks-front{
  z-index:20 !important;
  scale:1.10 !important;
  translate:0px -12px !important;
  box-shadow:0 48px 88px -22px rgba(20,17,15,.75),
             0 12px 30px rgba(20,17,15,.26) !important;
  filter:saturate(1.06) contrast(1.03) !important;
  transition:
    scale     0.55s cubic-bezier(0.34,1.56,0.64,1),
    translate 0.55s cubic-bezier(0.34,1.56,0.64,1),
    box-shadow 0.45s ease !important;
}

/* ─── Override old settle animation on .obj — scatter handles it now ─── */
.ks-reel.in .obj{ animation:none !important; }
/* Keep settle on non-cluster panel elements */
.ks-reel.in .ks-intro,
.ks-reel.in .ks-vreel,
.ks-reel.in .ks-quote__note,
.ks-reel.in .ks-end,
.ks-reel.in .ks-single{
  animation:kssettle .9s var(--ease) both;
}

/* ─── COVER CLUSTER: polaroids settle in on page load ─── */
.ks-cover__cluster .ks-cover__ph{
  animation:ks-cover-in 1.3s cubic-bezier(0.22,1,0.36,1) both;
}
.cph-1{ animation-delay:.08s !important; } .cph-2{ animation-delay:.18s !important; }
.cph-3{ animation-delay:.28s !important; } .cph-4{ animation-delay:.38s !important; }
@keyframes ks-cover-in{
  from{ opacity:0; scale:.72; translate:0px 28px; }
  to  { opacity:1; scale:1;   translate:0px 0px;  }
}

/* ─── REEL EDGE VIGNETTES — light fades at left/right edges ─── */
.ks-reel__sticky::before,
.ks-reel__sticky::after{
  content:""; position:absolute; top:0; bottom:0; width:min(11vw,100px); z-index:11; pointer-events:none;
}
.ks-reel__sticky::before{
  left:0;
  background:linear-gradient(90deg,var(--bg-tint,rgba(248,243,236,.95)) 30%,transparent);
}
.ks-reel__sticky::after{
  right:0;
  background:linear-gradient(270deg,var(--bg-tint,rgba(248,243,236,.95)) 30%,transparent);
}

/* ─── REDUCED MOTION: flatten everything ─── */
@media (prefers-reduced-motion:reduce){
  .ks-cluster .obj:not(.scatter-in){ opacity:1; scale:1; translate:0 0; transition:none !important; }
  .ks-cluster .obj{ transition:none; }
  .ks-cluster .obj.ks-front{ transition:none !important; }
  .ks-panel{ transform:none; transition:none; }
  #ks-maptrail{ display:none; }
  .ks-cover__cluster .ks-cover__ph{ animation:none; }
  .ks-reel__sticky::before,.ks-reel__sticky::after{ display:none; }
}

/* ============================================================
   v3 — real printed decor · adaptive video · scroll zoom · layouts
   ============================================================ */

/* ---- printed botanical decor (rasterised hand-stamped PNGs) ---- */
img.ks-leaf{
  position:absolute; z-index:6; pointer-events:none; display:block;
  width:auto; height:auto; user-select:none;
  filter:drop-shadow(0 8px 12px rgba(20,17,15,.10));
  transform-origin:center bottom;
  animation:ksLeafSway 9s ease-in-out infinite alternate;
}
img.ks-leaf.no-sway{ animation:none; }
@keyframes ksLeafSway{ from{ rotate:var(--lr0,-3deg); } to{ rotate:var(--lr1,3deg); } }
img.ks-leaf:nth-of-type(even){ animation-duration:12s; animation-delay:-3s; }
.ks-cover__cluster img.ks-leaf{ z-index:1; }

/* parallax drift: leaves ride the panel offset for depth */
img.ks-leaf{ translate:calc(var(--poff,0) * 12px) calc(var(--poff,0) * -5px); }
.ks-cover__cluster img.ks-leaf{ translate:none; }

/* ---- adaptive film reel: orientation decided in JS ---- */
.ks-panel--video{ flex-basis:auto; }
.ks-vreel{ width:min(56vw,340px); aspect-ratio:9/16; }   /* default until metadata */
.ks-vreel.is-tall{ width:min(56vw,346px); aspect-ratio:9/16; }
.ks-vreel.is-wide{ width:min(84vw,780px); aspect-ratio:16/9; }
.ks-vreel.is-wide{ padding:14px; }
.ks-vreel.is-wide .ks-vreel__label{ bottom:-1.7rem; }

/* ---- proximity ZOOM: content swells as its panel hits centre ---- */
.ks-panel{ --pprox:.55; --poff:0; }
.ks-panel--single .ks-single,
.ks-panel--video  .ks-vreel,
.ks-panel--quote  .ks-quote,
.ks-panel--intro  .ks-intro,
.ks-panel--cluster .ks-cluster{
  scale:calc(.9 + .12 * var(--pprox));
  transition:scale .45s var(--ease);
}
@media (prefers-reduced-motion:reduce){
  .ks-panel--single .ks-single,.ks-panel--video .ks-vreel,.ks-panel--quote .ks-quote,
  .ks-panel--intro .ks-intro,.ks-panel--cluster .ks-cluster{ scale:1 !important; }
}

/* ---- slow ken-burns on hero singles while the reel is live ---- */
@keyframes ksKen{ from{ scale:1.001; } to{ scale:1.07; } }
.ks-reel.in .ks-single img{ animation:ksKen 16s ease-in-out infinite alternate; }
@media (prefers-reduced-motion:reduce){ .ks-reel.in .ks-single img{ animation:none; } }

/* =========================================================
   CLUSTER LAYOUT VARIANTS — each engineered with gaps so
   photos kiss at the corners but never bury faces.
   Children are plain `.obj` figures; position set by nth-child.
   ========================================================= */
.ks-cluster .obj{ overflow:visible; }
.ks-cluster .obj img{ width:100%; height:auto; flex:1 1 auto; min-height:0; object-fit:cover; }

/* shared: drop pos-* dependence inside variant clusters */
.ks-cluster--gallery .obj,.ks-cluster--cascade .obj,.ks-cluster--filmstrip .obj,
.ks-cluster--triptych .obj,.ks-cluster--mosaic .obj,.ks-cluster--pile .obj{ position:absolute; }

/* A · GALLERY WALL — neat 2×2, tiny tilts, clear gutters */
.ks-cluster--gallery{ height:min(76vh,650px); }
.ks-cluster--gallery .obj:nth-child(1){ left:1%;  top:2%;  width:45%; height:46%; rotate:-2.4deg; z-index:2; }
.ks-cluster--gallery .obj:nth-child(2){ left:52%; top:0;   width:46%; height:44%; rotate:1.8deg;  z-index:3; }
.ks-cluster--gallery .obj:nth-child(3){ left:4%;  top:53%; width:42%; height:44%; rotate:1.6deg;  z-index:4; }
.ks-cluster--gallery .obj:nth-child(4){ left:53%; top:50%; width:45%; height:47%; rotate:-2deg;   z-index:5; }

/* B · CASCADE — diagonal staircase, corner overlaps only */
.ks-cluster--cascade{ height:min(78vh,660px); }
.ks-cluster--cascade .obj:nth-child(1){ left:0;   top:0;   width:40%; height:52%; rotate:-3deg;  z-index:2; }
.ks-cluster--cascade .obj:nth-child(2){ left:32%; top:24%; width:40%; height:52%; rotate:2.2deg; z-index:3; }
.ks-cluster--cascade .obj:nth-child(3){ left:63%; top:47%; width:37%; height:51%; rotate:-1.8deg;z-index:4; }

/* C · FILMSTRIP — taped horizontal row of equal frames */
.ks-cluster--filmstrip{ height:min(64vh,520px); }
.ks-cluster--filmstrip .obj{ top:15%; height:70%; width:24.5%; }
.ks-cluster--filmstrip .obj:nth-child(1){ left:0;     rotate:-1.6deg; z-index:2; }
.ks-cluster--filmstrip .obj:nth-child(2){ left:25.2%; rotate:1.4deg;  z-index:3; }
.ks-cluster--filmstrip .obj:nth-child(3){ left:50.4%; rotate:-1.2deg; z-index:2; }
.ks-cluster--filmstrip .obj:nth-child(4){ left:75.6%; rotate:1.6deg;  z-index:3; }

/* D · TRIPTYCH — three talls, generous gutters */
.ks-cluster--triptych{ height:min(80vh,680px); }
.ks-cluster--triptych .obj{ top:6%; height:86%; width:30%; }
.ks-cluster--triptych .obj:nth-child(1){ left:1%;  rotate:-2.2deg; top:9%; z-index:2; }
.ks-cluster--triptych .obj:nth-child(2){ left:35%; rotate:1.4deg;  top:0;  height:92%; z-index:4; }
.ks-cluster--triptych .obj:nth-child(3){ left:69%; rotate:-1.6deg; top:9%; z-index:3; }

/* E · MOSAIC — one hero + two stacked, finale spread */
.ks-cluster--mosaic{ height:min(80vh,680px); }
.ks-cluster--mosaic .obj:nth-child(1){ left:0;   top:1%;  width:54%; height:92%; rotate:-2deg;  z-index:2; }
.ks-cluster--mosaic .obj:nth-child(2){ left:59%; top:2%;  width:40%; height:44%; rotate:1.8deg; z-index:3; }
.ks-cluster--mosaic .obj:nth-child(3){ left:59%; top:53%; width:40%; height:45%; rotate:-1.6deg;z-index:4; }

/* F · PILE — kitchen-table spread: three across the top, one print
   settling over their lower corners. Faces stay clear; corners kiss. */
.ks-cluster--pile{ height:min(78vh,660px); }
.ks-cluster--pile .obj:nth-child(1){ left:1%;  top:3%;  width:33%; height:55%; rotate:2.4deg;  z-index:3; }
.ks-cluster--pile .obj:nth-child(2){ left:30%; top:0;   width:39%; height:56%; rotate:-3deg;   z-index:2; }
.ks-cluster--pile .obj:nth-child(3){ left:65%; top:6%;  width:34%; height:50%; rotate:-1.6deg; z-index:3; }
.ks-cluster--pile .obj:nth-child(4){ left:24%; top:54%; width:40%; height:42%; rotate:2deg;    z-index:5; }

@media (max-width:760px){
  .ks-cluster--gallery,.ks-cluster--cascade,.ks-cluster--triptych,.ks-cluster--mosaic,.ks-cluster--filmstrip,.ks-cluster--pile{ height:62vh; }
}

/* =========================================================
   FILM-REEL FRAME — sprocket holes along the film edges so the
   video sits inside a real strip of celluloid
   ========================================================= */
.ks-vreel::before,.ks-vreel::after{ content:""; position:absolute; z-index:3; pointer-events:none; }
.ks-vreel.is-tall::before,.ks-vreel::before{ left:2.5px; top:16px; bottom:16px; width:7px; right:auto; height:auto;
  background:repeating-linear-gradient(180deg, rgba(244,239,230,.24) 0 9px, rgba(244,239,230,0) 9px 20px); border-radius:1px; }
.ks-vreel.is-tall::after,.ks-vreel::after{ right:2.5px; top:16px; bottom:16px; width:7px; left:auto; height:auto;
  background:repeating-linear-gradient(180deg, rgba(244,239,230,.24) 0 9px, rgba(244,239,230,0) 9px 20px); border-radius:1px; }
.ks-vreel.is-wide::before{ top:2.5px; left:18px; right:18px; height:8px; width:auto; bottom:auto;
  background:repeating-linear-gradient(90deg, rgba(244,239,230,.24) 0 10px, rgba(244,239,230,0) 10px 22px); border-radius:1px; }
.ks-vreel.is-wide::after{ bottom:2.5px; top:auto; left:18px; right:18px; height:8px; width:auto;
  background:repeating-linear-gradient(90deg, rgba(244,239,230,.24) 0 10px, rgba(244,239,230,0) 10px 22px); border-radius:1px; }
