/* ===== RESET ===== */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

/* ===== CSS VARIABLES — default (editorial) ===== */
:root {
    --bg:           #0d0d0d;
    --text:         #f0ece4;
    --muted:        #8f8f8f;
    --accent:       #d01359;
    --border:       #222;
    --card-bg:      #111;
    --font-display: 'Montserrat', sans-serif;
    --font-body:    'Montserrat', sans-serif;
    --font-mono:    'Montserrat', sans-serif;
    --hero-size:    clamp(4rem, 10vw, 9rem);
    --radius:       0px;
    --transition:   0.25s ease;
}

/* ===== SCRAPBOOK MODE ===== */
[data-mode="scrapbook"] {
    --bg:           #ede5d8;
    --text:         #1a0f00;
    --muted:        #7a6040;
    --accent:       #d01359;
    --border:       #1a0f00;
    --card-bg:      #f5eed8;
    --radius:       2px;
}

body[data-mode="scrapbook"] {
    background: #ffffff;
}

/* ===== ACCESSIBLE MODE ===== */
[data-mode="accessible"] {
    --bg:           #ffffff;
    --text:         #111111;
    --muted:        #555555;
    --accent:       #d01359;
    --border:       #e0e0e0;
    --card-bg:      #f7f7f7;
    --font-display: 'Montserrat', sans-serif;
    --font-body:    'Montserrat', sans-serif;
    --radius:       6px;
}

/* ===== BASE ===== */
html { scroll-behavior: smooth; }

body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    overflow-x: hidden;
    transition: background var(--transition), color var(--transition);
}

/* ===== MODE SWITCHER =====
   Styled to match Flo's own speech-bubble chips (.helper-chip /
   .helper-bubble-actions below) instead of its own separate joined pill
   bar — a plain row of independently-bordered pill buttons, so it reads
   as the same kind of control as the helper widget elsewhere on the
   page. Built on the same custom properties .helper-chip uses, so
   scrapbook/accessible fall out correctly with no per-mode overrides
   here — only editorial needs one, mirroring .helper-chip's own pixel
   treatment below. */
.mode-switcher {
    display: flex;
    gap: 0.4rem;
    z-index: 300;
}

.mode-btn {
    background: none;
    border: 1px solid var(--border);
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.05em;
    padding: 0.3rem 0.6rem;
    border-radius: 99px;
    cursor: pointer;
    transition: color var(--transition), border-color var(--transition), background var(--transition);
    white-space: nowrap;
}

.mode-btn:hover { color: var(--text); border-color: var(--text); }

.mode-btn.active {
    background: var(--text);
    color: var(--bg);
    border-color: var(--text);
}

/* ===== HERO ===== */
.hero {
    position: relative;
    min-height: 100vh;
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--border);
    transition: border-color var(--transition);
    overflow: hidden;
}

#hero-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: none;
    z-index: 0;
}

[data-mode="editorial"] #hero-canvas { display: block; }

.hero-content {
    padding: 0 0 0 10vw;
    max-width: 80vw;
    position: relative;
    z-index: 1;
}

.hero-kicker {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.4em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 1rem;
}

.hero-title {
    font-family: var(--font-display);
    font-size: var(--hero-size);
    font-weight: 700;
    line-height: 0.95;
    text-transform: uppercase;
    letter-spacing: -0.03em;
}

.hero-subtitle {
    margin-top: 2rem;
    font-size: 1rem;
    line-height: 1.6;
    color: var(--muted);
    max-width: 36ch;
}

.hero-scroll-hint {
    position: absolute;
    bottom: 2rem;
    left: 10vw;
    font-family: var(--font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    color: var(--muted);
}

/* Editorial — hero gets a red underline on title */
[data-mode="editorial"] .hero-title {
    -webkit-text-stroke: 1px var(--text);
}

[data-mode="editorial"] .hero::after {
    content: '';
    position: absolute;
    left: 10vw;
    bottom: 0;
    width: 60vw;
    height: 3px;
    background: var(--accent);
}

/* Scrapbook — slightly rotated, warmer */
[data-mode="scrapbook"] .hero-content {
    position: relative;
}

[data-mode="scrapbook"] .hero-title {
    font-weight: 400;
    letter-spacing: -0.01em;
    position: relative;
    display: inline-block;
}

[data-mode="scrapbook"] .hero-title::after {
    content: '';
    position: absolute;
    bottom: -4px;
    left: 0;
    width: 100%;
    height: 2px;
    background: var(--accent);
    transform: rotate(-0.3deg);
}

[data-mode="scrapbook"] .hero-kicker {
    font-family: var(--font-mono);
    transform: rotate(-1deg);
    display: inline-block;
}

/* Easy — large, readable, no decoration */
[data-mode="accessible"] .hero-title {
    font-size: clamp(3rem, 7vw, 6rem);
    letter-spacing: -0.02em;
    font-weight: 700;
}

[data-mode="accessible"] .hero-subtitle {
    font-size: 1.1rem;
    color: var(--muted);
}

/* ===== SIDE NAV ===== */
.side-nav {
    position: fixed;
    right: 0;
    top: 0;
    height: 100vh;
    width: 200px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    z-index: 100;
    padding: 2rem;
}

.side-nav-menu { list-style: none; text-align: right; }

.side-nav-menu li { margin: 1rem 0; }

.side-nav-menu a {
    color: var(--muted);
    text-decoration: none;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    transition: color 0.2s;
}

.side-nav-menu a:hover,
.side-nav-menu a.active { color: var(--text); }

/* Scrapbook nav */
[data-mode="scrapbook"] .side-nav-menu a {
    font-family: var(--font-mono);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* Easy nav */
[data-mode="accessible"] .side-nav-menu a {
    font-family: var(--font-body);
    font-size: 0.85rem;
    letter-spacing: 0;
    text-transform: none;
}

/* ===== ABOUT ===== */
.about {
    min-height: 100vh;
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--border);
    padding: 6rem 10vw;
    transition: border-color var(--transition);
}

.about-content-full { max-width: 820px; }

.about-content-full p {
    font-size: clamp(1.4rem, 3vw, 2.2rem);
    line-height: 1.55;
    margin-bottom: 1.8rem;
}

/* Editorial — bold drop cap feel */
[data-mode="editorial"] .about-content-full p:first-child::first-letter {
    font-size: 4.5em;
    font-weight: 700;
    float: left;
    line-height: 0.75;
    margin: 0.1em 0.08em 0 0;
    color: var(--accent);
}

/* Scrapbook — smaller, messier */
[data-mode="scrapbook"] .about-content-full p {
    font-size: clamp(1.1rem, 2.2vw, 1.7rem);
    font-family: var(--font-mono);
    line-height: 1.7;
}

/* Easy — clean sans-serif, larger line height */
[data-mode="accessible"] .about-content-full p {
    font-size: clamp(1.1rem, 2vw, 1.5rem);
    line-height: 1.7;
}

/* ===== HOVER EFFECTS ===== */
.hover-bold { transition: font-weight 0.1s; cursor: default; }
.hover-bold:hover { font-weight: 700; }

.hover-shake { display: inline-block; cursor: default; }
.hover-shake:hover { animation: shake 0.3s; }
@keyframes shake {
    0%,100% { transform: translateX(0); }
    25% { transform: translateX(-4px); }
    75% { transform: translateX(4px); }
}

.hover-glitch { cursor: default; transition: color 0.1s; }
.hover-glitch:hover { color: var(--accent); text-shadow: 2px 0 red, -2px 0 cyan; }

.hover-scale { display: inline-block; transition: transform 0.2s; cursor: default; }
.hover-scale:hover { transform: scale(1.1); }

.hover-spin { display: inline-block; transition: transform 0.4s; cursor: default; }
.hover-spin:hover { transform: rotate(5deg); }

.hover-wave { display: inline-block; cursor: default; }
.hover-wave:hover { animation: wave 0.5s ease; }
@keyframes wave {
    0%,100% { transform: translateY(0); }
    25% { transform: translateY(-4px); }
    75% { transform: translateY(4px); }
}

.hover-blur { transition: filter 0.2s; cursor: default; }
.hover-blur:hover { filter: blur(2px); }

/* ===== ARCHIVE ===== */
.archive {
    min-height: 100vh;
    border-bottom: 1px solid var(--border);
    padding: 6rem 10vw;
    transition: border-color var(--transition);
}

.container { max-width: 900px; }

.section-title {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.4em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 4rem;
    border-bottom: 1px solid var(--border);
    padding-bottom: 1rem;
}

[data-mode="accessible"] .section-title {
    font-family: var(--font-body);
    font-size: 0.85rem;
    letter-spacing: 0.1em;
    font-weight: 600;
}

.archive-list {
    display: flex;
    flex-direction: column;
}

.archive-empty {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    color: var(--muted);
    letter-spacing: 0.1em;
}

/* Archive row — default */
.archive-row {
    display: grid;
    grid-template-columns: 70px 1fr;
    gap: 2rem;
    padding: 1.8rem 0;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
    transition: background var(--transition), padding-left var(--transition);
}

.archive-row:hover { background: var(--card-bg); padding-left: 0.8rem; }

.archive-year {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--muted);
    padding-top: 0.3rem;
}

