/* Club Kahiki — loyalty program (public). Same visual language as the venue pages
   (Jost/Bungee, ink+bamboo+cream palette) but app-like: compact cards, big tap targets. */

:root{
  --ink:#150f0a;
  --ink-2:#1e150d;
  --ink-3:#28170c;
  --bamboo:#caa15c;
  --bamboo-dark:#6e4f28;
  --cream:#f4e8ce;
  --cream-dim:#d8c3a5;
  --accent:#8fce3e;
  --accent-2:#4f8f1f;
  --danger:#e0574a;
  --radius:18px;
  --shadow:0 20px 50px rgba(0,0,0,.45);
  --maxw:480px;
  --tap:48px;
  --ease-out:cubic-bezier(.23,1,.32,1);      /* strong ease-out — entrances/exits */
  --ease-in-out:cubic-bezier(.77,0,.175,1);  /* strong ease-in-out — movement on screen */
}
*,*::before,*::after{
  box-sizing:border-box;
  /* No gray tap-flash on links/buttons — a native app never shows this, only mobile Safari/
     Chrome's default touch feedback does. Each interactive element already has its own
     :active press-scale instead (see .btn, .quick-actions a, .bottom-nav button, etc.). */
  -webkit-tap-highlight-color:transparent;
}
html{ scroll-behavior:smooth; }
body{
  margin:0; min-height:100dvh; background:var(--ink); color:var(--cream);
  font-family:'Jost', system-ui, sans-serif; font-size:16px; line-height:1.55;
  /* Stops the whole-page rubber-band bounce at the very top/bottom from revealing anything
     behind the app (browser chrome / the ink page peeking past its own edge) — installed apps
     don't bounce the whole viewport like a browser tab does. */
  overscroll-behavior-y:contain;
}
/* app.js already toggles this on every modal (wheel, passport capture) — the rule itself was
   missing, so background scroll was never actually locked while a modal sat on top. */
body.modal-open{ overflow:hidden; }
h1,h2,h3{ font-family:'Bungee', system-ui, sans-serif; font-weight:400; line-height:1.1; margin:0 0 .5rem; }
p{ margin:0 0 1rem; color:var(--cream-dim); }
a{ color:var(--bamboo); }
img{ max-width:100%; display:block; }

.grain{
  position:fixed; inset:0; z-index:0; pointer-events:none; opacity:.04; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}

.wrap{ position:relative; z-index:1; max-width:var(--maxw); margin:0 auto; padding:20px 20px 60px; min-height:100dvh; }
.wrap--app{ padding-bottom:calc(80px + env(safe-area-inset-bottom, 0px)); touch-action:pan-y; }

/* Cold-start loading screen (index.php / login.php) — see app-loader.php + app-loader.js.
   Hidden by default (opacity:0/visibility:hidden) so a normal fast navigation never shows it at
   all — app-loader.js only adds .is-visible if the page is still loading past a short delay,
   so this only ever appears on a genuinely slow load, not on every page open. */
.app-loader{
  position:fixed; inset:0; z-index:9999; background:var(--ink);
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1.1rem;
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .4s ease;
}
.app-loader.is-visible{ opacity:1; visibility:visible; pointer-events:auto; }
.app-loader.is-hiding{ opacity:0; pointer-events:none; }
.app-loader__glow{
  position:absolute; width:220px; height:220px; border-radius:50%;
  background:radial-gradient(circle, rgba(202,161,92,.35) 0%, rgba(202,161,92,0) 70%);
}
.app-loader.is-visible .app-loader__glow{ animation:loaderGlow 2.4s ease-in-out infinite; }
.app-loader__logo{
  position:relative; width:88px; height:auto; opacity:0;
  filter:drop-shadow(0 8px 22px rgba(0,0,0,.55));
}
.app-loader.is-visible .app-loader__logo{
  animation:loaderLogoIn .7s cubic-bezier(.22,.61,.36,1) .05s both,
            loaderLogoPulse 2.4s ease-in-out .75s infinite;
}
.app-loader__title{
  position:relative; display:flex; font-family:'Bungee', system-ui, sans-serif; font-weight:400;
  font-size:1.15rem; letter-spacing:.03em; color:var(--cream);
}
.app-loader__title span{ display:inline-block; opacity:0; transform:translateY(12px); }
.app-loader.is-visible .app-loader__title span{
  animation:loaderLetterIn .5s cubic-bezier(.22,.61,.36,1) forwards;
  animation-delay:calc(.5s + var(--i) * .045s);
}
.app-loader__space{ width:.4em; }
.app-loader__dots{ position:relative; display:flex; gap:.4rem; margin-top:.2rem; opacity:0; }
.app-loader.is-visible .app-loader__dots{ animation:loaderFadeIn .4s ease 1.3s forwards; }
.app-loader__dots span{ width:6px; height:6px; border-radius:50%; background:var(--bamboo); }
.app-loader.is-visible .app-loader__dots span{ animation:loaderDotBounce 1.1s ease-in-out infinite; }
.app-loader__dots span:nth-child(2){ animation-delay:.15s; }
.app-loader__dots span:nth-child(3){ animation-delay:.3s; }
@keyframes loaderGlow{
  0%,100%{ transform:scale(.9); opacity:.6; }
  50%{ transform:scale(1.15); opacity:1; }
}
@keyframes loaderLogoIn{
  0%{ opacity:0; transform:scale(.6) translateY(10px); }
  100%{ opacity:1; transform:scale(1) translateY(0); }
}
@keyframes loaderLogoPulse{
  0%,100%{ transform:scale(1); }
  50%{ transform:scale(1.06); }
}
@keyframes loaderLetterIn{
  to{ opacity:1; transform:translateY(0); }
}
@keyframes loaderFadeIn{
  to{ opacity:1; }
}
@keyframes loaderDotBounce{
  0%,60%,100%{ transform:translateY(0); opacity:.5; }
  30%{ transform:translateY(-5px); opacity:1; }
}
@media(prefers-reduced-motion:reduce){
  .app-loader{ transition:none; }
  .app-loader__glow, .app-loader__logo, .app-loader__title span, .app-loader__dots, .app-loader__dots span{
    animation:none !important; opacity:1 !important; transform:none !important;
  }
}

