/* SpringBreakClubCard.com motion layer (2026-10-22). Dark editorial identity, no stickers/pills.
   Rules: transform/opacity (plus grid-row expands for the two accordions), IntersectionObserver-driven from sbcc-motion.js,
   gated on html.js (set before first paint by functions.php), every animation's base state is the FINAL state so the global
   prefers-reduced-motion block in sbcc.css (animation:none; transition:none) leaves a static, fully visible page.
   Markup hooks (.kh .w, .kb, .bar, .qnav, .pcb-t/.pcb-c) are added server-side in functions.php, so nothing shifts after paint. */
:root{--m-ease:cubic-bezier(.22,1,.36,1);--m-out:cubic-bezier(.2,.7,.2,1)}

/* ---------- 1. hero: kinetic headline ---------- */
.js .hero .kh{animation:none;text-wrap:wrap} /* greedy breaks: balance re-breaks on the serif swap and the word boxes would register as layout shift */
.js .kh .w{display:inline-block;overflow:hidden;vertical-align:bottom;padding:.12em .03em .2em 0;margin:-.12em -.03em -.2em 0;max-width:100%}
.js .kh .w>span{display:inline-block;animation:khw .85s var(--m-ease) both;animation-delay:calc(.1s + var(--i,0) * .055s)}
.js .kh .w>.hl{animation-name:khl;animation-duration:1.05s;animation-delay:calc(.22s + var(--i,0) * .055s);transform-origin:left bottom}
@keyframes khw{from{opacity:0;transform:translateY(140%)}60%{opacity:1}to{opacity:1;transform:none}}
@keyframes khl{from{opacity:0;transform:translateY(140%) skewY(5deg)}55%{opacity:1}to{opacity:1;transform:none}}
.js .hero .hx:nth-child(3){animation-delay:.55s}
.js .hero .three li{animation:mup .6s var(--m-ease) both;animation-delay:calc(.75s + var(--k,0) * .09s)}
.js .hero .three li:nth-child(2){--k:1}.js .hero .three li:nth-child(3){--k:2}
@keyframes mup{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* hero photo: slow Ken Burns settle inside a clipped frame (.kb), scroll parallax where scroll-driven animations exist */
.js .hero-fig picture::before{display:none}
.js .hero-fig::before{content:"";position:absolute;inset:14% -6% 10% 14%;border-radius:40%;background:radial-gradient(closest-side,rgba(255,122,47,.32),rgba(255,61,138,.12) 60%,transparent);filter:blur(26px);z-index:-1;animation:glow 9s var(--m-out) both}
@keyframes glow{from{opacity:0;transform:scale(.8)}to{opacity:1;transform:none}}
.js .kb{position:relative;overflow:hidden;border-radius:var(--r);border:1px solid var(--line-2);box-shadow:0 40px 70px -36px rgba(0,0,0,.9);aspect-ratio:4/3;transform:translateZ(0)}
@media(min-width:900px){.js .kb{aspect-ratio:4/5}}
.js .kb img{border:0;border-radius:0;box-shadow:none;width:100%;height:100%;aspect-ratio:auto;animation:kb 8s var(--m-out) both;transform-origin:50% 40%;will-change:transform}
@keyframes kb{from{opacity:0;transform:scale(1.16) translateY(-1.5%)}18%{opacity:1}to{opacity:1;transform:none}}
@supports (animation-timeline:view()){
 .js .kb{animation:kbpar linear both;animation-timeline:view();animation-range:exit 0% exit 100%}
 @keyframes kbpar{to{transform:translateY(-34px)}}
}
/* drifting sunset hairline under the hero + a scroll cue line (desktop) */
.js .hero::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;pointer-events:none;opacity:.8;background:linear-gradient(90deg,transparent,var(--sun-1) 25%,var(--sun-2) 50%,var(--sun-3) 75%,transparent);background-size:200% 100%;animation:drift 14s ease-in-out infinite alternate}
@keyframes drift{from{background-position:0% 0}to{background-position:100% 0}}
.js .hero .wrap{position:relative}
@media(min-width:900px){
 .js .hero .wrap::after{content:"";position:absolute;left:28px;bottom:-28px;width:1px;height:24px;background:linear-gradient(var(--sun-1),transparent);transform-origin:top;animation:scue 2.2s var(--m-out) infinite;transition:opacity .4s}
 .js.sc .hero .wrap::after{opacity:0}
}
@keyframes scue{0%{transform:scaleY(0);transform-origin:top}45%,55%{transform:scaleY(1)}56%{transform-origin:bottom}100%{transform:scaleY(0);transform-origin:bottom}}

