/* Puppi3 — a Ghost theme for DJ Puppi3. Neon club nights, vinyl, and a wagging tail. */

/* 1. Design tokens --------------------------------------------------------- */
:root {
    /* Brand accent comes from Ghost Admin → Settings → Design → Accent colour */
    --accent: var(--ghost-accent-color, #ff1a75);
    --accent-ink: #170d22;          /* text that sits on the accent */

    /* Night club (default) — sampled from neon tubes, purple decks & warm wood */
    --bg: #140c1f;
    --bg-2: #1d1330;
    --surface: #251a3a;
    --ink: #fff4e8;
    --muted: #c3b2d6;
    --line: rgba(255, 244, 232, 0.14);
    --biscuit: #ffb85c;
    --lilac: #b28cff;
    --lime: #d4ff3a;
    --shadow-ink: #fff4e8;
    --neon-1: #ff4fd8;
    --neon-2: #9d5cff;
    --trance-blue: #2fb8ff;
    --glow: 0.55;
    /* Ready-mixed glow colours. Firefox can't cache color-mix() when its percentage comes from a variable and repaints
       it every frame, so these use literal percentages, set per colour scheme. */
    --glow-pink: color-mix(in srgb, var(--accent) 25%, transparent);
    --glow-pink-strong: color-mix(in srgb, var(--accent) 33%, transparent);
    --glow-violet: color-mix(in srgb, var(--neon-2) 33%, transparent);
    --glow-blue: color-mix(in srgb, var(--trance-blue) 33%, transparent);
    --title-glow: color-mix(in srgb, var(--accent) 38%, transparent);

    --font-display: var(--gh-font-heading, "Bricolage Grotesque"), ui-rounded, "Avenir Next", system-ui, sans-serif;
    --font-body: var(--gh-font-body, "DM Sans"), system-ui, -apple-system, "Segoe UI", sans-serif;
    --font-mono: "Space Mono", ui-monospace, "SF Mono", Menlo, monospace;

    --radius: 22px;
    --radius-sm: 14px;
    --container: 1200px;
    --gutter: clamp(18px, 4vw, 40px);
    --beat: calc(60s / 140);         /* one beat at 140 bpm — trance tempo */
    /* Frame clock: every looping animation uses steps() so it updates exactly 13 times per beat (~30 fps), and all
       durations and delays are whole beats so every animation updates on the same frames. The slow glow updates every
       3rd tick (~10 fps) on the same grid. Between ticks the browser has nothing to redraw, which cuts CPU/GPU use
       dramatically on high-refresh screens (120–160 Hz) versus smooth animation. Keep new animations on this grid:
       steps() counts per stretch between two keyframes, so a stretch lasting N beats gets steps(13 × N) (set per
       keyframe with animation-timing-function when stretches differ), and delays are whole steps (1/13 beat). main.js
       lines up start times (lockBeat); repeat a short loop several times in one cycle (bob: 16 beats) so cycles end
       rarely (see Keyframes). */

    color-scheme: dark;
}

.scheme-day {
    --bg: #fff6ee; --bg-2: #ffeede; --surface: #ffffff; --ink: #23142e; --muted: #6d5a7c;
    --line: rgba(35, 20, 46, 0.14); --biscuit: #f39a2c; --lilac: #7f52f0; --lime: #8fbf00; --shadow-ink: #23142e;
    --neon-1: #ff7ad9; --neon-2: #b08cff; --trance-blue: #2a8cff; --glow: 0.3;
    --glow-pink: color-mix(in srgb, var(--accent) 14%, transparent);
    --glow-pink-strong: color-mix(in srgb, var(--accent) 18%, transparent);
    --glow-violet: color-mix(in srgb, var(--neon-2) 18%, transparent);
    --glow-blue: color-mix(in srgb, var(--trance-blue) 18%, transparent);
    --title-glow: color-mix(in srgb, var(--accent) 21%, transparent); color-scheme: light;
}

@media (prefers-color-scheme: light) {
    .scheme-auto {
        --bg: #fff6ee; --bg-2: #ffeede; --surface: #ffffff; --ink: #23142e; --muted: #6d5a7c;
        --line: rgba(35, 20, 46, 0.14); --biscuit: #f39a2c; --lilac: #7f52f0; --lime: #8fbf00; --shadow-ink: #23142e;
        --neon-1: #ff7ad9; --neon-2: #b08cff; --trance-blue: #2a8cff; --glow: 0.3;
        --glow-pink: color-mix(in srgb, var(--accent) 14%, transparent);
        --glow-pink-strong: color-mix(in srgb, var(--accent) 18%, transparent);
        --glow-violet: color-mix(in srgb, var(--neon-2) 18%, transparent);
        --glow-blue: color-mix(in srgb, var(--trance-blue) 18%, transparent);
        --title-glow: color-mix(in srgb, var(--accent) 21%, transparent); color-scheme: light;
    }
}

/* 2. Base ------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }

html {
    -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 90px;
    /* On html as well as body: phones (iOS Safari especially) ignore body's clip and let the page slide sideways when
       something pokes past the edge, like the spinning sticker's corners */
    overflow-x: clip;
}

body {
    margin: 0; background: var(--bg); color: var(--ink); font-family: var(--font-body); font-size: 1.0625rem;
    line-height: 1.65; -webkit-font-smoothing: antialiased; overflow-x: clip;
}

img, svg, video, iframe { max-width: 100%; }
img { display: block; height: auto; }
a { color: inherit; }
h1, h2, h3, h4, h5, h6 { font-family: var(--font-display); line-height: 1.05; letter-spacing: -0.02em; margin: 0; }
p { margin: 0; }
em { font-style: normal; }

::selection { background: var(--accent); color: var(--accent-ink); }

:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 6px; }

.sr-only {
    position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
    position: absolute; left: 16px; top: -100px; z-index: 100; padding: 10px 16px; background: var(--accent);
    color: var(--accent-ink); font-weight: 700; border-radius: 999px;
}
.skip-link:focus { top: 16px; }

.container {
    width: 100%; max-width: calc(var(--container) + var(--gutter) * 2); margin-inline: auto;
    padding-inline: var(--gutter);
}

.mono { font-family: var(--font-mono); font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase; }

svg { flex-shrink: 0; }

/* 3. Small building blocks ------------------------------------------------- */
.eyebrow {
    display: inline-flex; align-items: center; gap: 0.5em; margin-bottom: 0.9rem; color: var(--accent);
    font-family: var(--font-mono); font-size: 0.8rem; font-weight: 700; letter-spacing: 0.12em;
    text-transform: uppercase;
}
.eyebrow svg { width: 1.15em; height: 1.15em; transform: rotate(-15deg); }
.eyebrow a { text-decoration: none; }
.eyebrow a:hover { text-decoration: underline; }
.eyebrow--ink { color: var(--accent-ink); }

.chip {
    display: inline-flex; align-items: center; gap: 0.6em; padding: 0.45em 1em; border: 1.5px solid var(--line);
    border-radius: 999px; background: color-mix(in srgb, var(--surface) 88%, transparent);
    font-family: var(--font-mono); font-size: 0.78rem; letter-spacing: 0.06em; text-transform: uppercase;
}

.live-dot { width: 9px; height: 9px; border-radius: 50%; position: relative; background: var(--lime); }
.live-dot::after {
    content: ""; position: absolute; inset: 0; border-radius: 50%; background: var(--lime);
    animation: pulse calc(var(--beat) * 16) steps(26) infinite;
}

.tag-chip {
    display: inline-block; padding: 0.2em 0.75em; border-radius: 999px;
    background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--ink); font-family: var(--font-mono);
    font-size: 0.72rem; letter-spacing: 0.06em; text-decoration: none; text-transform: uppercase;
}
a.tag-chip:hover { background: var(--accent); color: var(--accent-ink); }

.tag-list { display: flex; flex-wrap: wrap; gap: 8px; margin: 1.5rem 0 0; padding: 0; list-style: none; }

.link-arrow {
    display: inline-flex; align-items: center; gap: 0.4em; color: var(--ink); font-weight: 700; text-decoration: none;
    white-space: nowrap;
}
.link-arrow svg { width: 1.1em; height: 1.1em; color: var(--accent); transition: transform 0.2s; }
.link-arrow:hover svg, a:hover .link-arrow svg { transform: translateX(4px); }

/* Tiny animated equaliser */
.eq { display: inline-flex; align-items: flex-end; gap: 2px; height: 1em; }
.eq i {
    display: block; width: 3px; height: 100%; border-radius: 2px; background: currentColor; transform-origin: bottom;
    animation: eq calc(var(--beat) * 16) steps(13) infinite;
}
.eq i:nth-child(2) { animation-delay: calc(var(--beat) * -7 / 13); }
.eq i:nth-child(3) { animation-delay: calc(var(--beat) * -3 / 13); }
.eq i:nth-child(4) { animation-delay: calc(var(--beat) * -10 / 13); }

/* 4. Buttons — chunky, with a hard shadow and a little wag on hover -------- */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 0.55em; padding: 0.9em 1.5em;
    border: 2px solid var(--shadow-ink); border-radius: 999px; background: var(--accent); color: var(--accent-ink);
    box-shadow: 4px 4px 0 var(--shadow-ink); font-family: var(--font-display); font-size: 1rem; font-weight: 700;
    line-height: 1; text-decoration: none; cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.btn svg { width: 1.1em; height: 1.1em; }
.btn--caps { text-transform: uppercase; letter-spacing: 0.05em; }
.btn:hover { transform: translate(-2px, -2px) rotate(-1.5deg); box-shadow: 6px 6px 0 var(--shadow-ink); }
.btn:active { transform: translate(3px, 3px); box-shadow: 1px 1px 0 var(--shadow-ink); }

.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--surface); }

.btn--small { padding: 0.65em 1.1em; font-size: 0.92rem; box-shadow: 3px 3px 0 var(--shadow-ink); }