.archive-title {
    font-size: 1.5rem;
    font-weight: 400;
    margin-bottom: 0.4rem;
    font-family: var(--font-display);
}

.archive-desc {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--muted);
}

/* Editorial archive — big titles, strong hover */
[data-mode="editorial"] .archive-title {
    font-size: 1.8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: -0.02em;
}

[data-mode="editorial"] .archive-row:hover .archive-title {
    color: var(--accent);
}

/* Scrapbook archive — index card feel */
[data-mode="scrapbook"] .archive-row {
    border-bottom: 1px dashed var(--border);
    padding: 1.5rem 0.5rem;
    position: relative;
}

[data-mode="scrapbook"] .archive-row::before {
    content: '—';
    position: absolute;
    left: -1rem;
    color: var(--muted);
    opacity: 0;
    transition: opacity 0.2s;
}

[data-mode="scrapbook"] .archive-row:hover::before { opacity: 1; }

[data-mode="scrapbook"] .archive-title {
    font-family: var(--font-mono);
    font-size: 1.1rem;
}

/* Easy archive — card layout */
[data-mode="accessible"] .archive-list {
    gap: 0.75rem;
}

[data-mode="accessible"] .archive-row {
    border: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.2rem 1.5rem;
    background: var(--card-bg);
}

[data-mode="accessible"] .archive-row:hover {
    border-color: var(--accent);
    padding-left: 1.5rem;
    background: var(--card-bg);
}

[data-mode="accessible"] .archive-title {
    font-size: 1.1rem;
    font-weight: 600;
}

[data-mode="accessible"] .archive-year {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--accent);
}

/* ===== CONTACT ===== */
.contact {
    min-height: 60vh;
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--border);
    padding: 6rem 10vw;
    transition: border-color var(--transition);
}

.contact .container { text-align: left; }

.contact-text {
    font-size: 1rem;
    color: var(--muted);
    margin-bottom: 3rem;
    max-width: 40ch;
    line-height: 1.6;
}

.social-links { display: flex; gap: 1rem; flex-wrap: wrap; }

.social-btn {
    display: inline-block;
    padding: 0.75rem 2rem;
    border: 1px solid var(--border);
    color: var(--text);
    text-decoration: none;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    border-radius: var(--radius);
    transition: border-color 0.2s, background 0.2s, color 0.2s;
}

.social-btn:hover {
    background: var(--text);
    color: var(--bg);
    border-color: var(--text);
}

[data-mode="accessible"] .social-btn {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
    font-family: var(--font-body);
    text-transform: none;
    letter-spacing: 0;
    font-size: 0.9rem;
}

[data-mode="accessible"] .social-btn:hover {
    opacity: 0.85;
    background: var(--accent);
    color: #fff;
}

/* ===== FOOTER ===== */
.footer {
    padding: 3rem 10vw;
    border-top: 1px solid var(--border);
}

.footer p {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    color: var(--muted);
    letter-spacing: 0.1em;
    margin-bottom: 0.4rem;
}

.footer-tagline { opacity: 0.5; }

/* ===== MOBILE NAV ===== */
.mobile-menu-btn {
    display: none;
    position: fixed;
    top: 1.2rem;
    right: 1.5rem;
    z-index: 200;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--text);
    font-family: var(--font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    padding: 0.5rem 1rem;
    cursor: pointer;
    border-radius: 99px;
}

.mobile-nav {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--bg);
    z-index: 250;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.mobile-nav.open { display: flex; }

.mobile-nav ul { list-style: none; text-align: center; }

.mobile-nav ul li { margin: 1.5rem 0; }

.mobile-nav ul a {
    color: var(--text);
    text-decoration: none;
    font-family: var(--font-mono);
    font-size: 1rem;
    letter-spacing: 0.3em;
    text-transform: uppercase;
}

.mobile-nav-close {
    position: absolute;
    top: 1.5rem;
    right: 1.5rem;
    background: none;
    border: none;
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    cursor: pointer;
}

/* ===== RESPONSIVE (legacy single-page) ===== */
@media (max-width: 768px) {
    .side-nav { display: none; }
    .mobile-menu-btn { display: block; }
    .hero-content { padding: 0 6vw; max-width: 100%; }
    .about { padding: 5rem 6vw; }
    .archive { padding: 5rem 6vw; }
    .contact { padding: 5rem 6vw; }
    .footer { padding: 2rem 6vw; }
}

/* ============================================================ */
/* ==================== MULTI-PAGE REDESIGN =================== */
/* ============================================================ */

/* Mode switcher buttons are now <a> links */
a.mode-btn {
    text-decoration: none;
    display: inline-block;
    line-height: 1.4;
}

/* ===== PAGE TOP BAR (content pages) ===== */
.page-topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.5rem;
    z-index: 300;
    pointer-events: none;
}

.page-topbar > * { pointer-events: auto; }

/* Centred on the topbar independently of the logo — .page-topbar's own
   fixed positioning already gives this an absolute containing block, so
   this doesn't need a position:relative wrapper of its own. */