.club-header{ position:relative; display:flex; align-items:center; justify-content:center; gap:.6rem; padding:14px 0 18px; text-align:center; }
.club-header img{ height:28px; }
.club-header .eyebrow{
  display:block; font-size:.7rem; letter-spacing:.28em; text-transform:uppercase; color:var(--bamboo);
  margin-top:.4rem;
}
.club-header-row{ display:flex; flex-direction:column; align-items:center; }

/* Small "Mi perfil" entry point, top-right of the app header — the app's only 4 primary
   sections (Home/Tarjeta/Recompensas/Pasaporte) live in the bottom tab bar; Perfil is
   deliberately kept off it (secondary/settings-like, not something you flip to constantly) and
   reached from here instead. Only rendered on index.php (the logged-in app shell) — login.php/
   registro.php/etc. share the same .club-header but have no profile to link to. */
.club-header__profile-btn{
  position:absolute; top:50%; right:0; transform:translateY(-50%);
  display:flex; align-items:center; justify-content:center;
  width:34px; height:34px; border-radius:50%;
  background:rgba(244,232,206,.08); border:1px solid rgba(202,161,92,.3);
  font-size:1rem; line-height:1; text-decoration:none; cursor:pointer;
  transition:background .2s ease, border-color .2s ease, transform .2s ease;
}
.club-header__profile-btn:active{ transform:translateY(-50%) scale(.9); background:rgba(244,232,206,.16); }

/* Buttons */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.5rem; width:100%;
  min-height:var(--tap); padding:.85rem 1.4rem; border-radius:100px; border:1px solid transparent;
  font-size:.92rem; font-weight:600; letter-spacing:.02em; text-decoration:none; cursor:pointer;
  transition:background-color 180ms ease, color 180ms ease, border-color 180ms ease,
             box-shadow 180ms ease, transform 90ms ease;
  font-family:inherit;
}
/* Press feedback on every variant (previously only .btn--solid had one) — the instant-down,
   ease-back-up asymmetry (90ms in via the transition above, a touch slower back out) is what
   makes a tap feel acknowledged immediately, the way native controls do. */