.btn--ink {
    border-color: var(--accent-ink); background: var(--accent-ink); color: #fff4e8; box-shadow: 4px 4px 0 #fff4e8;
}
.btn--ink:hover { box-shadow: 6px 6px 0 #fff4e8; }
.btn--outline-ink {
    border-color: var(--accent-ink); background: transparent; color: var(--accent-ink);
    box-shadow: 4px 4px 0 var(--accent-ink);
}
.btn--outline-ink:hover { box-shadow: 6px 6px 0 var(--accent-ink); background: rgba(255, 255, 255, 0.2); }

/* 5. Header ---------------------------------------------------------------- */
.site-header { position: sticky; top: 0; z-index: 50; transition: background 0.25s, box-shadow 0.25s; }
.site-header.is-scrolled {
    background: color-mix(in srgb, var(--bg) 95%, transparent); box-shadow: 0 1px 0 var(--line);
}
.site-header__inner { display: flex; align-items: center; justify-content: space-between; gap: 24px; min-height: 78px; }

.brand {
    display: inline-flex; align-items: center; gap: 10px; color: var(--ink); font-family: var(--font-display);
    font-size: 1.35rem; font-weight: 800; letter-spacing: -0.02em; text-decoration: none;
}
.brand__logo { max-height: 44px; width: auto; }
.brand__mark { width: 46px; height: 46px; }
.brand__mark .pup-body { transition: transform 0.3s; }
.brand:hover .brand__mark .pup-body { animation: wiggle 0.5s ease-in-out; }

.site-nav { display: flex; align-items: center; gap: 28px; }
.site-nav .nav { display: flex; gap: 6px; margin: 0; padding: 0; list-style: none; }
.site-nav .nav a {
    display: block; padding: 0.45em 0.9em; border-radius: 999px; color: var(--ink); font-weight: 600;
    text-decoration: none; transition: background 0.15s;
}
.site-nav .nav a:hover { background: var(--surface); }
.site-nav .nav-current a { background: color-mix(in srgb, var(--accent) 20%, transparent); }
.site-nav__cta svg { transform: rotate(-15deg); }
.site-nav__actions { display: flex; align-items: center; gap: 12px; }

.nav-toggle {
    display: none; width: 46px; height: 46px; padding: 10px; border: 2px solid var(--ink); border-radius: 50%;
    background: transparent; color: var(--ink); cursor: pointer;
}
.nav-toggle svg { width: 100%; height: 100%; }
.nav-toggle__close { display: none; }

@media (max-width: 1000px) {
    .nav-toggle { display: inline-flex; position: relative; z-index: 60; }
    .site-nav {
        position: fixed; inset: 0; z-index: 55; flex-direction: column; justify-content: center; gap: 36px;
        padding: 100px var(--gutter) 40px; background: var(--bg); opacity: 0; visibility: hidden;
        transition: opacity 0.25s, visibility 0.25s;
    }
    .site-nav .nav { flex-direction: column; align-items: center; gap: 8px; }
    .site-nav .nav a { font-family: var(--font-display); font-size: 2rem; font-weight: 800; }
    .nav-open .site-nav { opacity: 1; visibility: visible; }
    .nav-open .nav-toggle__open { display: none; }
    .nav-open .nav-toggle__close { display: block; }
    .nav-open { overflow: hidden; }
}

/* 6. Hero ------------------------------------------------------------------ */
.hero {
    --hero-pad-top: clamp(24px, 5vw, 60px); --hero-pad-bottom: clamp(60px, 8vw, 110px); position: relative;
    padding: var(--hero-pad-top) 0 var(--hero-pad-bottom); isolation: isolate;
}
/* Static club haze behind page headers (painted once, then free) */
.page-hero, .mix-hero, .error-page { position: relative; isolation: isolate; }
.page-hero::before, .mix-hero::before, .error-page::before {
    content: ""; position: absolute; top: -120px; bottom: 0; left: calc(50% - 50vw); right: calc(50% - 50vw);
    z-index: -2;
    background:
        radial-gradient(40% 50% at 78% 30%, var(--glow-violet), transparent 70%),
        radial-gradient(35% 45% at 12% 20%, var(--glow-pink), transparent 70%);
    opacity: 0.6; pointer-events: none; -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent);
    mask-image: linear-gradient(to bottom, #000 55%, transparent);
}

/* Colour-shifting haze on the homepage: three soft glows (pink, violet, electric blue) that drift and take turns fading
   up. Only transform and opacity animate, so the GPU moves pre-drawn layers instead of repainting. */
.aurora {
    position: absolute; top: -120px; bottom: 0; left: calc(50% - 50vw); right: calc(50% - 50vw); z-index: -3;
    overflow: hidden; pointer-events: none;
}
.aurora i {
    position: absolute; width: max(60vw, 420px); aspect-ratio: 1; border-radius: 50%;
    background: radial-gradient(closest-side, var(--c), transparent); opacity: 0.35;
    animation: aurora calc(var(--beat) * 54) steps(117) infinite; /* ~10 fps */
    will-change: transform, opacity;
}
.aurora i:nth-child(1) { --c: var(--glow-pink-strong); left: -18%; top: -25%; }
.aurora i:nth-child(2) { --c: var(--glow-violet); right: -12%; top: -20%; animation-delay: calc(var(--beat) * -18); }
.aurora i:nth-child(3) { --c: var(--glow-blue); left: 28%; top: 5%; animation-delay: calc(var(--beat) * -36); }

/* A soft shadow behind the hero text keeps it readable over the glows */
.hero__copy { position: relative; }
.hero__copy::before {
    content: ""; position: absolute; inset: -8% -12%; z-index: -1;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--bg) 70%, transparent), transparent);
    pointer-events: none;
}

/* Two neon tubes, like the ones glowing over the decks. Now and then one flickers like a tube on its way out
   (neon-flicker-a/-b): stutters, brownouts, near-dropouts and lone blinks at uneven gaps, about every 20 s (a) and 30 s
   (b). Each tube has its own cycle length so they rarely flicker together, and main.js starts each at a random whole
   beat of it (--neon-skip) so every visit differs. The jumps are steps(1) between keyframes placed on whole frame ticks
   (1/13 beat), so nothing redraws between flickers. */
.hero__neon { position: absolute; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; opacity: calc(var(--glow) + 0.2); }
.hero__neon span {
    position: absolute; height: 6px; border-radius: 6px; background: var(--neon-1);
    box-shadow:
        0 0 12px 2px var(--neon-1),
        0 0 40px 8px color-mix(in srgb, var(--neon-1) 60%, transparent);
    animation: neon-flicker-a calc(var(--beat) * 200) steps(1, end) calc(var(--beat) * var(--neon-skip, 0) * -1) infinite;
    will-change: opacity;
}
/* Parallel and overlapping, the second a fixed step below the first, so on wide screens they don't line up into one
   kinked line. Both turn about their left end: the 1.5vw is how far the first has dropped where the second starts (tan
   3deg × 29% of the width). */
.hero__neon span:nth-child(1) { top: 5%; left: -5%; width: 38%; transform-origin: 0 50%; transform: rotate(3deg); }
.hero__neon span:nth-child(2) { top: calc(5% + 1.5vw + 44px); left: 24%; width: 30%; transform-origin: 0 50%; transform: rotate(3deg); background: var(--neon-2); box-shadow: 0 0 12px 2px var(--neon-2), 0 0 40px 8px color-mix(in srgb, var(--neon-2) 60%, transparent); animation-name: neon-flicker-b; animation-duration: calc(var(--beat) * 280); }
/* Phones: the title covers the middle, so the second reaches out past its end */
@media (max-width: 700px) { .hero__neon span:nth-child(2) { left: 30%; width: 36%; } }

.hero__inner { display: grid; grid-template-columns: 1.1fr 0.9fr; align-items: center; gap: clamp(32px, 6vw, 80px); }

.hero__title {
    margin: 1.2rem 0 1.2rem; font-size: clamp(3.6rem, 10.5vw, 8.8rem); font-weight: 800;
    font-variation-settings: "wdth" 88, "opsz" 96; line-height: 0.88; letter-spacing: -0.045em;
    text-shadow: 0 0 40px var(--title-glow); overflow-wrap: anywhere;
}

.hero__tagline { max-width: 30ch; color: var(--muted); font-size: clamp(1.15rem, 1.8vw, 1.4rem); line-height: 1.45; }

.hero__actions { display: flex; flex-wrap: wrap; gap: 14px 18px; margin-top: 2rem; }
.hero .socials { margin-top: 2rem; }
/* On the dark hero a 14% ring vanished: a firmer ring and a faint fill make each one read as a button */
.hero .socials a {
    border-color: color-mix(in srgb, var(--ink) 45%, transparent); background: color-mix(in srgb, var(--ink) 8%, transparent);
}

.hero__media { position: relative; justify-self: center; width: min(100%, 500px); }