.page-topbar .mode-switcher {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

.home-link {
    display: flex;
    align-items: center;
    text-decoration: none;
    transition: transform 0.2s ease;
}

.home-link:hover { transform: translateY(-1px); }

.home-logo {
    display: block;
    height: 90px;
    width: auto;
}

/* ===== LANDING PAGE ===== */
/* Pink paper border, white centre panel. Texture served from Cloudflare R2.
   Brand colours: #d01359 (pink) and white. */
body.landing {
    min-height: 100vh;
    background-color: #d01359;
    background-image: url('https://media.downtownpompey.online/Pink-Texture.jpg');
    background-size: cover;
    background-position: center;
    background-attachment: fixed;
    padding: clamp(1.2rem, 3.5vw, 3rem);
}

.landing-panel {
    background: #ffffff;
    color: #1a1a1a;
    min-height: calc(100vh - 2 * clamp(1.2rem, 3.5vw, 3rem));
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2.6rem;
    padding: 3rem clamp(1.5rem, 5vw, 4rem);
    box-shadow: 0 12px 40px rgba(60, 20, 20, 0.3);
}

.landing-header { text-align: center; }

.landing-logo {
    max-width: min(280px, 65vw);
    height: auto;
    display: block;
    margin: 0 auto 1.4rem;
}

.landing-title {
    font-family: var(--font-display);
    font-size: clamp(1.1rem, 2.2vw, 1.6rem);
    font-weight: 700;
    letter-spacing: -0.01em;
    color: #1a1a1a;
}

.landing-nav {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
    align-items: start;
    width: 100%;
    max-width: 620px;
    margin: 0 auto;
}

.landing-btn {
    position: relative;
    display: block;
    text-decoration: none;
    color: #1a1a1a;
    overflow: hidden;
    box-shadow: 3px 3px 0 rgba(26, 26, 26, 0.15);
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

/* No real preview media yet on any of the three — a fixed-height box with a
   flat background-colour fallback stands in until each gets a real image. */
.landing-btn--placeholder {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 150px;
}

/* Editorial's placeholder is dark (echoing its own dark theme) rather than
   light like Scrapbook/Accessible's — the label needs light text here, or
   it's invisible against the base rule's dark #1a1a1a. */
.landing-btn--dark { color: #f0ece4; }

/* The whole button scales on hover now, not the image inside a fixed box —
   scaling the image alone either cropped it against the button's own
   overflow:hidden, or left it visibly floating past the button's edges. */
.landing-btn:hover {
    transform: translateY(-4px) scale(1.04);
    box-shadow: 6px 6px 0 rgba(26, 26, 26, 0.15);
}

.landing-btn-preview {
    position: absolute;
    inset: 0;
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
}

.landing-btn-label {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.9rem 0.8rem;
    text-align: center;
}

.landing-btn-name {
    font-family: var(--font-display);
    font-size: clamp(1.05rem, 1.8vw, 1.4rem);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: -0.01em;
    transition: color 0.2s;
}

.landing-btn:hover .landing-btn-name { color: #d01359; }

.process-link {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    letter-spacing: 0.15em;
    color: #555;
    text-decoration: underline;
    text-underline-offset: 4px;
    transition: color 0.2s;
}

.process-link:hover { color: #d01359; }

.landing-footer { width: 100%; max-width: 620px; }

.logo-strip {
    display: flex;
    gap: 1.5rem;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
}

.logo-placeholder {
    width: 110px;
    height: 44px;
    border: 1px dashed #bbb;
    position: relative;
}

.logo-placeholder::after {
    content: 'logo';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: 0.55rem;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    color: #bbb;
}

/* ===== SITE HELPER ===== */
/* Flo sits in the bottom-right corner at ~1/6 of the viewport height —
   a torso-up figure (placeholder SVG until the final PNG is supplied, see
   ARCHIE_IMAGE_URL in helper.js). The bubble stacks above it in the same
   fixed-position flex column, so it repositions itself automatically if
   the figure's size changes. */
.helper-widget {
    position: fixed;
    bottom: 0;
    right: 1.4rem;
    z-index: 500;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.7rem;
    pointer-events: none;
}

.helper-widget > * { pointer-events: auto; }

.helper-figure-btn {
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    line-height: 0;
    cursor: pointer;
}

.helper-figure-img {
    display: block;
    height: 25vh;
    min-height: 195px;
    max-height: 360px;
    width: auto;
    filter: drop-shadow(0 10px 16px rgba(0, 0, 0, 0.35));
}

.helper-bubble {
    position: relative;
    align-self: flex-end;
    width: min(220px, calc(100vw - 2.8rem));
    background: var(--card-bg);
    border: 1px solid var(--border);
    color: var(--text);
    border-radius: 14px;
    padding: 1rem 1.1rem;
    margin-bottom: 0.3rem;
    font-family: var(--font-mono);
    font-size: 0.78rem;
    line-height: 1.55;
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    pointer-events: none;
    transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s;
}

.helper-bubble.open {
    opacity: 1;
    visibility: visible;
    transform: none;
    pointer-events: auto;
}

/* Speech-bubble tail, pointing down toward Flo's head */
.helper-bubble::after {
    content: '';
    position: absolute;
    bottom: -8px;
    right: 34px;
    width: 16px;
    height: 16px;
    background: var(--card-bg);
    border-right: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    transform: rotate(45deg);
}

/* Scrapbook mode — a real photographed torn-paper speech bubble
   (images/torn-paper-bubble.png, a 600x600 canvas: a wide torn oval with
   its tail already baked in, plenty of transparent margin for the drop
   shadow) instead of the plain rounded bubble used elsewhere.

   Third attempt at getting this right, after two approaches that each
   traded one problem for another:
     1. Box grew with content, image stretched via background-size:100%
        100% — long tips elongated the tail until text spilled off the
        visible paper entirely.
     2. Box locked to a size tier picked from tip length (bigger tiers for
        longer tips), narrowed to 3:4 via background-size:cover — fixed
        the spilling, but introduced three new problems: the crop read as
        a visibly flat-cut edge against the otherwise organic tear, short
        tips left a large dead gap between the text and the buttons (the
        text area was flex-grow:1, stretching to fill the tier's full
        height regardless of how little text there was), and the largest
        tiers (up to 540px) could cover most of a phone screen when
        Flo auto-opened with a long tip.

   This version: ONE fixed size, always — aspect-ratio:1 + background-
   size:contain shows the complete, undistorted, un-cropped photo at
   every viewport (no more flat-cut edges). justify-content:center on the
   safe-text-zone column means the name+text+buttons group centers as a
   compact block when text is short (no dead gap — the whole block just
   takes up less room and sits centered), and gracefully falls back to
   top-aligned-with-internal-scroll if a tip is ever long enough to fill
   the available space (.helper-bubble-text is flex-shrink:1, not
   flex-grow — it only shrinks to make room, never stretches to fill it).
   A single fixed size, capped by the same viewport-relative formula as
   before, also means it can never balloon to dominate a phone screen the
   way the old size-tier system could. */
[data-mode="scrapbook"] .helper-bubble {
    aspect-ratio: 1 / 1;
    width: min(300px, calc(100vw - 2.8rem));
    height: auto;
    background-color: transparent;
    background-image: url('images/torn-paper-bubble.png');
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
    border: none;
    border-radius: 0;
    box-shadow: none;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 24% 20% 42%;
    box-sizing: border-box;
    /* Without this, a flex column's content can force the box taller than
       its aspect-ratio (the ratio is only a preferred size, not a cap) —
       which would grow the box past 1:1 and force the browser to stretch
       the background image to keep covering it. Clipping here instead
       makes the square genuinely fixed, so the text flex child (below)
       is what absorbs any rare overflow via its own scroll, never the
       image. */
    overflow: hidden;
}

[data-mode="scrapbook"] .helper-bubble-name {
    flex: 0 0 auto;
}

[data-mode="scrapbook"] .helper-bubble-text {
    /* flex-shrink (not flex-grow) — a short tip stays its natural compact
       size and the block above centers as a whole; a tip long enough to
       fill the safe zone shrinks to fit instead of pushing the block
       taller than its container, with overflow-y as the rare fallback. */
    flex: 0 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}

[data-mode="scrapbook"] .helper-bubble-actions {
    flex: 0 0 auto;
    margin-top: 0.9rem;
}

[data-mode="scrapbook"] .helper-bubble::after {
    display: none;
}

.helper-bubble-name {
    font-size: 0.6rem;
    letter-spacing: 0.25em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 0.5rem;
}

.helper-bubble-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.9rem;
}

.helper-chip {
    background: none;
    border: 1px solid var(--border);
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.05em;
    padding: 0.3rem 0.6rem;
    border-radius: 99px;
    cursor: pointer;
    white-space: nowrap;
    transition: color 0.2s, border-color 0.2s;
}

.helper-chip:hover {
    color: var(--text);
    border-color: var(--text);
}

/* Editorial — pixel/retro treatment matching the 3D room's own low-poly,
   N64-style render (three-scene.js's RETRO_RENDER_SCALE). Press Start 2P
   is a real 8-bit bitmap font, so it needs real headroom vs Montserrat —
   it reads much wider and taller per character at the same rem value. */
[data-mode="editorial"] .helper-bubble {
    border-radius: 0;
    border: 3px solid var(--text);
    box-shadow: 6px 6px 0 rgba(0, 0, 0, 0.7);
}

[data-mode="editorial"] .helper-bubble::after {
    border-right-width: 3px;
    border-bottom-width: 3px;
}

[data-mode="editorial"] .helper-bubble-name,
[data-mode="editorial"] .helper-bubble-text,
[data-mode="editorial"] .helper-chip {
    font-family: 'Press Start 2P', var(--font-mono);
}

[data-mode="editorial"] .helper-bubble-name {
    font-size: 0.5rem;
    letter-spacing: 0.1em;
}

[data-mode="editorial"] .helper-bubble-text {
    font-size: 0.62rem;
    line-height: 1.8;
}

[data-mode="editorial"] .helper-chip {
    font-size: 0.5rem;
    border-radius: 0;
    border: 2px solid var(--border);
    padding: 0.5rem 0.6rem;
    letter-spacing: 0.03em;
}

[data-mode="editorial"] .helper-chip:hover {
    background: var(--text);
    color: var(--bg);
    border-color: var(--text);
}

/* Applied via helper.js (a class, not a page selector — see FLO_IMAGES
   there) to any page whose Flo widget has real photos instead of the
   placeholder SVG. Editorial's are landscape (~3:2, waist-up with
   gesturing arms) where the placeholder .helper-figure-img everywhere
   else is a tall, narrow SVG figure — the base rule's fixed height:25vh
   + width:auto would make a photo like this render ~500px wide at the
   max-height end, easily wide enough to overlap the bubble or run off a
   narrow viewport. height:auto plus a max-width cap (instead of a fixed
   height) lets the browser scale the whole image to fit inside both
   bounds at once, whichever is tighter, same idea as a standard
   responsive img — no distortion, no overflow. These exact numbers were
   tuned for editorial's photos specifically — if another page's turn
   out to need different sizing, override with a
   `[data-page="x"].helper-figure-img--photo` rule rather than changing
   this shared default. */
.helper-figure-img--photo {
    height: auto;
    min-height: 0;
    max-height: 369px;
    max-width: 307px;
    /* Flush against the right edge (no overflow past it, unlike the
       previous 20%-off-screen treatment) — this cancels out
       .helper-widget's own right:1.4rem offset exactly, so the image's
       own right edge lands right on the viewport edge. Flush against the
       bottom needs no equivalent rule: .helper-widget already sits at
       bottom:0 with display:block on the image (no inline-baseline gap
       to cancel there). */
    transform: translateX(1.4rem);
}

/* Mode switcher gets the exact same pixel-chip treatment as .helper-chip
   above, so it reads as the same control in this room. */
[data-mode="editorial"] .mode-btn {
    font-family: 'Press Start 2P', var(--font-mono);
    font-size: 0.5rem;
    border-radius: 0;
    border: 2px solid var(--border);
    padding: 0.5rem 0.6rem;
    letter-spacing: 0.03em;
}

[data-mode="editorial"] .mode-btn:hover {
    background: var(--text);
    color: var(--bg);
    border-color: var(--text);
}

/* On narrow screens Flo's full-height figure sits over interactive
   content underneath (e.g. filter chips) whenever the bubble is open —
   shrink the figure so the widget takes less of the viewport. */
@media (max-width: 480px) {
    .helper-figure-img {
        height: 14vh;
        min-height: 110px;
        max-height: 160px;
    }
    .helper-figure-img--photo {
        height: auto;
        min-height: 0;
        max-height: 164px;
        max-width: 143px;
    }
    .helper-bubble {
        width: min(180px, calc(100vw - 5.5rem));
        padding: 0.75rem 0.85rem;
        font-size: 0.7rem;
    }
}

/* Short viewports (landscape phones) — Flo's normal 195px min-height
   figure eats over half of a ~375px-tall screen regardless of width, which
   no reasonable amount of page-content padding can reliably out-pad (see
   process.html's .shell-main below, which needs both this AND its own
   padding bump). Keyed on height, not width, so this also covers portrait
   phones with an unusually short viewport (address bar expanded, etc). */
@media (max-height: 480px) {
    .helper-figure-img {
        height: 20vh;
        min-height: 90px;
        max-height: 140px;
    }
    .helper-figure-img--photo {
        height: auto;
        min-height: 0;
        max-height: 143px;
        max-width: 123px;
    }
}

/* ===== SCRAPBOOK ARCHIVE PAGE ===== */
/* ===== FILTER BAR =====
   Always visible (no click needed to reveal filters) — but solid/opaque
   instead of transparent+blurred. The transparency was the actual problem:
   moving tiles showing through the bar read as noisy/messy, not the fact
   that it was always on screen. Solid var(--bg) also means the centred
   .grid-status "0 results" message (rendered behind this bar when the bar
   overlaps the viewport centre) can never look like it's just missing. */
/* ===== FILTER CARD =====
   A neither-transparent-bar-nor-click-to-reveal-panel: styled and sized like
   the media tiles themselves (same border/background/radius as
   .pan-tile-inner) and fixed dead-centre, so it reads as "one of the boxes"
   that just happens to hold the controls rather than as a separate strip
   of app chrome laid over the canvas. Always visible, no interaction
   needed to reveal it. */
/* ===== FILTER BAR (bottom) =====
   A thin, always-visible, fully opaque strip anchored to the bottom of the
   screen instead of the top — the top edge is already busy with the site's
   own logo/nav, but the bottom was empty, and a bottom bar needs none of
   the ~8rem clearance padding a top bar needed to duck under that nav, so
   it can stay genuinely thin. Right edge stops short of Flo's corner
   widget rather than running full-bleed underneath it. */
/* Same pink paper texture the whole page used to have — now confined to
   just this strip, since the page background itself is plain white. */
.filter-bar-bottom {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 200;
    padding: 0.72rem 1.44rem 0.84rem;
    padding-right: clamp(1.2rem, 22vw, 260px);
    background-color: #ede5d8;
    background-image: url('textures/paper-pink.jpg');
    background-size: cover;
    background-position: center;
    background-blend-mode: multiply;
    border-top: 1px solid var(--border);
}

.tag-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.48rem;
    padding: 0.24rem 0 0.6rem;
}

.tag-pill {
    flex-shrink: 0;
    background: #ffffff;
    border: 1px solid var(--accent);
    border-radius: 999px;
    padding: 0.384rem 1.02rem;
    font-family: var(--font-mono);
    font-size: 0.816rem;
    color: var(--accent);
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.tag-pill:hover { background: rgba(208, 19, 89, 0.1); }

.tag-pill.active {
    background: var(--accent);
    color: #ffffff;
    border-color: var(--accent);
}

/* Sits as the first item in the tag row — the actual way keyboard/screen-
   reader users reach every item, since pan-canvas tiles are deliberately
   unfocusable (see .pan-canvas[aria-hidden] in the HTML). Solid/bold
   rather than another outline pill so it doesn't read as just another
   filter. Resets the base .room-items-toggle rule's fixed positioning,
   which is for its other use as a floating overlay on editorial.html. */
.tag-bar .room-items-toggle {
    position: relative;
    top: auto;
    left: auto;
}

.tag-bar .room-items-toggle summary {
    display: inline-block;
    background: var(--accent);
    color: #ffffff;
    border: 1px solid #ffffff;
    border-radius: 999px;
    padding: 0.384rem 1.02rem;
    font-size: 0.816rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: none;
}

.tag-bar .room-items-toggle[open] summary { margin-bottom: 0; }

/* position:fixed (not absolute) and placed via JS (see scrapbook.js's
   'toggle' listener) rather than a CSS bottom:100% anchor — .tag-bar
   needs overflow-x:auto on mobile to let 46 tags scroll sideways, which
   (per the CSS overflow spec) forces overflow-y to auto too, silently
   clipping any absolutely-positioned popup that tries to extend above it. */
.tag-bar .room-items-toggle ul {
    position: fixed;
    max-width: calc(100vw - 2rem);
    width: max(240px, 40vw);
    max-height: 50vh;
    overflow-y: auto;
    background: var(--card-bg);
    border-color: var(--border);
}

.tag-bar .room-items-toggle button:hover,
.tag-bar .room-items-toggle button:focus-visible {
    background: rgba(0, 0, 0, 0.06);
}

.filter-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem 1rem;
    font-family: var(--font-mono);
    font-size: 0.65rem;
    color: var(--muted);
    letter-spacing: 0.1em;
    padding-top: 0.3rem;
}

.clear-filters {
    background: none;
    border: none;
    color: var(--accent);
    font-family: var(--font-mono);
    font-size: 0.65rem;
    letter-spacing: 0.1em;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
    display: none;
}

.clear-filters.visible { display: inline; }

/* ===== PAN CANVAS ===== */
.pan-canvas {
    position: fixed;
    inset: 0;
    z-index: 10;                 /* behind .filter-bar-bottom(200) / .page-topbar(300) */
    overflow: hidden;
    touch-action: none;
    user-select: none;
    cursor: grab;
    /* The "page" the tiles sit on — repeats infinitely and pans in lockstep
       with them (pan-canvas.js writes background-position every frame from
       the same renderPanX/Y the tiles use), rather than sitting fixed
       behind a moving foreground. */
    background-image: url('textures/paper-white.jpg');
    background-repeat: repeat;
}

.pan-canvas.is-dragging { cursor: grabbing; }

/* Outer: raw JS transform every frame — no transition here, or per-frame
   writes fight the transition system and rubber-band instead of tracking
   smoothly. width/height are the exception: pan-canvas.js only changes
   those once per tile (the instant a photo/video's real aspect ratio
   becomes known — see makeTile), not every frame, so a transition here has
   nothing to fight and just smooths that one resize instead of a hard pop. */
.pan-tile {
    position: absolute;
    top: 0;
    left: 0;
    will-change: transform;
    transition: width 0.3s ease, height 0.3s ease;
}

/* Inner: CSS-transitioned scale/opacity, fully decoupled from the outer
   element's raw positioning. No background — the tile's own box now
   matches its media's real aspect ratio (see pan-canvas.js), so there's no
   letterbox gap left for a fill colour to show through. */
.pan-tile-inner {
    width: 100%;
    height: 100%;
    border-radius: var(--radius);
    overflow: hidden;
    opacity: 0;
    transform: scale(0.92);
    transition: opacity 0.4s ease, transform 0.4s ease;
    cursor: pointer;
}

.pan-tile-inner.tile-in { opacity: 1; transform: scale(1); }
.pan-tile-inner.tile-fading { opacity: 0; transform: scale(0.9); }
.pan-tile-inner.tile-active { opacity: 1; transform: scale(1.04); z-index: 2; }

.pan-tile-inner img,
.pan-tile-inner video {
    width: 100%;
    height: 100%;
    /* contain, not cover — the tile's own box is still slot-shaped (see
       pan-canvas.js's ratioForSlot, kept for layout stability across
       recycling), but the photo itself now shows its real proportions
       inside that box rather than being cropped to fill it. */
    object-fit: contain;
    display: block;
    -webkit-user-drag: none;
    pointer-events: none;
}

/* Scrapbook decoration — a sibling of .pan-tile-inner (child of .pan-tile
   itself, see pan-canvas.js's renderOverlay), specifically so it sits
   outside .pan-tile-inner's own overflow:hidden crop and isn't caught by
   the width:100%/object-fit rule above meant for the actual photo.
   pointer-events:none — decorative only, never blocks the tap that opens
   the tile underneath. */
.tile-tape {
    position: absolute;
    top: -14px;
    left: calc(50% + var(--tape-shift, 0%));
    width: 58%;
    height: auto;
    transform: translateX(-50%) rotate(var(--tape-rotate, 0deg));
    transform-origin: center;
    pointer-events: none;
    z-index: 1;
    /* Tight and barely-offset — tape sits flush against the photo/page, not
       floating above it, so this should read as a thin edge shadow (like a
       real decal) rather than a soft ambient one. */
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.2));
}

.pan-tile-inner .media-item-audio {
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 1rem;
    pointer-events: auto;
}

/* Grid-only stand-in for an audio item — no controls of its own (unlike
   .media-item-audio above), so a tap falls through to the normal tile
   activate/lightbox handling instead of being swallowed by a play button. */
.media-item-audio-badge {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.audio-badge-circle {
    /* Set per-instance in JS (scrapbook.js's audioBadgeCircle) — longer
       descriptions push this toward the tile's edge, since a bigger circle
       is what keeps a smaller-relative font (also set per-instance) from
       reading as physically tiny. */
    height: var(--audio-circle-size, 70%);
    max-width: var(--audio-circle-size, 70%);
    aspect-ratio: 1;
}

.audio-badge-svg {
    width: 100%;
    height: 100%;
    display: block;
    overflow: visible;
}

.audio-badge-disc { fill: var(--accent); }

.audio-badge-curved-text {
    fill: #fff;
    font-family: var(--font-mono);
    letter-spacing: 0.02em;
}

.audio-badge-icon-svg {
    fill: #fff;
    font-size: 22px;
    opacity: 0.9;
}

/* Test/placeholder content — dashed border marks it clearly as stand-in,
   not real archive media. Disappears automatically once real items exist. */
.media-placeholder-box {
    width: 100%;
    height: 100%;
    background: var(--ph-bg, #eee);
    color: var(--ph-fg, #555);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 0.7rem;
    border: 1px dashed var(--ph-fg, #999);
    box-sizing: border-box;
}

.media-placeholder-box--large {
    width: min(60vw, 640px);
    height: min(60vh, 640px);
}

.media-placeholder-type {
    align-self: flex-start;
    font-family: var(--font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    background: rgba(255, 255, 255, 0.6);
    padding: 0.2rem 0.5rem;
    border-radius: 99px;
}

.media-placeholder-title {
    font-family: var(--font-mono);
    font-size: 0.85rem;
    font-weight: 700;
}

/* Stand-in for a download (PDF) item whose thumbnail hasn't been generated
   yet — a pink sticky note rather than a plain grey box, fitting the
   scrapbook page's own physical-page/tape/sticker look. Rotation is set
   per-instance in JS (documentPlaceholder), deterministic per item. */
.postit-note {
    position: relative;
    width: 100%;
    height: 100%;
    background: #ffc2e2;
    color: #4a1030;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 0.8rem;
    box-sizing: border-box;
    transform: rotate(var(--postit-rotate, 0deg));
    box-shadow: 2px 3px 6px rgba(0, 0, 0, 0.25);
    overflow: hidden;
}

/* A folded-corner shadow, like a lifted page curl. */
.postit-note::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 22px;
    height: 22px;
    background: linear-gradient(135deg, transparent 50%, rgba(0, 0, 0, 0.18) 50%);
}

.postit-note--large {
    width: min(50vw, 420px);
    aspect-ratio: 1;
    height: auto;
}

.postit-type {
    align-self: flex-start;
    font-family: var(--font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    background: rgba(255, 255, 255, 0.5);
    padding: 0.2rem 0.5rem;
    border-radius: 99px;
}

.postit-title {
    font-family: var(--font-mono);
    font-size: 0.85rem;
    font-weight: 700;
    line-height: 1.3;
}

.media-item-audio { padding: 1rem 1rem 0.4rem; }

.media-item-audio audio { width: 100%; }

/* ===== CONTENT WARNING ===== */
.cw-wrap {
    position: relative;
    width: 100%;
    height: 100%;
}

.cw-wrap-large {
    display: inline-flex;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 85vh;
}

.cw-blurred { filter: blur(28px) brightness(0.7); }

.cw-badge {
    position: absolute;
    top: 0.5rem;
    left: 0.5rem;
    z-index: 3;
    font-family: var(--font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    background: rgba(10, 8, 5, 0.75);
    color: #f0ece4;
    padding: 0.25rem 0.55rem;
    border-radius: 99px;
    pointer-events: none;
}

.cw-gate {
    position: absolute;
    inset: 0;
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    background: rgba(10, 8, 5, 0.55);
    border: none;
    color: #f0ece4;
    font-family: var(--font-mono);
    cursor: pointer;
    text-align: center;
    padding: 1.5rem;
}

.cw-gate-icon { font-size: 1.6rem; }

.cw-gate-text {
    font-size: 0.75rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    max-width: 280px;
}

.cw-gate:hover .cw-gate-text { text-decoration: underline; }

.grid-status {
    position: fixed;
    inset: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    font-family: var(--font-mono);
    font-size: 0.72rem;
    color: var(--muted);
    letter-spacing: 0.15em;
    pointer-events: none;
    padding: 0 8vw;
}

/* ===== LIGHTBOX ===== */
.lightbox {
    position: fixed;
    inset: 0;
    background: rgba(10, 8, 5, 0.93);
    z-index: 600;
    display: none;
}

.lightbox.open { display: flex; }

.lightbox-media {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 3rem;
    min-width: 0;
    /* Swipe-to-advance (scrapbook.js) needs to preventDefault() on a
       horizontal drag — pan-y still allows normal vertical page scroll
       and stops the browser's native edge-swipe-back gesture from
       competing with it. */
    touch-action: pan-y;
}

.lightbox-media img,
.lightbox-media video {
    max-width: 100%;
    max-height: 85vh;
    display: block;
}

/* .media-item-audio (the wrapper div) has no width of its own here — as a
   flex child of .lightbox-media with no explicit size, it never gets a
   definite width for its own content to lay out against, so the audio
   element's percentage width below couldn't resolve against anything and
   collapsed to 0 (confirmed: the wrapper rendered at exactly its own
   horizontal padding, with zero width left for actual content). Giving the
   wrapper an explicit size first fixes that. */
.lightbox-media .media-item-audio { width: min(420px, 80vw); }
.lightbox-media audio { width: 100%; }

/* download-type items (PDFs) — the thumbnail is the visual, this is the
   actual way to reach the real file, since item.url is a PDF/document and
   can never be shown directly as an image. */
.media-item-download {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

.media-download-link {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--bg);
    background: var(--accent);
    padding: 0.6rem 1.2rem;
    border-radius: 99px;
    text-decoration: none;
    white-space: nowrap;
}

.media-download-link:hover { opacity: 0.85; }

.lightbox-info {
    width: 300px;
    flex-shrink: 0;
    background: var(--bg);
    color: var(--text);
    padding: 4rem 1.6rem 2rem;
    border-left: 1px solid var(--border);
    overflow-y: auto;
}

.lightbox-info h3 {
    font-family: var(--font-display);
    font-size: 1.3rem;
    margin-bottom: 0.5rem;
}

.lightbox-info .lb-meta {
    font-family: var(--font-mono);
    font-size: 0.68rem;
    color: var(--muted);
    margin-bottom: 1rem;
    letter-spacing: 0.08em;
}

.lightbox-info .lb-desc {
    font-family: var(--font-mono);
    font-size: 0.78rem;
    line-height: 1.6;
    margin-bottom: 1rem;
}

.lb-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.lb-tag {
    font-family: var(--font-mono);
    font-size: 0.6rem;
    border: 1px solid var(--border);
    border-radius: 99px;
    padding: 0.2rem 0.6rem;
    color: var(--muted);
}

.lightbox-close,
.lightbox-prev,
.lightbox-next {
    position: fixed;
    background: none;
    border: 1px solid #444;
    color: #f0ece4;
    font-family: var(--font-mono);
    font-size: 1rem;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    cursor: pointer;
    z-index: 610;
    transition: border-color 0.2s;
}

.lightbox-close:hover,
.lightbox-prev:hover,
.lightbox-next:hover { border-color: #f0ece4; }

.lightbox-close { top: 1.2rem; left: 1.2rem; }
.lightbox-prev { top: 50%; left: 1.2rem; transform: translateY(-50%); }
.lightbox-next { top: 50%; right: calc(300px + 1.2rem); transform: translateY(-50%); }

/* ===== EDITORIAL ROOM PAGE ===== */
#room-canvas {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
    /* The renderer draws at a reduced internal resolution (three-scene.js's
       RETRO_RENDER_SCALE) and relies on this element's CSS size stretching
       it back up — pixelated (nearest-neighbour) instead of the browser's
       smooth default is what turns that stretch into genuine blocky
       pixel-art rather than a soft low-res blur. */
    image-rendering: pixelated;
    image-rendering: -moz-crisp-edges;
    image-rendering: crisp-edges;
}

/* 90s MySpace glitter-GIF energy — the bubble display font those
   cooltext.com/glitter-graphics.net generators used (Luckiest Guy, see
   editorial.html's font link), a rainbow gradient sweeping across the
   fill instead of a flat colour, and a hard dark stroke so the letters
   read as "glitter text" rather than just coloured type. Sat on its own
   solid dark plate with a hard border — the previous flat-pink-on-the-
   room's-own-pink-and-magenta walls had nowhere near enough contrast to
   actually read, no matter how the type itself was treated. One line
   rather than wrapping — there's an entire corner of empty room floor to
   the right of it on any real desktop viewport, so nowrap costs nothing. */
.room-hint {
    position: fixed;
    bottom: 1.6rem;
    left: 1.6rem;
    z-index: 100;
    padding: 0.55rem 0.9rem;
    background: rgba(10, 6, 12, 0.82);
    border: 3px solid var(--text);
    box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.65);
    white-space: nowrap;
    line-height: 1.8;
    pointer-events: none;
}

.room-hint .wave-char {
    display: inline-block;
    /* Without this, a lone space character as the entire content of an
       inline-block box collapses to zero width — confirmed the word
       gaps were vanishing entirely, not just shrinking. */
    white-space: pre;
    font-family: 'Luckiest Guy', 'Press Start 2P', var(--font-mono);
    font-size: 0.9rem;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    /* The glitter sweep: a repeating rainbow strip wider than the text,
       animated sideways — background-clip:text plus a transparent fill
       is what lets the gradient itself become the letterforms rather
       than sitting behind them. */
    background-image: linear-gradient(100deg, #ff2fb0, #ffe94d, #43e6ff, #b968ff, #ff2fb0);
    background-size: 300% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-stroke: 1.5px #24081a;
    animation: room-hint-wave 1.6s ease-in-out infinite, room-hint-glitter 3.5s linear infinite;
    animation-delay: calc(var(--i) * 0.045s), calc(var(--i) * -0.12s);
}

@keyframes room-hint-wave {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-5px); }
}

@keyframes room-hint-glitter {
    0% { background-position: 0% 50%; }
    100% { background-position: -300% 50%; }
}

/* A few fixed twinkling sparkles on the plate itself — glitter-GIFs
   almost always had loose stars scattered around the text, not just
   glinting off the letters themselves. */
.room-hint::before,
.room-hint::after {
    content: '\2726';
    position: absolute;
    color: #fff6c9;
    text-shadow: 0 0 4px #ffe94d, 0 0 8px #ff2fb0;
    animation: room-hint-twinkle 1.8s ease-in-out infinite;
    pointer-events: none;
}

.room-hint::before {
    top: -0.5rem;
    left: 0.8rem;
    font-size: 0.85rem;
    animation-delay: 0.3s;
}

.room-hint::after {
    bottom: -0.55rem;
    right: 1.4rem;
    font-size: 0.65rem;
    animation-delay: 1s;
}

@keyframes room-hint-twinkle {
    0%, 100% { opacity: 0.25; transform: scale(0.7) rotate(0deg); }
    50% { opacity: 1; transform: scale(1.15) rotate(15deg); }
}

@media (prefers-reduced-motion: reduce) {
    .room-hint .wave-char { animation: none; }
    .room-hint::before,
    .room-hint::after { animation: none; opacity: 0.85; }
}

/* Keyboard/screen-reader route to the room's content, since the 3D canvas
   itself has no accessible representation of what's on display. */
.room-items-toggle {
    position: fixed;
    top: 8.6rem;
    left: 1.6rem;
    z-index: 100;
    font-family: var(--font-mono);
    font-size: 0.62rem;
    color: var(--muted);
}

.room-items-toggle summary {
    cursor: pointer;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    padding: 0.4rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 99px;
    background: rgba(13, 13, 13, 0.6);
    list-style: none;
}

.room-items-toggle summary::-webkit-details-marker { display: none; }

.room-items-toggle[open] summary { margin-bottom: 0.5rem; }

.room-items-toggle ul {
    list-style: none;
    background: rgba(13, 13, 13, 0.85);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.5rem;
    max-width: 240px;
}

.room-items-toggle li { margin: 0.15rem 0; }

.room-items-toggle button {
    background: none;
    border: none;
    color: var(--text);
    font-family: var(--font-mono);
    font-size: 0.68rem;
    text-align: left;
    padding: 0.35rem 0.5rem;
    width: 100%;
    cursor: pointer;
    border-radius: 4px;
}

.room-items-toggle button:hover,
.room-items-toggle button:focus-visible {
    background: rgba(255, 255, 255, 0.08);
    outline: 1px solid var(--accent);
}

.info-panel {
    position: fixed;
    top: 0;
    right: 0;
    height: 100vh;
    width: min(50vw, 720px);
    background: rgba(13, 13, 13, 0.92);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-left: 1px solid #222;
    padding: 4.5rem 2.4rem 2rem;
    transform: translateX(100%);
    transition: transform 0.32s ease;
    /* Above .helper-widget (z-index 500) so the panel covers Flo when
       open, rather than his fixed-position figure floating on top of it —
       harmless while closed (translateX(100%) is fully off-screen
       regardless of stacking order). */
    z-index: 550;
    color: #f0ece4;
    overflow-y: auto;
}

.info-panel.open { transform: none; }

.info-image {
    /* Natural aspect ratio at the panel's full width — no fixed height/
       object-fit/background, which was letterboxing most images into a
       visible black box whenever their own ratio didn't exactly match a
       45vh crop. */
    display: block;
    width: 100%;
    height: auto;
    margin-top: 1.5rem;
}

.info-close {
    position: absolute;
    top: 1.2rem;
    right: 1.2rem;
    background: none;
    border: 1px solid #444;
    color: #f0ece4;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    font-size: 0.9rem;
    cursor: pointer;
    transition: border-color 0.2s;
}

.info-close:hover { border-color: #f0ece4; }

.info-kicker {
    font-family: var(--font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 0.6rem;
}

.info-title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    margin-bottom: 0.5rem;
}

.info-meta {
    font-family: var(--font-mono);
    font-size: 0.68rem;
    color: #888;
    margin-bottom: 1.2rem;
    letter-spacing: 0.08em;
}

.info-desc {
    font-family: var(--font-mono);
    font-size: 0.78rem;
    line-height: 1.65;
    margin-bottom: 1.2rem;
}

/* ===== SHELL PAGES ===== */
.shell-main {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 9rem 10vw 6rem;
}

.shell-kicker {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.4em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 1rem;
}

.shell-title {
    font-family: var(--font-display);
    font-size: clamp(2.5rem, 6vw, 5rem);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: -0.02em;
    margin-bottom: 1.5rem;
}

.shell-text {
    color: var(--muted);
    max-width: 55ch;
    line-height: 1.7;
    font-size: 1.05rem;
}

.process-transition {
    margin-top: 1.2rem;
    color: var(--text);
    font-style: italic;
}

/* .page-topbar has no background anywhere else on the site (transparent,
   pointer-events:none on its own padding area) — harmless on every other
   page since none scroll far enough to reveal it, but this page is
   genuinely long-form, so scrolled paragraph text was showing straight
   through the fixed header instead of disappearing behind it. Scoped to
   this page only, rather than changing the shared rule everyone else
   already looks fine without. */
[data-page="process"] .page-topbar {
    background: rgba(13, 13, 13, 0.85);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

/* ===== PROCESS PAGE CONTENT =====
   A contained, centred column of distinct cards — not one long
   continuous scroll of grey paragraphs. Each process step is its own
   card with a slight alternating tilt (borrowing the same "scattered
   instant photos" tilt already used for the team photo-stack elsewhere
   on this page, and the tape/tilt language scrapbook.html uses), a
   round sticker-style number badge instead of a subtle watermark, and
   its pull-quote styled as a real pink sticky note — reusing the exact
   look .postit-note already established for PDF thumbnails elsewhere,
   so this page reads as part of the same site instead of a separate,
   more serious "editorial" page bolted on. */
.process-content {
    /* Matches .shell-main's own padding formula (10vw, no real max-width
       cap) exactly, so the cards line up with "OUR PROCESS" above them
       instead of sitting in a narrower, separately-centred column — the
       previous 1040px cap plus its own 6vw padding was compounding into
       ~250px narrower than the hero text at a typical desktop width. */
    max-width: 1400px;
    margin: 0 auto;
    padding: 2rem 10vw 8rem;
}

/* The 4 numbered process cards sit two-up so they actually use the
   page's width, rather than one long single-file column of cards —
   read in the usual left-to-right, top-to-bottom order (01/02 top row,
   03/04 bottom row), which still matches their real chronological
   sequence. */
.process-cards-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2.5rem;
    margin-bottom: 3rem;
    /* Grid rows stretch every cell to match the tallest by default — the
       4 cards hold very different amounts of text, so that left a big
       dead gap inside whichever card was shorter. align-items:start lets
       each card just be its own natural height instead. */
    align-items: start;
}

.process-card {
    position: relative;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 2.6rem 2.4rem;
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35);
}

.process-card--video { margin-bottom: 3rem; }

/* A tiny, deliberately imperfect tilt per card — alternating left/right
   so consecutive cards don't lean the same way — for a "handmade,
   scattered" feel rather than a stack of identical corporate tiles.
   Small enough (<1deg) that body text stays comfortably readable. */
.process-card:nth-of-type(odd) { transform: rotate(-0.5deg); }
.process-card:nth-of-type(even) { transform: rotate(0.5deg); }

/* The team card already has its own tilted photo-stack inside it, and
   the video card is just a placeholder — an extra tilt on top of either
   would compete rather than add character. */
.process-card--video,
.process-card.team-section {
    transform: none;
}

.process-card-badge {
    position: absolute;
    top: -1.1rem;
    left: -1.1rem;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    background: var(--accent);
    color: #fff;
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 800;
    display: flex;
    align-items: center;
    justify-content: center;
    transform: rotate(-8deg);
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
}

.process-heading {
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 2.6vw, 1.85rem);
    font-weight: 700;
    letter-spacing: -0.01em;
    margin-bottom: 1.3rem;
    color: var(--text);
}

.process-card p {
    color: var(--muted);
    line-height: 1.75;
    font-size: 1.02rem;
}

.process-card p + p { margin-top: 1.1rem; }

/* Same visual language as .postit-note (scrapbook's PDF-thumbnail
   sticky note) — a real pink paper note dropped into the reading flow,
   not a magazine-style blockquote. */
.process-note {
    position: relative;
    font-family: var(--font-mono);
    font-size: 0.95rem;
    font-weight: 700;
    line-height: 1.5;
    color: #4a1030;
    background: #ffc2e2;
    max-width: 32ch;
    margin: 1.6rem 0.3rem;
    padding: 1.1rem 1.2rem;
    border-radius: 3px;
    box-shadow: 2px 4px 8px rgba(0, 0, 0, 0.3);
    transform: rotate(-1.5deg);
    overflow: hidden;
}

/* A folded-corner shadow, matching .postit-note's own real paper-note
   treatment exactly, so this reads as the same physical object. */
.process-note::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 20px;
    height: 20px;
    background: linear-gradient(135deg, transparent 50%, rgba(0, 0, 0, 0.18) 50%);
}

.video-placeholder {
    aspect-ratio: 16 / 9;
    max-width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg);
    border: 1px dashed var(--border);
    border-radius: 8px;
    margin-top: 1rem;
}

.video-placeholder-text {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--muted);
}

/* ===== TEAM SECTION ===== */
.team-logo {
    display: block;
    width: 90px;
    height: 90px;
    object-fit: contain;
    margin-bottom: 1.2rem;
}

.team-layout {
    display: flex;
    align-items: center;
    gap: 4rem;
    margin-top: 2rem;
    /* Never wraps — the photo stack stays beside the bios at every
       viewport width; both shrink together on narrow screens instead
       (see the mobile override below) rather than stacking vertically. */
    flex-wrap: nowrap;
}

.team-stack {
    position: relative;
    width: 260px;
    height: 340px;
    flex-shrink: 0;
}

.team-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: var(--card-bg);
    border: 7px solid #f0ece4;
    box-sizing: border-box;
    box-shadow: 0 10px 22px rgba(0, 0, 0, 0.45);
    cursor: pointer;
    transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.4s ease;
}

