/* wiqi — shared styles for the multi-page site */
  :root{
    --sky: #1e56fb;
    --sky-deep: #143fc2;
    --cloud: #ffffff;
    --spark: #ffe94a;
    --bubblegum: #ff5fa2;
    --lime: #7ed957;
    --ink: #0b1b4d;
  }

  *{ box-sizing: border-box; }
  html{ scroll-behavior: smooth; }
  body{
    margin:0;
    min-height: 100vh;
    font-family:'Nunito', sans-serif;
    color: var(--ink);
    background: radial-gradient(130% 90% at 50% 6%, #3a78ff 0%, #1e56fb 42%, #123fcf 74%, #0a2c93 100%);
    background-attachment: fixed;
    background-repeat: no-repeat;
    background-size: cover;
    overflow-x: hidden;
  }
  /* background-attachment:fixed is a known scroll-jank source on iOS Safari —
     it forces a repaint of the body background on every scroll frame, which
     competes with .hero-logo's transform+filter animation right as a scroll
     gesture starts. .sky (position:fixed, inset:0) already
     gives the fixed-backdrop illusion, so the fixed body background is purely
     redundant on mobile — safe to drop there for a smoother scroll. */
  @media (max-width: 700px){
    body{ background-attachment: scroll; }
  }

  h1,h2,h3,.display{
    font-family:'Fredoka', sans-serif;
    font-weight:700;
    margin:0;
  }

  /* ---------- SKY BACKGROUND ---------- */
  .sky{
    position: fixed;
    inset:0;
    z-index:0;
    overflow:hidden;
    pointer-events:none;
    /* fades the whole sky layer out near the left/right edges so drifting
       clouds ease into transparency instead of being hard-clipped the
       instant they cross the viewport boundary — this is what was reading
       as an abrupt "pop" before */
    -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 14%, #000 86%, transparent 100%);
    mask-image: linear-gradient(to right, transparent 0%, #000 14%, #000 86%, transparent 100%);
  }
  /* vignette — darkens the edges so the vibrant blue reads as an atmosphere with
     depth rather than a flat fill; painted above the clouds since it's the last
     generated layer in .sky's stacking context */
  .sky::after{
    content:"";
    position:absolute;
    inset:0;
    background: radial-gradient(ellipse 85% 70% at 50% 38%, rgba(0,0,0,0) 45%, rgba(4,10,40,0.22) 78%, rgba(3,8,32,0.4) 100%);
  }
  .cloud{
    position:absolute;
    will-change: transform;
  }
  .cloud-inner{
    width:100%; height:100%;
    display:block;
    object-fit: contain;
    -webkit-user-drag: none;
    user-select: none;
    /* same recipe as the hero logo: a tight ambient contact-shadow layer plus
       a soft white bloom halo around the art, so clouds read as glowing,
       lit objects instead of flat cutouts — and it doubles as a gentle
       mask over any hard raster edges. */
    filter:
      drop-shadow(0 10px 14px rgba(11,27,77,0.14))
      drop-shadow(0 0 10px rgba(255,255,255,0.3))
      drop-shadow(0 0 22px rgba(255,255,255,0.14));
    animation: cloud-float 6.5s ease-in-out infinite;
    transform-origin: 50% 65%;
  }
  @keyframes cloud-float{
    0%,100%{ transform: translateY(0) scale(1); }
    50%{ transform: translateY(-9px) scale(1.015); }
  }
  /* depth tiers — layered opacity/blur/shadow so the cloud field reads as
     several parallax planes instead of one flat layer */
  .cloud--back{ filter: blur(4px); }
  .cloud--back .cloud-inner{
    filter:
      drop-shadow(0 6px 8px rgba(6,14,45,0.1))
      drop-shadow(0 0 12px rgba(255,255,255,0.2))
      drop-shadow(0 0 26px rgba(255,255,255,0.1));
  }
  .cloud--mid{ filter: blur(1.5px); }
  .cloud--mid .cloud-inner{
    filter:
      drop-shadow(0 10px 14px rgba(6,14,45,0.16))
      drop-shadow(0 0 11px rgba(255,255,255,0.26))
      drop-shadow(0 0 24px rgba(255,255,255,0.12));
  }
  .cloud--front{ filter: none; opacity: .82; }
  .cloud--front .cloud-inner{
    filter:
      drop-shadow(0 16px 22px rgba(5,11,40,0.18))
      drop-shadow(0 0 9px rgba(255,255,255,0.22))
      drop-shadow(0 0 20px rgba(255,255,255,0.1));
  }
  .drift{ animation: drift linear infinite; }
  @keyframes drift{
    from{ transform: translateX(-10vw); }
    to{ transform: translateX(140vw); }
  }

  .spark{
    position:absolute;
    width:14px; height:14px;
    background: var(--spark);
    clip-path: polygon(50% 0%, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0% 50%, 39% 39%);
    animation: twinkle 2.4s ease-in-out infinite;
    filter: drop-shadow(0 0 6px rgba(255,233,74,0.9));
  }
  @keyframes twinkle{
    0%,100%{ transform: scale(0.6) rotate(0deg); opacity:.4; }
    50%{ transform: scale(1.15) rotate(20deg); opacity:1; }
  }

  /* ---------- LAYOUT ---------- */
  /* footer sticks to the bottom on short pages (e.g. links.html) instead of
     floating right under the content; on taller pages it simply sits after
     the content as before. Uses absolute positioning (not flex) so it never
     touches how individual <section>s (e.g. .hero) size or center themselves. */
  .wrap{
    position:relative; z-index:1;
    min-height: 100vh;
    padding-bottom: 9rem; /* reserves room so content never sits under the absolutely-positioned footer */
  }
  .wrap > footer{
    position: absolute;
    left: 0; right: 0; bottom: 0;
  }
  section{
    padding: 7rem 6vw;
    max-width: 1100px;
    margin: 0 auto;
  }

  /* ---------- NAV ---------- */
  nav{
    position: sticky; top:0; z-index:5;
    display:flex; justify-content:center; align-items:center; gap:.6rem;
    /* relative anchor for the absolutely-positioned .lang-switch */
    padding: 1rem 5vw;
    background: linear-gradient(180deg, rgba(30,95,255,0.85), rgba(30,95,255,0));
    backdrop-filter: blur(2px);
  }
  nav a{
    font-family:'Fredoka', sans-serif;
    font-weight:600;
    color:#fff;
    text-decoration:none;
    font-size: 0.95rem;
    padding: .5rem 1.1rem;
    border-radius: 999px;
    border: 2px solid rgba(255,255,255,0.5);
    transition: all .25s ease;
  }
  nav a:hover, nav a:focus-visible{
    background: var(--spark);
    color: var(--ink);
    border-color: var(--spark);
    transform: translateY(-2px);
  }
  nav a.active{
    background: #fff;
    color: var(--sky-deep);
    border-color: #fff;
  }
  .lang-switch{
    position: absolute;
    right: 5vw;
    top: 50%;
    transform: translateY(-50%);
    display:flex;
    gap:.3rem;
  }
  .lang-switch button{
    font-family:'Fredoka', sans-serif;
    font-weight:600;
    font-size: .8rem;
    color:#fff;
    background: transparent;
    border: 2px solid rgba(255,255,255,0.5);
    border-radius: 999px;
    padding: .35rem .7rem;
    cursor:pointer;
    transition: all .25s ease;
  }
  .lang-switch button:hover, .lang-switch button:focus-visible{
    border-color: var(--spark);
  }
  .lang-switch button.active{
    background: var(--spark);
    color: var(--ink);
    border-color: var(--spark);
  }
  @media (max-width: 700px){
    nav{
      flex-wrap: wrap;
      justify-content: center;
      gap: .4rem;
      /* pulled up tight against the top edge instead of floating with
         generous breathing room — still readable, just leaner */
      padding: .55rem 5vw .6rem;
    }
    /* tighter tap targets than before — still comfortably tappable, just
       leaner so the whole bar reads as a compact strip rather than a
       full section of its own. Border + fill on .active / :hover keep it
       visually prominent despite the smaller footprint. */
    nav a{
      flex: 1 1 auto;
      min-width: 40%;
      min-height: 38px;
      display: flex;
      align-items: center;
      justify-content: center;
      text-align: center;
      font-size: .78rem;
      padding: .45rem .9rem;
      border-width: 1.5px;
    }
    nav a:active{ transform: scale(.95); }
    /* language switch hidden on mobile everywhere except the home/about
       page — desktop keeps it on every page, this only scopes mobile */
    .lang-switch{ display:none; }
    body.page-home .lang-switch{
      display:flex;
      position:static; transform:none;
      justify-content:center;
      width: 100%;
      margin-top:.45rem;
      gap:.4rem;
    }
    body.page-home .lang-switch button{ min-height: 32px; padding: .3rem .85rem; font-size: .75rem; }
  }

  /* ---------- SCROLL REVEAL ---------- */
  .reveal{
    opacity: 0;
    transform: translateY(28px);
    transition: opacity .6s ease, transform .6s ease;
  }
  .reveal.in{
    opacity: 1;
    transform: translateY(0);
  }
  .grid-3 .reveal:nth-child(2){ transition-delay: .1s; }
  .grid-3 .reveal:nth-child(3){ transition-delay: .2s; }

  /* ---------- HERO ---------- */
  .hero{
    position: relative;
    min-height: 90vh;
    display:flex;
    flex-direction:column;
    align-items:center;
    justify-content:center;
    text-align:center;
    padding-top: 4rem;
  }
  /* tall plant-like creature anchored to the left edge of the hero, its
     "head" sitting near the top of the hero. It's pinned by `top` + a fixed
     width; JS (once on load/resize — never on scroll or pointer move) sets
     an explicit height so its base always reaches the actual bottom of the
     page, however long that page is (with a small deliberate overshoot —
     see script.js — so a late layout shift never leaves a gap short of the
     bottom). object-fit:cover keeps the artwork's proportions intact at
     that height instead of stretching it — any excess width is simply
     cropped, which reads fine since the creature already bleeds off the
     left edge of the viewport by design. It sits behind the "who i am"
     copy/card below (z-index 0 vs #about's z-index 1 — see #about) and
     ignores pointer events so it never competes for clicks.
     The mask below fades the last stretch of it out to transparent, so at
     the very bottom of the page it dissolves softly into the sky instead
     of ending in a hard, visible rectangular edge. */
  .hero-creature-wrap{
    position: absolute;
    left: clamp(-25vw, -18vw, -11vw);
    top: clamp(0vh, 6vh, 12vh);
    width: clamp(380px, 48vw, 680px);
    /* fallback so there's no flash of a squashed image before the JS
       height calculation runs on load; overwritten immediately after */
    height: clamp(560px, 90vh, 1200px);
    z-index: 0;
    pointer-events: none;
    will-change: transform;
    -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 94%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 0%, #000 94%, transparent 100%);
  }
  .hero-creature{
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center top;
    /* same recipe as .hero-logo / .cloud-inner: a faint blur softens the
       cutout's jagged edges, and the stacked white drop-shadows add a soft
       halo that hides any leftover fringe while doubling as ambient lift */
    filter:
      blur(0.4px)
      drop-shadow(0 0 1.5px rgba(255,255,255,0.55))
      drop-shadow(0 0 6px rgba(255,255,255,0.35))
      drop-shadow(0 10px 16px rgba(4,10,40,0.35));
    /* fully static — no idle sway/breathe. Kept motionless on purpose so it
       reads as a still illustration anchored to the page, not a decorative
       animation competing for attention (or for scroll-compositing budget
       on mobile). */
  }
  /* scale the creature down progressively as the viewport narrows, instead
     of jumping straight from full size to hidden */
  @media (max-width: 1200px){
    .hero-creature-wrap{ width: clamp(320px, 42vw, 560px); left: clamp(-21vw, -15vw, -9vw); }
  }
  @media (max-width: 1000px){
    .hero-creature-wrap{ width: clamp(260px, 36vw, 440px); left: clamp(-17vw, -12vw, -7vw); }
  }
  @media (max-width: 700px){
    /* mobile does NOT use the desktop's "stretch to full page height +
       object-fit:cover" trick — the artwork is much narrower than it is
       tall, so once the wrap gets stretched to the page's full height its
       width becomes tiny relative to that height, and cover crops hard
       into the left/right sides of the artwork (that's what was cutting
       off the right side of the creature). Instead the wrap is sized by
       width and its height follows the image's own aspect ratio, so the
       full artwork always shows uncropped — it still stays absolutely
       positioned and bleeds down far enough to pass behind #about/"who i
       am" on scroll, just without stretching past its natural proportions. */
    .hero-creature-wrap{
      width: clamp(180px, 46vw, 300px);
      aspect-ratio: 672 / 1584;
      height: auto;
      left: clamp(-16vw, -9vw, -3vw);
      top: clamp(1vh, 5vh, 9vh);
    }
    .hero-creature{
      object-fit: contain;
    }
  }
  .hero .hero-logo-wrap{
    position:relative;
    display:inline-flex;
    flex-direction:column;
    align-items:center;
    z-index:3; /* above .sky / .cloud--front (z-index:0) for max prominence */
    margin:0; /* it's an <h1>; reset default heading margin */
    filter: drop-shadow(0 6px 18px rgba(5,11,40,0.35));
  }
  /* soft twin-color glow behind the wordmark — carries the playful color accent
     that used to live on a single letter, without ever touching glyph fill */
  .hero .hero-logo-wrap::before{
    content:"";
    position:absolute;
    inset:-20% -8%;
    z-index:-1;
    background:
      radial-gradient(closest-side, rgba(255,233,74,0.42), transparent 72%) 14% 32% / 48% 72% no-repeat,
      radial-gradient(closest-side, rgba(255,95,162,0.36), transparent 72%) 86% 68% / 48% 72% no-repeat;
    filter: blur(36px);
    pointer-events:none;
  }
  .hero-logo{
    display:block;
    width: min(66vw, 540px);
    height:auto;
    /* the faint blur softens any leftover jagged/aliased pixel edges from the
       source art so they blend into the sky instead of reading as rough; the
       stacked drop-shadows add a soft white halo that further hides rough
       edges while still doubling as the "lifted off the background" shadow */
    filter:
      blur(0.4px)
      drop-shadow(0 0 1.5px rgba(255,255,255,0.55))
      drop-shadow(0 0 6px rgba(255,255,255,0.35))
      drop-shadow(0 20px 32px rgba(4,10,40,0.4));
    /* organic multi-step float: a longer, custom-eased arc (instead of a plain
       ease-in-out) reads as weightless drifting rather than a mechanical bounce —
       the extra keyframes add a gentle sway/settle instead of a straight up-down. */
    animation: float 5.2s cubic-bezier(.45,.05,.55,.95) infinite;
    transform-origin: 50% 65%;
  }
  @keyframes float{
    0%,100%{ transform: translateY(0) rotate(-2.5deg) scale(1); }
    22%{     transform: translateY(-14px) rotate(-0.5deg) scale(1.02); }
    50%{     transform: translateY(-26px) rotate(2.5deg) scale(1.05); }
    78%{     transform: translateY(-12px) rotate(1deg) scale(1.02); }
  }
  /* ---------- HERO — MOBILE ONLY (desktop/tablet above 700px untouched) ---------- */
  @media (max-width: 700px){
    .hero{
      /* no overflow:hidden here (unlike before) — the creature is meant to
         bleed down past the hero and behind #about now, same as desktop.
         Horizontal bleed is still caught page-wide by body{overflow-x:hidden}. */
      padding-top: 3rem;
      padding-bottom: 0;
      /* plain 90vh is measured against the URL-bar-hidden viewport, so
         while the bar is showing (the common case on load) the real
         visible area is shorter than 90vh and the content sits partly
         below the fold — hence the vh fallback here. --vh100 (set once on
         load/resize by script.js, never live during scroll) gives the
         accurate visible height without dvh's mid-scroll recalculation
         jump; kept as a calc() so a plain vh value still applies until
         the script sets the variable. */
      min-height: 90vh;
      min-height: calc(var(--vh100, 100vh) * 90 / 100);
      /* centered vertically, same as desktop. This used to anchor to
         flex-end because the in-flow creature below the logo pushed the
         group down naturally — now the creature is absolutely positioned
         and out of flow, so flex-end left the logo sitting low with a big
         empty gap above it. Centering keeps the logo mid-screen. */
      justify-content: center;
    }

    /* explicit full-width centering for the wordmark — belt-and-braces on
       top of the parent's flex centering so it can never drift off-center */
    .hero .hero-logo-wrap{
      order: 1;
      width: 100%;
      display: flex;
      justify-content: center;
    }

    /* the 0.4px blur on .hero-logo was tuned for large desktop rendering —
       on a phone's smaller, denser screen it reads as genuinely out of
       focus rather than "softened edges", so it's dropped here entirely;
       the drop-shadow halo is tightened to match */
    .hero-logo{
      width: min(72vw, 380px);
      filter:
        drop-shadow(0 0 1px rgba(255,255,255,0.5))
        drop-shadow(0 0 4px rgba(255,255,255,0.3))
        drop-shadow(0 10px 18px rgba(4,10,40,0.4));
      /* lighter mobile-only float: translateY/rotate only, no scale.
         The desktop animation's scale-up-to-1.05 forces the browser to
         rasterize the element at one size and stretch it for the animated
         frames — on a phone's higher pixel density that stretch is what
         was reading as blurry/lower-quality. Dropping scale keeps every
         frame pixel-crisp and is noticeably cheaper to composite too,
         which helps the scroll smoothness below. */
      animation: float-mobile 5.2s cubic-bezier(.45,.05,.55,.95) infinite;
    }
    @keyframes float-mobile{
      0%,100%{ transform: translateY(0) rotate(-2deg); }
      50%{     transform: translateY(-10px) rotate(2deg); }
    }
    /* frozen at its current frame (not reset to 0%) while body.is-scrolling
       is set by script.js, so it never fights scroll compositing — then
       picks the float back up the instant scrolling settles */
    body.is-scrolling .hero-logo{ animation-play-state: paused; }

    /* creature stays absolutely positioned (sizing set in the 700px tier
       above, alongside the other size tiers), sized by its own aspect
       ratio instead of desktop's stretch-to-page-bottom, so nothing gets
       cropped. It's still tall enough to bleed past the hero and pass
       behind #about/"who i am" on scroll (see #about's z-index note
       below). blur fully removed — it was softening the upscaled asset
       rather than helping it. Halo matches .hero-logo's 3-layer glow so
       the two elements read as the same lit "family". Fully static, no
       animation. */
    .hero-creature{
      filter:
        drop-shadow(0 0 1px rgba(255,255,255,0.5))
        drop-shadow(0 0 4px rgba(255,255,255,0.3))
        drop-shadow(0 8px 14px rgba(4,10,40,0.35));
    }

    .scroll-cue{ order: 3; }
  }

  .about-venues{
    display:flex;
    align-items:flex-start;
    gap:.55rem;
    font-style: italic;
  }
  /* small pin marker ties this line visually to "places played" — lives
     entirely in CSS via ::before so it survives the i18n text swap, which
     replaces the paragraph's textContent when switching EN/IT. */
  .about-venues::before{
    content:"";
    flex:0 0 auto;
    width:16px; height:16px;
    margin-top:.2rem;
    background-color: currentColor;
    opacity:.5;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2C7.58 2 4 5.58 4 10c0 5.25 7 12 7.5 12.5.3.3.7.3 1 0C13 22 20 15.25 20 10c0-4.42-3.58-8-8-8zm0 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6z'/%3E%3C/svg%3E") no-repeat center / contain;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2C7.58 2 4 5.58 4 10c0 5.25 7 12 7.5 12.5.3.3.7.3 1 0C13 22 20 15.25 20 10c0-4.42-3.58-8-8-8zm0 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6z'/%3E%3C/svg%3E") no-repeat center / contain;
  }
  .scroll-cue{
    margin-top: 3.5rem;
    display:flex;
    justify-content:center;
    opacity:.85;
    animation: floaty 2s ease-in-out infinite;
  }
  .scroll-cue svg{
    display:block;
    filter: drop-shadow(0 4px 8px rgba(0,0,0,0.2));
  }
  @keyframes floaty{
    0%,100%{ transform: translateY(0); }
    50%{ transform: translateY(8px); }
  }
  .sr-only{
    position:absolute;
    width:1px; height:1px;
    padding:0; margin:-1px;
    overflow:hidden;
    clip:rect(0,0,0,0);
    white-space:nowrap;
    border:0;
  }

  /* ---------- STICKER CARDS ---------- */
  .eyebrow{
    display:inline-block;
    font-family:'Fredoka';
    font-weight:600;
    font-size: .85rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--sky-deep);
    background: var(--spark);
    padding: .3rem .9rem;
    border-radius: 999px;
    margin-bottom: 1rem;
  }
  .section-title{
    font-size: clamp(2.2rem, 5vw, 3.2rem);
    color:#fff;
    text-shadow: 0 4px 0 var(--sky-deep);
    margin-bottom: 2.5rem;
  }

  /* #about gets its own stacking context above the hero creature (which
     bleeds down behind it at z-index:0 — see .hero-creature-wrap) so the
     whole section, not just the card, reliably paints in front: the
     "who i am" label included. Without this, a positioned z-index:0
     element like the creature paints above normal in-flow content
     regardless of DOM order, so text would end up behind it. */
  #about{
    position: relative;
    z-index: 1;
  }
  .card{
    background: var(--cloud);
    border-radius: 34px;
    padding: 2.2rem;
    box-shadow: 0 14px 0 rgba(11,27,77,0.18), 0 20px 40px rgba(11,27,77,0.25);
    position: relative;
  }
  .card::after{
    content:"";
    position:absolute;
    top:-14px; right:34px;
    width: 34px; height: 34px;
    background: var(--cloud);
    border-radius: 50%;
    box-shadow: -24px 6px 0 -4px var(--cloud), 20px 4px 0 -6px var(--cloud);
  }

  .grid-3{
    display:grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1.6rem;
  }
  @media (max-width: 800px){ .grid-3{ grid-template-columns: 1fr; } }

  /* magnetic hover targets get a bit of GPU-friendly lift */
  .tile, .link-btn{ will-change: transform; }

  .bg-mail{ background: var(--sky); color:#fff; }

  .copied-tag{
    position:absolute;
    top:-2.4rem; left:50%;
    transform: translateX(-50%) translateY(6px);
    background: var(--ink);
    color:#fff;
    font-family:'Fredoka';
    font-weight:600;
    font-size:.8rem;
    padding:.35rem .8rem;
    border-radius:999px;
    opacity:0;
    pointer-events:none;
    transition: opacity .2s ease, transform .2s ease;
    white-space:nowrap;
  }
  .copied-tag.show{ opacity:1; transform: translateX(-50%) translateY(0); }

  .tile{
    background: var(--cloud);
    border-radius: 26px;
    padding: 1.6rem;
    box-shadow: 0 10px 0 rgba(11,27,77,0.15);
    transition: transform .25s ease;
  }
  .tile:hover{ transform: translateY(-6px) rotate(-1deg); }
  .tile-link{ display:block; text-decoration:none; color:inherit; cursor:pointer; }
  .tile-link:focus-visible{ outline: 3px solid var(--spark); outline-offset: 3px; }
  .tile .icon{
    width: 52px; height:52px;
    border-radius: 16px;
    display:flex; align-items:center; justify-content:center;
    font-size: 1.6rem;
    margin-bottom: 1rem;
  }
  .tile h3{ font-size:1.2rem; margin-bottom:.4rem; }
  .tile p{ font-size:.95rem; line-height:1.5; margin:0; color:#334; }

  .bg-pink{ background: var(--bubblegum); color:#fff; }
  .bg-lime{ background: var(--lime); color:#08320f; }
  .bg-spark{ background: var(--spark); color: var(--ink); }

  /* ---------- LINKS / FOOTER ---------- */
  .links{
    text-align:center;
  }
  .links-page{
    padding-top: 11rem;
  }
  @media (max-width: 700px){
    .links-page{ padding-top: 8rem; }
  }
  .link-row{
    display:flex; flex-wrap:wrap; justify-content:center; gap: 1.8rem;
    margin-top: 2.4rem;
  }
  .link-btn{
    display:flex; align-items:center; gap:.7rem;
    font-family:'Fredoka'; font-weight:600; font-size:1.05rem;
    text-decoration:none;
    color: var(--ink);
    background:#fff;
    padding: 1rem 1.8rem;
    border-radius: 999px;
    box-shadow: 0 8px 0 rgba(11,27,77,0.2);
    transition: transform .2s ease, box-shadow .2s ease;
  }
  .link-btn:hover, .link-btn:focus-visible{
    transform: translateY(-5px);
    box-shadow: 0 12px 0 rgba(11,27,77,0.2);
  }
  .link-btn .dot{
    width: 14px; height:14px; border-radius:50%;
  }

  /* icon-only variant (links page) — die-cut sticker look */
  .link-btn.icon-only{
    --rot: 0deg;
    width: 84px;
    height: 84px;
    padding: 0;
    justify-content: center;
    color: #fff;
    border-radius: 26px;
    border: 4px solid var(--cloud);
    box-shadow: 0 10px 0 rgba(11,27,77,0.22), 0 16px 26px rgba(11,27,77,0.28);
    transition: transform .3s cubic-bezier(.34,1.56,.64,1), box-shadow .25s ease;
    animation: stickerFloat 4s ease-in-out infinite;
  }
  .link-btn.icon-only i{
    font-size: 2rem;
    line-height: 1;
    filter: drop-shadow(0 2px 0 rgba(0,0,0,0.12));
  }
  .link-btn.icon-only.icon-dark{
    color: var(--ink);
  }
  /* each sticker bobs at its own duration/offset so the row never moves in
     lockstep — reads as loosely floating rather than mechanically synced */
  .link-btn.icon-only:nth-child(1){ --rot: -6deg; animation-duration: 3.6s; animation-delay: -0.4s; }
  .link-btn.icon-only:nth-child(2){ --rot: 4deg;  animation-duration: 4.1s; animation-delay: -1.6s; }
  .link-btn.icon-only:nth-child(3){ --rot: -3deg; animation-duration: 3.8s; animation-delay: -2.5s; }
  .link-btn.icon-only:nth-child(4){ --rot: 5deg;  animation-duration: 4.4s; animation-delay: -0.9s; }
  @keyframes stickerFloat{
    0%   { transform: translateY(0)     rotate(calc(var(--rot) - 1.5deg)); }
    50%  { transform: translateY(-10px) rotate(calc(var(--rot) + 1.5deg)); }
    100% { transform: translateY(0)     rotate(calc(var(--rot) - 1.5deg)); }
  }
  .link-btn.icon-only:hover, .link-btn.icon-only:focus-visible{
    animation: none; /* pausing alone would still let the keyframe's transform win over this hover state */
    transform: translateY(-8px) rotate(0deg) scale(1.06);
    box-shadow: 0 14px 0 rgba(11,27,77,0.22), 0 22px 34px rgba(11,27,77,0.3);
  }
  .link-btn.icon-only.pressed{
    transform: scale(0.87) rotate(0deg) !important;
    box-shadow: 0 4px 0 rgba(11,27,77,0.22) !important;
    transition: transform .12s ease, box-shadow .12s ease !important;
  }
  /* starting state for the JS-driven sticker pop-in — prevents a flash before the animation runs */
  .sticker-reveal{ opacity: 0; }
  @media (max-width: 500px){
    .link-btn.icon-only{ width:68px; height:68px; border-radius:22px; }
    .link-btn.icon-only i{ font-size:1.6rem; }
  }

  footer{
    text-align:center;
    padding: 3rem 6vw 4rem;
    color: rgba(255,255,255,0.85);
    font-family:'Fredoka';
    font-size:.9rem;
  }

  @media (prefers-reduced-motion: reduce){
    .drift, .spark, .cloud-inner, .hero-logo, .hero-creature, .scroll-cue, .reveal, .sticker-reveal, .link-btn.icon-only, .page-transition{ animation: none !important; transition: none !important; }
    .reveal{ opacity:1 !important; transform:none !important; }
    .sticker-reveal{ opacity:1 !important; }
    .page-transition{ transform: none !important; opacity: 0 !important; }
    body.pt-leaving .wrap, body.pt-entering .wrap{ opacity: 1 !important; transform: none !important; filter: none !important; }
  }

  /* ---------- PAGE TRANSITION OVERLAY ---------- */
  /* soft crossfade, no directional wipe: the overlay just fades in/out while
     the page content itself gently blurs, scales and dims underneath — reads
     as the content "settling" rather than being cut or swept off screen */
  .page-transition{
    position: fixed;
    inset: 0;
    z-index: 9999;
    background: var(--sky-deep);
    opacity: 1;
    pointer-events: none;
    transition: opacity .5s cubic-bezier(.4,0,.2,1);
    will-change: opacity;
  }
  .page-transition.pt-hidden{ opacity: 0; }

  /* outgoing page: fades, softens and eases inward slightly as it exits */
  body.pt-leaving .wrap{
    transition: opacity .42s cubic-bezier(.4,0,.2,1), transform .42s cubic-bezier(.4,0,.2,1), filter .42s cubic-bezier(.4,0,.2,1);
    opacity: 0;
    transform: scale(1.012);
    filter: blur(5px);
  }
  /* incoming page: starts in that same softened state, then eases to normal
     right as the overlay clears — the two motions are timed to overlap so
     the whole thing reads as one continuous, fluid crossfade */
  body.pt-entering .wrap{
    opacity: 0;
    transform: scale(1.012);
    filter: blur(5px);
  }
  .wrap{
    transition: opacity .5s cubic-bezier(.4,0,.2,1) .05s, transform .5s cubic-bezier(.4,0,.2,1) .05s, filter .5s cubic-bezier(.4,0,.2,1) .05s;
  }

  /* ---------- NIGHT SKY + CLUB LIGHTS (sets page) ---------- */
  body.page-sets{
    background: linear-gradient(180deg, #0c1130 0%, #070a1f 55%, #030410 100%);
  }
  body.page-sets nav{
    background: linear-gradient(180deg, rgba(7,10,31,0.85), rgba(7,10,31,0));
  }

  .strobe-layer{
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
    mix-blend-mode: screen;
  }
  .strobe-beam{
    position: absolute;
    bottom: -15%;
    width: 140px;
    height: 140%;
    transform-origin: bottom center;
    opacity: 0;
    filter: blur(8px);
  }
  .strobe-beam:nth-child(1){ left: 8%;  background: linear-gradient(0deg, var(--bubblegum), transparent 75%); animation: beamRise 6.5s ease-in-out infinite; }
  .strobe-beam:nth-child(2){ left: 38%; background: linear-gradient(0deg, var(--lime), transparent 75%); animation: beamRise 7.5s ease-in-out infinite 1.6s; }
  .strobe-beam:nth-child(3){ left: 64%; background: linear-gradient(0deg, var(--spark), transparent 75%); animation: beamRise 6s ease-in-out infinite 3s; }
  .strobe-beam:nth-child(4){ left: 88%; background: linear-gradient(0deg, var(--sky), transparent 75%); animation: beamRise 8s ease-in-out infinite 0.8s; }

  @keyframes beamRise{
    0%, 100%{ opacity: 0; transform: rotate(-22deg) scaleY(0.5); }
    12%{ opacity: .55; transform: rotate(-22deg) scaleY(0.85); }
    28%{ opacity: .15; transform: rotate(16deg) scaleY(1.05); }
    45%{ opacity: .5; transform: rotate(-10deg) scaleY(1); }
    60%{ opacity: .08; transform: rotate(8deg) scaleY(0.9); }
    75%{ opacity: .42; transform: rotate(20deg) scaleY(1.02); }
    88%{ opacity: .15; transform: rotate(-6deg) scaleY(0.8); }
  }
  
  /* synced to 170 BPM (60/170 ≈ 0.353s per beat) — kept low-opacity/blended so it reads as a
     rhythmic pulse rather than a high-contrast strobe */
  .strobe-flash{
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: #fff;
    opacity: 0;
    mix-blend-mode: overlay;
    animation: flashPulse 0.353s steps(1, end) infinite;
  }
  @keyframes flashPulse{
    0%{ opacity: 0; }
    8%{ opacity: .2; }
    20%{ opacity: 0; }
    100%{ opacity: 0; }
  }

  @media (prefers-reduced-motion: reduce){
    .strobe-beam, .strobe-flash{ animation: none !important; opacity: 0 !important; }
  }

  .video-frame{
    max-width: 900px;
    margin: 0 auto;
    border-radius: 28px;
    overflow: hidden;
    aspect-ratio: 16 / 9;
    border: 3px solid rgba(255,255,255,0.15);
    box-shadow: 0 14px 0 rgba(0,0,0,0.35), 0 0 40px rgba(255,95,162,0.35), 0 0 70px rgba(30,95,255,0.3);
    transition: transform .45s cubic-bezier(.2,.8,.2,1), box-shadow .45s ease, border-color .45s ease;
    position: relative;
    background: #04060f;
  }
  .video-frame:hover, .video-frame:focus-within{
    transform: translateY(-6px) scale(1.012);
    border-color: rgba(255,255,255,0.32);
    box-shadow: 0 20px 0 rgba(0,0,0,0.35), 0 0 55px rgba(255,95,162,0.5), 0 0 95px rgba(30,95,255,0.4);
  }
  .video-frame iframe{
    width: 100%;
    height: 100%;
    display: block;
    border: 0;
    background: #04060f;
  }

  /* ---------- video content swap (poster <-> playing iframe) ---------- */
  .video-media{
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    background: #04060f;
    transition: opacity .32s ease, transform .32s cubic-bezier(.3,.7,.4,1);
  }
  .video-media.is-swapping{
    opacity: 0;
    transform: scale(.96);
  }
  .video-media iframe{ position:absolute; inset:0; }

  .video-poster{
    position: absolute;
    inset: 0;
    cursor: pointer;
    overflow: hidden;
    background: #04060f;
  }
  .video-poster img{
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    filter: brightness(.7);
    transition: filter .35s ease, transform .6s ease;
  }
  .video-poster:hover img, .video-poster:focus-visible img{
    filter: brightness(.5);
    transform: scale(1.045);
  }

  /* YouTube-style play button: dark translucent disc, solidifies to red on hover */
  .video-play{
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%,-50%);
    width: 72px; height: 72px;
    border-radius: 50%;
    background: rgba(5,7,20,0.55);
    border: 2px solid rgba(255,255,255,0.85);
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 6px 18px rgba(0,0,0,0.45);
    transition: transform .25s cubic-bezier(.25,.8,.25,1), background .25s ease, border-color .25s ease;
    backdrop-filter: blur(2px);
  }
  .video-poster:hover .video-play, .video-poster:focus-visible .video-play{
    transform: translate(-50%,-50%) scale(1.08);
    background: #ff0000;
    border-color: #ff0000;
  }
  .video-play svg{ width: 24px; height: 24px; fill: #fff; margin-left: 4px; }
  .video-slot--secondary .video-play{ width: 52px; height: 52px; }
  .video-slot--secondary .video-play svg{ width: 18px; height: 18px; margin-left: 3px; }
  .video-poster:focus-visible{ outline: 3px solid var(--spark); outline-offset: -3px; }

  /* video title — shown only on the poster (before play), top-left */
  .video-poster .video-title{
    position: absolute;
    left: 1rem;
    top: 1rem;
    max-width: calc(100% - 2rem);
    padding: .5rem .9rem;
    border-radius: 999px;
    background: rgba(4,6,15,0.62);
    backdrop-filter: blur(6px);
    color: #fff;
    font-family: 'Nunito', sans-serif;
    font-weight: 700;
    font-size: .92rem;
    line-height: 1.3;
    letter-spacing: .01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    pointer-events: none;
    opacity: 1;
    transition: opacity .28s ease;
    z-index: 2;
  }
  .video-poster .video-title.is-hidden{ opacity: 0; }
  .video-slot--secondary .video-poster .video-title{
    left: .8rem;
    top: .8rem;
    font-size: .82rem;
    padding: .4rem .75rem;
    max-width: calc(100% - 1.6rem);
  }
  @media (max-width: 500px){
    .video-poster .video-title{ font-size: .82rem; padding: .4rem .75rem; }
  }

  @media (prefers-reduced-motion: reduce){
    .video-frame, .video-frame:hover, .video-media, .video-media.is-swapping, .video-poster img, .video-play, .video-poster .video-title{
      transition: none !important; transform: none !important;
    }
  }

  /* ---------- SETS SHOWCASE (sets page) ---------- */
  .sets-showcase{
    padding-top: 3rem;
    padding-bottom: 2rem;
    display: flex;
    flex-direction: column;
    gap: 2.6rem;
  }
  @media (max-width: 700px){
    .sets-showcase{ padding-top: 2.5rem; gap: 2rem; }
  }

  .video-slot--featured{
    position: relative;
    max-width: 1100px;
    width: 100%;
    margin: 0 auto;
  }
  .video-slot--featured::before{
    content: "";
    position: absolute;
    inset: -12%;
    background: radial-gradient(ellipse at center, rgba(255,95,162,0.28), rgba(30,95,255,0.16) 45%, transparent 72%);
    filter: blur(48px);
    z-index: -1;
  }
  .video-slot--featured .video-frame{
    max-width: none;
    margin: 0;
    border-radius: 34px;
    border-width: 4px;
  }

  .video-grid-secondary{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 1.8rem;
    max-width: 1100px;
    width: 100%;
    margin: 0 auto;
  }
  .video-grid-secondary .video-frame{
    max-width: none;
    margin: 0;
  }

  /* ---------- TRACKS / MIXES SHOWCASE (sets page, SoundCloud embeds) ---------- */
  .tracks-showcase-section{
    padding-top: 1rem;
  }

  .tracks-grid{
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.8rem;
  }
  .tracks-grid .reveal:nth-child(2){ transition-delay: .1s; }
  .tracks-grid .reveal:nth-child(3){ transition-delay: .2s; }

  .track-card{
    --accent: 255,45,106; /* club neon red-pink, shared across every track card */
    position: relative;
    flex: 1 1 300px;
    max-width: 360px;
    background: rgba(9,12,32,0.72);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 22px;
    padding: 0 1.1rem 1.1rem;
    overflow: hidden;
    backdrop-filter: blur(10px);
    box-shadow: 0 10px 0 rgba(0,0,0,0.35), 0 16px 30px rgba(0,0,0,0.35), 0 0 30px rgba(var(--accent),0.18);
    transition: transform .35s cubic-bezier(.2,.8,.2,1), box-shadow .35s ease, border-color .35s ease;
  }
  .track-card::before{
    content: "";
    display: block;
    height: 3px;
    margin: 0 -1.1rem 1.1rem;
    background: linear-gradient(90deg, rgba(var(--accent),0.85), rgba(255,255,255,0.65) 50%, rgba(var(--accent),0.85));
    background-size: 220% 100%;
    animation: accentSheen 7s ease-in-out infinite;
  }
  .track-card:hover, .track-card:focus-within{
    transform: translateY(-6px);
    border-color: rgba(255,255,255,0.26);
    box-shadow: 0 14px 0 rgba(0,0,0,0.35), 0 22px 40px rgba(0,0,0,0.4), 0 0 46px rgba(var(--accent),0.36);
  }
  @keyframes accentSheen{
    0%,100%{ background-position: 0% 50%; }
    50%{ background-position: 100% 50%; }
  }

  /* SoundCloud's "visual" widget renders dark by design — full-bleed cover
     art with a built-in gradient scrim behind the title/waveform, so it
     already reads as native to a dark club aesthetic instead of the
     classic player's white bar. The screen keeps a dark placeholder
     background so there's no white flash while the iframe loads, and sits
     in a hardware-style bezel like the display on a CDJ/mixer. */
  .track-frame{
    position: relative;
    padding: 7px;
    border-radius: 16px;
    background: linear-gradient(160deg, #22263f, #0a0c1c);
    border: 1px solid rgba(255,255,255,0.12);
    box-shadow: inset 0 1px 2px rgba(255,255,255,0.08), inset 0 -2px 6px rgba(0,0,0,0.55);
    transition: box-shadow .35s ease;
  }
  .track-card:hover .track-frame, .track-card:focus-within .track-frame{
    box-shadow: inset 0 1px 2px rgba(255,255,255,0.08), inset 0 -2px 6px rgba(0,0,0,0.55), 0 0 0 1px rgba(var(--accent),0.45), 0 0 18px rgba(var(--accent),0.35);
  }
  .track-frame-screen{
    position: relative;
    border-radius: 10px;
    overflow: hidden;
    background: linear-gradient(160deg, #14162a, #05060f);
  }
  .track-frame-screen iframe{
    display: block;
    width: 100%;
    border: 0;
    position: relative;
    z-index: 1;
  }
  .track-frame.is-loading .track-frame-screen::after{
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
    background: linear-gradient(100deg, rgba(0,0,0,0.02) 30%, rgba(var(--accent),0.18) 50%, rgba(0,0,0,0.02) 70%);
    background-size: 220% 100%;
    animation: shimmer 1.4s ease-in-out infinite;
  }
  @keyframes shimmer{
    0%{ background-position: 160% 0; }
    100%{ background-position: -60% 0; }
  }

  @media (prefers-reduced-motion: reduce){
    .track-card::before, .track-frame.is-loading .track-frame-screen::after{ animation: none !important; }
  }

  /* ---------- PERFORMANCE GALLERY (performances page) ---------- */
  /* dark stage backdrop instead of the daytime sky, mirroring the sets page
     treatment — the photos are the light source here, so the chrome around
     them stays quiet and out of the way. */
  body.page-performances{
    background: linear-gradient(180deg, #150a12 0%, #0d070f 55%, #050308 100%);
  }
  body.page-performances nav{
    background: linear-gradient(180deg, rgba(10,6,12,0.85), rgba(10,6,12,0));
  }

  .performance-gallery{
    padding-top: 6.5rem;
    padding-bottom: 2rem;
  }
  @media (max-width: 700px){
    .performance-gallery{ padding-top: 5.5rem; }
  }

  /* CSS-columns masonry — handles the mixed landscape/portrait shots without
     forcing a uniform crop, so each photo keeps its own framing. */
  .photo-grid{
    column-count: 3;
    column-gap: 1.6rem;
    max-width: 1200px;
    margin: 0 auto;
  }
  @media (max-width: 900px){ .photo-grid{ column-count: 2; } }
  @media (max-width: 560px){ .photo-grid{ column-count: 1; max-width: 480px; } }

  .photo-card{
    --accent: 255,95,162;
    appearance: none;
    display: block;
    width: 100%;
    margin: 0 0 1.6rem;
    padding: 0;
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 24px;
    overflow: hidden;
    background: #0a0710;
    cursor: zoom-in;
    position: relative;
    break-inside: avoid;
    box-shadow: 0 10px 0 rgba(0,0,0,0.4), 0 18px 34px rgba(0,0,0,0.45);
    transition: transform .4s cubic-bezier(.2,.8,.2,1), box-shadow .4s ease, border-color .4s ease;
  }
  .photo-card img{
    display: block;
    width: 100%;
    height: auto;
    filter: brightness(.92);
    transition: transform .6s ease, filter .4s ease;
  }
  .photo-card:hover, .photo-card:focus-visible{
    transform: translateY(-6px);
    border-color: rgba(255,255,255,0.28);
    box-shadow: 0 14px 0 rgba(0,0,0,0.4), 0 22px 44px rgba(0,0,0,0.5), 0 0 40px rgba(var(--accent),0.32);
  }
  .photo-card:hover img, .photo-card:focus-visible img{
    transform: scale(1.045);
    filter: brightness(1);
  }
  .photo-card:focus-visible{ outline: 3px solid var(--spark); outline-offset: 3px; }

  /* zoom affordance — echoes the play-button treatment used on the sets page videos */
  .photo-card .zoom-cue{
    position: absolute;
    top: .9rem; right: .9rem;
    width: 38px; height: 38px;
    border-radius: 50%;
    background: rgba(5,7,20,0.55);
    border: 2px solid rgba(255,255,255,0.8);
    display: flex; align-items: center; justify-content: center;
    opacity: 0;
    transform: scale(.85);
    transition: opacity .25s ease, transform .25s ease;
    backdrop-filter: blur(2px);
    pointer-events: none;
  }
  .photo-card:hover .zoom-cue, .photo-card:focus-visible .zoom-cue{
    opacity: 1; transform: scale(1);
  }
  .photo-card .zoom-cue svg{ width: 16px; height: 16px; color: #fff; }

  /* ---------- VIDEO CARDS (performances grid) ---------- */
  /* same footprint as .photo-card — the poster <img> is what the masonry
     layout sizes against, the <video> sits absolutely on top of it so
     adding it never disturbs the column layout */
  .video-card{ position: relative; cursor: pointer; } /* "play", not "zoom" — this tile opens a clip, not a bigger photo */
  .video-card .card-video{
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity .35s ease;
    pointer-events: none;
  }
  /* crossfade: poster fades out as the preview fades in, so hovering never
     shows a jarring hard-cut between the still frame and the moving clip */
  .video-card.is-previewing img{ opacity: 0; }
  .video-card.is-previewing .card-video{ opacity: 1; }
  .video-card:hover img, .video-card:focus-visible img{ transform: none; } /* the crossfade replaces the usual zoom-on-hover for video cards */

  /* small always-visible pill (not hover-only, unlike .zoom-cue) so a client
     scanning the grid immediately understands which tiles are clips before
     even touching them */
  .video-badge{
    position: absolute;
    left: .9rem; bottom: .9rem;
    display: flex; align-items: center; gap: .3rem;
    padding: .3rem .6rem .3rem .45rem;
    border-radius: 999px;
    background: rgba(5,7,20,0.6);
    border: 2px solid rgba(255,255,255,0.75);
    backdrop-filter: blur(2px);
    color: #fff;
    font-family: 'Fredoka', sans-serif;
    font-weight: 600;
    font-size: .72rem;
    letter-spacing: .02em;
    transition: background .25s ease, border-color .25s ease, transform .25s ease;
  }
  .video-badge svg{ width: 13px; height: 13px; }
  .video-card:hover .video-badge, .video-card:focus-visible .video-badge{
    background: var(--bubblegum);
    border-color: var(--bubblegum);
    transform: scale(1.05);
  }
  @media (prefers-reduced-motion: reduce){
    .video-card .card-video{ display: none; } /* never autoplay a preview for reduced-motion users — the badge + poster + click-to-open in lightbox still works */
  }

  /* ---------- LIGHTBOX ---------- */
  .lightbox{
    position: fixed;
    inset: 0;
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(3,3,8,0.92);
    backdrop-filter: blur(6px);
    opacity: 0;
    pointer-events: none;
    transition: opacity .3s ease;
  }
  .lightbox.is-open{ opacity: 1; pointer-events: auto; }
  .lightbox-figure{
    position: relative;
    margin: 0;
    transform: scale(.96);
    transition: transform .3s cubic-bezier(.2,.8,.2,1);
  }
  .lightbox.is-open .lightbox-figure{ transform: scale(1); }
  .lightbox img, .lightbox-media{
    display: block;
    max-width: min(92vw, 1200px);
    max-height: 88vh;
    width: auto; height: auto;
    border-radius: 16px;
    box-shadow: 0 20px 60px rgba(0,0,0,0.6);
  }
  .lightbox-media[hidden], .lightbox img[hidden]{ display: none; }
  .lightbox-close, .lightbox-prev, .lightbox-next{
    position: fixed;
    display: flex; align-items: center; justify-content: center;
    width: 48px; height: 48px;
    border-radius: 50%;
    background: rgba(255,255,255,0.08);
    border: 2px solid rgba(255,255,255,0.35);
    color: #fff;
    cursor: pointer;
    transition: background .2s ease, border-color .2s ease, transform .2s ease;
    backdrop-filter: blur(4px);
  }
  .lightbox-close:hover, .lightbox-close:focus-visible,
  .lightbox-prev:hover, .lightbox-prev:focus-visible,
  .lightbox-next:hover, .lightbox-next:focus-visible{
    background: var(--bubblegum); border-color: var(--bubblegum);
  }
  .lightbox-close{ top: 1.4rem; right: 1.4rem; }
  .lightbox-close:hover, .lightbox-close:focus-visible{ transform: scale(1.06); }
  .lightbox-prev{ left: 1.4rem; top: 50%; transform: translateY(-50%); }
  .lightbox-next{ right: 1.4rem; top: 50%; transform: translateY(-50%); }
  .lightbox-prev:hover, .lightbox-prev:focus-visible,
  .lightbox-next:hover, .lightbox-next:focus-visible{ transform: translateY(-50%) scale(1.06); }
  .lightbox-close svg, .lightbox-prev svg, .lightbox-next svg{ width: 20px; height: 20px; }
  .lightbox-counter{
    position: fixed;
    bottom: 1.4rem; left: 50%;
    transform: translateX(-50%);
    color: #fff;
    opacity: .75;
    font-family: 'Nunito', sans-serif;
    font-weight: 700;
    font-size: .85rem;
    letter-spacing: .04em;
  }
  @media (max-width: 600px){
    .lightbox-prev{ left: .6rem; width: 40px; height: 40px; }
    .lightbox-next{ right: .6rem; width: 40px; height: 40px; }
    .lightbox-close{ top: .8rem; right: .8rem; width: 40px; height: 40px; }
  }
  @media (prefers-reduced-motion: reduce){
    .photo-card, .photo-card img, .photo-card .zoom-cue, .lightbox, .lightbox-figure{ transition: none !important; }
  }

  /* ---------- FLOATING BOOKING CTA ---------- */
  .float-book{
    position: fixed;
    right: 1.6rem;
    bottom: 1.6rem;
    z-index: 20;
    display:flex;
    align-items:center;
    gap:.6rem;
    font-family:'Fredoka'; font-weight:700; font-size:.95rem;
    letter-spacing:.01em;
    color: var(--ink);
    background: var(--spark);
    padding: .85rem 1.3rem;
    border-radius: 999px;
    text-decoration:none;
    box-shadow: 0 10px 0 rgba(11,27,77,0.28), 0 16px 30px rgba(11,27,77,0.3);
    animation: pulseCta 2.6s ease-in-out infinite;
    transition: transform .2s cubic-bezier(.25,.8,.25,1), box-shadow .2s ease, background .2s ease;
  }
  .float-book:hover, .float-book:focus-visible{
    transform: translateY(-4px) scale(1.03);
    background: #fff;
    box-shadow: 0 14px 0 rgba(11,27,77,0.28), 0 22px 36px rgba(11,27,77,0.32);
  }
  .float-book:active{
    transform: translateY(-1px) scale(0.98);
    box-shadow: 0 4px 0 rgba(11,27,77,0.28), 0 8px 16px rgba(11,27,77,0.3);
  }
  .float-book:focus-visible{
    outline: 3px solid #fff;
    outline-offset: 3px;
  }
  .float-book .float-dot{
    width:10px; height:10px; border-radius:50%;
    background: var(--bubblegum);
  }
  @keyframes pulseCta{
    0%,100%{ box-shadow: 0 10px 0 rgba(11,27,77,0.28), 0 16px 30px rgba(11,27,77,0.3), 0 0 0 0 rgba(255,233,74,0.55); }
    50%{ box-shadow: 0 10px 0 rgba(11,27,77,0.28), 0 16px 30px rgba(11,27,77,0.3), 0 0 0 12px rgba(255,233,74,0); }
  }
  @media (max-width: 700px){
    .float-book{ right:1rem; bottom:1rem; padding:.7rem 1.05rem; font-size:.85rem; }
  }

  /* ---------- CUSTOM WORM CURSOR (pointer-fine devices only) ---------- */
  body.has-worm-cursor,
  body.has-worm-cursor a,
  body.has-worm-cursor button,
  body.has-worm-cursor [role="button"]{
    cursor: none;
  }
  .worm-cursor{
    position: fixed;
    top:0; left:0;
    width:0; height:0;
    pointer-events:none;
    z-index: 9999;
  }
  .worm-segment{
    position:absolute;
    top:0; left:0;
    border-radius:50%;
    background:
      radial-gradient(circle at 35% 28%, rgba(255,255,255,0.65), transparent 42%),
      linear-gradient(160deg, #fffbe6 0%, var(--spark) 55%, #e0b400 100%);
    /* faint inset groove at the base of each segment reads as a body ring,
       like an earthworm's segmented cuticle, instead of a plain flat circle */
    box-shadow:
      inset 0 -3px 3px rgba(140,100,0,0.28),
      0 2px 0 rgba(160,120,0,0.35),
      0 4px 8px rgba(4,10,40,0.25);
    will-change: transform;
  }
  /* tail segments fade toward the bubblegum accent for a little gradient trail */
  .worm-segment:nth-child(n+4){
    background:
      radial-gradient(circle at 35% 28%, rgba(255,255,255,0.55), transparent 42%),
      linear-gradient(160deg, #ffe1ee 0%, var(--bubblegum) 60%, #d63d84 100%);
    box-shadow:
      inset 0 -3px 3px rgba(120,20,60,0.25),
      0 2px 0 rgba(140,20,70,0.3),
      0 4px 8px rgba(4,10,40,0.2);
  }
  .worm-segment:first-child{
    z-index:2;
    transition: filter .2s ease;
  }
  .worm-eye{
    position:absolute;
    top:28%;
    width:22%; height:22%;
    background: var(--ink);
    border-radius:50%;
  }
  .worm-eye--l{ left:20%; }
  .worm-eye--r{ right:20%; }
  /* small inverted triangle marking on the forehead, above the eyes */
  .worm-mark{
    position:absolute;
    top:10%;
    left:50%;
    transform: translateX(-50%);
    width:0; height:0;
    border-left: 2px solid transparent;
    border-right: 2px solid transparent;
    border-top: 3px solid var(--ink);
  }
  /* worm "perks up" with a little glow when hovering anything clickable */
  .worm-cursor.is-alert .worm-segment:first-child{
    filter: drop-shadow(0 0 10px rgba(255,233,74,0.85));
  }
  @media (max-width: 700px), (pointer: coarse){
    /* never engage on touch devices — no persistent pointer to trail */
    .worm-cursor{ display:none; }
  }