.polaroid {
    position: relative; margin: 0; padding: 14px 14px 56px; background: #fffaf3; border-radius: 6px;
    box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(0, 0, 0, 0.06); transform: rotate(3deg);
    transition: transform 0.4s cubic-bezier(.34, 1.56, .64, 1);
}
.polaroid:hover { transform: rotate(0.5deg) scale(1.01); }
.polaroid img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 2px; }
.polaroid figcaption {
    position: absolute; left: 18px; right: 18px; bottom: 16px; color: #3a2a46; text-align: right; font-weight: 700;
}
.polaroid figcaption::first-letter { color: #ff2d55; }
.polaroid__tape {
    position: absolute; top: -16px; left: 50%; z-index: 2; width: 120px; height: 34px;
    background: color-mix(in srgb, var(--accent) 55%, rgba(255, 255, 255, 0.3));
    transform: translateX(-50%) rotate(-4deg); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
    mask: linear-gradient(90deg, transparent 0 3px, #000 3px calc(100% - 3px), transparent calc(100% - 3px));
}

.hero__record { width: 100%; }
.hero__record .vinyl { width: 100%; }

/* Spinning sticker */
.sticker {
    position: absolute; left: -54px; bottom: -44px; z-index: 3; display: grid; place-items: center;
    width: 150px; height: 150px; border: 2px solid var(--accent-ink); border-radius: 50%; background: var(--biscuit);
    color: var(--accent-ink); box-shadow: 4px 4px 0 var(--accent-ink); text-decoration: none;
    transition: transform 0.2s;
}
.sticker:hover { transform: scale(1.06) rotate(-6deg); }
/* The spinning and bobbing happen on HTML wrappers around the SVGs: browsers can hand those to the GPU, but they redraw
   a moving SVG every frame */
.sticker__ring {
    position: absolute; inset: 0; display: block; animation: spin calc(var(--beat) * 33) steps(429) infinite;
}
.sticker__ring svg,
.sticker__puppy svg,
.booking__puppy svg { display: block; width: 100%; height: 100%; }
.sticker:hover .sticker__ring { animation-duration: calc(var(--beat) * 11); }
.sticker__ring text {
    fill: currentColor; font-family: var(--font-display); font-size: 19px; font-weight: 800; letter-spacing: 0.08em;
    text-transform: uppercase;
}
.sticker__puppy { position: relative; display: block; width: 70px; height: 70px; animation: bob calc(var(--beat) * 16) steps(13) infinite; }

@media (max-width: 900px) {
    .hero__inner { grid-template-columns: 1fr; }
    .hero__media { width: min(88%, 440px); margin-top: 20px; }
    .sticker { left: auto; right: -30px; bottom: -40px; width: 124px; height: 124px; }
    .polaroid figcaption { text-align: left; } /* the sticker moves to the right here */
    .sticker__puppy { width: 58px; height: 58px; }
}

/* 7. Marquee --------------------------------------------------------------- */
/* Performance notes for the banner:
   - Firefox only hands a moving element to the GPU if it's roughly screen-sized or smaller; one long ~5000px strip got
     redrawn on the CPU every frame. So main.js splits the text into words and slides each word on its own (all in step,
     via a generated @keyframes), keeping every moving piece small.
   - The clip lives on this straight wrapper: clipping moving content inside a rotated box costs Chrome an extra render
     pass every frame. */
.marquee-wrap { position: relative; z-index: 2; overflow-x: clip; }
.marquee {
    margin: 0 -2vw; padding: 16px 0; border-block: 2px solid var(--shadow-ink); background: var(--accent);
    color: var(--accent-ink); transform: rotate(-1.5deg);
}
.marquee__track {
    display: flex; align-items: center; gap: 28px; width: max-content;
    /* Fallback without JavaScript: the whole strip slides (70 beats = 30 s) */
    animation: marquee calc(var(--beat) * 70) steps(910) infinite;
}
.marquee__track span {
    font-family: var(--font-display); font-size: clamp(1.4rem, 3vw, 2.2rem); font-weight: 800; letter-spacing: -0.01em;
    text-transform: uppercase; white-space: nowrap;
}
.marquee__track svg { width: 30px; height: 30px; transform: rotate(-20deg); }
/* Split into words by main.js */
.marquee__track.is-split { position: relative; gap: 0; animation: none; } /* positioned: main.js measures words from here */
.marquee__track.is-split .marquee__item { padding-right: 0.3em; }
.marquee__track.is-split .marquee__paw { display: flex; padding: 0 28px 0 calc(28px - 0.3em); }
/* Then pinned in place, each word looping on its own (main.js sets left/top) */
.marquee__track.is-placed { display: block; position: relative; }
.marquee__track.is-placed > .marquee__item { position: absolute; }

/* 8. Sections -------------------------------------------------------------- */
.section { padding-block: clamp(64px, 9vw, 120px); }
.section--flush-top { padding-top: 0; }
.section--tint {
    background:
        radial-gradient(60% 80% at 100% 0%, color-mix(in srgb, var(--lilac) 14%, transparent), transparent 70%),
        var(--bg-2);
}

.section-head {
    display: flex; align-items: flex-end; justify-content: space-between; gap: 24px;
    margin-bottom: clamp(32px, 4vw, 52px);
}
.section-title { font-size: clamp(2.3rem, 5vw, 4rem); font-weight: 800; letter-spacing: -0.035em; }

@media (max-width: 640px) { .section-head { flex-direction: column; align-items: flex-start; } }

/* Page hero (listing pages, gigs) */
.page-hero { padding-block: clamp(40px, 7vw, 90px) clamp(36px, 5vw, 60px); }
.page-hero__title {
    font-size: clamp(2.8rem, 8vw, 6rem); font-weight: 800; font-variation-settings: "wdth" 90, "opsz" 96;
    line-height: 0.95; letter-spacing: -0.04em;
}
.page-hero__lede { max-width: 52ch; margin-top: 1.2rem; color: var(--muted); font-size: 1.2rem; }
.author-hero { display: flex; align-items: center; gap: 28px; }
.author-hero__avatar {
    width: 120px; height: 120px; border: 3px solid var(--accent); border-radius: 50%; object-fit: cover;
}

/* 9. Vinyl ----------------------------------------------------------------- */
.vinyl {
    position: relative; display: block; aspect-ratio: 1; border-radius: 50%;
    background:
        conic-gradient(from 20deg,
            transparent 0 8%, rgba(255, 255, 255, 0.16) 12%, transparent 17% 55%,
            rgba(255, 255, 255, 0.1) 60%, transparent 66%),
        repeating-radial-gradient(circle at center, #121014 0 1.5px, #1d1a21 2px 3.5px),
        #111;
    box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.6), inset 0 0 0 2px #000;
}
.vinyl__label {
    position: absolute; inset: 33%; display: grid; place-items: center; border-radius: 50%;
    background:
        radial-gradient(circle, #111 0 7%, transparent 7.5%),
        var(--accent);
    color: var(--accent-ink); box-shadow: 0 0 0 4px #0b0a0d;
}
.vinyl__label svg { width: 44%; height: 44%; opacity: 0.85; transform: translateY(-20%); }
.vinyl--spin { animation: spin calc(var(--beat) * 8) steps(104) infinite; }

/* 10. Mix cards — record sleeves with the vinyl peeking out ---------------- */
.mix-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
    gap: clamp(28px, 4vw, 48px) clamp(24px, 3vw, 40px);
}

.mix-card__link { display: block; color: inherit; text-decoration: none; }

.mix-card__art { position: relative; padding-right: 14%; }
.mix-card__sleeve {
    position: relative; z-index: 2; aspect-ratio: 1; overflow: hidden; border: 2px solid var(--shadow-ink);
    border-radius: var(--radius-sm); background: var(--surface); box-shadow: 5px 5px 0 var(--shadow-ink);
    transition: transform 0.3s cubic-bezier(.34, 1.56, .64, 1), box-shadow 0.3s;
}
.mix-card__sleeve img { width: 100%; height: 100%; object-fit: cover; }
.mix-card__vinyl {
    position: absolute !important; top: 5%; right: 0; z-index: 1; width: 80%;
    transition: transform 0.6s cubic-bezier(.34, 1.56, .64, 1);
}
.mix-card__play {
    position: absolute; left: 16px; bottom: 16px; z-index: 3; display: grid; place-items: center;
    width: 54px; height: 54px; border: 2px solid var(--accent-ink); border-radius: 50%; background: var(--accent);
    color: var(--accent-ink); transform: scale(0.8); opacity: 0; transition: transform 0.25s, opacity 0.25s;
}
.mix-card__play svg { width: 22px; height: 22px; margin-left: 3px; }

.mix-card__link:hover .mix-card__sleeve { transform: rotate(-2deg); box-shadow: 8px 8px 0 var(--shadow-ink); }
.mix-card__link:hover .mix-card__vinyl { transform: translateX(14%) rotate(160deg); }
.mix-card__link:hover .mix-card__play,
.mix-card__link:focus-visible .mix-card__play { transform: none; opacity: 1; }

/* Mascot stand-in for posts without a feature image (partials/mascot-image.hbs) */
.mascot-fill {
    display: grid; place-items: center; width: 100%; height: 100%;
    background:
        radial-gradient(circle at 80% 20%, color-mix(in srgb, var(--biscuit) 70%, transparent), transparent 45%),
        linear-gradient(140deg, var(--accent), var(--lilac));
}
.mascot-fill img,
.post-card__image .mascot-fill img,
.mix-card__sleeve .mascot-fill img,
.mix-hero__sleeve .mascot-fill img { width: auto; height: 78%; max-width: 78%; object-fit: contain; }

.mix-card__meta { padding: 22px 14% 0 0; }
.mix-card__meta time { color: var(--accent); }
.mix-card__title { margin-top: 6px; font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; }
.mix-card__excerpt { margin-top: 8px; color: var(--muted); font-size: 0.98rem; }

/* 11. Post cards ----------------------------------------------------------- */
.post-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); gap: clamp(22px, 3vw, 36px);
}

.post-card__link {
    display: flex; flex-direction: column; height: 100%; overflow: hidden; border: 1.5px solid var(--line);
    border-radius: var(--radius); background: var(--surface); color: inherit; text-decoration: none;
    transition: transform 0.25s, border-color 0.25s, box-shadow 0.25s;
}
.post-card__link:hover {
    transform: translateY(-4px); border-color: var(--accent);
    box-shadow: 0 18px 40px -18px color-mix(in srgb, var(--accent) 60%, transparent);
}
.post-card__image { aspect-ratio: 16 / 10; overflow: hidden; }
.post-card__image img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.5s; }
.post-card__link:hover .post-card__image img { transform: scale(1.04); }
.post-card__body { display: flex; flex-direction: column; flex: 1; padding: 22px 24px 26px; }
.post-card__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; color: var(--muted); }
.post-card__title { margin-top: 12px; font-size: 1.45rem; font-weight: 700; }
.post-card__excerpt { margin: 10px 0 18px; color: var(--muted); font-size: 0.98rem; }
.post-card .link-arrow { margin-top: auto; }
.post-grid .mix-card { align-self: start; }