/* A curated scatter, not random jitter — each photo has its own resting
   tilt/offset so the pile reads as deliberately messy, like a handful of
   instant photos dropped on a table. */
.team-photo:nth-child(1) { transform: rotate(-7deg) translate(-14px, 8px); z-index: 1; }
.team-photo:nth-child(2) { transform: rotate(5deg) translate(10px, -6px); z-index: 2; }
.team-photo:nth-child(3) { transform: rotate(-3deg) translate(6px, 12px); z-index: 3; }
.team-photo:nth-child(4) { transform: rotate(8deg) translate(-8px, -10px); z-index: 4; }
.team-photo:nth-child(5) { transform: rotate(-9deg) translate(12px, 4px); z-index: 5; }

.team-photo.is-active {
    transform: rotate(0deg) translate(0, -6px) scale(1.06);
    box-shadow: 0 18px 34px rgba(0, 0, 0, 0.55);
    z-index: 50;
}

.team-bios {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 1.1rem;
}

.team-bio {
    font-family: var(--font-display);
    font-size: 1.15rem;
    padding: 0.3rem 0;
    border-bottom: 1px solid transparent;
    transition: border-color 0.2s ease;
    cursor: pointer;
}

.team-bio a {
    color: var(--text);
    text-decoration: none;
    font-weight: 600;
}