.btn:active{ transform:scale(.96); }
.btn--solid{ background:var(--bamboo); color:#241a0a; }
.btn--solid:hover{ background:#e0b876; transform:translateY(-1px); }
.btn--outline{ border-color:rgba(244,232,206,.3); color:var(--cream); background:none; }
.btn--outline:hover{ border-color:var(--bamboo); color:var(--bamboo); }
.btn--ghost{ background:none; border:none; color:var(--cream-dim); text-decoration:underline; min-height:auto; width:auto; padding:.3rem; font-weight:400; font-size:.85rem; }
.btn--ghost:active{ transform:scale(.97); }
.btn[disabled]{ opacity:.55; pointer-events:none; }
@media (prefers-reduced-motion:reduce){
  .btn, .btn:active{ transition:none; transform:none !important; }
}

/* Cards */
.card{
  background:var(--ink-2); border:1px solid rgba(202,161,92,.22); border-radius:var(--radius);
  padding:1.5rem 1.4rem; margin-bottom:1.1rem; box-shadow:var(--shadow);
}
.card h2{ font-size:1.1rem; margin-bottom:.7rem; }

/* Forms */
.field{ display:flex; flex-direction:column; gap:.4rem; margin-bottom:1rem; }
.field label{ font-size:.78rem; color:var(--cream-dim); text-transform:uppercase; letter-spacing:.05em; }
.field input, .field textarea{
  background:var(--ink); border:1px solid rgba(244,232,206,.22); border-radius:10px;
  padding:.85rem .9rem; color:var(--cream); font-size:1rem; font-family:inherit; min-height:var(--tap);
}
.field input:focus, .field textarea:focus{ outline:none; border-color:var(--bamboo); }
.field-hint{ font-size:.75rem; color:var(--cream-dim); opacity:.85; text-transform:none; letter-spacing:normal; }
.field-check{ display:flex; align-items:flex-start; gap:.6rem; font-size:.82rem; color:var(--cream-dim); }
.field-check input{ margin-top:.2rem; width:18px; height:18px; accent-color:var(--bamboo); flex:0 0 auto; }
.form-msg{ font-size:.85rem; padding:.7rem .9rem; border-radius:10px; margin-bottom:1rem; }
.form-msg--error{ background:rgba(224,87,74,.15); color:#ff9e91; }
.form-msg--ok{ background:rgba(143,206,62,.15); color:#c3ec8f; }

/* Perfil — read-only account summary (name/email/DOB come from signup, not editable here) */
.profile-view__row{
  display:flex; justify-content:space-between; align-items:baseline; gap:1rem;
  padding:.6rem 0; border-bottom:1px solid rgba(244,232,206,.1); font-size:.92rem;
}
.profile-view__row:last-child{ border-bottom:none; padding-bottom:0; }
.profile-view__row span{ color:var(--cream-dim); font-size:.82rem; }
.profile-view__row strong{ color:var(--cream); text-align:right; }

/* Membership card */
.member-card{
  position:relative; border-radius:20px; padding:1.3rem 1.3rem; margin-bottom:1rem;
  background:
    radial-gradient(circle at 15% -10%, rgba(202,161,92,.35), transparent 55%),
    linear-gradient(155deg, #241a0d 0%, #150f0a 65%);
  border:1px solid rgba(202,161,92,.4); box-shadow:0 25px 60px rgba(0,0,0,.55);
  overflow:hidden;
}
.member-card::before{
  content:''; position:absolute; top:-40%; right:-30%; width:220px; height:220px; border-radius:50%;
  background:radial-gradient(circle, rgba(143,206,62,.18), transparent 70%); pointer-events:none;
}
.member-card__top{ display:flex; justify-content:space-between; align-items:flex-start; margin-bottom:1rem; }
.member-card__brand{ font-family:'Bungee', system-ui, sans-serif; font-size:1rem; color:var(--bamboo); letter-spacing:.02em; }
.member-card__tier{ font-size:.65rem; text-transform:uppercase; letter-spacing:.14em; color:var(--cream-dim); }
.member-card__name{ font-size:1.15rem; font-weight:600; margin-bottom:.2rem; word-break:break-word; }
.member-card__code{ font-size:.72rem; color:var(--cream-dim); letter-spacing:.08em; font-variant-numeric:tabular-nums; }
.member-card__points{ display:flex; align-items:baseline; gap:.4rem; margin-top:1.1rem; }
.member-card__points strong{ font-family:'Bungee', system-ui, sans-serif; font-size:2.4rem; color:var(--accent); line-height:1; }
.member-card__points span{ font-size:.78rem; color:var(--cream-dim); text-transform:uppercase; letter-spacing:.05em; }

.qr-wrap{
  background:var(--cream); border-radius:16px; padding:14px; display:flex; align-items:center;
  justify-content:center; margin:0 0 .9rem;
}
.qr-wrap img{ width:100%; max-width:210px; }
.qr-hint{ text-align:center; font-size:.78rem; color:var(--cream-dim); margin:-.5rem 0 1rem; }

/* Rewards list */
.rewards-list{ display:flex; flex-direction:column; gap:.7rem; }
.reward-item{
  display:flex; align-items:center; gap:.9rem; background:var(--ink); border:1px solid rgba(244,232,206,.1);
  border-radius:14px; padding:.8rem .9rem;
}
.reward-item__info{ flex:1; min-width:0; }
.reward-item__name{ font-weight:600; font-size:.92rem; margin-bottom:.1rem; }
.reward-item__desc{ font-size:.78rem; color:var(--cream-dim); }
.reward-item__cost{
  flex:0 0 auto; font-size:.85rem; font-weight:700; color:var(--bamboo); white-space:nowrap;
  background:rgba(202,161,92,.12); padding:.4rem .7rem; border-radius:100px;
}
.reward-item--locked{ opacity:.5; }

/* History */
.history-item{
  display:flex; justify-content:space-between; align-items:center; gap:.8rem; padding:.7rem 0;
  border-top:1px dashed rgba(244,232,206,.1); font-size:.85rem;
}
.history-item:first-child{ border-top:none; }
.history-item__desc{ color:var(--cream); }
.history-item__date{ font-size:.72rem; color:var(--cream-dim); }
.history-item__points{ font-weight:700; white-space:nowrap; }
.history-item__points--earn{ color:var(--accent); }
.history-item__points--redeem{ color:var(--danger); }

.tabs{ display:flex; gap:.4rem; margin-bottom:1rem; background:var(--ink); border-radius:100px; padding:4px; }
.tabs button{
  flex:1; background:none; border:none; color:var(--cream-dim); font-family:inherit; font-size:.82rem;
  padding:.6rem 0; border-radius:100px; cursor:pointer; min-height:40px;
  transition:background-color .22s ease, color .22s ease, transform 90ms ease;
}
.tabs button.is-active{ background:var(--bamboo); color:#241a0a; font-weight:600; }
.tabs button:active{ transform:scale(.96); }
.tab-panel{ display:none; }
.tab-panel.is-active{ display:block; animation:kahikiFadeUp .28s cubic-bezier(.22,.61,.36,1); }
@keyframes kahikiFadeUp{ from{ opacity:0; transform:translateY(6px); } to{ opacity:1; transform:translateY(0); } }
@media (prefers-reduced-motion:reduce){
  .tabs button{ transition:none; }
  .tab-panel.is-active{ animation:none; }
}

.club-footer{ text-align:center; margin-top:2rem; }
.club-footer a{ font-size:.8rem; }

/* Small "what's new" banner at the bottom of login/registro — announces a feature without
   competing with the form above it. Same warm accent as .giftcard-promo for visual continuity. */
.login-promo{
  display:flex; align-items:center; gap:.9rem;
  background:linear-gradient(155deg, rgba(224,120,150,.14) 0%, var(--ink-2) 70%);
  border:1px solid rgba(224,120,150,.3); border-radius:14px;
  padding:.8rem 1rem; margin-top:1.6rem;
}
.login-promo__icon{ width:34px; height:34px; flex:0 0 auto; }
.login-promo__text{ display:flex; flex-direction:column; gap:.15rem; }
.login-promo__text strong{ font-size:.78rem; color:#e07896; font-family:'Jost',system-ui,sans-serif; font-weight:600; }
.login-promo__text span{ font-size:.76rem; color:var(--cream-dim); line-height:1.35; }

.empty-note{ text-align:center; color:var(--cream-dim); font-size:.85rem; padding:1rem 0; }

@media (min-width:560px){
  .wrap{ padding-top:40px; }
}

/* ==========================================================================
   Installable webapp: bottom nav, push banner, hero, big points, wallet card
   ========================================================================== */

/* Bottom nav — same component/measurements as the staff CMS for a consistent feel */
.bottom-nav{
  position:fixed; left:0; right:0; bottom:0; z-index:25; max-width:var(--maxw); margin:0 auto;
  display:flex; background:var(--ink-2); border-top:1px solid rgba(202,161,92,.22);
  padding-bottom:env(safe-area-inset-bottom, 0);
}
.bottom-nav a, .bottom-nav button{
  flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:.15rem;
  padding:.6rem 0 .5rem; text-decoration:none; color:var(--cream-dim); font-size:.68rem; min-height:56px;
  background:none; border:none; font-family:inherit; cursor:pointer;
  transition:color .2s ease;
}
.bottom-nav a:active, .bottom-nav button:active{ transform:scale(.92); }
.bottom-nav__icon{ font-size:1.25rem; line-height:1; transition:transform .2s ease; display:inline-block; }
.bottom-nav a.is-active, .bottom-nav button.is-active{ color:var(--accent); }
/* Glowing bar that slides to sit above whichever tab is active — app.js moves it on every
   section change (tap, swipe, or browser back/forward), same easing family as the section
   slide-in so the whole nav reads as one coordinated motion instead of a plain color swap. */
.bottom-nav__indicator{
  position:absolute; top:0; left:0; width:25%; height:3px; border-radius:0 0 4px 4px;
  background:var(--accent); box-shadow:0 0 10px rgba(143,206,62,.65);
  transition:transform .32s cubic-bezier(.34,1.2,.4,1);
  pointer-events:none;
}
.bottom-nav__icon--pop{ animation:bottomNavIconPop .38s cubic-bezier(.34,1.56,.64,1); }
@keyframes bottomNavIconPop{
  0%{ transform:scale(1); }
  40%{ transform:scale(1.35); }
  100%{ transform:scale(1); }
}
@media (prefers-reduced-motion:reduce){
  .bottom-nav__indicator{ transition:none; }
  .bottom-nav__icon--pop{ animation:none; }
}

/* App sections (Home / Tarjeta / Recompensas) — switched client-side, no page reload, so the
   background video and any push-permission state never get interrupted mid-session. */
.app-section{ display:none; }
.app-section.is-active{ display:block; }

/* Live swipe drag (see enableSwipeNav in app.js): for the moment of the gesture, the outgoing
   (.is-active) and incoming (.is-dragging) sections both become an absolutely-positioned
   overlay so they can sit side by side and slide together instead of stacking in the document.
   `top` is set explicitly by app.js (measured at drag start) rather than left to the browser's
   implicit "static position" fallback — that fallback turned out unreliable in practice (cards
   visibly resizing/jumping mid-drag), which is why an explicit, measured value replaced it.
   .wrap--app gets an inline min-height at drag start so the page doesn't jump while its
   children are briefly out of flow. */
.wrap--app.is-swiping{ position:relative; overflow-x:hidden; }
.app-section.is-dragging,
.wrap--app.is-swiping .app-section.is-active{
  display:block; position:absolute; left:0; width:100%;
  /* Hints the browser to promote both cards to their own compositor layer up front — without
     this, the very first transform write of a drag can force a late layer promotion mid-gesture,
     which is what a "mini glitch" right as the swipe starts usually is. Only applied while a
     swipe is actually live (these classes toggle off at drag end), not left on permanently. */
  will-change:transform;
  backface-visibility:hidden;
}
/* .club-footer ("Cerrar sesión") is a normal-flow sibling that comes AFTER all four sections —
   once the active section is pulled out of flow above (position:absolute, regardless of its
   `top` value), it stops contributing height to the page, so the next flow sibling collapses
   upward to sit right under the header instead of at the bottom. Simplest fix: it's not worth
   seeing at all for the ~300ms a swipe is actually in progress, so just hide it for that window
   rather than trying to keep a flow element's position stable while its neighbors are yanked out
   of flow around it. */
.wrap--app.is-swiping .club-footer{ visibility:hidden; }

/* Swiping (or tapping the bottom nav) between Home / Tarjeta / Recompensas plays a short
   slide-in, direction-aware — makes the switch read as moving between adjacent cards rather
   than a plain content swap, closer to a native app than a web page. */
.app-section.slide-in-right{ animation:kahikiSlideInRight .26s cubic-bezier(.22,.61,.36,1); }
.app-section.slide-in-left{ animation:kahikiSlideInLeft .26s cubic-bezier(.22,.61,.36,1); }
@keyframes kahikiSlideInRight{
  from{ opacity:0; transform:translateX(28px); }
  to{ opacity:1; transform:translateX(0); }
}
@keyframes kahikiSlideInLeft{
  from{ opacity:0; transform:translateX(-28px); }
  to{ opacity:1; transform:translateX(0); }
}
@media (prefers-reduced-motion:reduce){
  .app-section.slide-in-right, .app-section.slide-in-left{ animation:none; }
}

/* Push notification banner */
.push-banner{
  display:none; align-items:center; justify-content:space-between; gap:.8rem; flex-wrap:wrap;
  background:rgba(202,161,92,.12); border:1px solid rgba(202,161,92,.3); border-radius:12px;
  padding:.7rem .9rem; margin:0 0 .8rem; font-size:.82rem; color:var(--cream); line-height:1.4;
}
.push-banner .btn{ flex:0 0 auto; width:auto; }

/* Home page background video — fixed behind the whole viewport, not just a card. The video
   itself has its white background already keyed out and composited onto var(--ink) at export
   time (see coin-hero-bg.mp4), so it drops straight onto the page with no visible seam. */
.page-bg-video{ position:fixed; inset:0; z-index:0; overflow:hidden; background:var(--ink); }
.page-bg-video video{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; opacity:.7; }
.page-bg-video::after{
  content:''; position:absolute; inset:0;
  background:
    radial-gradient(circle at 50% 30%, transparent 0%, rgba(21,15,10,.35) 55%, var(--ink) 92%);
}
body.has-video-bg{ background:var(--ink); }
body.has-video-bg .wrap{ position:relative; z-index:2; }
body.has-video-bg .grain{ z-index:1; }

.home-greeting{ position:relative; z-index:2; text-align:center; padding-top:1rem; }
.home-greeting__hi{ font-size:.85rem; color:var(--cream-dim); margin-bottom:.2rem; }
.home-points{ font-family:'Bungee', system-ui, sans-serif; font-size:4.4rem; line-height:1; color:var(--accent); text-shadow:0 6px 24px rgba(0,0,0,.5); }
.home-points__label{ font-size:.78rem; color:var(--cream-dim); text-transform:uppercase; letter-spacing:.12em; margin-top:.3rem; }

.quick-actions{ display:grid; grid-template-columns:repeat(3,1fr); gap:.6rem; margin:1.1rem 0 .9rem; }
.quick-actions a{
  display:flex; flex-direction:column; align-items:center; gap:.4rem; text-align:center;
  background:var(--ink-2); border:1px solid rgba(202,161,92,.22); border-radius:16px;
  padding:1.1rem .6rem; text-decoration:none; color:var(--cream); font-size:.82rem; font-weight:600;
  transition:transform 90ms ease, border-color 180ms ease;
}
.quick-actions a span.qa-icon{ font-size:1.6rem; }
.quick-actions a:active{ transform:scale(.97); border-color:rgba(202,161,92,.5); }

.home-activity__item{
  display:flex; justify-content:space-between; align-items:center; gap:.8rem; padding:.6rem 0;
  border-top:1px dashed rgba(244,232,206,.1); font-size:.85rem;
}
.home-activity__item:first-child{ border-top:none; }

/* Tarjeta page: wallet / install card */
.wallet-card{
  background:var(--ink-2); border:1px solid rgba(202,161,92,.22); border-radius:var(--radius);
  padding:1.05rem 1.15rem 1.15rem; margin-bottom:.8rem;
}
.wallet-card h3{ font-family:'Jost',system-ui,sans-serif; font-weight:600; font-size:.95rem; color:var(--bamboo); margin:0 0 .4rem; }
.wallet-card p{ font-size:.83rem; margin-bottom:.7rem; }
.wallet-card .btn{ margin-bottom:.6rem; }
.wallet-card .btn:last-child{ margin-bottom:0; }
.wallet-steps{ margin:0; padding-left:1.1rem; font-size:.82rem; color:var(--cream-dim); line-height:1.7; }

/* Home: "Regala Kahiki" promo card — same shape as .wallet-card, warmer accent to stand out */
.giftcard-promo{
  background:linear-gradient(155deg, rgba(224,120,150,.14) 0%, var(--ink-2) 70%);
  border-color:rgba(224,120,150,.35);
}
.giftcard-promo h3{ color:#e07896; }
.giftcard-promo p{ margin-bottom:0; }

/* Home's "Regala Kahiki" card as a tappable button (2026-09) — same footprint/background as the
   plain .giftcard-promo card above (still used as-is for the hero block inside the full
   Regala Kahiki section), just a <button> now: taps through to #section-regalo instead of
   sitting there as a dead-end paragraph. Only resets the native <button> properties that would
   otherwise fight the shared .wallet-card/.giftcard-promo look (border/font/appearance) —
   background, border-radius, padding etc. still come from those two classes untouched. */
.giftcard-promo--btn{
  border:none; -webkit-appearance:none; appearance:none; font:inherit; color:inherit;
  text-align:left; width:100%; display:block; cursor:pointer; transition:transform 90ms ease;
}
.giftcard-promo--btn:active{ transform:scale(.98); }
.giftcard-promo__row{ display:flex; align-items:center; gap:.9rem; }
.giftcard-promo__icon{ font-size:1.8rem; line-height:1; flex:0 0 auto; }
.giftcard-promo__text{ flex:1; display:flex; flex-direction:column; gap:.15rem; min-width:0; }
.giftcard-promo__text strong{ font-family:'Bungee', system-ui, sans-serif; font-weight:400; font-size:.92rem; color:#e07896; }
.giftcard-promo__text span{ font-size:.78rem; color:var(--cream-dim); }
.giftcard-promo__chevron{ font-size:1.5rem; color:#e07896; opacity:.7; flex:0 0 auto; }

/* Home's compact Pasaporte progress bar (2026-09) — replaces what used to be a full .wallet-card
   with a title/paragraph/button; the full explanation now lives on the passport's own cover
   (.passport-cover__desc in passport.css) since that's the natural place to read it, right
   before opening it. This is deliberately just a slim tappable row to save space on Home. */
.passport-mini{
  display:flex; align-items:center; gap:.8rem; text-decoration:none; color:var(--cream);
  background:var(--ink-2); border:1px solid rgba(202,161,92,.22); border-radius:14px;
  padding:.75rem .9rem; margin-bottom:.8rem; transition:transform 90ms ease, border-color 180ms ease;
}
.passport-mini:active{ transform:scale(.98); border-color:rgba(202,161,92,.5); }
.passport-mini__icon{ font-size:1.5rem; line-height:1; flex:0 0 auto; }
.passport-mini__body{ flex:1; display:flex; flex-direction:column; gap:.35rem; min-width:0; }
.passport-mini__label{ font-size:.8rem; font-weight:600; }
.passport-mini__track{ display:block; height:5px; border-radius:100px; background:rgba(244,232,206,.12); overflow:hidden; }
.passport-mini__track span{ display:block; height:100%; background:var(--accent); border-radius:100px; }
.passport-mini__chevron{ font-size:1.4rem; color:var(--bamboo); opacity:.7; flex:0 0 auto; }

/* Small sub-header for a section that isn't in the bottom nav (Regala Kahiki) — a back button +
   title, the same circular-icon language as .club-header__profile-btn so it reads as one
   consistent design system rather than a one-off. */
.section-subheader{ display:flex; align-items:center; gap:.7rem; margin:0 0 1.1rem; }
.section-subheader h2{ margin:0; }
.section-back{
  display:flex; align-items:center; justify-content:center; flex:0 0 auto;
  width:34px; height:34px; border-radius:50%;
  background:rgba(244,232,206,.08); border:1px solid rgba(202,161,92,.3);
  color:var(--cream); font-size:1.4rem; line-height:1; text-decoration:none;
  transition:transform .2s ease, background .2s ease;
}
.section-back:active{ transform:scale(.9); background:rgba(244,232,206,.16); }
@media (prefers-reduced-motion:reduce){
  .giftcard-promo--btn, .passport-mini, .section-back{ transition:none; }
}

/* Install banner (iOS "add to home screen" instructions on tarjeta.php) */
.install-banner{
  background:rgba(202,161,92,.1); border:1px dashed rgba(202,161,92,.35); border-radius:12px;
  padding:.9rem 1rem; margin-bottom:1rem; font-size:.82rem; color:var(--cream-dim); display:none;
}
.install-banner.is-visible{ display:block; }

/* "Añadir a Apple Wallet" — real .pkpass download once the cert is installed */
.apple-wallet-btn{
  display:flex; align-items:center; justify-content:center; gap:.55rem; width:100%;
  min-height:var(--tap); padding:.85rem 1.4rem; border-radius:12px; background:#000; color:#fff;
  text-decoration:none; font-family:inherit; font-size:.92rem; font-weight:600;
  transition:transform 90ms ease;
}
.apple-wallet-btn:active{ transform:scale(.98); }
.apple-wallet-btn__icon{
  width:20px; height:20px; flex:0 0 auto; display:inline-block; background:#fff;
  -webkit-mask-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.5 12.5c0-2-1.6-3-3-3H4.5v9c0 .8.7 1.5 1.5 1.5h11c.8 0 1.5-.7 1.5-1.5v-6zM19.5 9.5h-16V7c0-.8.7-1.5 1.5-1.5h13c.8 0 1.5.7 1.5 1.5v2.5z'/></svg>");
  mask-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.5 12.5c0-2-1.6-3-3-3H4.5v9c0 .8.7 1.5 1.5 1.5h11c.8 0 1.5-.7 1.5-1.5v-6zM19.5 9.5h-16V7c0-.8.7-1.5 1.5-1.5h13c.8 0 1.5.7 1.5 1.5v2.5z'/></svg>");
  -webkit-mask-size:contain; mask-size:contain; -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
}

/* "Guardar en Google Wallet" — a signed link, not a file download, but styled to match */
.google-wallet-btn{
  display:flex; align-items:center; justify-content:center; gap:.55rem; width:100%;
  min-height:var(--tap); padding:.85rem 1.4rem; border-radius:12px;
  background:#fff; color:#1f1f1f; text-decoration:none; font-family:inherit;
  font-size:.92rem; font-weight:600; border:1px solid rgba(0,0,0,.08); margin-top:.6rem;
  transition:transform 90ms ease;
}
.google-wallet-btn:active{ transform:scale(.98); }

/* QR tappable to save to wallet, when available */
.qr-wrap--tappable{ cursor:pointer; transition:transform 90ms ease; }
.qr-wrap--tappable:active{ transform:scale(.98); }
@media (prefers-reduced-motion:reduce){
  .quick-actions a, .apple-wallet-btn, .google-wallet-btn, .qr-wrap--tappable{ transition:none; }
}

/* Home: "Ruleta" promo card — same shape as .wallet-card, gold accent for the gamified feel */
.wheel-promo{
  background:linear-gradient(155deg, rgba(202,161,92,.16) 0%, var(--ink-2) 70%);
  border-color:rgba(202,161,92,.4);
}
.wheel-promo h3{ color:var(--bamboo); }

/* Prize wheel modal — shared shell, also used by the Pasaporte Tiki self-stamp camera modal.
   Kept as display:flex at all times (rather than display:none/flex toggling) so opening/closing
   can actually transition — opacity+scale, not an instant flash-in/flash-out. */
.wheel-modal{
  position:fixed; inset:0; z-index:200; background:#090603d9;
  display:flex; align-items:center; justify-content:center; padding:20px;
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .22s ease;
}
.wheel-modal.is-open{ opacity:1; visibility:visible; pointer-events:auto; }
.wheel-modal__panel{
  position:relative; background:var(--ink-2); border:1px solid rgba(202,161,92,.3);
  border-radius:20px; padding:1.8rem 1.4rem 1.6rem; width:100%; max-width:360px;
  text-align:center; box-shadow:0 30px 80px rgba(0,0,0,.6);
  transform:scale(.9) translateY(14px);
  transition:transform .32s cubic-bezier(.34,1.4,.4,1);
}
.wheel-modal.is-open .wheel-modal__panel{ transform:scale(1) translateY(0); }
@media (prefers-reduced-motion:reduce){
  .wheel-modal, .wheel-modal__panel{ transition:none; }
}
.wheel-modal__panel h3{ margin:0 0 .3rem; font-family:'Bungee', system-ui, sans-serif; font-size:1.1rem; color:var(--bamboo); }
.wheel-modal__panel .muted{ font-size:.82rem; margin-bottom:1.1rem; }
.wheel-modal__close{
  position:absolute; top:14px; right:16px; background:none; border:none;
  color:var(--cream-dim); font-size:1.3rem; cursor:pointer; line-height:1;
}

/* "Native OS permission sheet" — install-app and notification-permission prompts, styled as a
   bottom sheet that slides up from the screen edge (like the actual OS-level prompts these
   stand in for) rather than a centered dialog — kept visually distinct from the celebratory,
   centered .wheel-modal above. Same open/close mechanics (opacity+visibility+pointer-events, so
   it can actually transition instead of flashing), just anchored to the bottom with a transform
   slide instead of a scale. */
.native-sheet{
  position:fixed; inset:0; z-index:210; display:flex; align-items:flex-end; justify-content:center;
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .25s ease;
}
.native-sheet.is-open{ opacity:1; visibility:visible; pointer-events:auto; }
.native-sheet__backdrop{ position:absolute; inset:0; background:#090603d9; }
.native-sheet__panel{
  position:relative; width:100%; max-width:480px; background:var(--ink-2);
  border:1px solid rgba(202,161,92,.3); border-bottom:none;
  border-radius:24px 24px 0 0; padding:.5rem 1.6rem calc(1.7rem + env(safe-area-inset-bottom,0px));
  text-align:center; box-shadow:0 -20px 60px rgba(0,0,0,.55);
  transform:translateY(100%);
  transition:transform .36s var(--ease-out);
}
.native-sheet.is-open .native-sheet__panel{ transform:translateY(0); }
.native-sheet__handle{ display:block; width:36px; height:4px; border-radius:2px; background:rgba(244,232,206,.25); margin:.7rem auto 1.1rem; }
.native-sheet__icon{ font-size:2.3rem; line-height:1; margin-bottom:.6rem; }
.native-sheet__panel h3{ font-size:1.1rem; margin-bottom:.5rem; }
.native-sheet__panel p{ font-size:.85rem; margin-bottom:1.2rem; }
.native-sheet__actions{ display:flex; flex-direction:column; gap:.6rem; }
/* Android/generic copy shows by default; .is-ios flips which half is visible — no separate
   markup variant needed, both live in the DOM and CSS decides which one's shown. */
.native-sheet__ios-copy{ display:none; }
#installPromptSheet.is-ios .native-sheet__android-copy{ display:none; }
#installPromptSheet.is-ios .native-sheet__ios-copy{ display:block; }
#installPromptSheet.is-ios .native-sheet__android-only{ display:none; }
@media (prefers-reduced-motion:reduce){
  .native-sheet, .native-sheet__panel{ transition:none; }
}
.wheel-wrap{ position:relative; width:220px; height:220px; margin:0 auto 1.3rem; }
.wheel-pointer{
  position:absolute; top:-6px; left:50%; transform:translateX(-50%); z-index:2;
  color:var(--bamboo); font-size:1.6rem; line-height:1; text-shadow:0 2px 6px rgba(0,0,0,.6);
}
.wheel{
  width:100%; height:100%; border-radius:50%; position:relative;
  border:4px solid var(--bamboo); box-shadow:0 10px 30px rgba(0,0,0,.5), inset 0 0 0 2px rgba(21,15,10,.4);
  transform:rotate(0deg);
}
.wheel__label{
  position:absolute; top:50%; left:50%; width:50%; height:0;
  transform-origin:0 0; display:flex; align-items:center; justify-content:flex-end;
  padding-right:14px;
}
.wheel__label span{
  display:inline-block; transform:rotate(90deg); transform-origin:center;
  font-size:.7rem; font-weight:700; color:#fff; text-shadow:0 1px 3px rgba(0,0,0,.6);
  white-space:nowrap;
}
.wheel-result{ margin-top:.4rem; }
.wheel-result__prize{
  font-size:1rem; font-weight:700; color:var(--accent); margin-bottom:.9rem;
}

/* First-run GUIDED tour — a spotlight over the real on-screen zone plus a tooltip beside it,
   instead of a generic centered carousel. The dimming is four plain rectangles (top/bottom/
   left/right strips framing the highlighted zone) rather than the more common "huge box-shadow
   spread" coachmark trick — that technique turned out to render inconsistently at very large
   spread values in testing, while four ordinary boxes have no such edge case and degrade to a
   perfectly gap-free full-screen dim on their own whenever the highlighted rect is 0×0 (a bookend
   step with nothing to point at). Each strip also doubles as the "tap outside to skip" surface
   (pointer-events:auto), so there's no separate backdrop element. All four plus the accent frame
   around the highlighted zone are positioned in px by JS (assets/app.js) against the real target
   element's getBoundingClientRect(), recomputed on every step and on resize. */
.tour-overlay{
  position:fixed; inset:0; z-index:300;
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .22s var(--ease-out);
}
.tour-overlay.is-open{ opacity:1; visibility:visible; pointer-events:auto; }
/* Base is a 1×1px box pinned to the viewport's top-left corner with the transform origin there
   too — JS then expresses each strip's real rectangle purely as `translate(x,y) scale(w,h)`
   (scale factors ARE the pixel width/height, since the base is 1px). transform+opacity only,
   composited on the GPU, no layout/paint cost — a flat color fill with no border or content can't
   visibly distort under a non-uniform scale, which is what makes this safe here. Movement and
   opacity share their duration/easing exactly with .tour-highlight-frame and .tour-tooltip below
   (.32s move / .18s fade) so all three read as one synchronized piece, never three things
   independently drifting into place. Opacity is what app.js crossfades around a section change
   (see activateStep()) — a same-section move never touches it, only the transform. */
.tour-dim{
  position:fixed; top:0; left:0; width:1px; height:1px; transform-origin:0 0;
  z-index:301; background:rgba(9,6,3,.82); pointer-events:auto; opacity:1;
  transition:transform .32s var(--ease-in-out), opacity .18s var(--ease-out);
}
/* The one deliberate exception to transform-only in this file: a border that must stay crisp
   while morphing between two arbitrary rectangles has no distortion-free transform equivalent
   (non-uniform scale stretches border width unevenly) — same class of case the skill itself
   carves out for accordion height. Everything else in this tour is transform/opacity only. */
.tour-highlight-frame{
  position:fixed; z-index:301; border-radius:14px; border:2px solid rgba(202,161,92,.7);
  box-shadow:0 0 20px rgba(202,161,92,.4); pointer-events:none; opacity:1;
  transition:top .32s var(--ease-in-out), left .32s var(--ease-in-out),
             width .32s var(--ease-in-out), height .32s var(--ease-in-out),
             opacity .18s var(--ease-out);
}
.tour-tooltip{
  position:fixed; top:0; left:0; z-index:302; background:var(--ink-2);
  border:1px solid rgba(202,161,92,.3); border-radius:18px; padding:1.5rem 1.3rem 1.3rem;
  width:calc(100% - 32px); max-width:300px; text-align:center; box-shadow:0 20px 60px rgba(0,0,0,.6);
  opacity:0; transition:transform .32s var(--ease-in-out), opacity .18s var(--ease-out);
}
.tour-tooltip__icon{ font-size:2.2rem; line-height:1; margin-bottom:.5rem; }
.tour-tooltip h3{ margin:0 0 .3rem; font-family:'Bungee', system-ui, sans-serif; font-size:1.02rem; color:var(--bamboo); }
.tour-tooltip__text{ font-size:.85rem; line-height:1.5; color:var(--cream-dim); margin:0 0 1.1rem; }
.tour-tooltip__close{
  position:absolute; top:12px; right:14px; background:none; border:none;
  color:var(--cream-dim); font-size:1.2rem; cursor:pointer; line-height:1;
}
.tour-dots{ display:flex; gap:.4rem; justify-content:center; margin-bottom:1.1rem; }
.tour-dots span{
  width:7px; height:7px; border-radius:50%; background:rgba(244,232,206,.25);
  transition:background-color .2s var(--ease-out), width .2s var(--ease-out), border-radius .2s var(--ease-out);
}
.tour-dots span.is-active{ background:var(--accent); width:18px; border-radius:5px; }
.tour-actions{ display:flex; gap:.6rem; }
.tour-actions .btn{ flex:1; padding:.6rem 1rem; font-size:.85rem; }
@media (prefers-reduced-motion:reduce){
  /* Fewer and gentler, not zero: the opacity fades stay (they aid comprehension — something
     appearing/disappearing), only the sliding/resizing movement between zones is dropped. Each
     zeroed list matches its own element's transition-property order above (movement first,
     opacity last). */
  .tour-dim{ transition-duration:0s,.18s; }
  .tour-highlight-frame{ transition-duration:0s,0s,0s,0s,.18s; }
  .tour-tooltip{ transition-duration:0s,.18s; }
  .tour-dots span{ transition:none; }
}