/* 12. Gigs — each bullet becomes a ticket stub ----------------------------- */
.gig-list ul { display: grid; gap: 14px; margin: 0 0 2.5rem; padding: 0; list-style: none; }
.gig-list ul > li {
    position: relative; display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 18px 28px;
    margin: 0; padding: 20px 28px; border: 1.5px solid var(--line); border-radius: var(--radius-sm);
    background: var(--surface); transition: transform 0.2s, border-color 0.2s;
    /* ticket notches */
    mask:
        radial-gradient(circle 12px at 0 50%, transparent 98%, #000) left / 51% 100% no-repeat,
        radial-gradient(circle 12px at 100% 50%, transparent 98%, #000) right / 51% 100% no-repeat;
}
.gig-list ul > li:hover { transform: translateX(6px); border-color: var(--accent); }
.gig-list ul > li::before { display: none; }

.gig__date {
    display: grid; justify-items: center; min-width: 76px; padding-right: 26px; border-right: 2px dashed var(--line);
    font-family: var(--font-mono); line-height: 1.1; text-transform: uppercase;
}
.gig__month { color: var(--accent); font-size: 0.8rem; font-weight: 700; letter-spacing: 0.1em; }
.gig__day { font-family: var(--font-display); font-size: 2.4rem; font-weight: 800; letter-spacing: -0.03em; }
.gig__dow { color: var(--muted); font-size: 0.72rem; letter-spacing: 0.1em; }
.gig__date--raw { font-size: 0.95rem; font-weight: 700; color: var(--accent); }

.gig__info { display: grid; gap: 2px; min-width: 0; }
.gig__venue { font-family: var(--font-display); font-size: 1.35rem; font-weight: 700; line-height: 1.2; }
.gig__where { color: var(--muted); }
.gig__cta { justify-self: end; }
.gig__soon {
    justify-self: end; color: var(--muted); font-family: var(--font-mono); font-size: 0.75rem;
    text-transform: uppercase;
}

.gig-list ul.is-past > li { opacity: 0.55; }
.gig-list ul.is-past > li:hover { opacity: 0.85; }

/* Without JavaScript: keep the raw bullet readable */
.gig-list ul > li:not(.gig) { grid-template-columns: 1fr; }
.gig-list ul > li:not(.gig) strong { color: var(--accent); font-family: var(--font-mono); }

/* Home preview: first list only, max 4 dates */
.gig-list--preview > :not(ul:first-of-type) { display: none; }
.gig-list--preview ul { margin-bottom: 0; }
.gig-list--preview ul > li:nth-child(n+5) { display: none; }

.gig-page { padding-bottom: clamp(40px, 6vw, 80px); }
.gig-page .gig-list { max-width: 900px; }
.gig-list.gh-content > h2,
.gig-list.gh-content > h3 { margin: 2.5rem 0 1rem; }

@media (max-width: 640px) {
    .gig-list ul > li { grid-template-columns: auto 1fr; padding: 18px 20px; gap: 14px 18px; }
    .gig__date { min-width: 60px; padding-right: 16px; }
    .gig__cta, .gig__soon { grid-column: 1 / -1; justify-self: stretch; }
}

/* 13. About teaser --------------------------------------------------------- */
.about { display: grid; grid-template-columns: 0.85fr 1.15fr; align-items: center; gap: clamp(36px, 6vw, 90px); }
.about__media { position: relative; }
.about__blob {
    aspect-ratio: 1; overflow: hidden; border: 2px solid var(--shadow-ink);
    border-radius: 58% 42% 50% 50% / 48% 55% 45% 52%; background: linear-gradient(140deg, var(--accent), var(--lilac));
    box-shadow: 8px 8px 0 var(--shadow-ink);
}
.about__blob img { width: 100%; height: 100%; object-fit: cover; }
.about__blob--mascot { display: grid; place-items: center; }
.about__blob--mascot svg { width: 70%; height: 70%; }
.about__badge {
    position: absolute; right: 4%; bottom: 6%; display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px;
    border: 2px solid var(--accent-ink); border-radius: 999px; background: var(--lime); color: var(--accent-ink);
    font-weight: 700; transform: rotate(-6deg); box-shadow: 3px 3px 0 var(--accent-ink);
}
.about__badge svg { width: 18px; height: 18px; }
.about__text { margin: 1.4rem 0 2rem; color: var(--muted); font-size: 1.15rem; }

@media (max-width: 800px) {
    .about { grid-template-columns: 1fr; }
    .about__media { max-width: 380px; }
}

/* 14. Booking -------------------------------------------------------------- */
.booking {
    --booking-pad-top: clamp(40px, 6vw, 80px); position: relative; isolation: isolate;
    padding-block: var(--booking-pad-top) clamp(64px, 9vw, 120px);
}
/* A third neon tube, amber (the card's own peach corner), on the wall above the card: in the dark gap over its right
   half (the hero's are on the left), sloping down towards it, behind the card if they meet (z-index -1 inside .booking's isolate). Bookends the
   hero's two, at full strength (dimmed, the cream glass shows through and greys it). Its own flicker (neon-flicker-c)
   and random start (--neon-skip, main.js); a real element, not ::before, so is-offscreen pauses it. The wrapper holds
   the unlit glass; the inner span is the light, and flickers. */
.booking__neon {
    position: absolute; top: calc(var(--booking-pad-top) * 0.35); right: calc(var(--gutter) + 4%); z-index: -1;
    width: 36%; transform-origin: 100% 50%; transform: rotate(-4deg); pointer-events: none;
}
/* The unlit glass, always there: when the light dips it's a pale tube, not nothing. Not animated, so a pseudo-element
   is fine. */
.booking__neon::before {
    content: ""; position: absolute; inset: 0; border-radius: 6px;
    background: linear-gradient(color-mix(in srgb, var(--biscuit) 18%, #fff), color-mix(in srgb, var(--biscuit) 30%, #e6d6c9));
    box-shadow: 0 0 0 1px rgb(20 12 40 / 0.35), 0 2px 4px rgb(20 12 40 / 0.35);
}
.booking__neon span {
    position: relative; display: block; height: 6px; border-radius: 6px; background: var(--biscuit);
    box-shadow:
        0 0 12px 2px var(--biscuit),
        0 0 40px 8px color-mix(in srgb, var(--biscuit) 60%, transparent);
    animation: neon-flicker-c calc(var(--beat) * 350) steps(1, end) calc(var(--beat) * var(--neon-skip, 0) * -1) infinite;
    will-change: opacity;
}
.booking__card {
    position: relative; display: grid; grid-template-columns: 1.4fr 0.6fr; align-items: center; gap: 40px;
    overflow: hidden; padding: clamp(32px, 6vw, 72px); border: 2px solid var(--shadow-ink);
    border-radius: calc(var(--radius) * 1.5);
    background:
        radial-gradient(circle at 90% 110%, color-mix(in srgb, var(--biscuit) 80%, transparent), transparent 45%),
        var(--accent);
    color: var(--accent-ink); box-shadow: 8px 8px 0 var(--shadow-ink);
}
.booking__card::after {
    content: ""; position: absolute; inset: 0;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='80' viewBox='0 0 24 24'%3E%3Cg fill='%23170d22' opacity='.07' transform='rotate(-20 12 12) translate(6 6) scale(.5)'%3E%3Cpath d='M12 12.6c-3.1 0-6.3 3.3-6.3 6 0 1.8 1.4 2.9 3.2 2.9 1.3 0 2.1-.7 3.1-.7s1.8.7 3.1.7c1.8 0 3.2-1.1 3.2-2.9 0-2.7-3.2-6-6.3-6z'/%3E%3Cellipse cx='4.6' cy='10.4' rx='2.1' ry='2.6'/%3E%3Cellipse cx='8.9' cy='5.6' rx='2.3' ry='2.9'/%3E%3Cellipse cx='15.1' cy='5.6' rx='2.3' ry='2.9'/%3E%3Cellipse cx='19.4' cy='10.4' rx='2.1' ry='2.6'/%3E%3C/g%3E%3C/svg%3E");
    pointer-events: none;
}
.booking__copy { position: relative; z-index: 1; }
.booking__title {
    max-width: 14ch; font-size: clamp(2.4rem, 5.5vw, 4.4rem); font-weight: 800;
    font-variation-settings: "wdth" 90, "opsz" 96; line-height: 0.95; letter-spacing: -0.04em;
}
.booking__text { max-width: 46ch; margin-top: 1.2rem; font-size: 1.15rem; line-height: 1.5; }
.booking__actions { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 2rem; }
.booking .socials { margin-top: 1.8rem; }
.booking .socials a { border-color: var(--accent-ink); background: var(--accent-ink); color: #fff4e8; }
.booking .socials a:hover { background: #fff4e8; color: var(--accent-ink); }

.booking__mascot { position: relative; z-index: 1; display: grid; justify-items: center; gap: 10px; }
.booking__puppy {
    display: block; width: min(100%, 260px); aspect-ratio: 1; animation: bob calc(var(--beat) * 16) steps(13) infinite;
    transform-origin: 50% 90%;
}
.booking__puppy .pup-body { transform-origin: 50% 90%; }
.booking__puppy svg { filter: drop-shadow(6px 6px 0 rgba(23, 13, 34, 0.9)); }
.booking__bpm { font-weight: 700; opacity: 0.75; }

@media (max-width: 760px) {
    .booking__card { grid-template-columns: 1fr; }
    .booking__mascot { order: -1; justify-items: start; }
    .booking__puppy { width: 120px; }
    .booking__bpm { display: none; }
    .booking__neon { width: 60%; }
}

/* 15. Socials -------------------------------------------------------------- */
.socials { display: flex; flex-wrap: wrap; gap: 10px; margin: 0; padding: 0; list-style: none; }
.socials:empty { display: none; }
.socials a {
    display: grid; place-items: center; width: 44px; height: 44px; border: 1.5px solid var(--line); border-radius: 50%;
    color: var(--ink); transition: background 0.15s, color 0.15s, transform 0.2s, border-color 0.15s;
}
.socials a:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); transform: translateY(-3px) rotate(-8deg); }
.socials svg { width: 20px; height: 20px; }

/* 16. Articles & Ghost content --------------------------------------------- */
.gh-canvas {
    display: grid;
    grid-template-columns:
        [full-start] minmax(var(--gutter), auto)
        [wide-start] minmax(auto, 240px)
        [main-start] min(720px, calc(100% - var(--gutter) * 2))
        [main-end] minmax(auto, 240px)
        [wide-end] minmax(var(--gutter), auto)
        [full-end];
}
.gh-canvas > * { grid-column: main-start / main-end; }
.kg-width-wide { grid-column: wide-start / wide-end; }
.kg-width-full { grid-column: full-start / full-end; }
.kg-width-full img { width: 100%; }

.article__head { padding-block: clamp(40px, 7vw, 90px) 0; }
.article__title {
    font-size: clamp(2.5rem, 6vw, 4.6rem); font-weight: 800; font-variation-settings: "wdth" 92, "opsz" 96;
    line-height: 1; letter-spacing: -0.035em;
}
.article__lede { margin-top: 1.2rem; color: var(--muted); font-size: 1.3rem; line-height: 1.5; }
.article__image { margin: clamp(32px, 5vw, 56px) 0 0; }
.article__image img { width: 100%; border-radius: var(--radius); }
.article__image--mascot .mascot-fill { height: clamp(220px, 32vw, 380px); border-radius: var(--radius); }
.article__image--mascot .mascot-fill img { width: auto; border-radius: 0; }
/* Only show the feature image when the post body has no media of its own. Bookmark/audio card thumbnails don't count as
   media here. */
.article:has(.gh-content :is(img, video, iframe[src*="youtube"], iframe[src*="youtu.be"], iframe[src*="vimeo"]):not(:is(.kg-bookmark-card, .kg-audio-card) *)) .article__image { display: none; }
.article__image figcaption, .gh-content figcaption {
    margin-top: 12px; color: var(--muted); font-size: 0.9rem; text-align: center;
}

.gh-content { padding-block: clamp(36px, 5vw, 64px); font-size: 1.15rem; }
.gh-content > * + * { margin-top: 1.5em; }
.gh-content > :is(h2, h3, h4) { margin-top: 2em; }
.gh-content h2 { font-size: clamp(1.8rem, 3.5vw, 2.4rem); font-weight: 800; }
.gh-content h3 { font-size: 1.6rem; font-weight: 700; }
.gh-content h4 { font-size: 1.25rem; font-weight: 700; }
.gh-content a {
    color: var(--ink); text-decoration-color: var(--accent); text-decoration-thickness: 2px; text-underline-offset: 3px;
}
.gh-content a:hover { color: var(--accent); }
.gh-content ul, .gh-content ol { padding-left: 1.4em; }
.gh-content li + li { margin-top: 0.5em; }
.gh-content ul:not(.kg-product-card-rating) li::marker { color: var(--accent); }
.gh-content blockquote:not([class]) {
    margin-inline: 0; padding: 0.2em 0 0.2em 1.2em; border-left: 4px solid var(--accent);
    font-family: var(--font-display); font-size: 1.4rem; font-weight: 600; line-height: 1.35;
}
.gh-content blockquote.kg-blockquote-alt {
    font-family: var(--font-display); font-size: 1.8rem; font-weight: 700; line-height: 1.25; text-align: center;
    color: var(--accent);
}
.gh-content hr {
    height: 26px; margin-block: 3em; border: 0;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='%23ff1a75'%3E%3Cpath d='M12 12.6c-3.1 0-6.3 3.3-6.3 6 0 1.8 1.4 2.9 3.2 2.9 1.3 0 2.1-.7 3.1-.7s1.8.7 3.1.7c1.8 0 3.2-1.1 3.2-2.9 0-2.7-3.2-6-6.3-6z'/%3E%3Cellipse cx='4.6' cy='10.4' rx='2.1' ry='2.6'/%3E%3Cellipse cx='8.9' cy='5.6' rx='2.3' ry='2.9'/%3E%3Cellipse cx='15.1' cy='5.6' rx='2.3' ry='2.9'/%3E%3Cellipse cx='19.4' cy='10.4' rx='2.1' ry='2.6'/%3E%3C/g%3E%3C/svg%3E") center / 26px no-repeat;
    opacity: 0.8;
}
.gh-content img { border-radius: var(--radius-sm); }
.gh-content .kg-width-full img { border-radius: 0; }
.gh-content code:not(pre code) {
    padding: 0.15em 0.4em; border-radius: 6px; background: var(--surface); font-family: var(--font-mono);
    font-size: 0.85em;
}
.gh-content pre {
    overflow-x: auto; padding: 20px; border-radius: var(--radius-sm); background: #0d0813; color: #fff4e8;
    font-family: var(--font-mono); font-size: 0.9rem;
}
.gh-content iframe { border-radius: var(--radius-sm); }
.gh-content .kg-embed-card { display: flex; flex-direction: column; align-items: center; }
.gh-content .kg-embed-card iframe { width: 100%; }
.gh-content .kg-callout-card { border-radius: var(--radius-sm); }
.gh-content .kg-bookmark-card a.kg-bookmark-container { border-radius: var(--radius-sm); color: var(--ink); }
.gh-content .kg-button-card a.kg-btn,
.gh-content .kg-header-card a.kg-header-card-button { border-radius: 999px; font-family: var(--font-display); font-weight: 700; }
.gh-content table { width: 100%; border-collapse: collapse; }
.gh-content th, .gh-content td { padding: 10px 12px; border-bottom: 1px solid var(--line); text-align: left; }

.article__comments { padding-bottom: 40px; }
/* The comments iframe's document is light; if its color-scheme differs from ours (dark) the browser paints it an opaque
   white backdrop, hiding the widget's white-on-dark text. Matching schemes keeps it transparent. */
.article__comments iframe { color-scheme: light; }

/* Mix post header */
.mix-hero {
    display: grid; grid-template-columns: 0.9fr 1.1fr; align-items: center; gap: clamp(40px, 7vw, 100px);
    padding-block: clamp(40px, 7vw, 90px) clamp(10px, 2vw, 20px);
}
.mix-hero__art { position: relative; padding-right: 20%; }
.mix-hero__sleeve {
    position: relative; z-index: 2; aspect-ratio: 1; overflow: hidden; border: 2px solid var(--shadow-ink);
    border-radius: var(--radius-sm); box-shadow: 8px 8px 0 var(--shadow-ink);
}
.mix-hero__sleeve img { width: 100%; height: 100%; object-fit: cover; }
.mix-hero__vinyl { position: absolute !important; top: 5%; right: 0; z-index: 1; width: 90%; }
@media (max-width: 800px) {
    .mix-hero { grid-template-columns: 1fr; }
    .mix-hero__art { max-width: 400px; }
}

/* Prev / next */
.more { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; padding-bottom: 20px; }
.more__link {
    display: grid; gap: 6px; padding: 22px 26px; border: 1.5px solid var(--line); border-radius: var(--radius);
    color: inherit; text-decoration: none; transition: border-color 0.2s, transform 0.2s;
}
.more__link:hover { border-color: var(--accent); transform: translateY(-3px); }
.more__link span { color: var(--accent); }
.more__link strong { font-family: var(--font-display); font-size: 1.25rem; line-height: 1.2; }
.more__link--next { grid-column: 2; text-align: right; }
@media (max-width: 640px) {
    .more { grid-template-columns: 1fr; }
    .more__link--next { grid-column: auto; }
}

/* Pagination */
.pagination {
    display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-top: clamp(40px, 6vw, 64px);
}
.pagination__info { color: var(--muted); }

/* 17. Footer --------------------------------------------------------------- */
.site-footer { padding-top: 20px; border-top: 1.5px solid var(--line); background: var(--bg-2); }

.site-footer__inner { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 36px; padding-block: 40px; }
.site-footer__brand { display: grid; gap: 14px; max-width: 380px; }
.site-footer__desc { color: var(--muted); }
.site-footer__nav .nav { display: flex; flex-wrap: wrap; gap: 8px 22px; margin: 0; padding: 0; list-style: none; }
.site-footer__nav a { color: var(--muted); font-weight: 600; text-decoration: none; }
.site-footer__nav a:hover { color: var(--accent); }

.site-footer__base {
    display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px 24px; padding-block: 22px 32px;
    border-top: 1px solid var(--line); color: var(--muted); font-size: 0.9rem;
}
.site-footer__wag { display: inline-flex; align-items: center; gap: 8px; }
.site-footer__wag svg { width: 16px; height: 16px; color: var(--accent); transform: rotate(-15deg); }

/* 17b. "Join the pack" popup (partials/join-dialog.hbs) -------------------- */
.join {
    width: min(560px, calc(100% - 32px)); max-height: calc(100% - 32px); margin: auto; padding: 0; overflow: auto;
    border: 2px solid var(--shadow-ink); border-radius: calc(var(--radius) * 1.3); background: var(--surface);
    color: var(--ink); box-shadow: 8px 8px 0 var(--shadow-ink); overscroll-behavior: contain; scrollbar-width: thin;
    scrollbar-color: var(--line) transparent;
}
/* A plain dim, not a blur: a blurred backdrop would be recalculated every frame over the animations behind it */
.join::backdrop { background: rgba(10, 5, 18, 0.75); }
/* On touch screens the popup itself takes focus (so the keyboard doesn't pop up); a ring around the whole card isn't
   useful. Fields and buttons inside still show their own focus rings. */
.join:focus-visible { outline: none; }
.is-dialog-open { overflow: hidden; }
.is-dialog-open .site *,
.is-dialog-open .site *::before,
.is-dialog-open .site *::after { animation-play-state: paused !important; }

.join__panel { position: relative; padding: clamp(22px, 4vw, 36px); }
.join [data-view] { display: none; }
.join[data-mode="signup"] [data-view="signup"],
.join[data-mode="signin"] [data-view="signin"] { display: block; }

.join__close {
    position: absolute; top: 14px; right: 14px; display: grid; place-items: center; width: 40px; height: 40px;
    border: 1.5px solid var(--line); border-radius: 50%; background: transparent; color: var(--ink); cursor: pointer;
    transition: background 0.15s, transform 0.2s;
}
.join__close:hover { background: var(--bg); transform: rotate(90deg); }
.join__close svg { width: 18px; height: 18px; }

.join__head { display: flex; align-items: center; gap: 16px; padding-right: 40px; margin-bottom: 0.8rem; }
.join__head .eyebrow { margin-bottom: 0.3rem; }
.join__puppy {
    display: block; flex-shrink: 0; width: 68px; height: 68px; transform-origin: 50% 90%;
    animation: bob calc(var(--beat) * 16) steps(13) infinite;
}
.join__puppy .pup-body { transform-origin: 50% 90%; }
.join__puppy svg { display: block; width: 100%; height: 100%; }
.join__title {
    font-size: clamp(2rem, 6vw, 2.8rem); font-weight: 800; font-variation-settings: "wdth" 90, "opsz" 96;
    letter-spacing: -0.035em;
}
.join__lede { margin-bottom: 0.2rem; color: var(--muted); }

.join__perks { display: grid; gap: 8px; margin: 0 0 0.6rem; padding: 0; list-style: none; }
.join__perks li { display: grid; grid-template-columns: 22px 1fr; gap: 10px; color: var(--muted); line-height: 1.45; }
.join__perks strong { color: var(--ink); }
.join__perks svg { width: 20px; height: 20px; margin-top: 2px; color: var(--accent); transform: rotate(-15deg); }

.join-form__fields { display: grid; gap: 12px; }
.join-form__field { display: grid; gap: 6px; }
.join-form__field > span {
    color: var(--muted); font-family: var(--font-mono); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase;
}
.join-form__field em { font-weight: 400; text-transform: none; letter-spacing: 0; }
.join-form__field input {
    width: 100%; padding: 12px 14px; border: 2px solid var(--line); border-radius: var(--radius-sm);
    background: var(--bg); color: var(--ink); font: inherit; transition: border-color 0.15s;
}
.join-form__field input::placeholder { color: var(--muted); opacity: 0.7; }
.join-form__field input:focus { outline: none; border-color: var(--accent); }
.join-form__field input:focus-visible { outline: 3px solid color-mix(in srgb, var(--accent) 35%, transparent); outline-offset: 2px; }
.join-form__submit { width: 100%; margin-top: 4px; }
.join-form__label { display: inline-flex; align-items: center; gap: 0.5em; }
.join-form__label svg { width: 1.1em; height: 1.1em; transform: rotate(-15deg); }

/* Ghost adds loading / success / error classes to the form */
.join-form__loading,
.join-form__error,
.join-form__done { display: none; }
.join-form.loading .join-form__label { display: none; }
.join-form.loading .join-form__loading { display: inline; }
.join-form.loading .join-form__submit { pointer-events: none; opacity: 0.8; }
.join-form.error .join-form__error { display: block; color: var(--accent); font-weight: 600; }
.join-form.success .join-form__fields { display: none; }
.join-form.success .join-form__done { display: block; }
.join-form.success ~ .join__switch-line { display: none; }

.join-form__done {
    padding: 28px 24px; border: 2px dashed var(--line); border-radius: var(--radius); text-align: center;
}
.join-form__done svg { width: 44px; height: 44px; margin-bottom: 10px; color: var(--accent); transform: rotate(-15deg); }
.join-form__done p { color: var(--muted); }
.join-form__done .join-form__done-title {
    margin-bottom: 0.5rem; color: var(--ink); font-family: var(--font-display); font-size: 1.5rem; font-weight: 800;
    letter-spacing: -0.02em;
}

.join__fine { color: var(--muted); font-size: 0.9rem; text-align: center; }
.join__legal { margin-top: -6px; font-size: 0.8rem; }
.join__legal a { color: var(--ink); text-decoration-color: var(--accent); text-underline-offset: 2px; }
.join__legal a:hover { color: var(--accent); }
.join__switch-line { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--line); color: var(--muted); text-align: center; }
.join__switch {
    padding: 0; border: 0; background: none; color: var(--accent); font: inherit; font-weight: 700;
    text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}

/* 18. Error page ----------------------------------------------------------- */
.error-page { display: grid; justify-items: center; padding-block: clamp(60px, 10vw, 140px); text-align: center; }
.error-page__code {
    display: flex; align-items: center; gap: 0.05em; font-family: var(--font-display);
    font-size: clamp(6rem, 22vw, 14rem); font-weight: 800; line-height: 1; letter-spacing: -0.05em;
}
.error-page__vinyl { width: 0.82em; margin-inline: 0.04em; }
.error-page .page-hero__lede { margin-inline: auto; }
.error-page .hero__actions { justify-content: center; }

/* Fetch game (main.js): the yard is one big button; the ball rests at the puppy's mouth */
.fetch { width: min(100%, 560px); margin-top: clamp(32px, 6vw, 56px); }
.fetch__yard {
    position: relative; display: block; width: 100%; height: 220px; padding: 0; overflow: hidden;
    border: 2px dashed var(--line); border-radius: var(--radius);
    background:
        radial-gradient(70% 70% at 50% 100%, var(--glow-pink), transparent 70%),
        radial-gradient(120% 80% at 50% 110%, var(--glow-violet), transparent 75%);
    color: var(--muted); font: inherit; cursor: pointer;
}
.fetch__hint {
    position: absolute; top: 16px; left: 0; right: 0; font-family: var(--font-mono); font-size: 0.8rem;
    transition: opacity 0.3s;
}
.fetch__yard.is-played .fetch__hint { opacity: 0; }
.fetch__pup { position: absolute; left: 50%; bottom: 10px; z-index: 1; width: 72px; height: 72px; margin-left: -36px; }
.fetch__pup svg { display: block; width: 100%; height: 100%; }
.fetch__pup .pup-body { transform-origin: 50% 85%; transition: transform 0.2s; }
.fetch__pup.is-running .pup-body { transform: rotate(var(--lean, 0deg)); }
.fetch__ball { position: absolute; left: 50%; bottom: 19px; z-index: 2; width: 22px; height: 22px; margin-left: -11px; }
.fetch__score { min-height: 1.5em; margin-top: 12px; color: var(--muted); font-family: var(--font-mono); font-size: 0.9rem; }

/* 19. Playful extras ------------------------------------------------------- */
.paw-print {
    position: fixed; z-index: 9999; width: 34px; height: 34px; margin: -17px 0 0 -17px; color: var(--accent);
    pointer-events: none; animation: paw-fade 1.1s ease-out forwards;
}

.is-barking .brand__mark .pup-body,
.is-barking .sticker__puppy .pup-body,
.is-barking .booking__puppy .pup-body { animation: bark 0.3s ease-in-out 3 !important; }

/* Petting a puppy (main.js): a wag, hearts, and every few pets a speech bubble */
.is-petted .pup-body { transform-origin: 50% 85% !important; animation: wag 0.55s ease-in-out !important; }
.about__blob--mascot.is-petted .pup-body { transform-origin: 50% 100% !important; }   /* her feet: the svg is 70% of the blob */
.brand__mark, .sticker__puppy, .about__blob--mascot svg, .booking__puppy, .join__puppy { cursor: grab; }
.pet-heart {
    position: fixed; z-index: 9999; margin: -0.6em 0 0 -0.3em; color: var(--accent); font-size: 22px; line-height: 1;
    pointer-events: none; animation: heart-float 0.95s ease-out forwards;
}
.pet-bubble {
    position: fixed; z-index: 9999; padding: 5px 14px; border: 2px solid var(--accent-ink); border-radius: 999px;
    background: var(--biscuit); color: var(--accent-ink); box-shadow: 3px 3px 0 var(--accent-ink);
    font-family: var(--font-display); font-size: 1rem; font-weight: 800; white-space: nowrap; pointer-events: none;
    --ty: calc(-100% - 8px); transform: translate(-50%, var(--ty)); animation: bubble-pop 1.5s ease-out forwards;
}
.pet-bubble--below { --ty: 8px; }

/* Secret words (main.js): bones for "treat", a spin for "goodpup", a racing pack for "zoomies" */
.paw-rain.bone-rain { width: 60px; height: 60px; margin-left: -30px; }
.is-spinning .pup-body { transform-origin: 50% 55% !important; animation: pup-spin 0.85s ease-in-out !important; }
.zoomies {
    position: fixed; left: 0; bottom: 14vh; z-index: 9998; width: 84px; height: 84px; pointer-events: none;
    animation: zoomies 4s ease-in-out both;   /* size, lane, delay and length per puppy from main.js */
}
.zoomies--rtl { animation-name: zoomies-rtl; }   /* starts off the right edge */
/* its "wuff!" bubbles ride along above it */
.zoomies .pet-bubble { position: absolute; left: 50%; top: -6px; animation: zoomies-wuff 0.33s ease-out forwards; }
.zoomies svg { display: block; width: 100%; height: 100%; overflow: visible; animation: zoomies-hop 0.18s ease-in-out infinite alternate; }

/* Seasonal outfits (main.js): the hat pokes out above the puppy's box */
svg.is-dressed { overflow: visible; }

/* Her own moves (wiggle, wag, bark, spin, dozing, sniffing…) go on .pup-body, the <g> round #i-puppy and what she
   wears in each puppy's svg, not on the svg or its box: what floats round her or sits behind her (outfits' -float
   and -back, main.js) is outside it, so it stays put. Origins are in her 64×64 box (the svg fills its box).
   The bob, which never stops, stays on the box, which the browser moves without redrawing her (redrawing the svg
   every step costs Chrome a few % CPU), except on days something floats round her (.pup-floats on <html>, main.js).
   A pet, bark or spin stops the box's bob while it plays, as it replaces .pup-body's. */
.pup-body { transform-box: view-box; transform-origin: 50% 50%; }
.pup-floats .sticker__puppy, .pup-floats .booking__puppy, .pup-floats .join__puppy,
.pup-floats .live-bar__pup svg { animation: none; }
.pup-floats .sticker__puppy .pup-body, .pup-floats .booking__puppy .pup-body, .pup-floats .join__puppy .pup-body,
.pup-floats .live-bar__pup[data-mood="playing"] .pup-body { animation: bob calc(var(--beat) * 16) steps(13) infinite; }
.is-petted, .is-spinning, .is-barking .sticker__puppy, .is-barking .booking__puppy { animation: none !important; }
/* What flies above her (the Phoenix) needs headroom where her box clips: the About blob's curved edge, the phone's booking card */
.pup-floats .about__blob--mascot svg { width: 62%; height: 62%; translate: 0 9%; }
@media (max-width: 900px) { .pup-floats .booking__mascot { padding-top: 12px; } }

/* Sleepy logo puppy (main.js): eyes shut (--pup-sleep shows the closed eyes in #i-puppy), slumped a little, z z z
   floating up; it stretches when it wakes */
.brand { position: relative; }
.brand__mark.is-sleepy { --pup-sleep: 1; }
.brand__mark.is-sleepy .pup-body { transform: rotate(-10deg) scale(1.03, 0.92); transform-origin: 50% 85%; }
.brand__mark.is-waking .pup-body { transform-origin: 50% 85%; animation: pup-stretch 0.85s ease-out; }
.pup-zzz {
    position: absolute; left: 38px; top: 4px; color: var(--lilac); text-shadow: 0 0 6px var(--glow-violet);
    font-family: var(--font-display); font-weight: 800; line-height: 1; pointer-events: none;
}
.pup-zzz span {
    position: absolute; opacity: 0; font-size: 14px; animation: pup-zzz calc(var(--beat) * 6) steps(78) infinite;
}
.pup-zzz span:nth-child(2) { font-size: 17px; animation-delay: calc(var(--beat) * 2); }
.pup-zzz span:nth-child(3) { font-size: 21px; animation-delay: calc(var(--beat) * 4); }

/* Peekaboo puppy (main.js): peeks up from the bottom corner, then ducks down */
.peekaboo {
    position: fixed; right: 24px; bottom: 0; z-index: 40; width: 96px; height: 96px; transform: translateY(105%);
    transition: transform 0.6s cubic-bezier(0.3, 1.4, 0.5, 1); pointer-events: none;
}
.peekaboo--left { right: auto; left: 24px; }
.peekaboo.is-up { transform: translateY(15%); pointer-events: auto; }
.peekaboo svg { display: block; width: 100%; height: 100%; cursor: grab; }
.peekaboo .pup-body { transform-origin: 50% 85%; }
.peekaboo.is-up .pup-body { animation: wag 0.55s ease-in-out 0.6s 2; }
@media (max-width: 480px) {
    .peekaboo { right: 12px; width: 68px; height: 68px; }
    .peekaboo--left { right: auto; left: 12px; }
}
.paw-rain {
    position: fixed; top: -40px; z-index: 9999; width: 30px; height: 30px; color: var(--accent); pointer-events: none;
    opacity: 0; animation: paw-rain 2s linear forwards;
}

/* Sections scrolled out of view, and the whole page while the visitor is in another window, stop animating (see
   main.js) */
.is-offscreen,
.is-offscreen *,
.is-away *,
.is-away *::before,
.is-away *::after { animation-play-state: paused !important; }

/* 20. Keyframes ------------------------------------------------------------ */
@keyframes spin { to { transform: rotate(360deg); } }
/* Looping animations run on one clock: steps() applies to each stretch between two keyframes, and every stretch steps
   once per 1/13 beat (or a whole multiple of it), so everything on the page moves on the same frames (~30 a second;
   main.js keeps their start times in line too). Each cycle holds several beats' worth of movement (bob, eq, pulse,
   live-pulse: 16 or 64 beats) rather than one: the end of every cycle is an event, and Ghost's Portal and search listen
   for those, which makes Chrome wake the page for each one. Neon flicker: made by a seeded random script (kinds and
   beats in each comment); lit the rest of the time, and ends lit, so reduced motion shows it on. */
@keyframes neon-flicker-a { /* 200 beats: stutter, brownout, blink, stutter, dropout */
    0% { opacity: 1; }
    11.6923% { opacity: 0.25; } 11.7692% { opacity: 1; } 11.8077% { opacity: 0.25; } 11.8462% { opacity: 1; }
    11.8846% { opacity: 0.25; } 11.9615% { opacity: 1; }
    30.8077% { opacity: 0.08; } 30.8462% { opacity: 0.4; } 31.1154% { opacity: 0.08; } 31.1538% { opacity: 0.55; }
    31.3077% { opacity: 0.08; } 31.3846% { opacity: 0.7; } 31.5385% { opacity: 1; }
    52.0385% { opacity: 0.25; } 52.0769% { opacity: 1; }
    59.3846% { opacity: 0.25; } 59.5% { opacity: 1; } 59.5769% { opacity: 0.08; } 59.6154% { opacity: 1; }
    82.3077% { opacity: 0.4; } 82.3462% { opacity: 0.08; } 82.8846% { opacity: 0.55; } 82.9231% { opacity: 0.15; }
    82.9615% { opacity: 0.55; } 83% { opacity: 0.08; } 83.0385% { opacity: 1; } 83.0769% { opacity: 0.08; }
    83.1154% { opacity: 1; }
    100% { opacity: 1; }
}
@keyframes neon-flicker-b { /* 280 beats: blink, dropout, stutter, brownout, blink, stutter */
    0% { opacity: 1; }
    11.3187% { opacity: 0.25; } 11.3462% { opacity: 1; }
    18.6538% { opacity: 0.4; } 18.7088% { opacity: 0.08; } 19.2582% { opacity: 1; } 19.2857% { opacity: 0.15; }
    19.3681% { opacity: 1; } 19.3956% { opacity: 0.15; } 19.478% { opacity: 0.55; } 19.5055% { opacity: 0.08; }
    19.5604% { opacity: 0.55; } 19.5879% { opacity: 0.15; } 19.6703% { opacity: 1; }
    34.0659% { opacity: 0.25; } 34.1209% { opacity: 1; } 34.1484% { opacity: 0.25; } 34.1758% { opacity: 1; }
    34.2308% { opacity: 0.15; } 34.2582% { opacity: 1; } 34.2857% { opacity: 0.15; } 34.3407% { opacity: 1; }
    34.3681% { opacity: 0.08; } 34.4505% { opacity: 1; }
    53.8187% { opacity: 0.15; } 53.8736% { opacity: 0.4; } 54.0934% { opacity: 0.08; } 54.1484% { opacity: 0.4; }
    54.2582% { opacity: 0.08; } 54.3132% { opacity: 0.55; } 54.4231% { opacity: 0.15; } 54.478% { opacity: 0.7; }
    54.5604% { opacity: 1; }
    71.7308% { opacity: 0.25; } 71.7857% { opacity: 1; }
    84.4231% { opacity: 0.15; } 84.478% { opacity: 1; } 84.5055% { opacity: 0.08; } 84.5879% { opacity: 1; }
    100% { opacity: 1; }
}
@keyframes neon-flicker-c { /* 350 beats: stutter, blink, brownout, stutter, dropout, blink, stutter */
    0% { opacity: 1; }
    5.4286% { opacity: 0.08; } 5.4725% { opacity: 1; } 5.5385% { opacity: 0.15; } 5.5604% { opacity: 1; }
    5.6044% { opacity: 0.08; } 5.6484% { opacity: 1; }
    22.1538% { opacity: 0.25; } 22.1978% { opacity: 1; }
    28.0879% { opacity: 0.15; } 28.1099% { opacity: 0.4; } 28.3077% { opacity: 0.15; } 28.3516% { opacity: 0.25; }
    28.4615% { opacity: 0.08; } 28.4835% { opacity: 0.25; } 28.5934% { opacity: 0.08; } 28.6154% { opacity: 0.7; }
    28.6813% { opacity: 1; }
    46.7692% { opacity: 0.15; } 46.8132% { opacity: 1; } 46.8352% { opacity: 0.15; } 46.8571% { opacity: 1; }
    46.9231% { opacity: 0.25; } 46.967% { opacity: 1; }
    63.2527% { opacity: 0.4; } 63.2747% { opacity: 0.08; } 63.7363% { opacity: 0.55; } 63.7582% { opacity: 0.15; }
    63.8462% { opacity: 1; } 63.8681% { opacity: 0.15; } 63.956% { opacity: 0.55; } 63.978% { opacity: 0.15; }
    64.0659% { opacity: 0.55; } 64.0879% { opacity: 0.08; } 64.1319% { opacity: 1; }
    76.6374% { opacity: 0.08; } 76.6813% { opacity: 1; }
    85.7363% { opacity: 0.08; } 85.8022% { opacity: 1; } 85.8242% { opacity: 0.25; } 85.8462% { opacity: 1; }
    85.8681% { opacity: 0.08; } 85.9341% { opacity: 1; } 85.978% { opacity: 0.08; } 86.044% { opacity: 1; }
    100% { opacity: 1; }
}
@keyframes aurora {
    0%, 100% { opacity: 0.35; transform: translate3d(0, 0, 0) scale(1); }
    50% { opacity: 1; transform: translate3d(6%, 4%, 0) scale(1.15); }
}
@keyframes marquee { to { transform: translateX(-50%); } }
@keyframes bob { /* 8 bobs up and down, a beat each way */
    0%, 12.5%, 25%, 37.5%, 50%, 62.5%, 75%, 87.5%, 100% { transform: translateY(0) rotate(-2deg); }
    6.25%, 18.75%, 31.25%, 43.75%, 56.25%, 68.75%, 81.25%, 93.75% { transform: translateY(-6%) rotate(2deg); }
}
@keyframes wiggle { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-12deg); } 75% { transform: rotate(12deg); } }
@keyframes bark { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.18) rotate(-6deg); } }
@keyframes wag {
    0%, 100% { transform: rotate(0); }
    20% { transform: rotate(-14deg) scale(1.06); }
    45% { transform: rotate(11deg) scale(1.06); }
    70% { transform: rotate(-6deg); }
    88% { transform: rotate(3deg); }
}
@keyframes heart-float {
    0% { opacity: 0; transform: translate(0, 0) scale(0.5); }
    20% { opacity: 1; transform: translate(calc(var(--dx, 0px) * 0.3), -12px) scale(1.15); }
    100% { opacity: 0; transform: translate(var(--dx, 0px), -64px) scale(0.9); }
}
@keyframes bubble-pop {
    0% { opacity: 0; transform: translate(-50%, calc(var(--ty) + 6px)) scale(0.6); }
    12% { opacity: 1; transform: translate(-50%, calc(var(--ty) - 2px)) scale(1.06); }
    20%, 80% { opacity: 1; transform: translate(-50%, var(--ty)) scale(1); }
    100% { opacity: 0; transform: translate(-50%, calc(var(--ty) - 12px)) scale(1); }
}
@keyframes paw-rain {
    0% { opacity: 0; transform: translateY(0) rotate(var(--r, 0deg)); }
    10%, 85% { opacity: 1; }
    100% { opacity: 0; transform: translateY(calc(100vh + 80px)) rotate(calc(var(--r, 0deg) + 120deg)); }
}
@keyframes pup-spin {
    0% { transform: none; }
    50% { transform: translateY(-14%) rotate(180deg) scale(1.1); }
    100% { transform: rotate(360deg); }
}
@keyframes zoomies {
    0% { transform: translateX(-110px) rotate(10deg); }
    46% { transform: translateX(calc(100vw + 20px)) rotate(10deg); }
    54% { transform: translateX(calc(100vw + 20px)) rotate(-10deg); }
    100% { transform: translateX(-110px) rotate(-10deg); }
}
@keyframes zoomies-rtl {
    0% { transform: translateX(calc(100vw + 20px)) rotate(-10deg); }
    46% { transform: translateX(-110px) rotate(-10deg); }
    54% { transform: translateX(-110px) rotate(10deg); }
    100% { transform: translateX(calc(100vw + 20px)) rotate(10deg); }
}
@keyframes zoomies-wuff {
    0% { opacity: 0; transform: translate(-50%, calc(var(--ty) + 6px)) scale(0.6); }
    40%, 100% { opacity: 1; transform: translate(-50%, var(--ty)) scale(1); }
}
@keyframes zoomies-hop { to { transform: translateY(-14px); } }
@keyframes pup-zzz { /* 6 beats = 78 steps: fades in over 15, drifts off over 63 */
    0% { opacity: 0; transform: translate(0, 0) rotate(0deg); animation-timing-function: steps(15); }
    19.2308% { opacity: 1; transform: translate(2.69px, -3.85px) rotate(2.31deg); animation-timing-function: steps(63); }
    100% { opacity: 0; transform: translate(14px, -20px) rotate(12deg); }
}
@keyframes pup-stretch {
    0% { transform: rotate(-10deg) scale(1.03, 0.92); }
    35% { transform: rotate(4deg) scale(1.14, 0.86); }
    65% { transform: rotate(-3deg) scale(0.94, 1.1); }
    100% { transform: none; }
}
@keyframes eq { /* 8 times up and down, a beat each way */
    0%, 12.5%, 25%, 37.5%, 50%, 62.5%, 75%, 87.5%, 100% { transform: scaleY(0.25); }
    6.25%, 18.75%, 31.25%, 43.75%, 56.25%, 68.75%, 81.25%, 93.75% { transform: scaleY(1); }
}
@keyframes pulse { /* 8 pulses of 2 beats; each snaps back to small in a split millisecond */
    0%, 12.5%, 25%, 37.5%, 50%, 62.5%, 75%, 87.5% { transform: scale(1); opacity: 0.7; }
    12.499%, 24.999%, 37.499%, 49.999%, 62.499%, 74.999%, 87.499%, 100% { transform: scale(3.2); opacity: 0; }
}
@keyframes paw-fade {
    0% { opacity: 0; transform: scale(0.4) rotate(var(--r, 0deg)); }
    20% { opacity: 1; transform: scale(1.1) rotate(var(--r, 0deg)); }
    100% { opacity: 0; transform: scale(0.9) translateY(-10px) rotate(var(--r, 0deg)); }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important; scroll-behavior: auto !important;
    }
    .marquee__track,
    .marquee__item,
    .pet-bubble { animation: none !important; } /* the bubble just shows, then goes */
    .pup-zzz span { opacity: 1; animation: none !important; } /* the z's just sit there */
    .pup-zzz span:nth-child(2) { transform: translate(7px, -8px); }
    .pup-zzz span:nth-child(3) { transform: translate(15px, -17px); }
}