.team-bio a:hover { color: var(--accent); }

.team-bio.is-active { border-bottom-color: var(--accent); }

.team-bio.is-active a { color: var(--accent); }

.team-pronouns {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--muted);
    margin-top: 0.2rem;
}

/* ===== REDESIGN RESPONSIVE ===== */
@media (max-width: 768px) {
    body.landing { padding: 0.9rem; }
    .landing-panel {
        min-height: calc(100vh - 1.8rem);
        padding: 2.5rem 1.2rem 5.5rem;
        gap: 2rem;
    }
    .landing-nav { grid-template-columns: 1fr; }
    .landing-btn--placeholder { min-height: 130px; }

    .page-topbar { padding: 0.6rem 0.7rem; flex-wrap: wrap; row-gap: 0.4rem; }
    .page-topbar .home-logo { height: 60px; }
    /* ~43px tall (line-height 1.4 on 0.62rem font + generous vertical
       padding) — was ~24px, well under the ~44px touch-target guideline.
       Height is the dimension that actually matters for a horizontal row
       of thumb targets. */
    /* Horizontal padding/gap trimmed from desktop's — three individually
       bordered chips (vs. the old single joined pill bar) need real
       width savings to fit a 320px screen at all; vertical padding is
       untouched since that's what keeps the ~43px touch-target height. */
    .page-topbar .mode-btn { padding: 0.85rem 0.25rem; font-size: 0.54rem; letter-spacing: 0.02em; }
    /* Desktop centres the switcher with position:absolute over the whole
       topbar, which works there because there's room either side of the
       logo — at mobile widths the three (now individually bordered,
       touch-sized) buttons are wider than the viewport itself and would
       sit directly on top of the logo instead. Drop back to a normal
       flex item on its own full-width wrapped row instead (flex-basis
       100% forces the wrap; the row-gap above spaces it from the logo
       row), centring its own buttons within that row via
       justify-content — measured clear of the logo at 320/375/390px. */
    .page-topbar .mode-switcher {
        position: static;
        transform: none;
        flex: 1 1 100%;
        justify-content: center;
        gap: 0.15rem;
    }

    /* The desktop one-line treatment needs real width at 0.9rem — a bold
       display font, and shrinking it enough to fit a 375px phone on one
       line would be illegible, losing the whole point of a glitter-text
       treatment. Wrapping to 2-3 lines at a still-readable size is the
       better trade-off here. font-size lives on .wave-char now (each
       character's own span), not this container, so it's set there too. */
    .room-hint {
        white-space: normal;
        max-width: calc(100vw - 3.2rem);
    }
    .room-hint .wave-char {
        font-size: 0.62rem;
    }

    /* All 46 tags wrapped at mobile width need ~16 rows — the bar would
       grow taller than the viewport itself and (being fixed) extend off
       the top of the screen with no way to scroll to the rest. Falls back
       to a single horizontally-scrolling row here only; desktop keeps the
       full wrapped grid with no scroll. */
    .tag-bar { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: thin; }
    /* Flo's figure doesn't shrink on mobile (min-height:195px, ~150px
       wide), and his speech bubble (220px, right-aligned) reaches further
       left still when open. Fully clearing the bubble every time would cost
       more width than a mobile bar can spare, so this is a middle ground —
       clears the idle figure with room to spare; a fully-open bubble may
       still brush the corner briefly, which is an acceptable trade since
       the bubble is transient and dismissible. */
    .filter-bar-bottom { padding: 0.5rem 1rem 0.6rem; padding-right: 200px; }

    .lightbox.open { flex-direction: column; }
    .lightbox-media { padding: 3.5rem 1rem 0.5rem; }
    .lightbox-info {
        width: 100%;
        border-left: none;
        border-top: 1px solid var(--border);
        padding: 1.2rem 1.4rem;
        max-height: 40vh;
    }
    .lightbox-next { right: 1.2rem; }
    /* Desktop centers both on the full viewport height (top:50%), but the
       mobile column layout puts a scrollable up-to-40vh info panel below
       the media — the real media region is only the top ~60vh, so 50%
       sits too low. */
    .lightbox-prev,
    .lightbox-next { top: 30vh; }

    /* .page-topbar wraps to 2 rows on mobile (measured ~128.7px tall) but
       sits above .info-panel (z-index 300 vs 250) — padding-top clears the
       flow content (kicker/title/etc), but .info-close is position:absolute
       relative to the panel's own top:0 box, so it needs its own explicit
       override; padding alone doesn't move it. */
    .info-panel { width: 100vw; padding-top: 9.2rem; }
    .info-close { top: 8.8rem; }
    /* Desktop centers content vertically in a min-height:100vh box — on
       mobile that box can render taller than the viewport (a long title
       + paragraph + top padding for the topbar easily exceeds ~640px),
       and once it does, centering silently pushes part of the content
       off-screen with NO way to scroll to it, while Flo's fixed-
       position bubble (which auto-opens and can be ~170px tall) sits on
       top of whatever ends up in the bottom portion of the viewport —
       no amount of bottom padding fixes this, since extra padding on an
       already-overflowing centered box just grows the invisible part.
       Switching to top-aligned flow sidesteps the problem entirely: the
       box can still be exactly 100vh tall when content is short, but
       when content is tall it just grows and the page scrolls normally,
       like everywhere else on the web. Verified clear (100px+ of margin)
       on every common modern phone size (390px+ wide); a genuinely short
       viewport — old iPhone SE-class devices (~568-667px tall) or
       landscape phones — can still see Flo's bubble brush the last
       line of the paragraph. Known, accepted residual, not a full fix. */
    .shell-main { justify-content: flex-start; padding: 9rem 8vw 4rem; }

    .process-content { padding: 1rem 6vw 6rem; }
    /* Two-up cards only make sense with real width to share — back to a
       single column on narrow screens, matching the site's other
       nowrap/reflow patterns (never a squeezed half-width card). */
    .process-cards-grid { grid-template-columns: 1fr; gap: 2.2rem; margin-bottom: 2.2rem; }
    .process-card { padding: 2.2rem 1.5rem 1.8rem; }
    .process-card--video { margin-bottom: 2.2rem; }
    .process-card-badge { width: 2.4rem; height: 2.4rem; font-size: 0.95rem; top: -0.9rem; left: -0.7rem; }
    .process-note { font-size: 0.85rem; max-width: 100%; }
    /* Stack + bios still never wrap to separate rows on mobile (see
       .team-layout's flex-wrap:nowrap) — both just get smaller instead. */
    .team-layout { gap: 1.1rem; align-items: flex-start; }
    .team-stack { width: 108px; height: 142px; flex-shrink: 0; }
    .team-bio { font-size: 0.82rem; }
    .team-pronouns { font-size: 0.56rem; }
}