/* ---------- 2. sections: directional reveals, ruled headings that draw, eyebrow numerals that count ---------- */
.js .rv{transition-duration:.7s;transition-timing-function:var(--m-ease)}
.js .box.rv,.js .flag.rv,.js .pc.rv{transform:translateY(22px) scale(.985)}
.js .box.rv.in,.js .flag.rv.in,.js .pc.rv.in{transform:none}
@media(min-width:720px){
 .js .grid2>.rv:first-child{transform:translateX(-26px)}
 .js .grid2>.rv:last-child{transform:translateX(26px)}
 .js .grid2>.rv.in{transform:none}
}
/* the tiers inside the pick box deal in after the box */
.js .pick.rv:not(.in) .tier{opacity:0}
.js .pick.rv.in .tier{animation:mup .7s var(--m-ease) backwards}
.js .pick.rv.in .tier:nth-child(1){animation-delay:.18s}.js .pick.rv.in .tier:nth-child(2){animation-delay:.3s}.js .pick.rv.in .tier:nth-child(3){animation-delay:.42s}
/* ruled h2: the hairline draws from the left (JS adds .in on view) */
.js .art h2,.js .prose h2:not(:first-child){position:relative;border-top-color:transparent}
.js .art h2::before,.js .prose h2:not(:first-child)::before{content:"";position:absolute;left:0;right:0;top:-1px;height:1px;background:linear-gradient(90deg,var(--sun-1),var(--line-2) 28%);transform:scaleX(0);transform-origin:left;transition:transform 1s var(--m-ease)}
.js .art h2.in::before,.js .prose h2.in::before{transform:scaleX(1)}
/* numerals: registered integer property, counted up in CSS (JS sets --n and .cnt only where @property exists) */
@property --mn{syntax:"<integer>";inherits:false;initial-value:0}
.js .sec .eyebrow.cnt::before{--mn:0;counter-reset:mn var(--mn);content:counter(mn,decimal-leading-zero);transition:--mn 1.1s var(--m-ease)}
.js .sec .eyebrow.cnt.in::before{--mn:var(--n)}