/* Button on Ghost's draft preview pages (post.hbs) to the social bridge's preview */
.social-preview-button {
    position: fixed; right: 16px; bottom: 16px; z-index: 1000; padding: 10px 16px; border-radius: 999px;
    background: var(--accent); color: var(--accent-ink); font: 700 14px/1 var(--font-body); text-decoration: none;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
}
.social-preview-button:hover,
.social-preview-button:focus-visible { filter: brightness(1.1); }

/* LIVE NOW bar (partials/live-bar.hbs): a pink strip at the top of the sticky header, shown while Puppi3 is streaming
   (main.js toggles [hidden]): LIVE NOW, the player, then the track playing when the stream sends it (long names are cut
   short with "…"). The dot pulses once every 2 beats, on the beat grid. */
.live-bar { background: var(--accent); color: var(--accent-ink); }
.live-bar__inner {
    position: relative;   /* the puppy's bubble hangs below it */
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; min-height: 48px; padding-block: 6px;
}
.live-bar__signal {
    display: inline-flex; align-items: center; gap: 8px; font: 700 13px/1 var(--font-mono); letter-spacing: 0.08em;
    text-transform: uppercase;
}
.live-bar__dot {
    width: 10px; height: 10px; border-radius: 50%; background: currentColor;
    animation: live-pulse calc(var(--beat) * 16) steps(13) infinite;
}
@keyframes live-pulse { /* 8 blinks of 2 beats */
    0%, 12.5%, 25%, 37.5%, 50%, 62.5%, 75%, 87.5%, 100% { opacity: 1; }
    6.25%, 18.75%, 31.25%, 43.75%, 56.25%, 68.75%, 81.25%, 93.75% { opacity: 0.25; }
}
/* The player comes before the track, so it stays put whether or not a track is sent */
.live-bar__track {
    flex: 1 1 0; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
    font: 600 14px/1.2 var(--font-body);
}
.live-bar__track[hidden] { display: none; }
/* The stream puppy (main.js, "Stream puppy"): sits still until play, sniffs about while the stream loads or buffers,
   bobs on the beat while it plays. Its bubble hangs below the whole bar (placed against .live-bar__inner, so on a
   phone, where the bar wraps, it doesn't cover the player). */