/* ===== ACCESSIBLE ARCHIVE ===== */
.acc-main {
    max-width: 900px;
    margin: 0 auto;
    padding: 8rem 6vw 6rem;
}

.acc-intro { margin-bottom: 2rem; }

.acc-search-form { margin-bottom: 1.8rem; }

.acc-search-label {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.8rem;
    font-weight: 700;
    margin-bottom: 0.5rem;
}

.acc-search-row {
    display: flex;
    gap: 0.6rem;
    flex-wrap: wrap;
}

.acc-search-input {
    flex: 1 1 320px;
    font-size: 1.1rem;
    font-family: var(--font-body);
    padding: 0.8rem 1rem;
    border: 2px solid var(--border);
    border-radius: var(--radius);
    background: #ffffff;
    color: var(--text);
}

.acc-search-input:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 1px;
}

.acc-search-btn {
    font-size: 1rem;
    font-weight: 700;
    padding: 0.8rem 1.6rem;
    border: none;
    border-radius: var(--radius);
    background: var(--accent);
    color: #ffffff;
    cursor: pointer;
}

.acc-search-btn:hover { opacity: 0.9; }

.acc-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 1.6rem;
    margin-bottom: 1.2rem;
}

.acc-filter-group { min-width: 0; }

.acc-filter-label {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 0.5rem;
}