/* ---------- 3. photos (the photos2 components live in sbcc.css: .hero-full, .pgrid, .pstrip, .pband, .photo) ---------- */
/* tiles: the frame moves from the img to the picture so the img can zoom inside it; grain + zoom on hover (fine pointer) */
.js .photo picture{position:relative;overflow:hidden;border-radius:var(--r);border:1px solid var(--line-2);background:var(--card-2);transform:translateZ(0)}
.js .photo img{border:0;border-radius:0;transition:transform 1s var(--m-ease)}
.js .photo picture::after,.js .pc .im::after{content:"";position:absolute;inset:0;pointer-events:none;opacity:0;mix-blend-mode:overlay;transition:opacity .5s;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E")}
.js .pc .im{position:relative}
@media(hover:hover) and (pointer:fine){
 .js .photo:hover img{transform:scale(1.06)}
 .js .photo:hover picture::after,.js .pc:hover .im::after{opacity:.5}
}
/* tile reveals (JS adds .in with a sibling stagger; fail-safe keyframe shows everything after 4 s) */
.js :is(.pgrid,.pstrip,.art,.prose) .photo{opacity:0;transform:translateY(18px) scale(.98);transition:opacity .75s var(--m-ease),transform .75s var(--m-ease)}
.js :is(.pgrid,.pstrip,.art,.prose) .photo:not(.in){animation:msafe .01s 4s forwards}
.js :is(.pgrid,.pstrip,.art,.prose) .photo.in{opacity:1;transform:none}
@keyframes msafe{to{opacity:1;transform:none}}
/* full-bleed photo layers: scroll-speed parallax (CSS scroll-driven, compositor only; older browsers keep the static photo) */
@supports (animation-timeline:view()){
 .js .pband,.js .hero-full{overflow:clip} /* hidden would make them scroll containers and freeze the view() timeline */
 .js .pband .bg,.js .hero-full .bg{inset:-12% 0;animation:bgpar linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
 @keyframes bgpar{from{transform:translateY(-6%)}to{transform:translateY(6%)}}
}
/* hero stack: slow vertical drift on the photo layers inside the taller .bg (desktop only: the frosted panel's backdrop blur stays cheap on phones) */
@media(min-width:900px) and (hover:hover){
 .js .hero-full .bg picture{animation:kbs 30s ease-in-out infinite alternate}
 @keyframes kbs{from{transform:translateY(0)}to{transform:translateY(-2.5%)}} /* vertical only: a scale would make the 100vw layer measure wider than the viewport */
}
/* photo strip: phones swipe it with snap; desktop runs it as a slow train (JS clones the 3 tiles twice; paused on hover and off-screen) */
@media(max-width:719px){
 .js .sec.strip .wrap{overflow:hidden}
 .js .pstrip{display:flex;gap:10px;margin:0 -16px;padding:0 16px 4px;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}
 .js .pstrip::-webkit-scrollbar{display:none}
 .js .pstrip .photo{flex:0 0 76%;scroll-snap-align:center;margin:0}
 .js .pstrip .photo img{aspect-ratio:4/5}
}
@media(min-width:720px) and (prefers-reduced-motion:no-preference){
 .js .sec.strip{overflow:hidden}
 .js .pstrip{display:flex;gap:14px;width:max-content;margin-left:calc(50% - 50vw);padding-left:14px;animation:train 54s linear infinite paused}
 .js .pstrip.run{animation-play-state:running}
 .js .pstrip:hover{animation-play-state:paused}
 .js .pstrip .photo{flex:0 0 clamp(240px,26vw,370px);margin:0}
 @keyframes train{to{transform:translateX(calc(-100% / 3))}}
}

/* ---------- 4. tools ---------- */
/* calculator: tabular numbers in pinned boxes, break-even bars (fill = nights needed out of 7, tick = your nights) */
.js #spend,.js .calc .out b{font-variant-numeric:tabular-nums}
.js #spend{display:inline-block;min-width:3.4ch}
.calc .out .bar{display:none}
.js .calc .out .bar{display:block;position:relative;height:3px;margin:10px 0 10px;border-radius:2px;background:var(--line-2);overflow:visible}
.js .calc .out .bar i{display:block;height:100%;border-radius:2px;background:var(--grad-btn);transform:scaleX(var(--p,0));transform-origin:left;transition:transform .6s var(--m-ease)}
.js .calc .out .bar.over i{background:var(--no)}
.js .calc .out .bar::after{content:"";position:absolute;top:-4px;bottom:-4px;left:calc(var(--n,0) * 100%);width:2px;margin-left:-1px;background:var(--ink);opacity:.7;transition:left .5s var(--m-ease)}
.js .calc .out div.tick b{animation:tick .45s var(--m-ease)}
@keyframes tick{40%{transform:scale(1.06);color:var(--sun-1)}}
/* level picker: one question at a time, slide between steps, verdict stamp */
.js .quiz:not(.stepping) .q+.q{display:none}
.js .quiz.stepping .q{display:none}
.js .quiz.stepping .q.cur{display:block;animation:qin .4s var(--m-ease) both}
.js .quiz.stepping .q+.q{padding-top:0;border-top:0}
.js .quiz .q{margin-bottom:18px}
@keyframes qin{from{opacity:0;transform:translateX(26px)}to{opacity:1;transform:none}}
.quiz .qnav{display:none}
.js .quiz .qnav{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:44px;margin:0 0 18px;padding-top:14px;border-top:1px solid var(--line)}
.js .quiz .qnav .qback[hidden],.js .quiz .qnav .qnext[hidden]{display:none}
.js .quiz .qnav .qback{margin-right:auto}
.js .quiz .qnav .qnext{margin-left:auto}
.qdots{list-style:none;display:flex;gap:10px;margin:0;padding:0;order:1;margin-left:auto;margin-right:auto}
.qdots li{width:8px;height:8px;margin:0;border-radius:50%;background:var(--line-2);transition:background .3s,transform .3s var(--m-ease),box-shadow .3s}
.qdots li.on{background:var(--sun-1)}
.qdots li.cur{transform:scale(1.4);box-shadow:0 0 0 1px var(--sun-1),0 0 12px rgba(255,122,47,.6)}
.js .result{position:relative}
.js .result.show{animation:resin .5s var(--m-ease) both}
@keyframes resin{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:none}}
.js .result.show::after{content:"Verdict";position:absolute;right:14px;top:12px;padding:6px 9px;border:2px solid var(--sun-1);border-radius:4px;color:var(--sun-1);font:800 .72rem/1 var(--body);letter-spacing:.22em;text-transform:uppercase;transform:rotate(-8deg);animation:stamp .55s .18s cubic-bezier(.2,1.6,.4,1) both;pointer-events:none}
@keyframes stamp{from{opacity:0;transform:rotate(-14deg) scale(2.4)}to{opacity:1;transform:rotate(-8deg) scale(1)}}
/* red flags: the PCB answer expands on tap with a smooth row transition; card tilts a touch as it opens */
.js .flag .pcb-t{all:unset;display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;min-height:36px;cursor:pointer;color:inherit;font:inherit;border-radius:4px}
.js .flag .pcb-t:focus-visible{outline:3px solid var(--gold);outline-offset:3px}
.js .flag .pcb-t b{margin:0}
.js .flag .pcb-t i{flex:none;position:relative;width:18px;height:18px;transition:transform .45s var(--m-ease)}
.js .flag .pcb-t i::before,.js .flag .pcb-t i::after{content:"";position:absolute;left:3px;right:3px;top:8px;height:2px;background:var(--ok);border-radius:1px}
.js .flag .pcb-t i::after{transform:rotate(90deg);transition:transform .45s var(--m-ease)}
.js .flag.open .pcb-t i{transform:rotate(180deg)}
.js .flag.open .pcb-t i::after{transform:rotate(0)}
.js .flag .pcb-c{display:grid;grid-template-rows:0fr;transition:grid-template-rows .5s var(--m-ease)}
.js .flag .pcb-c>div{overflow:hidden;min-height:0}
.js .flag .pcb-c p{padding-top:8px}
.js .flag.open .pcb-c{grid-template-rows:1fr}
.js .flag{transform-style:preserve-3d}
.js .flag.open{animation:flip .55s var(--m-ease)}
@keyframes flip{35%{transform:perspective(1100px) rotateX(-4deg)}}
/* faq: height is animated by JS (WAAPI on the details box); the answer fades/slides in */
.js .faq details[open] .a{animation:fa .4s .08s var(--m-ease) both}
@keyframes fa{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}

/* ---------- 5. buttons, links, header ---------- */
.js .btn{position:relative;overflow:hidden;-webkit-tap-highlight-color:transparent;transition:transform .25s var(--ease),box-shadow .25s var(--ease),background-color .25s var(--ease),border-color .25s,translate .45s var(--m-ease),scale .12s ease-out}
.js .btn:active{scale:.96}
@media(hover:hover) and (pointer:fine){
 .js .btn::after{content:"";position:absolute;top:-30%;bottom:-30%;left:0;width:40%;pointer-events:none;opacity:0;background:linear-gradient(105deg,rgba(255,255,255,0) 15%,rgba(255,255,255,.42) 50%,rgba(255,255,255,0) 85%);transform:translateX(-170%) skewX(-18deg)}
 .js .btn-g::after{background:linear-gradient(105deg,rgba(255,255,255,0) 15%,rgba(255,255,255,.14) 50%,rgba(255,255,255,0) 85%)}
 .js .btn:hover::after{animation:msheen .75s var(--m-ease) forwards}
}
@keyframes msheen{0%{transform:translateX(-170%) skewX(-18deg);opacity:0}12%{opacity:1}100%{transform:translateX(340%) skewX(-18deg);opacity:0}}
.js .nav a::after{transform-origin:right}
.js .nav a:hover::after,.js .nav a[aria-current=page]::after{transform-origin:left}
.js .hd{transition:background-color .4s,box-shadow .4s}
.js .hd::after{background-size:200% 100%;animation:drift 12s linear infinite alternate;transition:opacity .4s}
.js .hd .logo-img{transition:transform .5s var(--m-ease);transform-origin:left center}
.js.sc .hd{background:rgba(11,10,18,.95);box-shadow:0 14px 34px -22px rgba(0,0,0,.95)}
.js.sc .hd::after{opacity:1}
.js.sc .hd .logo-img{transform:scale(.86)}
.js .hd .hd-cta{transition:transform .5s var(--m-ease),box-shadow .25s var(--ease),background-color .25s,translate .45s var(--m-ease),scale .12s}
.js .mnav[open] .panel a{animation:mup .42s var(--m-ease) both;animation-delay:calc(var(--k,0) * 38ms)}
.js .mnav .panel a:nth-child(2){--k:1}.js .mnav .panel a:nth-child(3){--k:2}.js .mnav .panel a:nth-child(4){--k:3}.js .mnav .panel a:nth-child(5){--k:4}.js .mnav .panel a:nth-child(6){--k:5}.js .mnav .panel a:nth-child(7){--k:6}.js .mnav .panel a:nth-child(8){--k:7}.js .mnav .panel a:nth-child(9){--k:8}
/* reading progress (posts; JS inserts .prog, CSS scroll timeline where supported, JS scaleX otherwise) */
.prog{position:fixed;left:0;top:0;width:100%;height:2px;z-index:60;background:var(--grad);transform:scaleX(0);transform-origin:left;pointer-events:none}
@supports (animation-timeline:scroll()){.prog:not(.js){animation:prog linear both;animation-timeline:scroll(root)}}
@keyframes prog{to{transform:scaleX(1)}}

/* ---------- 6. page transitions + smooth anchors (feature-detected by the browser) ---------- */
@media(prefers-reduced-motion:no-preference){
 html{scroll-behavior:smooth}
 @view-transition{navigation:auto}
 ::view-transition-old(root){animation-duration:.2s}
 ::view-transition-new(root){animation-duration:.3s}
 .hd{view-transition-name:sbcc-hd}
}

/* ---------- 7. touch ---------- */
@media(pointer:coarse){
 .js .lift,.js .pc,.js .flag,.js .opt label{transition:transform .35s var(--ease),box-shadow .35s var(--ease),border-color .35s,background .2s,scale .18s var(--m-ease)}
 .js .lift:active,.js .pc:active,.js .opt input:active+label{scale:.985}
}

/* ---------- reduced motion: explicit static states (sbcc.css already zeroes every animation/transition) ---------- */
@media(prefers-reduced-motion:reduce){
 .js .pick.rv .tier,.js .kh .w>span{opacity:1;transform:none}
 .js .box.rv,.js .flag.rv,.js .pc.rv,.js .grid2>.rv{transform:none}
 .js .art h2::before,.js .prose h2::before{transform:scaleX(1)}
 .js .sec .eyebrow.cnt::before{--mn:var(--n)}
 .js .hero .wrap::after,.js .hero::after{display:none}
 .js .result.show::after{opacity:1}
}
@media print{
 .js .kh .w{overflow:visible}
 .js .flag .pcb-c{grid-template-rows:1fr!important}
 .js .quiz .q{display:block!important}
 .js .quiz .qnav,.prog,.js .calc .out .bar,.js .hero .wrap::after,.js .hero::after,.js .result.show::after{display:none!important}
 .js .pick.rv .tier,.js .kh .w>span{opacity:1!important;transform:none!important}
}