.live-bar__pup { flex: none; width: 34px; height: 34px; margin-block: -4px; }
.live-bar__pup svg {
    display: block; width: 100%; height: 100%; cursor: grab; transform-origin: 50% 85%;
    filter: drop-shadow(2px 2px 0 rgba(23, 13, 34, 0.5));
}
.live-bar__pup .pup-body { transform-origin: 50% 85%; }
.live-bar__pup[data-mood="playing"] svg { animation: bob calc(var(--beat) * 16) steps(13) infinite; }
.live-bar__pup[data-mood="loading"] .pup-body,
.live-bar__pup[data-mood="buffering"] .pup-body { animation: live-sniff calc(var(--beat) * 4) steps(52) infinite; }
.live-bar__pup[data-mood="paused"] svg { opacity: 0.85; }
.live-bar__pup[data-mood="paused"] .pup-body { transform: rotate(-8deg); }
/* Can't reach the stream: head down, sniffing slowly; its bubble goes pink so it reads as a problem */
.live-bar__pup[data-mood="trouble"] svg { opacity: 0.85; }
.live-bar__pup[data-mood="trouble"] .pup-body { animation: live-sniff-slow calc(var(--beat) * 8) steps(104) infinite; }
.live-bar__pup[data-mood="trouble"] .live-bar__say,
.live-bar__pup[data-mood="trouble"] .live-bar__say::before { background: var(--neon-1); }
/* 4 beats = 52 steps (trouble's slow copy: 8 beats = 104), split 10/13/13/16 */
@keyframes live-sniff {
    0% { transform: rotate(0); animation-timing-function: steps(10); }
    19.2308% { transform: rotate(-10deg) translateX(-6%); animation-timing-function: steps(13); }
    44.2308% { transform: rotate(9deg) translateX(6%); animation-timing-function: steps(13); }
    69.2308% { transform: rotate(-4deg); animation-timing-function: steps(16); }
    100% { transform: rotate(0); }
}
@keyframes live-sniff-slow {
    0% { transform: rotate(0); animation-timing-function: steps(20); }
    19.2308% { transform: rotate(-10deg) translateX(-6%); animation-timing-function: steps(26); }
    44.2308% { transform: rotate(9deg) translateX(6%); animation-timing-function: steps(26); }
    69.2308% { transform: rotate(-4deg); animation-timing-function: steps(32); }
    100% { transform: rotate(0); }
}
.live-bar__say {
    position: absolute; top: calc(100% + 10px); left: calc(var(--gutter) - 4px); z-index: 60; width: max-content;
    max-width: min(340px, calc(100vw - 32px)); padding: 6px 14px; border: 2px solid var(--accent-ink);
    border-radius: 16px; background: var(--biscuit); color: var(--accent-ink); box-shadow: 3px 3px 0 var(--accent-ink);
    font: 800 0.95rem/1.25 var(--font-display); pointer-events: none; animation: live-say-in 0.35s ease-out;
}
.live-bar__say::before {   /* the bubble's tail, pointing up at the puppy */
    content: "";
    position: absolute;
    top: -8px;
    left: 14px;
    width: 12px;
    height: 12px;
    border: solid var(--accent-ink);
    border-width: 2px 0 0 2px;
    background: var(--biscuit);
    transform: rotate(45deg);
}
.live-bar__say[hidden] { display: none; }
.live-bar__say.is-leaving { opacity: 0; transition: opacity 0.4s; }
@keyframes live-say-in {
    from { opacity: 0; transform: translateY(6px) scale(0.85); }
    to { opacity: 1; transform: none; }
}
/* Our own controls (the <audio> itself stays hidden): a round play/pause button, then a volume slider where there's a
   mouse (phones use their own buttons) */
.live-bar__player { display: none; }
.live-bar__controls { display: inline-flex; align-items: center; gap: 10px; }
.live-bar__play {
    display: grid; place-items: center; width: 36px; height: 36px; padding: 0; border: 0; border-radius: 50%;
    background: var(--accent-ink); color: var(--accent); cursor: pointer; transition: transform 0.15s;
}
.live-bar__play:hover { transform: scale(1.08); }
.live-bar__play:active { transform: scale(0.94); }
.live-bar__play:focus-visible { outline: 3px solid var(--accent-ink); outline-offset: 2px; }
.live-bar__play svg { width: 18px; height: 18px; }
.live-bar__icon-pause,
.live-bar[data-playing] .live-bar__icon-play { display: none; }
.live-bar[data-playing] .live-bar__icon-pause { display: block; }
.live-bar__volume { width: 96px; accent-color: var(--accent-ink); cursor: pointer; }
@media (hover: none), (pointer: coarse) { .live-bar__volume { display: none; } }