.acc-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.acc-chip {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    background: #ffffff;
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0.4rem 0.9rem;
    color: var(--text);
    cursor: pointer;
}

.acc-chip:hover { border-color: var(--accent); }

.acc-chip.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #ffffff;
}

.acc-select {
    font-size: 0.95rem;
    padding: 0.55rem 0.8rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: #ffffff;
    color: var(--text);
    max-width: 100%;
}

.acc-status {
    font-family: var(--font-mono);
    font-size: 0.85rem;
    color: var(--muted);
    margin-bottom: 1.2rem;
    min-height: 1.2em;
}

.acc-results {
    list-style: none;
    display: grid;
    gap: 0.9rem;
}

.acc-result-link {
    display: flex;
    gap: 1rem;
    align-items: center;
    text-decoration: none;
    color: var(--text);
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.7rem;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.acc-result-link:hover,
.acc-result-link:focus-visible {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px rgba(208, 19, 89, 0.15);
}

.acc-result-thumb {
    flex: 0 0 auto;
    width: 88px;
    height: 88px;
    object-fit: cover;
    border-radius: calc(var(--radius) * 0.7);
    background: #e8e8e8;
}

.acc-result-thumb--none {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    font-family: var(--font-mono);
    font-size: 0.68rem;
    color: var(--muted);
    padding: 0.4rem;
    box-sizing: border-box;
}

.acc-result-meta {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}

.acc-result-title {
    font-weight: 700;
    font-size: 1.05rem;
}

.acc-result-sub {
    font-family: var(--font-mono);
    font-size: 0.78rem;
    color: var(--muted);
}

.acc-result-reason {
    font-size: 0.85rem;
    color: var(--accent);
    margin-top: 0.15rem;
}

/* ----- item detail ----- */
.acc-back-link {
    display: inline-block;
    font-family: var(--font-mono);
    font-size: 0.85rem;
    color: var(--accent);
    text-decoration: none;
    margin-bottom: 1.6rem;
}

.acc-back-link:hover { text-decoration: underline; }

.acc-detail-media {
    display: block;
    width: 100%;
    max-height: 70vh;
    object-fit: contain;
    background: var(--card-bg);
    border-radius: var(--radius);
    margin-bottom: 1.6rem;
}

.acc-detail-media--audio { max-height: none; }

.acc-detail-download { margin-bottom: 1.6rem; }

.acc-open-link {
    display: inline-block;
    margin-top: 0.8rem;
    font-weight: 700;
    color: var(--accent);
}

.acc-detail-title {
    font-family: var(--font-display);
    font-size: clamp(1.6rem, 3.5vw, 2.4rem);
    margin: 0.3rem 0 1rem;
    line-height: 1.15;
}

.acc-detail-desc {
    font-size: 1.05rem;
    line-height: 1.7;
    max-width: 65ch;
    margin-bottom: 1.2rem;
}

.acc-tag-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 2rem;
}

.acc-tag-pill {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0.25rem 0.7rem;
    color: var(--muted);
}

.acc-share,
.acc-refine {
    border-top: 1px solid var(--border);
    padding-top: 1.4rem;
    margin-top: 1.4rem;
}

.acc-share-heading {
    font-size: 1rem;
    margin-bottom: 0.8rem;
}

.acc-share-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-bottom: 0.8rem;
}

.acc-btn {
    font-family: var(--font-body);
    font-size: 0.9rem;
    font-weight: 600;
    padding: 0.55rem 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: #ffffff;
    color: var(--text);
    cursor: pointer;
    text-decoration: none;
    display: inline-block;
}

.acc-btn:hover { border-color: var(--accent); color: var(--accent); }
.acc-btn:disabled { opacity: 0.6; cursor: default; }

.acc-share-url {
    width: 100%;
    max-width: 480px;
    font-family: var(--font-mono);
    font-size: 0.8rem;
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--card-bg);
    color: var(--muted);
}

.acc-refine-msg {
    font-size: 0.9rem;
    color: var(--accent);
    margin-top: 0.6rem;
}

@media (max-width: 640px) {
    .acc-main { padding: 7.5rem 5vw 4rem; }
    .acc-result-link { flex-wrap: wrap; }
}

/* ===== REDUCED MOTION ===== */
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    .hover-shake:hover,
    .hover-wave:hover { animation: none; }
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

