/* NEYA Demo — Polyspheric Visual Direction
   Late-night museum. Neon through atmosphere.
   Tilt cards with vortex/mist/orbs for registry display. */


:root {
    --bg-primary: #000000;
    --bg-elevated: #060606;
    --bg-highlight: #0c0c0c;

    --text-primary: #e8eef7;
    --text-secondary: #8b95a7;
    --text-tertiary: #4d5666;

    --accent-cyan: #4fd4ff;
    --accent-magenta: #ff4fb2;
    --accent-violet: #8b5fff;
    --accent-amber: #ffb84d;
    --accent-rose: #ff5c7c;

    --font-display: 'Space Grotesk', system-ui, sans-serif;
    --font-ui: 'DM Sans', system-ui, sans-serif;
    --font-round: 'Varela Round', system-ui, sans-serif;
    --font-oxanium: 'Oxanium', sans-serif;
    --font-cormorant: 'Cormorant Garamond', serif;

    --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

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

body {
    background: var(--bg-primary);
    color: var(--text-primary);
    font-family: var(--font-ui);
    min-height: 100vh;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    animation: body-fadein 150ms ease forwards;
}

@keyframes body-fadein {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ─── Floating Lines Background ─── */

#original-lines-bg {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    visibility: hidden;
    opacity: 0;
    transition: opacity 700ms var(--ease);
}

#original-lines-bg.active {
    visibility: visible;
    opacity: 0.62;
}

/* ─── VIEWS ─── */

.view {
    display: none;
    opacity: 0;
    transition: opacity 700ms var(--ease);
    max-width: 1200px;
    margin: 0 auto;
    padding: 32px 48px;
    position: relative;
    z-index: 1;
}

.view.active { display: block; }
.view.visible { opacity: 1; }

/* ─── REGISTRY (Landing) ─── */

.page-header {
    text-align: center;
    margin-bottom: 64px;
}

.page-header--inner {
    margin-bottom: 12px;
}

.page-header--inner .brand-logo {
    height: 48px;
}

.page-header--inner .subtitle {
    font-size: 11px;
}

.ico-container {
    width: 64px;
    height: 64px;
    position: fixed;
    top: 16px;
    left: 16px;
    filter: none;
    z-index: 50;
    display: none;
    cursor: pointer;
    transition: width 400ms var(--ease), height 400ms var(--ease), top 400ms var(--ease), left 400ms var(--ease), bottom 400ms var(--ease);
}

/* During the initial route resolution, freeze the iCO so it lands directly
   in the correct pose for the URL hash instead of animating from registry
   default. */
body.boot .ico-container {
    transition: none;
}

body:is(:has(#original-view.active), :has(#category-view.active), :has(#verdict-view.active), :has(#examine-view.active)) .ico-container {
    display: block;
    width: 128px;
    height: 128px;
    top: 40px;
}

body:has(#registry-view.active) .ico-container {
    display: block;
    width: 140px;
    height: 140px;
    top: auto;
    left: 50%;
    bottom: 16px;
    transform: translateX(-50%);
}

.ico-container canvas {
    display: block;
    width: 100% !important;
    height: 100% !important;
}

.ico-container::after {
    content: 'Glossary';
    position: absolute;
    top: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%) translateY(-6px);
    font-family: var(--font-oxanium);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.26em;
    text-transform: uppercase;
    color: rgba(240, 246, 255, 0.92);
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 999px;
    padding: 6px 14px;
    white-space: nowrap;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.10),
        0 4px 16px rgba(0, 0, 0, 0.4),
        0 0 14px rgba(180, 210, 255, 0.12);
    opacity: 0;
    pointer-events: none;
    transition: opacity 320ms var(--ease), transform 320ms var(--ease);
}

.ico-container:is(:hover, .menu-pinned)::after {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

body:has(#registry-view.active) .ico-container::after {
    top: auto;
    bottom: calc(100% + 6px);
    transform: translateX(-50%) translateY(6px);
}

body:has(#registry-view.active) .ico-container:is(:hover, .menu-pinned)::after {
    transform: translateX(-50%) translateY(0);
}

/* ─── iCO fan-out menu (original-view) ─── */

/* Suppress the single-pill tooltip on views that use the fan-out menu. */
body:is(:has(#original-view.active), :has(#registry-view.active), :has(#category-view.active), :has(#verdict-view.active), :has(#examine-view.active)) .ico-container::after {
    display: none;
}

.ico-menu {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

/* Menu only renders on views with the iCO present (original + registry). */
body:not(:has(#original-view.active)):not(:has(#registry-view.active)):not(:has(#category-view.active)):not(:has(#verdict-view.active)):not(:has(#examine-view.active)) .ico-menu {
    display: none;
}

/* On registry-view, the user is already home — hide that item. Only Test + Glossary remain. */
body:has(#registry-view.active) .ico-menu-home {
    display: none;
}

/* Invisible hover bridge — extends the :hover zone from the iCO out past the labels,
   so the cursor can travel from sphere to text without the menu briefly closing. */
.ico-menu::before {
    content: '';
    position: absolute;
    top: -8px;
    bottom: -8px;
    left: 100%;
    width: 220px;
    pointer-events: auto;
}

/* Registry-view: menu fans UPWARD, so the bridge needs to extend ABOVE the iCO
   to cover the Test + Glossary labels stacked overhead. */
body:has(#registry-view.active) .ico-menu::before {
    top: auto;
    bottom: 100%;
    left: -16px;
    right: -16px;
    width: auto;
    height: 80px;
}

/* Arc spans exactly the iCO's height — no overflow above/below.
   Pure decorative element threading past the label column. */
.ico-menu-arc {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 100%;
    width: 26px;
    margin-left: -22px;
    transform: translateY(15.8px);
    color: rgba(225, 240, 255, 0.55);
    opacity: 0;
    pointer-events: none;
    overflow: visible;
    /* Multi-layer for glass depth: inner edge highlight, atmospheric glow, ground shadow. */
    filter:
        drop-shadow(0 0 1px rgba(255, 255, 255, 0.7))
        drop-shadow(0 0 6px rgba(160, 200, 255, 0.35))
        drop-shadow(0 1px 0 rgba(0, 0, 0, 0.45));
    transition: opacity 380ms var(--ease);
}

.ico-menu-arc-path {
    stroke-dasharray: 130;
    stroke-dashoffset: 130;
    transition: stroke-dashoffset 600ms var(--ease);
}

body:is(:has(#original-view.active), :has(#registry-view.active), :has(#category-view.active), :has(#verdict-view.active), :has(#examine-view.active)) .ico-container:is(:hover, .menu-pinned) .ico-menu-arc {
    opacity: 1;
}

body:is(:has(#original-view.active), :has(#registry-view.active), :has(#category-view.active), :has(#verdict-view.active), :has(#examine-view.active)) .ico-container:is(:hover, .menu-pinned) .ico-menu-arc-path {
    stroke-dashoffset: 0;
}

.ico-menu-item {
    position: absolute;
    /* Glass-like text fill — soft etched gradient, lower opacity to feel ghosted. */
    background-image: linear-gradient(170deg, rgba(255, 255, 255, 0.62) 0%, rgba(195, 220, 255, 0.48) 100%);
    /* Expanded transparent hit zone so hovering near the text — not just exactly
       on a glyph — counts as hovering the label. The pseudo inherits pointer-events
       from the parent (auto when the menu is open), so it's only active when the
       menu is open. */
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    border: none;
    padding: 0;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    font-family: var(--font-oxanium);
    font-size: 10.5px;
    font-weight: 300;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    text-shadow: none;
    /* Minimal ground shadow — drop the atmospheric halo so the text reads as ghosted glass. */
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.55));
    white-space: nowrap;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transform-origin: left center;
    transform: translate(0, -50%);
    will-change: transform, filter, opacity;
    transition: opacity 520ms var(--ease), transform 260ms var(--ease), filter 260ms ease;
}

.ico-menu-item::before {
    content: '';
    position: absolute;
    inset: -10px -16px;
    pointer-events: inherit;
}

/* All three labels share the same left edge — clean vertical column.
   The arc threads past them as a decorative element. */
.ico-menu-home {
    top: 22.8px;
    left: calc(100% + 8px);
}
.ico-menu-test {
    top: 50%;
    left: calc(100% + 8px);
}
.ico-menu-glossary {
    top: calc(100% - 22.8px);
    left: calc(100% + 8px);
}

/* Registry-view: iCO is anchored bottom-center, so menu fans UPWARD instead of rightward.
   Arc curves over the top of the iCO like a halo; labels stack above it. */
body:has(#registry-view.active) .ico-menu-arc {
    top: -40px;
    bottom: auto;
    left: 50%;
    margin-left: -13px;
    width: 26px;
    height: 100px;
    transform: rotate(-90deg);
    transform-origin: 50% 50%;
}

/* Registry-view label layout — stacked above the iCO, horizontally centered. */
body:has(#registry-view.active) .ico-menu-test,
body:has(#registry-view.active) .ico-menu-glossary {
    top: auto;
    left: 50%;
    transform-origin: center center;
    transform: translate(-50%, 8px);   /* resting: nudged slightly down toward iCO + faded */
}

body:has(#registry-view.active) .ico-menu-test     { bottom: calc(100% + 40px); }
body:has(#registry-view.active) .ico-menu-glossary { bottom: calc(100% + 6px); }

/* Open state — slide up into final position above the arc. */
body:has(#registry-view.active) .ico-container:is(:hover, .menu-pinned) .ico-menu-test,
body:has(#registry-view.active) .ico-container:is(:hover, .menu-pinned) .ico-menu-glossary {
    transform: translate(-50%, 0);
}

/* Open state — all three labels fade in together, no positional shift. */
body:is(:has(#original-view.active), :has(#registry-view.active), :has(#category-view.active), :has(#verdict-view.active), :has(#examine-view.active)) .ico-container:is(:hover, .menu-pinned) .ico-menu-item {
    opacity: 1;
    pointer-events: auto;
}

/* Per-image glow color — defaults to neutral, overridden by body[data-orig]. */
.ico-menu-item {
    --menu-glow: 200, 220, 255;
    --menu-glow-strength: 0.55;
}
body[data-orig="face"]  .ico-menu-item { --menu-glow: 255, 225, 130; --menu-glow-strength: 0.55; }
body[data-orig="landscape"] .ico-menu-item { --menu-glow: 110, 175, 255; --menu-glow-strength: 1.0; }
/* Abstract mirrors portrait's treatment — same cool default glow at the same
   restrained strength. Portrait has no override and falls through to the
   default (200,220,255 @ 0.55), so abstract makes that explicit. The harsh
   magenta at full strength was reading aggressively on hover; the subtle
   cool tone holds the iCO's "instrument" feel across both views. */
body[data-orig="abstract"]  .ico-menu-item { --menu-glow: 200, 220, 255;  --menu-glow-strength: 0.55; }
body[data-orig="portrait"]  .ico-menu-item { --menu-glow: 200, 220, 255;  --menu-glow-strength: 0.55; }

/* Category pages inherit the parent original's floating-lines bg, so the menu
   glow stays on the body[data-orig] color above — no per-category override. */

/* Per-label hover — text lights up: brighten + colored glow bloom. No geometry shift. */
body:is(:has(#original-view.active), :has(#registry-view.active), :has(#category-view.active), :has(#verdict-view.active), :has(#examine-view.active)) .ico-container:is(:hover, .menu-pinned) .ico-menu-item:hover {
    filter:
        brightness(1.12)
        drop-shadow(0 0 20px rgba(var(--menu-glow), var(--menu-glow-strength)))
        drop-shadow(0 0 6px rgba(var(--menu-glow), calc(var(--menu-glow-strength) * 0.7)))
        drop-shadow(0 0 2px rgba(var(--menu-glow), calc(var(--menu-glow-strength) * 0.5)))
        drop-shadow(0 1px 1px rgba(0, 0, 0, 0.55));
}

.brand-logo {
    height: 48px;
    width: auto;
    display: block;
    margin: 0 auto 12px auto;
}

.subtitle {
    font-family: var(--font-ui);
    font-size: 11px;
    letter-spacing: 0.25em;
    text-transform: uppercase;
    color: var(--text-secondary);
}

/* ─── GLASS CARD CAROUSEL (Registry) ─── */

.registry-grid {
    position: relative;
    width: 100%;
    height: 500px;
    margin-top: 80px;
    margin-bottom: 28px;
    perspective: 1600px;
    overflow: visible;
    touch-action: pan-y;
}

.card-container {
    position: absolute;
    top: 50%;
    left: 50%;
    width: clamp(240px, 27vw, 380px);
    display: flex;
    flex-direction: column;
    align-items: center;
    cursor: pointer;
    transition: transform 560ms var(--ease), opacity 560ms var(--ease);
    will-change: transform, opacity;
}

/* Carousel slots — active card centred, one peeking each side, rest off-stage.
   cards.js reads the same data-pos to dim the WebGL render to match. */
.card-container[data-pos="0"] {
    transform: translate(-50%, -50%) scale(1);
    opacity: 1;
    z-index: 4;
}
.card-container[data-pos="1"] {
    transform: translate(-50%, -50%) translateX(305px) scale(0.62);
    opacity: 0.9;
    z-index: 3;
}
.card-container[data-pos="-1"] {
    transform: translate(-50%, -50%) translateX(-305px) scale(0.62);
    opacity: 0.9;
    z-index: 3;
}
.card-container[data-pos="2"] {
    transform: translate(-50%, -50%) translateX(560px) scale(0.42);
    opacity: 0;
    z-index: 1;
    pointer-events: none;
}
.card-container[data-pos="-2"] {
    transform: translate(-50%, -50%) translateX(-560px) scale(0.42);
    opacity: 0;
    z-index: 1;
    pointer-events: none;
}
/* Hidden until the carousel assigns a slot on first paint. */
.card-container:not([data-pos]) { opacity: 0; }

.card-canvas {
    width: 100%;
    aspect-ratio: 0.87;
    overflow: hidden;
}

.card-canvas canvas {
    display: block;
    width: 100% !important;
    height: 100% !important;
}

.card-name {
    font-family: var(--font-oxanium);
    font-size: 16px;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin-top: -30px;
    margin-bottom: 4px;
    position: relative;
    z-index: 2;
    transition: color 400ms var(--ease);
}

.card-container.is-active .card-name {
    color: var(--text-primary);
}

.card-type {
    font-family: var(--font-ui);
    font-size: 10px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--text-tertiary);
    transition: color 400ms var(--ease);
}

.card-container:hover .card-name {
    color: var(--text-primary);
}

.card-container:hover .card-type {
    color: var(--text-secondary);
}

.registry-divider-action {
    display: flex;
    align-items: center;
    gap: 0;
    cursor: pointer;
    padding: 0;
    margin: 0 auto;
    max-width: 480px;
    width: 100%;
    transition: all 400ms var(--ease);
}

.registry-divider-action:hover .divider-line {
    background: var(--text-primary);
}

.registry-divider-action:hover .sweep-letter {
    animation: text-pulse 1.6s ease-in-out infinite;
}

@keyframes text-pulse {
    0%, 100% { color: var(--text-tertiary); }
    50% { color: var(--text-primary); }
}

.divider-line {
    flex: 1;
    height: 1px;
    background: var(--text-tertiary);
    transition: all 400ms var(--ease);
    position: relative;
    overflow: hidden;
}

.divider-line::after {
    content: '';
    position: absolute;
    top: 0;
    left: -30%;
    width: 30%;
    height: 100%;
    background: linear-gradient(90deg, transparent, var(--text-primary), transparent);
    animation: line-sweep-left 4s ease-in-out infinite;
}

/* Right line — continues after the left finishes */
.divider-line:last-child::after {
    animation: line-sweep-right 4s ease-in-out infinite;
}

@keyframes line-sweep-left {
    0% { left: -30%; opacity: 0; }
    5% { opacity: 1; }
    40% { left: 100%; opacity: 1; }
    41% { opacity: 0; }
    100% { opacity: 0; }
}

@keyframes line-sweep-right {
    0% { opacity: 0; }
    62% { left: -30%; opacity: 0; }
    63% { opacity: 1; }
    90% { left: 100%; opacity: 1; }
    91% { opacity: 0; }
    100% { opacity: 0; }
}

.divider-text {
    font-family: var(--font-oxanium);
    font-size: 14px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-tertiary);
    white-space: nowrap;
    padding: 10px 24px;
    transition: all 400ms var(--ease);

}

.sweep-letter {
    color: var(--text-tertiary);
    animation: letter-glow 4s ease-in-out infinite;
    display: inline-block;
}

.sweep-letter:nth-child(1)  { animation-delay: 1.52s; }
.sweep-letter:nth-child(2)  { animation-delay: 1.58s; }
.sweep-letter:nth-child(3)  { animation-delay: 1.64s; }
.sweep-letter:nth-child(4)  { animation-delay: 1.70s; }
.sweep-letter:nth-child(5)  { animation-delay: 1.76s; }
.sweep-letter:nth-child(6)  { animation-delay: 1.82s; }
.sweep-letter:nth-child(7)  { animation-delay: 1.88s; }
.sweep-letter:nth-child(8)  { animation-delay: 1.94s; }
.sweep-letter:nth-child(9)  { animation-delay: 2.00s; }
.sweep-letter:nth-child(10) { animation-delay: 2.06s; }
.sweep-letter:nth-child(11) { animation-delay: 2.12s; }
.sweep-letter:nth-child(12) { animation-delay: 2.18s; }
.sweep-letter:nth-child(13) { animation-delay: 2.24s; }

@keyframes letter-glow {
    0%, 100% { color: var(--text-tertiary); }
    4% { color: var(--text-primary); }
    12% { color: var(--text-tertiary); }
}

/* ─── BUTTONS ─── */

.btn {
    font-family: var(--font-ui);
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    padding: 14px 36px;
    border: 1px solid var(--text-tertiary);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition: all 400ms var(--ease);
}

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

.btn-detect {
    font-family: var(--font-ui);
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    padding: 16px 48px;
    border: 1px solid var(--text-tertiary);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition: all 400ms var(--ease);
}

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

.btn-detect:disabled {
    opacity: 0.25;
    cursor: default;
}

.btn-detect:disabled:hover {
    border-color: var(--text-tertiary);
    color: var(--text-secondary);
    box-shadow: none;
}

.btn-back {
    font-family: var(--font-oxanium);
    font-size: 11px;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--text-secondary);
    background: none;
    border: none;
    cursor: pointer;
    transition: color 400ms var(--ease);
}

.btn-back:hover {
    color: var(--text-primary);
}

/* ─── Original swipe nav ─── */

.orig-nav {
    position: fixed;
    top: 50%;
    transform: translateY(-50%);
    width: 52px;
    height: 52px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.07);
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 1px 0 rgba(255, 255, 255, 0.06);
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
    transition: background 300ms var(--ease), border-color 300ms var(--ease), box-shadow 300ms var(--ease), transform 200ms var(--ease);
}

.orig-nav svg {
    filter:
        drop-shadow(0 0 4px rgba(var(--btn-glow-1, 139,95,255), 0.9))
        drop-shadow(0 0 10px rgba(var(--btn-glow-2, 44,135,15), 0.55))
        drop-shadow(0 0 18px rgba(var(--btn-glow-3, 255,184,77), 0.3));
    transition: filter 300ms var(--ease);
}

.orig-nav:hover {
    background: rgba(0, 0, 0, 0.12);
    border-color: rgba(255, 255, 255, 0.06);
    box-shadow:
        inset 0 3px 8px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05);
    transform: translateY(calc(-50% + 1px));
}

.orig-nav:hover svg {
    filter:
        drop-shadow(0 0 6px rgba(var(--btn-glow-1, 139,95,255), 1.0))
        drop-shadow(0 0 14px rgba(var(--btn-glow-2, 44,135,15), 0.75))
        drop-shadow(0 0 24px rgba(var(--btn-glow-3, 255,184,77), 0.5));
}

.orig-nav--prev { left: max(16px, calc(50% - 360px)); }
.orig-nav--next { right: max(16px, calc(50% - 360px)); }

/* Registry-view arrows sit further out than the per-original arrows because
 * the carousel has visible side cards (translateX ±305px, scale 0.62) that
 * the 360px-from-center default position would overlap. Pushed to ~540px
 * from center so the arrows clear the side cards with a comfortable gap. */
#registry-view .orig-nav--prev { left: max(16px, calc(50% - 540px)); }
#registry-view .orig-nav--next { right: max(16px, calc(50% - 540px)); }

/* ─── Portrait — same layout as Abstract/Landscape ─── */

#original-view.active[data-original="face"] {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

#original-view[data-original="face"] #original-sections,
#original-view[data-original="abstract"] #original-sections,
#original-view[data-original="landscape"] #original-sections,
#original-view[data-original="portrait"] #original-sections {
    position: fixed;
    bottom: -20px;
    left: 0;
    right: 0;
    margin: 0;
}

#original-view[data-original="face"] .original-hero {
    flex-direction: column;
    align-items: center;
    align-self: center;
    width: 100%;
    gap: 40px;
    margin-top: 40px;
}

#original-view[data-original="face"] .artwork-clip {
    width: 100% !important;
    max-width: 480px !important;
    height: auto !important;
    overflow: visible !important;
    margin-top: 110px;
}

#original-view[data-original="face"] .original-hero-text {
    flex: none;
}

#original-view[data-original="face"] .original-hero-imgwrap .original-hero-text {
    position: absolute;
    top: 12px;
    right: 12px;
    left: auto;
    transform: none;
    z-index: 2;
    margin: 0;
}

#original-view[data-original="face"] .original-hero-imgwrap {
    width: 100% !important;
    height: auto !important;
    aspect-ratio: 3 / 2;
    overflow: visible !important;
    position: relative;
    background:
        radial-gradient(ellipse 25% 34% at center, rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0.55) 50%, rgba(0, 0, 0, 0.15) 78%, rgba(0, 0, 0, 0) 95%),
        rgba(255, 255, 255, 0.03);
    -webkit-backdrop-filter: blur(6.5px) saturate(180%) brightness(1.1);
    backdrop-filter: blur(6.5px) saturate(180%) brightness(1.1);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    box-shadow:
        inset 0 0 80px 10px rgba(0, 0, 0, 0.45),
        inset 0 1px 0 rgba(255, 255, 255, 0.18),
        inset 0 0 0 1px rgba(255, 255, 255, 0.04),
        inset 0 -1px 0 rgba(0, 0, 0, 0.25),
        0 12px 48px rgba(0, 0, 0, 0.4);
    isolation: isolate;
    /* Force the GPU compositing layer up-front so the backdrop-filter resolves
       before the view fades in. Without this, the glass panel briefly renders
       fully transparent on initial paint while the layer is being created. */
    transform: translateZ(0);
    will-change: backdrop-filter;
}

#original-view[data-original="face"] .original-hero img,
#original-view[data-original="face"] .original-hero #original-hero-video,
#original-view[data-original="face"] .original-hero #original-hero-canvas {
    width: 100% !important;
    height: 100% !important;
    max-width: 100% !important;
    max-height: 100% !important;
    object-fit: contain !important;
    border-radius: 0 !important;
    background: transparent !important;
    position: absolute;
    inset: 0;
}

#original-view[data-original="face"] .original-hero #original-hero-img {
    display: none !important;
}

#original-view[data-original="face"] .original-hero #original-hero-canvas {
    display: block !important;
    filter: saturate(1.35) contrast(1.12) brightness(1.08)
            drop-shadow(0 0 10px rgba(180, 255, 120, 0.12))
            drop-shadow(0 12px 32px rgba(0, 0, 0, 0.7))
            drop-shadow(0 4px 12px rgba(0, 0, 0, 0.5));
}

#original-view[data-original="face"] .desc-glass {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    padding: 0 !important;
    margin: 0 !important;
}

#original-view[data-original="face"] .original-title,
#original-view[data-original="face"] .original-description {
    display: none;
}

#original-view[data-original="face"] .title-row {
    justify-content: center;
    gap: 20px;
    margin: 0;
}

#original-view[data-original="face"] .btn-action-label {
    display: none;
}

#original-view[data-original="face"] .cat-icons {
    margin-top: 0;
}

@keyframes portrait-label-pulse {
    0%, 100% {
        color: rgba(255, 255, 255, 0.5);
        text-shadow: 0 0 6px rgba(255, 248, 220, 0.2);
    }
    50% {
        color: rgba(255, 255, 255, 0.88);
        text-shadow: 0 0 10px rgba(255, 248, 220, 0.35);
    }
}

#original-view[data-original="face"] .original-hero-imgwrap::after {
    content: 'FACE';
    position: absolute;
    bottom: 0;
    left: 0;
    font-family: var(--font-oxanium);
    font-size: 13px;
    font-weight: 400;
    letter-spacing: 0.22em;
    color: rgba(255, 255, 255, 0.75);
    animation: portrait-label-pulse 3s ease-in-out infinite;
    padding: 6px 14px;
    background: rgba(255, 255, 255, 0.06);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-left: none;
    border-bottom: none;
    border-radius: 0 8px 0 16px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.08),
        0 0 3px rgba(255, 220, 80, 0.09),
        0 0 7px rgba(255, 220, 80, 0.04);
    pointer-events: none;
}

.artwork-clip {
    overflow: hidden;
    flex-shrink: 0;
    width: 300px;
    height: 400px;
}


/* ─── PER-ORIGINAL PAGE ─── */


#original-view .btn-back {
    font-size: 12px;
    margin-bottom: 4px;
}

.original-hero {
    display: flex;
    gap: 48px;
    align-items: center;
    margin: 8px 0 20px 0;
}

.original-hero-imgwrap {
    position: relative;
    width: 300px;
    height: 100%;
    flex-shrink: 0;
}

/* ─── Watermark reveal animation (triggered by .btn-eye) ─── */
/* Overlay covers the artwork. Default state = invisible. JS adds `.active`
 * to start the scan, then `.code-visible` mid-scan to surface the code panel. */
.wam-reveal {
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
    z-index: 5;
}

/* Scan line — thin horizontal white/chrome glow sweeping top to bottom of the
 * glass panel. Uses `top` (not `transform: translateY`) because CSS transform %
 * resolves against the element's own height (~2px), not the containing block,
 * so a translateY animation barely moves. Animating `top: 0 → 100%` is
 * relative to the .original-hero-imgwrap (300×400px) and gives a full sweep.
 * Chrome feel = bright white core + slightly cool outer halo. */
.wam-reveal-scanline {
    position: absolute;
    left: -8%;
    right: -8%;
    top: -6px;
    height: 2px;
    background: linear-gradient(
        90deg,
        transparent,
        rgba(255, 255, 255, 0.98) 50%,
        transparent
    );
    box-shadow:
        0 0 10px rgba(255, 255, 255, 0.95),
        0 0 32px rgba(235, 240, 250, 0.55),
        0 0 64px rgba(210, 220, 240, 0.3);
    opacity: 0;
}

.wam-reveal.active .wam-reveal-scanline {
    animation: wam-reveal-scan 1.8s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}

@keyframes wam-reveal-scan {
    0%   { opacity: 0; top: -6px; }
    8%   { opacity: 1; }
    92%  { opacity: 1; }
    100% { opacity: 0; top: calc(100% + 6px); }
}

/* Grid pattern — pulses briefly during scan as a "circuitry beneath the pixels" feel. */
.wam-reveal-grid {
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.10) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.10) 1px, transparent 1px);
    background-size: 14px 14px;
    opacity: 0;
    mix-blend-mode: screen;
}

.wam-reveal.active .wam-reveal-grid {
    animation: wam-reveal-grid 2.3s ease-out forwards;
}

@keyframes wam-reveal-grid {
    0%   { opacity: 0; }
    25%  { opacity: 1; }
    70%  { opacity: 0.4; }
    100% { opacity: 0; }
}

/* Code panel — self-contained frosted-glass card. The popup lives inside
 * .artwork-clip (overflow:hidden), which creates a stacking context. Inside
 * a stacking context backdrop-filter only blurs content painted in that
 * context — i.e., just the artwork. On alpha-transparent artworks (face,
 * portrait) there's nothing to blur in the popup's region, so a desc-glass-
 * style very-low-opacity surface looks invisible.
 *
 * Fix: give the panel its own glassy material via a subtle linear gradient
 * + a top-edge inner highlight + a bottom inner shadow. The backdrop-filter
 * still helps when the artwork IS opaque behind the panel; the gradients
 * carry the look when it isn't. */
.wam-reveal-panel {
    position: absolute;
    left: 50%;
    bottom: 10%;
    transform: translateX(-50%) translateY(12px);
    background:
        linear-gradient(180deg,
            rgba(255, 255, 255, 0.16) 0%,
            rgba(255, 255, 255, 0.08) 50%,
            rgba(255, 255, 255, 0.04) 100%
        ),
        rgba(10, 14, 22, 0.34);
    -webkit-backdrop-filter: blur(28px) saturate(160%);
    backdrop-filter: blur(28px) saturate(160%);
    border: 1px solid rgba(255, 255, 255, 0.10);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.14),
        inset 0 -1px 0 rgba(0, 0, 0, 0.08),
        0 14px 36px rgba(0, 0, 0, 0.38);
    border-radius: 18px;
    padding: 12px 20px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    opacity: 0;
    transition: opacity 380ms var(--ease), transform 380ms var(--ease);
    white-space: nowrap;
}

.wam-reveal.code-visible .wam-reveal-panel {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* Landscape artwork is significantly brighter than the others — instead of
 * darkening the panel (which would fight the artwork), lean into the
 * brightness: stronger backdrop blur smooths the busy landscape into a soft
 * luminance, slightly heavier white gradient gives the panel a frosted-on-
 * bright-glass feel, and a subtle dark text-shadow on the hex keeps the
 * code legible against the brighter backdrop without darkening the panel. */
body[data-orig="landscape"] .wam-reveal-panel {
    background:
        linear-gradient(180deg,
            rgba(255, 255, 255, 0.22) 0%,
            rgba(255, 255, 255, 0.12) 50%,
            rgba(255, 255, 255, 0.06) 100%
        ),
        rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(56px) saturate(160%);
    backdrop-filter: blur(56px) saturate(160%);
}

body[data-orig="landscape"] .wam-reveal-hex {
    text-shadow:
        0 0 14px rgba(255, 255, 255, 0.55),
        0 1px 6px rgba(0, 0, 0, 0.55);
}

body[data-orig="landscape"] .wam-reveal-label,
body[data-orig="landscape"] .wam-reveal-sub {
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.45);
}

.wam-reveal-label {
    font-family: var(--font-oxanium);
    font-size: 9px;
    letter-spacing: 0.32em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.85);
}

.wam-reveal-hex {
    font-family: var(--font-oxanium);
    font-size: 20px;
    font-weight: 500;
    letter-spacing: 0.14em;
    color: rgba(255, 255, 255, 0.97);
    text-shadow: 0 0 14px rgba(255, 255, 255, 0.55);
    min-height: 1em; /* prevent layout jump while characters type in */
}

.wam-reveal-sub {
    font-family: var(--font-ui);
    font-size: 10.5px;
    color: rgba(255, 255, 255, 0.82);
    margin-top: 3px;
    letter-spacing: 0.02em;
}

.original-hero-imgwrap::before {
    content: '';
    position: absolute;
    inset: -40px -50px;
    background: radial-gradient(ellipse at center,
        color-mix(in srgb, var(--artwork-tint, #fff) 12%, transparent) 0%,
        transparent 70%);
    z-index: -1;
    pointer-events: none;
}

.original-hero-imgwrap.no-glow::before {
    display: none;
}

.original-hero-imgwrap.no-glow #original-hero-video,
.original-hero-imgwrap.no-glow #original-hero-img {
    filter: none;
    animation: none;
}

.original-hero img {
    width: 300px;
    height: 100%;
    max-width: 300px;
    object-fit: contain;
    flex-shrink: 0;
    display: block;
    filter: drop-shadow(0 0 40px color-mix(in srgb, var(--artwork-tint, #fff) 35%, transparent))
            drop-shadow(0 20px 60px color-mix(in srgb, var(--artwork-tint, #fff) 15%, transparent));
}

#original-hero-video {
    width: 300px;
    height: 100%;
    max-width: 300px;
    object-fit: cover;
    flex-shrink: 0;
    display: block;
    border-radius: 4px;
}

.original-hero img.fingerprint-view {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity 500ms ease;
    pointer-events: none;
    border: none;
    background: #000;
}

.original-hero-imgwrap.show-fingerprint img.fingerprint-view {
    opacity: 1;
}

.original-hero-imgwrap .artwork-media {
    transition: opacity 500ms ease;
}

.original-hero-imgwrap.show-fingerprint .artwork-media {
    opacity: 0.15;
}

.fingerprint-toggle-wrap {
    margin-top: 14px;
    text-align: center;
    width: 100%;
}

.btn-fingerprint {
    font-family: var(--font-ui);
    font-size: 9px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    padding: 8px 18px;
    border: 1px solid var(--text-tertiary);
    background: transparent;
    color: var(--text-tertiary);
    cursor: pointer;
    transition: all 400ms var(--ease);
}

.btn-fingerprint:hover {
    border-color: #ffffff;
    color: #ffffff;
}

.original-hero-imgwrap.show-fingerprint .btn-fingerprint {
    border-color: #ffffff;
    color: #ffffff;
    box-shadow: 0 0 18px rgba(255, 255, 255, 0.25);
}

.fingerprint-caption {
    display: none;
    font-family: var(--font-ui);
    font-size: 9px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--text-tertiary);
    margin-top: 8px;
}

.original-hero-imgwrap.show-fingerprint .fingerprint-caption {
    display: block;
}

.original-hero-text {
    flex: 1;
}

.desc-glass {
    background: rgba(6, 8, 14, 0.06);
    -webkit-backdrop-filter: blur(40px) saturate(1.2);
    backdrop-filter: blur(40px) saturate(1.2);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 20px;
    padding: 24px 28px;
    margin-bottom: 24px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.1),
        0 20px 60px rgba(0, 0, 0, 0.35);
}

.title-row {
    display: flex;
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    gap: 16px;
    margin-bottom: 12px;
}

.title-row .original-title {
    flex: 0 0 auto;
    margin-bottom: 0;
}

.title-row .btn-eye,
.title-row .btn-fingerprint {
    flex-shrink: 0;
}

/* Mirror the .title-row .btn-fingerprint sizing onto .title-row .btn-eye
   so the eye + control icon buttons aren't squeezed to a 2px content area
   by the generic mobile `.btn-eye { padding: 12px 24px; }` rule (which is
   intended for the wide text-pill variant of .btn-eye, not the 52×52
   icon variant). Without this higher-specificity override, the SVG inside
   the eye + control buttons collapsed to a sliver on mobile while the
   fingerprint button — already protected by its own .title-row override
   below — rendered normally. */
.title-row .btn-eye {
    padding: 12px;
    min-width: 0;
    width: 52px;
    height: 52px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.btn-action-label {
    font-family: var(--font-oxanium);
    font-size: 12px;
    font-weight: 300;
    letter-spacing: 0.18em;
    color: rgba(255, 255, 255, 0.65);
    white-space: nowrap;
    opacity: 0;
    transform: translateX(-6px);
    transition: opacity 220ms ease, transform 220ms ease;
    pointer-events: none;
    align-self: center;
}

.btn-action-label.visible {
    opacity: 1;
    transform: translateX(0);
}

.title-row .btn-fingerprint {
    padding: 12px;
    min-width: 0;
    width: 52px;
    height: 52px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 999px;
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 1px 0 rgba(255, 255, 255, 0.06);
    color: var(--text-primary);
}


.desc-glass .original-title {
    font-family: var(--font-oxanium);
    font-weight: 400;
    text-transform: uppercase;
}

.desc-glass .original-description {
    font-family: var(--font-oxanium);
    font-weight: 300;
    color: #ffffff;
}

.original-title {
    font-family: var(--font-ui);
    font-size: 32px;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--text-primary);
    margin-bottom: 20px;
}

.original-description {
    font-family: var(--font-ui);
    font-size: 14px;
    line-height: 1.75;
    color: var(--text-secondary);
}

/* ─── EYE CTA ─── */

.eye-cta {
    margin-top: 28px;
    text-align: center;
}

.btn-eye {
    font-family: var(--font-ui);
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    padding: 14px 36px;
    border: 1px solid var(--text-tertiary);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition: all 400ms var(--ease);
}

.btn-eye:hover {
    border-color: var(--accent-cyan);
    color: var(--text-primary);
    box-shadow: 0 0 20px rgba(79, 212, 255, 0.15);
}

.eye-cta-note {
    font-family: var(--font-ui);
    font-size: 11px;
    color: var(--text-tertiary);
    margin-top: 12px;
}

.category-section {
    margin-bottom: 56px;
    padding-top: 40px;
    border-top: 1px solid var(--text-tertiary);
    position: relative;
}

.category-tag {
    display: inline-block;
    font-family: var(--font-ui);
    font-size: 9px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    padding: 4px 12px;
    border: 1px solid var(--text-tertiary);
    color: var(--text-tertiary);
    margin-bottom: 16px;
}

.category-tag[data-type="fingerprint"] { border-color: #ffffff; color: #ffffff; }
.category-tag[data-type="sd"] { border-color: var(--accent-cyan); color: var(--accent-cyan); }
.category-tag[data-type="flux"] { border-color: var(--accent-violet); color: var(--accent-violet); }
.category-tag[data-type="nanobanana"] { border-color: var(--accent-magenta); color: var(--accent-magenta); }
.category-tag[data-type="analog"] { border-color: var(--accent-amber); color: var(--accent-amber); }
.category-tag[data-type="negative"] { border-color: var(--accent-rose); color: var(--accent-rose); }

.category-header {
    font-family: var(--font-ui);
    font-size: 13px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--text-primary);
    margin-bottom: 12px;
}

.category-description {
    font-family: var(--font-ui);
    font-size: 13px;
    line-height: 1.7;
    color: var(--text-tertiary);
    margin-bottom: 28px;
    max-width: 680px;
}

.category-empty {
    font-family: var(--font-ui);
    font-size: 12px;
    font-style: italic;
    color: var(--text-tertiary);
}

.case-cards {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
}

.case-card {
    background: var(--bg-elevated);
    border: 1px solid var(--text-tertiary);
    padding: 14px;
    width: 180px;
    transition: all 400ms var(--ease);
    position: relative;
}

.case-card:hover {
    border-color: var(--text-secondary);
    transform: translateY(-2px);
}

.case-card:hover .case-card-label {
    color: var(--text-primary);
}

.case-card img {
    width: 100%;
    aspect-ratio: 1;
    object-fit: contain;
    display: block;
    margin-bottom: 10px;
}

.case-card-label {
    font-family: var(--font-ui);
    font-size: 10px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin-bottom: 10px;
    line-height: 1.5;
    transition: color 400ms var(--ease);
}

.case-card .btn {
    width: 100%;
    padding: 8px 0;
    font-size: 9px;
    letter-spacing: 0.15em;
}

/* ─── EXAMINE (Query Mode) ─── */

/* Centre the whole Test-an-image block in the viewport. The header + panels
   + action are short enough that top-aligned layout leaves a large empty
   band at the bottom — flex-centring splits the breathing room evenly above
   and below so the composition reads as deliberate. */
/* Header stays pinned at the top (like every other view); only the panels
   + action block centres in the leftover space below it. The auto margins
   on .image-pair / .examine-action absorb the free space equally above and
   below that block, so it sits centred without moving the NEYA logo. */
#examine-view.active {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

#examine-view.active .image-pair {
    margin-top: auto;
}

#examine-view.active .examine-action {
    margin-bottom: auto;
}

.examine-header {
    margin-bottom: 48px;
}

/* Examine-view back button — same glass-pill icon as glossary, fixed in viewport. */
#examine-view .btn-back {
    position: fixed;
    top: 240px;
    /* Anchored to the left edge of the centred 1200px content column
       (50% − half the column width) rather than a hardcoded pixel offset.
       On a 1920px screen this resolves to 360px — identical to before —
       but it now tracks the column on any window width instead of drifting. */
    left: calc(50% - 600px);
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 999px;
    color: var(--text-primary);
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 1px 0 rgba(255, 255, 255, 0.06);
    z-index: 5;
    transition: background 300ms var(--ease), border-color 300ms var(--ease), box-shadow 300ms var(--ease), transform 200ms var(--ease);
}

#examine-view .btn-back svg {
    display: block;
    filter:
        drop-shadow(0 0 3px rgba(180, 210, 255, 0.4))
        drop-shadow(0 0 7px rgba(180, 210, 255, 0.2));
    transition: filter 300ms var(--ease);
}

#examine-view .btn-back:hover {
    background: rgba(0, 0, 0, 0.12);
    border-color: rgba(255, 255, 255, 0.06);
    box-shadow:
        inset 0 3px 8px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05);
    transform: translateY(1px);
}

#examine-view .btn-back:hover svg {
    filter:
        drop-shadow(0 0 4px rgba(180, 210, 255, 0.6))
        drop-shadow(0 0 10px rgba(180, 210, 255, 0.3));
}

.case-label {
    font-family: var(--font-ui);
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--text-secondary);
    text-align: center;
    margin-bottom: 36px;
}

.image-pair {
    display: flex;
    gap: 40px;
    justify-content: center;
    align-items: stretch;
    margin-top: 40px;
    margin-bottom: 48px;
}

.image-slot {
    flex: 1;
    /* Sized so the Registry panel still fits all four showcase thumbnails on
       a single row (4 × 104px thumb + 3 × 14px gap + 40px preview padding
       = 498px) without the abstract thumbnail wrapping below. */
    max-width: 500px;
}

/* Horizontal UPLOAD pill — sits at the bottom of the Registry glass
   panel in the Test-an-image view. The pill is the same glass treatment
   as .btn-detect. The wrapping row lives inside the .image-frame so it's
   visually contained by the panel. */
.registry-upload-row {
    display: flex;
    justify-content: center;
    padding: 0 24px 24px;
}

/* Make the Registry frame a vertical stack: thumbnails on top, upload
   pill pinned to the bottom edge of the panel. Scoped via :has() so the
   Query-Image frame (next door) keeps its single-child behavior. */
#examine-view .image-frame:has(.registry-preview) {
    display: flex;
    flex-direction: column;
}

#examine-view .image-frame .registry-preview {
    flex: 1;
    min-height: 0;
    height: auto;
    overflow-y: auto;
    /* Thumbnails pinned to the top of the panel; the UPLOAD pill stays at
       the bottom edge via the flex column. */
    align-items: flex-start;
    align-content: flex-start;
}

/* Mirrors the .btn-eye base + hover physics: glass pill that PRESSES DOWN
   on hover (deeper inset shadow, slight +1px Y, darker tint) rather than
   lifting up with an outer glow. */
.btn-upload {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-family: var(--font-oxanium);
    font-size: 13px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    padding: 14px 56px;
    background: rgba(255, 255, 255, 0.02);
    -webkit-backdrop-filter: blur(6px) saturate(120%);
    backdrop-filter: blur(6px) saturate(120%);
    border: 1px solid rgba(255, 255, 255, 0.05);
    border-radius: 999px;
    color: var(--text-primary);
    text-shadow: 0 1px 4px rgba(0, 12, 40, 0.4);
    box-shadow:
        inset 0 2px 5px rgba(0, 0, 0, 0.28),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05),
        0 1px 0 rgba(255, 255, 255, 0.04);
    cursor: pointer;
    transition: background 300ms var(--ease), border-color 300ms var(--ease), box-shadow 300ms var(--ease), transform 200ms var(--ease);
}

/* The SVG icon shows only in the idle state; the text label shows only in
   the data-state (loading / download / delete-armed / error) variants. */
.btn-upload-icon { display: none; }

/* Idle state — compact circular icon button, deliberately a different shape
   from the Run Detection pill so the two don't read as twins. */
.btn-upload:not([data-state]) {
    padding: 0;
    width: 48px;
    height: 48px;
    border-radius: 50%;
}

/* Label visually hidden in the idle state (icon-only) but kept in the
   accessibility tree so the button still announces as "Upload". */
.btn-upload:not([data-state]) .btn-upload-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.btn-upload:not([data-state]) .btn-upload-icon {
    display: block;
    width: 22px;
    height: 22px;
}

.btn-upload:hover {
    background: rgba(0, 0, 0, 0.12);
    border-color: rgba(255, 255, 255, 0.06);
    box-shadow:
        inset 0 3px 8px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05);
    transform: translateY(1px);
    color: var(--text-primary);
}

/* Delete-armed state: same glass-pill physics, red tint so the user reads
   it unmistakably as destructive before committing. Triggered by clicking
   the × overlay on a user-uploaded registry thumb. */
.btn-upload[data-state="delete-armed"] {
    background: rgba(220, 38, 50, 0.18);
    border-color: rgba(255, 80, 100, 0.32);
    color: #ffd7dc;
    text-shadow: 0 1px 4px rgba(80, 0, 8, 0.5);
    box-shadow:
        inset 0 2px 5px rgba(120, 0, 12, 0.45),
        inset 0 -1px 0 rgba(255, 200, 210, 0.06),
        0 0 18px rgba(220, 38, 50, 0.35);
}

.btn-upload[data-state="delete-armed"]:hover {
    background: rgba(220, 38, 50, 0.28);
    border-color: rgba(255, 100, 120, 0.42);
    box-shadow:
        inset 0 3px 8px rgba(120, 0, 12, 0.55),
        inset 0 -1px 0 rgba(255, 200, 210, 0.06),
        0 0 26px rgba(220, 38, 50, 0.55);
    color: #ffffff;
}

.image-caption {
    font-family: var(--font-ui);
    font-size: 10px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--text-tertiary);
    margin-bottom: 12px;
    text-align: center;
}

.image-frame {
    aspect-ratio: 1;
    overflow: hidden;
    position: relative;
    background: rgba(255, 255, 255, 0.035);
    -webkit-backdrop-filter: blur(6.5px) saturate(180%) brightness(1.1);
    backdrop-filter: blur(6.5px) saturate(180%) brightness(1.1);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.06),
        inset 0 -1px 3px rgba(0, 30, 60, 0.18),
        0 8px 24px rgba(0, 0, 0, 0.45),
        0 0 28px rgba(140, 185, 255, 0.08);
    transition: border-color 320ms var(--ease), box-shadow 320ms var(--ease);
}

.image-frame img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

/* Remove-query control — pinned inside the Query panel, shown only once an
   image has been dropped in. Uses the exact same glass-pill treatment as the
   examine-view back button: translucent white fill, hairline border, inset
   shadows, and a blue-glow glyph that presses down on hover. */
.query-clear {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 999px;
    color: var(--text-primary);
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 1px 0 rgba(255, 255, 255, 0.06);
    cursor: pointer;
    z-index: 4;
    transition: background 300ms var(--ease), border-color 300ms var(--ease),
                box-shadow 300ms var(--ease), transform 200ms var(--ease);
}

/* Author display would otherwise win over the [hidden] UA default. */
.query-clear[hidden] { display: none; }

.query-clear svg {
    display: block;
    width: 15px;
    height: 15px;
    /* White glyph (stroke is currentColor) — the red lives only in the
       subtle shell glow, keeping the X itself clean and legible. */
    color: var(--text-primary);
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
    transition: filter 300ms var(--ease), color 200ms var(--ease);
}

.query-clear:hover {
    background: rgba(0, 0, 0, 0.12);
    border-color: rgba(255, 255, 255, 0.06);
    box-shadow:
        inset 0 3px 8px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05);
    transform: translateY(1px);
}

/* On hover the glyph itself turns deep red — the only colour cue, no glow. */
.query-clear:hover svg {
    color: #c62433;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.7));
}

.examine-action {
    text-align: center;
    margin-top: 4px;
}

/* The query-mode tagline is a hover affordance on the Run Detection button.
   Two messages share one slot: the ready tagline when a query image has
   been uploaded, and an "upload first" prompt when it hasn't. Both are
   absolutely stacked so swapping them never shifts the button. */
#examine-view .case-label {
    position: relative;
    min-height: 1.3em;
}

#examine-view .case-label-msg {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    white-space: nowrap;
    font-size: 10px;
    opacity: 0;
    transition: opacity 320ms var(--ease);
}

/* Query image present → button enabled → show the ready tagline. */
#examine-view .examine-action:has(.btn-detect-wrap:hover):has(.btn-detect:not(:disabled)) .case-label-ready {
    opacity: 1;
}

/* No query image → button disabled → prompt the user to upload first. */
#examine-view .examine-action:has(.btn-detect-wrap:hover):has(.btn-detect:disabled) .case-label-prompt {
    opacity: 1;
}

/* The wrapper exists purely so hover is detectable even while the button is
   disabled — browsers suppress :hover on disabled buttons themselves. */
.btn-detect-wrap {
    display: inline-block;
}

.upload-zone {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.upload-zone.hidden { display: none; }

.upload-zone.dragover ~ .image-frame,
.image-frame:has(.upload-zone.dragover) {
    border-color: rgba(140, 185, 255, 0.55);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.08),
        0 0 32px rgba(140, 185, 255, 0.35);
}

.upload-text {
    font-family: var(--font-ui);
    font-size: 13px;
    /* Near-white with a dark halo so it stays legible over the bright
       violet floating-lines that pass through the panel. */
    color: rgba(232, 238, 247, 0.88);
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.9);
    text-align: center;
    padding: 20px;
    line-height: 1.6;
}

.registry-preview {
    display: flex;
    gap: 14px;
    align-items: flex-start;
    justify-content: center;
    height: 100%;
    padding: 36px 20px 20px;
    flex-wrap: wrap;
}

.registry-thumb {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 4px;
    border-radius: 14px;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    outline: none;
    transition: transform 380ms var(--ease),
                opacity 320ms var(--ease),
                filter 320ms var(--ease);
}

.registry-thumb:focus-visible {
    box-shadow: 0 0 0 2px rgba(140, 185, 255, 0.55);
}

.registry-thumb img {
    width: 96px;
    height: 96px;
    object-fit: cover;
    border-radius: 12px;
    border: 1px solid rgba(255, 255, 255, 0.10);
    box-shadow:
        0 4px 14px rgba(0, 0, 0, 0.45),
        0 0 14px rgba(140, 185, 255, 0.06);
    transition: transform 380ms var(--ease),
                box-shadow 380ms var(--ease),
                border-color 380ms var(--ease);
    pointer-events: none;
    display: block;
}

/* Hover / selected keep the base hairline border untouched — the only
   accent is a soft purple glow, never a solid coloured outline. */
.registry-thumb:hover img {
    transform: scale(1.04) translateY(-2px);
    box-shadow:
        0 8px 22px rgba(0, 0, 0, 0.55),
        0 0 16px color-mix(in srgb, var(--lines-accent, #7C3AED) 45%, transparent),
        0 0 30px color-mix(in srgb, var(--lines-accent, #7C3AED) 55%, transparent);
}

.registry-thumb.selected img {
    transform: scale(1.06) translateY(-3px);
    box-shadow:
        0 12px 30px rgba(0, 0, 0, 0.58),
        0 0 16px color-mix(in srgb, var(--lines-accent, #7C3AED) 70%, transparent),
        0 0 40px color-mix(in srgb, var(--lines-accent, #7C3AED) 88%, transparent);
}

/* Delete × — a glass control (translucent dark disc, hairline border, soft
   rose glow) so it sits in the dark glassmorphic language rather than reading
   as an iOS-style sticker. Selection is signalled by the thumbnail's glow
   ring alone, so there is no separate check badge. Hidden until the thumb is
   selected, then scales in. Only rendered for `source == user_upload` thumbs. */
.registry-thumb-delete {
    position: absolute;
    top: -8px;
    left: -8px;
    width: 22px;
    height: 22px;
    display: grid;
    place-items: center;
    padding: 0;
    border-radius: 50%;
    background: rgba(10, 12, 20, 0.55);
    -webkit-backdrop-filter: blur(8px) saturate(140%);
    backdrop-filter: blur(8px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.12);
    box-shadow:
        0 2px 8px rgba(0, 0, 0, 0.5),
        0 0 10px rgba(255, 90, 110, 0.22);
    color: rgba(255, 150, 165, 0.92);
    cursor: pointer;
    transform: scale(0);
    opacity: 0;
    transition: transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1),
                opacity 200ms ease-out,
                box-shadow 200ms ease-out;
    pointer-events: none;
    z-index: 3;
}

.registry-thumb-delete svg {
    width: 12px;
    height: 12px;
    filter: drop-shadow(0 0 3px rgba(255, 90, 110, 0.5));
}

.registry-thumb.selected .registry-thumb-delete {
    transform: scale(1);
    opacity: 1;
    pointer-events: auto;
}

/* Scoped under .selected so it out-specifies the selected rule above —
   otherwise the hover scale would never win. */
.registry-thumb.selected .registry-thumb-delete:hover {
    background: rgba(40, 14, 20, 0.62);
    border-color: rgba(255, 120, 140, 0.42);
    color: #ffd2da;
    box-shadow:
        0 2px 10px rgba(0, 0, 0, 0.55),
        0 0 16px rgba(255, 90, 110, 0.5);
    transform: scale(1.1);
}

/* Inline display name; quietly off-white normally, glows cyan when selected. */
.registry-thumb-label {
    font-size: 0.62rem;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.68);
    letter-spacing: 0.10em;
    text-transform: uppercase;
    text-align: center;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
    transition: color 320ms var(--ease),
                text-shadow 320ms var(--ease);
}

.registry-thumb:hover .registry-thumb-label {
    color: rgba(255, 255, 255, 0.88);
}

.registry-thumb.selected .registry-thumb-label {
    /* Text stays white — only a soft purple glow halo behind it signals
       selection, so the label never reads as tinted/cheap. */
    color: rgba(255, 255, 255, 0.95);
    text-shadow: 0 0 8px color-mix(in srgb, var(--lines-accent, #7C3AED) 35%, transparent);
}

/* Spotlight: when one thumbnail is picked, drop the others to the
   background so the selected target reads as the active subject. */
.registry-preview:has(.registry-thumb.selected) .registry-thumb:not(.selected) {
    opacity: 0.32;
    filter: saturate(0.55);
}

.registry-preview:has(.registry-thumb.selected) .registry-thumb:not(.selected):hover {
    opacity: 0.72;
    filter: saturate(0.85);
}

@media (prefers-reduced-motion: reduce) {
    .registry-thumb,
    .registry-thumb img,
    .registry-thumb-delete,
    .registry-thumb-label {
        transition-duration: 0ms;
    }
}

/* ─── VERDICT ─── */

#verdict-view {
    text-align: center;
}

.verdict-images {
    display: flex;
    justify-content: center;
    gap: 32px;
    margin-bottom: 64px;
}

.verdict-img-slot {
    width: 180px;
    position: relative;
}

.verdict-img-slot img {
    width: 180px;
    height: 180px;
    object-fit: cover;
    border: 1px solid var(--text-tertiary);
    display: block;
}

/* Watermark-code overlay. Replaces the prior amplified-diff image overlay:
   the diff was a visualization of the *carrier* (pixel perturbation that
   encodes the bits), not the watermark itself. The 32-bit code is what
   WAM actually embeds and decodes, so the hover-reveal now surfaces that
   directly — accurate display of the data the system uses to identify
   the registered original. */
.verdict-code-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 180px;
    height: 180px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px;
    background: rgba(8, 10, 14, 0.78);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid var(--text-tertiary);
    opacity: 0;
    transition: opacity 220ms var(--ease);
    pointer-events: none;
    box-sizing: border-box;
}

.verdict-img-slot.has-code:hover .verdict-code-overlay {
    opacity: 1;
}

.verdict-code-label {
    font-family: var(--font-ui);
    font-size: 9px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--text-tertiary);
}

.verdict-code-hex {
    font-family: var(--font-oxanium);
    font-size: 18px;
    letter-spacing: 0.04em;
    color: var(--text-primary);
}

.verdict-code-bits {
    font-family: var(--font-oxanium);
    font-size: 10px;
    line-height: 1.45;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
    text-align: center;
    word-break: break-all;
    white-space: pre-wrap;
}

/* Absent-state: query had no decodable watermark. Muted treatment so the
   "Not detected" message reads as an absence rather than as a value. */
.verdict-code-overlay.is-absent .verdict-code-hex {
    font-size: 15px;
    color: var(--text-secondary);
    letter-spacing: 0.06em;
}

.verdict-code-overlay.is-absent .verdict-code-bits {
    font-family: var(--font-ui);
    font-size: 9px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-tertiary);
}

.verdict-img-label {
    font-family: var(--font-ui);
    font-size: 10px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: #fff;
    margin-top: 8px;
}

.verdict-result {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 40px 0 32px 0;
}

/* Reserve the analyzing orb's footprint ONLY while it is on screen. Once the
   result renders, the panel sizes to its content instead of leaving a tall
   empty gap below the verdict (the "glass panel extending down" issue). */
.verdict-result:has(.analyzing.active) {
    min-height: 320px;
    padding-bottom: 64px;
}

#verdict-content { align-self: flex-start; }

.analyzing { display: none; }
.analyzing.active {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 18px;
}

.analyzing-loader {
    width: 220px;
    height: 220px;
    display: block;
}

/* Status copy beneath the orb. Heading is the reassurance ("real work
   is happening, 9 signals"); subline rotates through phase descriptions
   so the eye has motion during long analyses (5-15s typical). */
.analyzing-text {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    max-width: 360px;
    text-align: center;
}

.analyzing-heading {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: 12px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin: 0;
}

.analyzing-subline {
    font-family: var(--font-display);
    font-weight: 300;
    font-size: 14px;
    letter-spacing: 0.02em;
    color: var(--text-tertiary);
    margin: 0;
    min-height: 1.4em;
    transition: opacity 320ms var(--ease);
}

.analyzing-subline.is-fading {
    opacity: 0;
}

.verdict-phase {
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 800ms var(--ease), transform 800ms var(--ease);
}

.verdict-phase.visible {
    opacity: 1;
    transform: translateY(0);
}

.verdict-phase-fade {
    opacity: 0;
    transition: opacity 400ms var(--ease);
}

.verdict-phase-fade.visible {
    opacity: 1;
}

.verdict-label {
    font-family: var(--font-display);
    font-weight: 300;
    font-size: 64px;
    letter-spacing: -0.02em;
    margin-bottom: 16px;
    color: var(--text-primary);
    position: relative;
    display: inline-block;
    padding-bottom: 10px;
}

.verdict-label.match-certain {
    color: var(--text-primary);
}

.verdict-score {
    font-family: var(--font-display);
    font-weight: 500;
    font-size: 32px;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    margin-bottom: 48px;
}

.signal-row {
    display: flex;
    justify-content: center;
    gap: 48px;
    margin-bottom: 40px;
    flex-wrap: wrap;
}

.signal { text-align: center; }

.signal-name {
    font-family: var(--font-ui);
    font-size: 11px;
    letter-spacing: 0.25em;
    text-transform: uppercase;
    color: #fff;
    margin-bottom: 8px;
}

.signal-name-link {
    cursor: pointer;
    transition: color 200ms var(--ease), text-shadow 200ms var(--ease);
    user-select: none;
}

/* Per-category hover glow for signal labels — mirrors the iCO menu items'
   category coloring so the verdict page reads in the active category's hue.
   Defaults to white when no category is set (e.g. examine / query mode). */
.signal-name-link:hover,
.signal-name-link:focus-visible {
    color: #ffffff;
    text-shadow:
        0 0 6px rgba(var(--signal-hover-glow-rgb, 255, 255, 255), calc(0.95 * var(--signal-hover-glow-strength, 1))),
        0 0 16px rgba(var(--signal-hover-glow-rgb, 255, 255, 255), calc(0.65 * var(--signal-hover-glow-strength, 1))),
        0 0 28px rgba(var(--signal-hover-glow-rgb, 255, 255, 255), calc(0.35 * var(--signal-hover-glow-strength, 1)));
    outline: none;
}

body[data-cat="chatgpt_derivatives"]    { --signal-hover-glow-rgb:  45, 168,  85; }
body[data-cat="sd_derivatives"]         { --signal-hover-glow-rgb:  79, 165, 255; }
body[data-cat="flux_derivatives"]       { --signal-hover-glow-rgb: 139,  95, 255; }
body[data-cat="nanobanana_derivatives"] { --signal-hover-glow-rgb: 255, 216,  77; --signal-hover-glow-strength: 0.6; }
body[data-cat="analog_chain"]           { --signal-hover-glow-rgb: 200, 204, 208; }

.signal-value {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: 20px;
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary);
}

.signal-value.fingerprint-detected {
    color: #ffffff;
    text-shadow: 0 0 16px rgba(255, 255, 255, 0.5);
    font-size: 13px;
    letter-spacing: 0.18em;
}

.signal-value.fingerprint-absent {
    color: var(--text-secondary);
    font-size: 13px;
    letter-spacing: 0.18em;
}

/* Watermark layer fired but cryptographic recovery failed — the layered
   architecture is doing exactly what it claims (perceptual catches what the
   watermark misses). Visually halfway between detected and absent: brighter
   than absent so the residual signal reads as present, dimmer than detected
   so it doesn't claim cryptographic match. */
.signal-value.fingerprint-partial {
    color: rgba(245, 215, 160, 0.92);
    text-shadow: 0 0 12px rgba(245, 215, 160, 0.32);
    font-size: 13px;
    letter-spacing: 0.18em;
}

/* mask_conf inline reading next to the watermark pill label.
   Smaller, dimmer — the label is the headline, the percentage is supporting
   evidence for users who want to see the actual decoder output. */
.fingerprint-subtext {
    font-size: 10px;
    letter-spacing: 0.08em;
    opacity: 0.62;
    margin-left: 6px;
    font-variant-numeric: tabular-nums;
}

/* Fifth signal (FACE). Hidden by default — only shown when both the
   query and the registered original have detectable faces. The
   escalated variants pick up the same accent treatment used elsewhere
   on the verdict page so a strong identity match reads as authoritative. */
.signal[hidden] { display: none; }

.signal-value.face-escalated-high {
    color: #ffffff;
    text-shadow: 0 0 16px rgba(170, 210, 255, 0.6);
}

.signal-value.face-escalated-medium {
    color: rgba(220, 235, 255, 0.95);
    text-shadow: 0 0 12px rgba(170, 210, 255, 0.45);
}

.verdict-meta {
    font-family: var(--font-ui);
    font-size: 13px;
    color: var(--text-tertiary);
    margin-top: 32px;
}


.verdict-glass {
    position: relative;
    max-width: 820px;
    margin: 72px auto 0;
    padding: 32px 44px 32px;
    background: rgba(255, 255, 255, 0.06);
    -webkit-backdrop-filter: blur(6.5px) saturate(1.6);
    backdrop-filter: blur(6.5px) saturate(1.6);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 24px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.18),
        0 24px 70px rgba(0, 0, 0, 0.5);
}

.verdict-glass .verdict-images {
    margin-bottom: 24px;
}

/* ─── RESPONSIVE ─── */

@media (max-width: 768px) {
    .view { padding: 16px; }
    #registry-view {
        height: 100vh;
        height: 100dvh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: space-between;
        overflow: hidden;
        padding: 20px 16px 100px 16px;
        gap: 0;
    }
    .page-header { margin-bottom: 0; }
    .brand-logo { height: 32px; }
    .subtitle { font-size: 8px; }
    .registry-grid {
        height: 62vh;
        margin-top: 0;
        margin-bottom: 0;
        /* Nudge the carousel up a touch without disturbing the flex
           space-between distribution. */
        transform: translateY(-32px);
    }
    /* Card-container trimmed from 74vw to 60vw on portrait phones to free
       up room for properly-sized neighbours alongside the centre. */
    .card-container { width: min(60vw, 260px); }
    /* Belt-and-braces touch handling: make the active + peeking slots
       explicitly tap-receptive (some iOS Safari builds inherit
       pointer-events:none from neighbouring rules) and force the WebGL
       overlay canvas to ignore pointer events even if the inline style
       attribute gets stripped or overridden. */
    .card-container[data-pos="0"],
    .card-container[data-pos="1"],
    .card-container[data-pos="-1"] {
        pointer-events: auto;
        touch-action: manipulation;
    }
    #registry-grid > canvas {
        pointer-events: none !important;
    }
    /* Neighbour cards: scale(0.65) brings the visible glass cube up to
       ~23vw wide (~92px on a 393px viewport) — close to the previous
       scale(0.32) miss of "tiny pellet". translateX(±30vw) parks the
       cube so its inner edge sits flush against the centre cube (the
       glass renders fill ~60% of the canvas, with transparent padding
       around — so the container's outer half extends behind the centre,
       but visually the cubes touch with no gap). Centre stays at scale 1
       when the carousel swipes a card to it. */
    .card-container[data-pos="1"] {
        transform: translate(-50%, -50%) translateX(30vw) scale(0.65);
        opacity: 0.85;
    }
    .card-container[data-pos="-1"] {
        transform: translate(-50%, -50%) translateX(-30vw) scale(0.65);
        opacity: 0.85;
    }
    /* pos ±2 stays off-stage (opacity 0 from the desktop rule). Sized
       between pos 0 and pos 1 so swipe-in reads as a smooth grow+slide. */
    .card-container[data-pos="2"] {
        transform: translate(-50%, -50%) translateX(48vw) scale(0.40);
    }
    .card-container[data-pos="-2"] {
        transform: translate(-50%, -50%) translateX(-48vw) scale(0.40);
    }
    .card-canvas { aspect-ratio: 0.9; }
    /* Mobile matches desktop placement — label sits BELOW the glass icon
       with a negative margin-top so it overlaps the empty bottom of the
       card-canvas. (Earlier mobile flipped this above via `order: -1` /
       negative margin-bottom; reverted for desktop-parity per L.) */
    .card-name {
        font-size: 14px;
        font-weight: 500;
        letter-spacing: 0.12em;
        margin-top: -30px;
        margin-bottom: 4px;
        z-index: 2;
        position: relative;
    }
    .card-type { display: none; }
    .registry-divider-action { max-width: 65%; margin-bottom: 120px; }
    .divider-text { font-size: 9px; padding: 5px 10px; }
    .ico-container {
        width: 120px;
        height: 120px;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        margin: 0 auto;
        z-index: 50;
        display: flex;
        justify-content: center;
        align-items: center;
    }
    .ico-container canvas {
        max-width: 120px !important;
        max-height: 120px !important;
        /* The WebGL canvas is appended after the menu items in the DOM,
           so it paints on top and steals taps from the menu items'
           expanded hit zones (::before with inset -40/-52). Making it
           pointer-transparent lets taps fall through to the menu items
           when their ::before is at the tap point, and to the container
           (which closes the menu) otherwise. The orb's open/close click
           is handled on .ico-container, not the canvas, so this doesn't
           break interaction. */
        pointer-events: none;
    }
    /* All inner-page views use the same scroll pattern on mobile: each is
       its own viewport-anchored layer with internal overflow. That keeps
       NEYA + content at the top of the screen on every navigation, because
       body scroll is irrelevant — the fixed view always renders starting
       at top:0 regardless of where body happens to be. category-view was
       previously body-scrolled, which is why landing on it from a sphere
       tap dropped the user mid-page (iOS Safari leaks the internal scroll
       of the previous fixed view into body, and the next body-scrolled
       view then shows at that leaked position). Putting category-view on
       the same pattern as original-view eliminates that whole class of
       bug. */
    #original-view,
    #category-view,
    #examine-view,
    #verdict-view,
    #glossary-view {
        position: fixed !important;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }
    #original-view { padding: 12px 16px 40px 16px !important; }
    #examine-view  { padding: 16px !important; }
    #verdict-view  { padding: 16px !important; }
    /* Stacked panels exceed the viewport on mobile — top-align so scrolling
       reaches the header instead of clipping a vertically-centred block. */
    #examine-view.active {
        min-height: 0;
    }
    /* No free space to absorb on mobile — restore normal flow spacing. */
    #examine-view.active .image-pair { margin-top: 40px; }
    #examine-view.active .examine-action { margin-bottom: 0; }
    .original-hero { flex-direction: column; align-items: center; gap: 12px; margin: 8px 0 16px 0; }
    .artwork-clip { height: auto; }
    .original-hero-imgwrap { height: auto; }
    .original-hero img { width: 160px; height: auto; max-width: 160px; object-fit: contain; }
    .original-hero-text { text-align: center; }
    .original-title { font-size: 18px; margin-bottom: 10px; }
    .original-description { font-size: 11px; line-height: 1.5; }
    .eye-cta { margin-bottom: 20px; }
    .btn-eye { font-size: 9px; padding: 10px 24px; }
    .eye-cta-note { font-size: 9px; }
    .category-section { margin-bottom: 20px; padding-top: 20px; }
    .category-tag { font-size: 7px; padding: 3px 8px; margin-bottom: 10px; }
    .category-header { font-size: 9px; }
    .category-description { font-size: 10px; line-height: 1.5; margin-bottom: 14px; }
    .case-cards { gap: 8px; }
    .case-card { width: 110px; padding: 8px; }
    .case-card-label { font-size: 7px; margin-bottom: 6px; }
    .case-card .btn { font-size: 7px; padding: 5px 0; }
    .image-pair { flex-direction: column; align-items: center; }
    .image-slot { max-width: 100%; }
    .verdict-images { gap: 16px; margin-bottom: 24px; }
    .verdict-img-slot { width: 100px; }
    .verdict-img-slot img { width: 100px; height: 100px; }
    .verdict-result { padding: 40px 0 30px 0; min-height: auto; }
    .verdict-label { font-size: 28px; }
    .verdict-score { font-size: 18px; margin-bottom: 24px; }
    .signal-row { gap: 32px; margin-bottom: 20px; }
    .signal-name { font-size: 8px; }
    .signal-value { font-size: 16px; }
    .verdict-meta { font-size: 10px; margin-top: 16px; }
    .verdict-back { margin-top: 8px; }
    .case-cards { justify-content: center; }
}

/* ─── iD Composer / Synergy — visual alignment ─────────────────────────────
   Applies to: original-view, examine-view, verdict-view
   Registry view (#registry-view) is deliberately untouched.
   ─────────────────────────────────────────────────────────────────────────── */

/* Back buttons */
.btn-back {
    font-family: var(--font-oxanium);
    font-size: 12px;
    letter-spacing: 0.12em;
    text-transform: none;
}

/* Primary CTA pill — detect + EYE */
.btn-detect,
.btn-eye {
    font-size: 13px;
    letter-spacing: 0.15em;
    text-transform: none;
    background: rgba(139, 95, 255, 0.4);
    border: none;
    border-radius: 999px;
    color: var(--text-primary);
    padding: 14px 32px;
    min-width: 180px;
}

.btn-eye    { font-family: var(--font-round); }

.btn-eye:hover {
    background: rgba(139, 95, 255, 0.62);
    border-color: unset;
    color: var(--text-primary);
    box-shadow: none;
    transform: translateY(-1px);
}

/* Run Detection — glass pill matching the back-button / iCO menu language.
   --glow tracks the floating-lines accent so the button's halo always
   matches the live background; falls back to a soft blue if unset. */
.btn-detect {
    --glow: var(--lines-accent, #8cb9ff);
    font-family: var(--font-oxanium);
    font-size: 13px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    padding: 14px 36px;
    min-width: 200px;
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 999px;
    color: var(--text-primary);
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 1px 0 rgba(255, 255, 255, 0.06),
        0 0 18px color-mix(in srgb, var(--glow) 12%, transparent);
    cursor: pointer;
    transition: background 300ms var(--ease), border-color 300ms var(--ease), box-shadow 300ms var(--ease), transform 200ms var(--ease);
}

.btn-detect:hover:not(:disabled) {
    background: color-mix(in srgb, var(--glow) 12%, transparent);
    border-color: color-mix(in srgb, var(--glow) 50%, transparent);
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 0 28px color-mix(in srgb, var(--glow) 34%, transparent);
    transform: translateY(-1px);
    /* Pause the breathing glow on hover so the hover state reads as a
       deliberate, responsive escalation rather than fighting the loop. */
    animation: none;
}

/* Once a query image is uploaded the button enables — give it a soft,
   slowly-breathing glow so it quietly draws the eye without shouting. */
.btn-detect:not(:disabled) {
    border-color: color-mix(in srgb, var(--glow) 26%, transparent);
    animation: detect-ready-glow 3.4s var(--ease) infinite;
}

@keyframes detect-ready-glow {
    0%, 100% {
        box-shadow:
            inset 0 2px 6px rgba(0, 0, 0, 0.45),
            inset 0 -1px 0 rgba(255, 255, 255, 0.08),
            0 1px 0 rgba(255, 255, 255, 0.06),
            0 0 15px color-mix(in srgb, var(--glow) 18%, transparent);
    }
    50% {
        box-shadow:
            inset 0 2px 6px rgba(0, 0, 0, 0.45),
            inset 0 -1px 0 rgba(255, 255, 255, 0.08),
            0 1px 0 rgba(255, 255, 255, 0.06),
            0 0 26px color-mix(in srgb, var(--glow) 36%, transparent);
    }
}

.btn-detect:disabled {
    opacity: 0.65;
    cursor: not-allowed;
    transform: none;
}

.btn-detect:disabled:hover {
    transform: none;
}

@media (prefers-reduced-motion: reduce) {
    .btn-detect:not(:disabled) { animation: none; }
}

/* Fingerprint toggle — smaller pill, cyan tint */
.btn-fingerprint {
    font-family: var(--font-round);
    font-size: 10px;
    letter-spacing: 0.18em;
    text-transform: none;
    background: rgba(79, 212, 255, 0.08);
    border: 1px solid rgba(79, 212, 255, 0.28);
    border-radius: 999px;
    color: var(--text-secondary);
    padding: 8px 20px;
}

.btn-fingerprint:hover {
    background: rgba(79, 212, 255, 0.18);
    border-color: var(--accent-cyan);
    color: var(--text-primary);
    box-shadow: none;
}

.original-hero-imgwrap.show-fingerprint .btn-fingerprint {
    background: rgba(79, 212, 255, 0.22);
    border-color: var(--accent-cyan);
    color: var(--text-primary);
    box-shadow: 0 0 14px rgba(79, 212, 255, 0.18);
}

/* Case card run-detection buttons */
.case-card .btn {
    font-family: var(--font-round);
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: none;
    background: rgba(139, 95, 255, 0.28);
    border: none;
    border-radius: 999px;
    color: var(--text-primary);
    padding: 8px 0;
}

.case-card .btn:hover {
    background: rgba(139, 95, 255, 0.5);
    border-color: unset;
    color: var(--text-primary);
}

/* Case card hover — cyan border */
.case-card:hover {
    border-color: rgba(79, 212, 255, 0.38);
}

/* Original view — typography */
.original-title {
    font-family: var(--font-round);
    font-size: 28px;
    font-weight: 400;
    letter-spacing: 0.1em;
    text-transform: none;
}

.original-description {
    font-family: var(--font-round);
    font-size: 14px;
    letter-spacing: 0.02em;
}

.fingerprint-caption {
    font-family: var(--font-round);
}

.eye-cta-note {
    font-family: var(--font-round);
    font-size: 12px;
    letter-spacing: 0.04em;
}

.category-tag {
    font-family: var(--font-round);
    font-size: 9px;
    letter-spacing: 0.15em;
}

.category-header {
    font-family: var(--font-round);
    font-size: 13px;
    font-weight: 400;
    letter-spacing: 0.12em;
    text-transform: none;
}

.category-description {
    font-family: var(--font-round);
    font-size: 13px;
    letter-spacing: 0.02em;
}

.category-empty {
    font-family: var(--font-round);
}

.case-card-label {
    font-family: var(--font-round);
    font-size: 10px;
    letter-spacing: 0.06em;
    text-transform: none;
}

/* Examine view */
.case-label {
    font-family: var(--font-oxanium);
    font-size: 12px;
    letter-spacing: 0.18em;
    margin: 0 0 18px;   /* sit just above the Run Detection button */
}

.image-caption {
    font-family: var(--font-oxanium);
    font-size: 16px;
    font-weight: 500;
    letter-spacing: 0.18em;
    /* Matches the registry thumbnail labels — one consistent caption colour,
       muted from pure white so the panel headers don't out-shout the art. */
    color: rgba(255, 255, 255, 0.68);
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}

.upload-text {
    font-family: var(--font-oxanium);
    font-size: 14px;
    letter-spacing: 0.04em;
    animation: upload-text-pulse 2400ms ease-in-out infinite;
}

@keyframes upload-text-pulse {
    0%, 100% { opacity: 0.74; }
    50%      { opacity: 1; }
}

/* Verdict view */
.verdict-label {
    font-family: var(--font-oxanium);
    font-weight: 400;
}

.verdict-score {
    font-family: var(--font-oxanium);
}

.verdict-img-label {
    font-family: var(--font-oxanium);
    letter-spacing: 0.16em;
}

.signal-name {
    font-family: var(--font-oxanium);
}

.signal-value {
    font-family: var(--font-oxanium);
}

.signal-value.fingerprint-detected,
.signal-value.fingerprint-absent,
.signal-value.fingerprint-partial {
    font-family: var(--font-oxanium);
}

.verdict-meta {
    font-family: var(--font-oxanium);
    letter-spacing: 0.04em;
}

/* Verdict back — icon button (mirrors category back) */
.verdict-glass #phase-back {
    position: absolute;
    top: 12px;
    left: 14px;
    z-index: 2;
}

.verdict-glass .verdict-back {
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 999px;
    color: var(--text-primary);
    text-shadow: 0 1px 4px rgba(0, 12, 40, 0.55);
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 1px 0 rgba(255, 255, 255, 0.06);
    transition: background 300ms var(--ease), border-color 300ms var(--ease), box-shadow 300ms var(--ease), transform 200ms var(--ease);
}

.verdict-glass .verdict-back svg {
    display: block;
    filter:
        drop-shadow(0 0 3px rgba(var(--btn-glow-1, 139,95,255), 0.5))
        drop-shadow(0 0 7px rgba(var(--btn-glow-2, 44,135,15), 0.3))
        drop-shadow(0 0 12px rgba(var(--btn-glow-3, 255,184,77), 0.15));
    transition: filter 300ms var(--ease);
}

.verdict-glass .verdict-back:hover {
    background: rgba(0, 0, 0, 0.12);
    border-color: rgba(255, 255, 255, 0.06);
    box-shadow:
        inset 0 3px 8px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05);
    transform: translateY(1px);
}

.verdict-glass .verdict-back:hover svg {
    filter:
        drop-shadow(0 0 4px rgba(var(--btn-glow-1, 139,95,255), 0.7))
        drop-shadow(0 0 9px rgba(var(--btn-glow-2, 44,135,15), 0.45))
        drop-shadow(0 0 16px rgba(var(--btn-glow-3, 255,184,77), 0.25));
}

/* ─── Glass Buttons (iD Composer glassmorph) ─── */

.btn-eye,
.btn-fingerprint {
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.07);
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 1px 0 rgba(255, 255, 255, 0.06);
    color: var(--text-primary);
    text-shadow: 0 1px 4px rgba(0, 12, 40, 0.55);
    border-radius: 999px;
    transition: background 300ms var(--ease), border-color 300ms var(--ease), box-shadow 300ms var(--ease), transform 200ms var(--ease);
}

.btn-eye {
    padding: 12px;
    min-width: 0;
    width: 52px;
    height: 52px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.btn-eye svg,
.title-row .btn-fingerprint svg {
    filter:
        drop-shadow(0 0 4px rgba(var(--btn-glow-1, 139,95,255), 0.9))
        drop-shadow(0 0 10px rgba(var(--btn-glow-2, 44,135,15), 0.55))
        drop-shadow(0 0 18px rgba(var(--btn-glow-3, 255,184,77), 0.3));
    transition: filter 300ms var(--ease);
}

.btn-eye:hover svg,
.title-row .btn-fingerprint:hover svg,
.title-row .btn-fingerprint.active svg {
    filter:
        drop-shadow(0 0 5px rgba(var(--btn-glow-1, 139,95,255), 1))
        drop-shadow(0 0 12px rgba(var(--btn-glow-2, 44,135,15), 0.75))
        drop-shadow(0 0 24px rgba(var(--btn-glow-3, 255,184,77), 0.5));
}

.btn-eye:hover,
.btn-fingerprint:hover {
    background: rgba(0, 0, 0, 0.12);
    border-color: rgba(255, 255, 255, 0.06);
    box-shadow:
        inset 0 3px 8px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05);
    transform: translateY(1px);
    color: var(--text-primary);
}

.original-hero-imgwrap.show-fingerprint .btn-fingerprint {
    background: rgba(180, 210, 255, 0.15);
    border-color: rgba(180, 210, 255, 0.65);
    box-shadow:
        0 0 22px rgba(180, 210, 255, 0.35),
        inset 0 1px 0 rgba(255, 255, 255, 0.5);
    color: var(--text-primary);
}

/* Mobile adjustments for iD style */
@media (max-width: 768px) {
    .btn-eye { font-size: 11px; padding: 12px 24px; min-width: 0; }
    .btn-detect { font-size: 11px; min-width: 0; }
    .btn-fingerprint { font-size: 9px; padding: 7px 16px; }
    .original-title { font-size: 20px; letter-spacing: 0.08em; text-transform: none; }
    .category-header { font-size: 11px; letter-spacing: 0.1em; }
    .category-description { font-size: 11px; letter-spacing: 0.01em; }
    .case-card .btn { font-size: 9px; }
    .case-card-label { font-size: 9px; }
    .eye-cta-note { font-size: 10px; }
    .verdict-back { font-size: 11px; padding: 10px 24px; }
}

/* ─── Category Icons Carousel ─── */

@keyframes icon-float {
    0%, 100% { transform: translateY(0px); }
    50%       { transform: translateY(-7px); }
}

.cat-icons {
    position: relative;
    width: 100%;
    height: 240px;
    display: flex;
    align-items: center;
    justify-content: center;
    perspective: 1200px;
    margin: 0 0 28px;
    overflow: visible;
}

/* Wrapper: this is what the carousel animates */
.cat-icon-wrap {
    position: absolute;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    transition: transform 500ms var(--ease), opacity 500ms var(--ease);
    cursor: pointer;
    user-select: none;
}

.cat-icon {
    position: relative;
    width: 132px;
    aspect-ratio: 1 / 1;
    height: auto;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    cursor: pointer;

    /* Abstract-panel glass body + sphere shading.
       Sphere illusion comes from ASYMMETRIC light/shadow: lit upper-left,
       shadowed lower-right. Symmetric (centered) gradients read as flat
       discs; offset centers + diffuse-vs-specular layering read as 3D. */
    background:
        /* Specular hot spot — small bright reflection of the light source */
        radial-gradient(circle at 32% 22%,
            rgba(255, 255, 255, 0.55) 0%,
            rgba(255, 255, 255, 0.18) 8%,
            rgba(255, 255, 255, 0) 22%),
        /* Diffuse lit zone — broad soft brightening of the upper-left hemisphere */
        radial-gradient(circle at 38% 30%,
            rgba(255, 255, 255, 0.12) 0%,
            rgba(255, 255, 255, 0.04) 35%,
            rgba(255, 255, 255, 0) 65%),
        /* Soft terminator — shadow on the lower-right (NOT centered) */
        radial-gradient(circle at 72% 78%,
            rgba(0, 0, 0, 0.38) 0%,
            rgba(0, 0, 0, 0.14) 35%,
            rgba(0, 0, 0, 0) 70%),
        rgba(255, 255, 255, 0.03);
    -webkit-backdrop-filter: blur(6.5px) saturate(180%) brightness(1.1);
    backdrop-filter: blur(6.5px) saturate(180%) brightness(1.1);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.22),
        inset 0 0 0 1px rgba(255, 255, 255, 0.04),
        inset -2px -2px 12px rgba(0, 0, 0, 0.25),
        inset 0 -1px 0 rgba(0, 0, 0, 0.25),
        0 8px 30px rgba(0, 0, 0, 0.42);
    isolation: isolate;

    transition:
        transform 700ms cubic-bezier(0.2, 0.7, 0.2, 1),
        box-shadow 700ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* Staggered float per card position */
.cat-icon-wrap:nth-child(1) .cat-icon { animation: icon-float 4.0s ease-in-out infinite; }
.cat-icon-wrap:nth-child(2) .cat-icon { animation: icon-float 4.4s ease-in-out infinite 0.6s; }
.cat-icon-wrap:nth-child(3) .cat-icon { animation: icon-float 3.8s ease-in-out infinite 1.1s; }
.cat-icon-wrap:nth-child(4) .cat-icon { animation: icon-float 4.2s ease-in-out infinite 0.3s; }
.cat-icon-wrap:nth-child(5) .cat-icon { animation: icon-float 4.6s ease-in-out infinite 0.9s; }
.cat-icon-wrap:nth-child(6) .cat-icon { animation: icon-float 4.0s ease-in-out infinite 1.5s; }

.card-inner-wrap {
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    border-radius: 20px;
    transform-style: preserve-3d;
    transition: transform 350ms ease;
}

/* Carousel positions */
.cat-icon-wrap[data-pos="0"] {
    transform: translateX(0) scale(1);
    opacity: 1;
    z-index: 3;
}
/* Active sphere uses the same material as the others — the carousel
   distinguishes it via scale + label color. When WebGL is available,
   glass-sphere.js renders real refractive glass spheres over this row
   (see the .cat-icons.gl-active rules below); these CSS spheres are the
   graceful fallback when WebGL is unavailable. */
.cat-icon-wrap[data-pos="1"] {
    transform: translateX(177px) scale(0.86);
    opacity: 0.6;
    z-index: 2;
}
.cat-icon-wrap[data-pos="-1"] {
    transform: translateX(-177px) scale(0.86);
    opacity: 0.6;
    z-index: 2;
}
.cat-icon-wrap[data-pos="2"] {
    transform: translateX(320px) scale(0.7);
    opacity: 0.3;
    z-index: 1;
}
.cat-icon-wrap[data-pos="-2"] {
    transform: translateX(-320px) scale(0.7);
    opacity: 0.3;
    z-index: 1;
}
.cat-icon-wrap[data-pos="3"],
.cat-icon-wrap[data-pos="-3"] {
    transform: translateX(0) scale(0.5);
    opacity: 0;
    z-index: 0;
    pointer-events: none;
}

/* Glass-sphere look: inner logos/glyphs are hidden so the sphere reads clean.
   Identity is carried by --cat-color rim glow + the label below. */
.cat-icon-glyph,
.cat-icon-glyph-img,
.cat-icon-nb-img,
.cat-icon-shine {
    display: none !important;
}

/* NB used to opt out of the card chrome to let its image overflow.
   Spheres are uniform — undo that opt-out. */
.cat-icon--nb {
    /* falls back to the base .cat-icon sphere styling */
}

/* Category title — set INSIDE the sphere, centred over the glass.
   The carousel scales the whole wrap, so side spheres get smaller text
   for free. Identity is carried by the title text + the active glow. */
.cat-icon-title {
    position: absolute;
    inset: 0;
    z-index: 4;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 0 16px;
    font-family: var(--font-oxanium);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.12em;
    line-height: 1.32;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.62);
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
    transition: color 320ms var(--ease), text-shadow 320ms var(--ease);
    pointer-events: none;
}

/* Active sphere — title brightens to full white with a soft halo. */
.cat-icon-wrap[data-pos="0"] .cat-icon-title {
    color: #ffffff;
    text-shadow:
        0 0 14px rgba(255, 255, 255, 0.4),
        0 1px 4px rgba(0, 0, 0, 0.65);
}

/* Hover preview on non-active spheres — lift the title toward white. */
.cat-icon-wrap:not([data-pos="0"]):hover .cat-icon-title {
    color: rgba(255, 255, 255, 0.92);
}

/* Grok's brand glyph — centred inside the sphere instead of a text title. */
.cat-icon-svg {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 44%;
    height: 44%;
    z-index: 4;
    color: rgba(255, 255, 255, 0.7);
    filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.55));
    transition: color 320ms var(--ease), filter 320ms var(--ease);
    pointer-events: none;
}

.cat-icon-wrap[data-pos="0"] .cat-icon-svg {
    color: #ffffff;
    filter:
        drop-shadow(0 0 12px rgba(255, 255, 255, 0.4))
        drop-shadow(0 1px 4px rgba(0, 0, 0, 0.6));
}

.cat-icon-wrap:not([data-pos="0"]):hover .cat-icon-svg {
    color: rgba(255, 255, 255, 0.92);
}

/* Label below the sphere — used only by Grok. Absolutely positioned so it
   doesn't change the wrap's height, keeping every sphere vertically aligned. */
.cat-icon-label {
    position: absolute;
    top: calc(100% + 14px);
    left: 50%;
    transform: translateX(-50%);
    font-family: var(--font-oxanium);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.62);
    text-align: center;
    line-height: 1.4;
    white-space: nowrap;
    transition: color 320ms var(--ease), text-shadow 320ms var(--ease);
    pointer-events: none;
}

.cat-icon-wrap[data-pos="0"] .cat-icon-label {
    color: #ffffff;
    text-shadow: 0 0 14px rgba(255, 255, 255, 0.4);
}

.cat-icon-wrap:not([data-pos="0"]):hover .cat-icon-label {
    color: rgba(255, 255, 255, 0.92);
}

/* shine layer */
.cat-icon-shine {
    position: absolute;
    inset: 0;
    z-index: 2;
    border-radius: 20px;
    pointer-events: none;
    background-image:
        repeating-linear-gradient(
            0deg,
            hsl(210,100%,75%) 0%, hsl(260,100%,76%) 14%,
            hsl(280,100%,78%) 28%, hsl(200,100%,74%) 42%,
            hsl(245,100%,73%) 56%, hsl(230,100%,72%) 70%,
            hsl(210,100%,75%) 84%
        );
    filter: brightness(0.6) contrast(1.4) saturate(0.3) opacity(0.45);
    mix-blend-mode: color-dodge;
    opacity: 0;
    transition: opacity 300ms ease;
}

.cat-icon-wrap[data-pos="0"] .cat-icon-shine { opacity: 1; }

/* glare layer */
.cat-icon-glare {
    position: absolute;
    inset: 0;
    z-index: 3;
    border-radius: 20px;
    pointer-events: none;
    background: radial-gradient(
        farthest-corner circle at var(--pointer-x, 50%) var(--pointer-y, 50%),
        hsl(248,25%,80%) 12%,
        hsla(207,40%,30%,0.8) 90%
    );
    mix-blend-mode: overlay;
    filter: brightness(0.8) contrast(1.2);
    opacity: 0;
    transition: opacity 300ms ease;
}

.cat-icon-wrap[data-pos="0"]:hover .cat-icon-glare { opacity: 0.45; }

/* ─── WebGL glass spheres (glass-sphere.js) ───
   Each .cat-icon gets its own small square WebGL canvas (a child of the
   button) rendering a real glass sphere — the iCO glass shader on sphere
   geometry. The carousel CSS moves / scales / floats / fades the button and
   the canvas rides along for free. `gl-on` is added per-button once that
   sphere's first frame is on its canvas; it drops the CSS glass body + glyph
   so only the WebGL sphere shows. A button without `gl-on` (no WebGL, or a
   lost context) keeps its original CSS sphere — per-sphere graceful fallback.
   The 1px border stays (transparent) so the box size is unchanged. */
.cat-sphere-gl {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.cat-icon.gl-on {
    background: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-color: transparent;
    box-shadow: none;
}

.cat-icon.gl-on .cat-icon-svg,
.cat-icon.gl-on .cat-icon-title,
.cat-icon.gl-on .cat-icon-glare,
.cat-icon.gl-on .cat-icon-shine {
    opacity: 0 !important;
}

/* ─── Cases Panel ─── */

.cat-cases-panel {
    padding-top: 8px;
}

/* ─── Verification Tools ─── */

.verif-section {
    margin-top: 56px;
    padding-top: 28px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.verif-section-label {
    font-family: var(--font-oxanium);
    font-size: 10px;
    font-weight: 400;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--text-tertiary);
    margin-bottom: 16px;
    text-align: center;
}

.verif-pills {
    display: flex;
    justify-content: center;
    gap: 12px;
    flex-wrap: wrap;
}

.verif-pill {
    font-family: var(--font-oxanium);
    font-size: 11px;
    font-weight: 400;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-secondary);
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 100px;
    padding: 8px 22px;
    cursor: pointer;
    transition: color 250ms ease, border-color 250ms ease, background 250ms ease, box-shadow 250ms ease;
}

.verif-pill:hover {
    color: var(--text-primary);
    border-color: color-mix(in srgb, var(--cat-color) 40%, transparent);
    background: rgba(255, 255, 255, 0.07);
}

.verif-pill.active {
    color: var(--text-primary);
    border-color: color-mix(in srgb, var(--cat-color) 55%, transparent);
    background: color-mix(in srgb, var(--cat-color) 8%, transparent);
    box-shadow: 0 0 18px color-mix(in srgb, var(--cat-color) 15%, transparent);
}


.coming-soon-label {
    font-family: var(--font-oxanium);
    font-size: 11px;
    font-weight: 300;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--text-tertiary);
    text-align: center;
    padding: 48px 0;
}

/* ─── Category Page ─── */

#category-view {
    min-height: 100vh;
    padding-bottom: 80px;
}

#category-view.active {
    display: flex;
    flex-direction: column;
}

#category-view #category-hero {
    margin-top: auto;
}

#category-view #category-cases {
    margin-bottom: auto;
}

.cat-page-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    max-width: 820px;
    margin: 140px auto 28px;
    padding: 0 24px;
}

.cat-page-icon {
    width: 200px;
    height: 200px;
    object-fit: contain;
    flex-shrink: 0;
    filter: drop-shadow(0 0 40px color-mix(in srgb, var(--cat-color, #fff) 30%, transparent));
    animation: icon-float 4s ease-in-out infinite;
    margin: -130px auto -8px;
    display: block;
}

.cat-page-hero-text {
    width: 100%;
}

.cat-page-glass {
    position: relative;
    width: 100%;
    margin-bottom: 0 !important;
}

.cat-page-glass > .btn-back {
    position: absolute;
    top: 12px;
    left: 14px;
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 999px;
    color: var(--text-primary);
    text-shadow: 0 1px 4px rgba(0, 12, 40, 0.55);
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 1px 0 rgba(255, 255, 255, 0.06);
    z-index: 2;
    transition: background 300ms var(--ease), border-color 300ms var(--ease), box-shadow 300ms var(--ease), transform 200ms var(--ease);
}

.cat-page-glass > .btn-back svg {
    display: block;
    filter:
        drop-shadow(0 0 3px rgba(var(--btn-glow-1, 139,95,255), 0.5))
        drop-shadow(0 0 7px rgba(var(--btn-glow-2, 44,135,15), 0.3))
        drop-shadow(0 0 12px rgba(var(--btn-glow-3, 255,184,77), 0.15));
    transition: filter 300ms var(--ease);
}

.cat-page-glass > .btn-back:hover {
    background: rgba(0, 0, 0, 0.12);
    border-color: rgba(255, 255, 255, 0.06);
    box-shadow:
        inset 0 3px 8px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05);
    transform: translateY(1px);
}

.cat-page-glass > .btn-back:hover svg {
    filter:
        drop-shadow(0 0 4px rgba(var(--btn-glow-1, 139,95,255), 0.7))
        drop-shadow(0 0 9px rgba(var(--btn-glow-2, 44,135,15), 0.45))
        drop-shadow(0 0 16px rgba(var(--btn-glow-3, 255,184,77), 0.25));
}


.cat-page-glass {
    background: rgba(255, 255, 255, 0.06) !important;
    -webkit-backdrop-filter: blur(6.5px) saturate(1.6) !important;
    backdrop-filter: blur(6.5px) saturate(1.6) !important;
    border: 1px solid rgba(255, 255, 255, 0.18) !important;
    border-radius: 24px !important;
    padding: 24px 36px !important;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.18),
        inset 0 0 40px color-mix(in srgb, var(--cat-color, #fff) 8%, transparent),
        0 24px 70px rgba(0, 0, 0, 0.5),
        0 0 32px color-mix(in srgb, var(--cat-color, #fff) 12%, transparent) !important;
}

.cat-page-title {
    font-family: var(--font-oxanium);
    font-size: 30px;
    font-weight: 400;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-primary);
    margin: 0 0 8px;
}

.cat-page-description {
    font-family: var(--font-oxanium);
    font-size: 14px;
    font-weight: 300;
    color: rgba(255, 255, 255, 0.78);
    line-height: 1.55;
    max-width: 700px;
    margin: 0 auto;
}

#category-cases {
    max-width: 960px;
    margin: 0 auto;
    padding: 28px 24px 0;
}

#category-cases .cat-cases-list {
    display: flex;
    flex-wrap: wrap;
    gap: 28px;
    justify-content: center;
}

@media (max-width: 768px) {
    .cat-page-hero { margin: 60px auto 32px; }
    .cat-page-icon { width: 140px; height: 140px; margin: -84px auto 4px; }
    .cat-page-title { font-size: 22px; }
    .cat-page-description { font-size: 13px; }
    .cat-page-glass { padding: 22px 24px 26px !important; }
}

.cat-cases-header {
    background: rgba(6, 8, 14, 0.06);
    -webkit-backdrop-filter: blur(40px) saturate(1.2);
    backdrop-filter: blur(40px) saturate(1.2);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 20px;
    padding: 24px 28px;
    margin-bottom: 28px;
    max-width: 640px;
    margin-left: auto;
    margin-right: auto;
}

.cat-cases-header .category-header {
    font-family: var(--font-oxanium);
    font-weight: 400;
    text-transform: uppercase;
}

.cat-cases-header .category-description {
    font-family: var(--font-oxanium);
    font-weight: 300;
    color: #ffffff;
}

.cat-cases-list {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
    justify-content: center;
}

.cat-case-item {
    display: flex;
    flex-direction: column;
    gap: 12px;
    cursor: pointer;
    width: 180px;
    transition: transform 300ms var(--ease);
}

.cat-case-item:hover {
    transform: translateY(-3px);
}

.cat-case-item img {
    width: 180px;
    aspect-ratio: 1;
    object-fit: cover;
    border-radius: 14px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    transition: border-color 300ms var(--ease), box-shadow 300ms var(--ease);
}

.cat-case-item:hover img {
    border-color: rgba(255, 255, 255, 0.22);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}

.cat-case-label {
    font-family: var(--font-oxanium);
    font-size: 13px;
    font-weight: 400;
    letter-spacing: 0.06em;
    color: rgba(255, 255, 255, 0.88);
    line-height: 1.5;
    text-align: center;
    transition: color 300ms var(--ease);
}

.cat-case-item:hover .cat-case-label {
    color: #ffffff;
}

@media (max-width: 768px) {
    /* ~18% smaller carousel — keeps the same 3-up arrangement but the
       spheres read as compact thumb-targets instead of dominating the
       lower third of the screen. Translate offsets and the glyph inside
       each sphere scale down proportionally so the layout stays balanced. */
    /* Shift the sphere bar down VISUALLY without touching the layout flow,
       so the artwork glass panels below it don't get pushed. Transform
       doesn't affect siblings — the spheres slide on top of whatever
       (transparent) gap is already there. */
    .cat-icons {
        height: 158px;
        margin: 24px 0 20px;
        transform: translateY(48px);
        /* Route horizontal touches to our pointer handlers (swipe carousel);
           vertical drags still scroll the page. Without this, iOS/Android
           Chrome claim near-horizontal touches as scroll attempts before
           our pointerdown/move/up handlers can see them, so the carousel
           feels unresponsive to thumb swipes. Mirrors .registry-grid:411. */
        touch-action: pan-y;
    }
    .cat-icon { width: 80px; height: auto; }
    .cat-icon-wrap[data-pos="1"]  { transform: translateX(92px) scale(0.88); }
    .cat-icon-wrap[data-pos="-1"] { transform: translateX(-92px) scale(0.88); }
    .cat-icon-wrap[data-pos="2"]  { transform: translateX(172px) scale(0.72); }
    .cat-icon-wrap[data-pos="-2"] { transform: translateX(-172px) scale(0.72); }
    .cat-icon-glyph { width: 32px; height: 32px; border-radius: 9px; }
    .cat-icon-label { font-size: 7px; }
    .cat-case-item { width: 120px; }
    .cat-case-item img { width: 120px; }
}

/* ─── Case Carousel ─── */

.case-scene {
    display: grid;
    overflow: hidden;
    perspective: 35em;
    mask: linear-gradient(90deg, #0000, red 20% 80%, #0000);
    -webkit-mask: linear-gradient(90deg, #0000, red 20% 80%, #0000);
    height: 340px;
    margin-bottom: 6px;
}

.case-a3d {
    display: grid;
    place-self: center;
    transform-style: preserve-3d;
    animation: case-ry 24s linear infinite;
}

.case-a3d:hover {
    animation-play-state: paused;
}

@keyframes case-ry { to { transform: rotateY(360deg); } }

.case-img-card {
    grid-area: 1/1;
    width: 17.5em;
    aspect-ratio: 7/10;
    object-fit: cover;
    border-radius: 1.5em;
    backface-visibility: hidden;
    cursor: pointer;
    transition: filter 300ms;
}

.case-img-card:hover {
    filter: brightness(1.28);
    outline: 2px solid var(--accent-cyan);
    outline-offset: 3px;
}

.case-carousel-hint {
    font-family: var(--font-round);
    font-size: 9px;
    letter-spacing: 0.2em;
    color: var(--text-tertiary);
    text-align: center;
    margin-bottom: 12px;
}

/* Single card fallback (N=1) */
.case-single {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 20px;
}

.case-single-img {
    width: 11em;
    aspect-ratio: 1;
    object-fit: cover;
    border-radius: 0.75em;
    border: 1px solid var(--text-tertiary);
    cursor: pointer;
    transition: filter 300ms, border-color 300ms;
}

.case-single-img:hover {
    filter: brightness(1.28);
    border-color: var(--accent-cyan);
}

/* Pair fallback (N=2) */
.case-pair {
    display: flex;
    gap: 20px;
    flex-wrap: wrap;
    margin-bottom: 20px;
}

.case-pair-item {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.case-pair-img {
    width: 11em;
    aspect-ratio: 1;
    object-fit: cover;
    border-radius: 0.75em;
    border: 1px solid var(--text-tertiary);
    cursor: pointer;
    transition: filter 300ms, border-color 300ms;
}

.case-pair-img:hover {
    filter: brightness(1.28);
    border-color: var(--accent-cyan);
}

.case-carousel-label {
    font-family: var(--font-round);
    font-size: 10px;
    letter-spacing: 0.08em;
    color: var(--text-tertiary);
}

/* ─── Abstract — centered hero on glass panel (matches Portrait) ─── */

#original-view.active[data-original="abstract"] {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}


#original-view[data-original="abstract"] .original-hero {
    flex-direction: column;
    align-items: center;
    align-self: center;
    width: 100%;
    gap: 40px;
    margin-top: 40px;
}

#original-view[data-original="abstract"] .artwork-clip {
    width: 100%;
    max-width: 480px;
    height: auto;
    margin-top: 110px;
}

#original-view[data-original="abstract"] .original-hero-imgwrap .original-hero-text {
    position: absolute;
    top: 12px;
    right: 12px;
    left: auto;
    transform: none;
    z-index: 2;
    margin: 0;
}

#original-view[data-original="abstract"] .original-hero-imgwrap {
    width: 100% !important;
    height: auto !important;
    aspect-ratio: 3 / 2;
    overflow: visible !important;
    position: relative;
    background:
        radial-gradient(ellipse 25% 34% at center, rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0.55) 50%, rgba(0, 0, 0, 0.15) 78%, rgba(0, 0, 0, 0) 95%),
        rgba(255, 255, 255, 0.03);
    -webkit-backdrop-filter: blur(6.5px) saturate(180%) brightness(1.1);
    backdrop-filter: blur(6.5px) saturate(180%) brightness(1.1);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    box-shadow:
        inset 0 0 80px 10px rgba(0, 0, 0, 0.45),
        inset 0 1px 0 rgba(255, 255, 255, 0.18),
        inset 0 0 0 1px rgba(255, 255, 255, 0.04),
        inset 0 -1px 0 rgba(0, 0, 0, 0.25),
        0 12px 48px rgba(0, 0, 0, 0.4);
    isolation: isolate;
    transform: translateZ(0);
    will-change: backdrop-filter;
}

#original-view[data-original="abstract"] .original-hero img,
#original-view[data-original="abstract"] .original-hero #original-hero-video,
#original-view[data-original="abstract"] .original-hero #original-hero-canvas {
    width: 100% !important;
    height: 100% !important;
    max-width: 100% !important;
    max-height: 100% !important;
    object-fit: contain !important;
    border-radius: 0 !important;
    background: transparent !important;
    position: absolute;
    inset: 0;
}

#original-view[data-original="abstract"] .original-hero #original-hero-canvas {
    display: block !important;
    transform: scale(0.92);
    filter: saturate(1.3) contrast(1.1) brightness(1.05)
            drop-shadow(0 0 10px rgba(233, 71, 245, 0.12))
            drop-shadow(0 12px 32px rgba(0, 0, 0, 0.7))
            drop-shadow(0 4px 12px rgba(0, 0, 0, 0.5));
}

#original-view[data-original="abstract"] .original-hero-text {
    flex: none;
}

#original-view[data-original="abstract"] .desc-glass {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    padding: 0 !important;
    margin: 0 !important;
}

#original-view[data-original="abstract"] .original-title,
#original-view[data-original="abstract"] .original-description {
    display: none;
}

#original-view[data-original="abstract"] .title-row {
    justify-content: center;
    gap: 20px;
    margin: 0;
}

#original-view[data-original="abstract"] .btn-action-label {
    display: none;
}

#original-view[data-original="abstract"] .cat-icons {
    margin-top: 0;
}

@keyframes abstract-label-pulse {
    0%, 100% {
        color: rgba(255, 255, 255, 0.45);
        text-shadow: 0 0 8px  rgba(var(--btn-glow-1), 0.6), 0 0 18px rgba(var(--btn-glow-3), 0.35);
    }
    50% {
        color: rgba(255, 255, 255, 0.9);
        text-shadow: 0 0 18px rgba(var(--btn-glow-1), 1.0), 0 0 36px rgba(var(--btn-glow-3), 0.7);
    }
}

#original-view[data-original="abstract"] .original-hero-imgwrap::after {
    content: 'ABSTRACT';
    position: absolute;
    bottom: 0;
    left: 0;
    font-family: var(--font-oxanium);
    font-size: 13px;
    font-weight: 400;
    letter-spacing: 0.22em;
    color: rgba(255, 255, 255, 0.75);
    animation: abstract-label-pulse 3s ease-in-out infinite;
    padding: 6px 14px;
    background: rgba(255, 255, 255, 0.06);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-left: none;
    border-bottom: none;
    border-radius: 0 8px 0 16px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.08),
        0 0 3px rgba(181, 149, 153, 0.09),
        0 0 7px rgba(181, 149, 153, 0.04);
    pointer-events: none;
}

/* ─── Landscape — same layout as Abstract ─── */

#original-view.active[data-original="landscape"],
#original-view.active[data-original="portrait"] {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}


#original-view[data-original="landscape"] .original-hero,
#original-view[data-original="portrait"] .original-hero {
    flex-direction: column;
    align-items: center;
    align-self: center;
    width: 100%;
    gap: 40px;
    margin-top: 40px;
}

#original-view[data-original="landscape"] .artwork-clip,
#original-view[data-original="portrait"] .artwork-clip {
    width: 100%;
    max-width: 480px;
    height: auto;
    margin-top: 110px;
}

#original-view[data-original="landscape"] .original-hero-imgwrap .original-hero-text,
#original-view[data-original="portrait"] .original-hero-imgwrap .original-hero-text {
    position: absolute;
    top: 12px;
    right: 12px;
    left: auto;
    transform: none;
    z-index: 2;
    margin: 0;
}

#original-view[data-original="landscape"] .original-hero-imgwrap .btn-eye,
#original-view[data-original="landscape"] .original-hero-imgwrap .btn-fingerprint,
#original-view[data-original="portrait"] .original-hero-imgwrap .btn-eye,
#original-view[data-original="portrait"] .original-hero-imgwrap .btn-fingerprint {
    background: rgba(0, 0, 0, 0.096);
}

#original-view[data-original="landscape"] .original-hero-imgwrap .btn-eye:hover,
#original-view[data-original="landscape"] .original-hero-imgwrap .btn-fingerprint:hover,
#original-view[data-original="portrait"] .original-hero-imgwrap .btn-eye:hover,
#original-view[data-original="portrait"] .original-hero-imgwrap .btn-fingerprint:hover {
    background: rgba(0, 0, 0, 0.16);
}

#original-view[data-original="landscape"] .original-hero-imgwrap,
#original-view[data-original="portrait"] .original-hero-imgwrap {
    width: 100%;
    height: auto;
}

#original-view[data-original="landscape"] .original-hero img,
#original-view[data-original="portrait"] .original-hero img,
#original-view[data-original="portrait"] .original-hero #original-hero-video {
    width: 100%;
    max-width: 100%;
    max-height: 42vh;
    height: auto;
    object-fit: contain;
    display: block;
    border-radius: 16px;
}

#original-view[data-original="portrait"] .original-hero #original-hero-video {
    aspect-ratio: 3 / 2;
    height: auto;
    object-fit: cover;
}

#original-view[data-original="landscape"] .desc-glass,
#original-view[data-original="portrait"] .desc-glass {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    padding: 0 !important;
    margin: 0 !important;
}

#original-view[data-original="landscape"] .original-title,
#original-view[data-original="landscape"] .original-description,
#original-view[data-original="portrait"] .original-title,
#original-view[data-original="portrait"] .original-description {
    display: none;
}

#original-view[data-original="landscape"] .title-row,
#original-view[data-original="portrait"] .title-row {
    justify-content: center;
    gap: 20px;
    margin: 0;
}

#original-view[data-original="landscape"] .btn-action-label,
#original-view[data-original="portrait"] .btn-action-label {
    display: none;
}

#original-view[data-original="landscape"] .cat-icons,
#original-view[data-original="portrait"] .cat-icons {
    margin-top: 0;
}

#original-view[data-original="landscape"] .original-hero-imgwrap,
#original-view[data-original="portrait"] .original-hero-imgwrap {
    position: relative;
}

@keyframes landscape-label-pulse {
    0%, 100% {
        color: rgba(255, 255, 255, 0.45);
        text-shadow: 0 0 8px  rgba(var(--btn-glow-1), 0.6), 0 0 18px rgba(var(--btn-glow-3), 0.35);
    }
    50% {
        color: rgba(255, 255, 255, 0.9);
        text-shadow: 0 0 18px rgba(var(--btn-glow-1), 1.0), 0 0 36px rgba(var(--btn-glow-3), 0.7);
    }
}

#original-view[data-original="landscape"] .original-hero-imgwrap::after,
#original-view[data-original="portrait"] .original-hero-imgwrap::after {
    position: absolute;
    bottom: 0;
    left: 0;
    font-family: var(--font-oxanium);
    font-size: 13px;
    font-weight: 400;
    letter-spacing: 0.22em;
    color: rgba(255, 255, 255, 0.75);
    animation: landscape-label-pulse 3s ease-in-out infinite;
    padding: 6px 14px;
    background: rgba(255, 255, 255, 0.04);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 0 8px 0 16px;
    box-shadow: none;
    pointer-events: none;
}

#original-view[data-original="landscape"] .original-hero-imgwrap::after { content: 'LANDSCAPE'; }
#original-view[data-original="portrait"] .original-hero-imgwrap::after { content: 'PORTRAIT'; }

@media (max-width: 768px) {
    .case-scene { height: 160px; perspective: 24em; }
    .case-img-card { --w: 8em; }
    .case-single-img,
    .case-pair-img { width: 8em; }
}

/* ─── Glossary ─── */

#glossary-view.active {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    padding: 24px 32px 96px;
    position: relative;
}

.glossary-flow {
    display: flex;
    flex-direction: column;
    gap: 20px;
    max-width: 860px;
    width: 100%;
    margin: 32px auto 0;
}

.glossary-card {
    background: rgba(255, 255, 255, 0.035);
    -webkit-backdrop-filter: blur(6.5px) saturate(140%);
    backdrop-filter: blur(6.5px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    padding: 28px 32px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.08),
        0 8px 28px rgba(0, 0, 0, 0.3);
    transition: border-color 300ms var(--ease);
}

.glossary-card:hover {
    border-color: rgba(255, 255, 255, 0.14);
}

.glossary-term {
    font-family: var(--font-oxanium);
    font-size: 16px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--text-primary);
    margin: 0 0 16px 0;
}

/* Collapsible glossary cards
 * Each .glossary-card is now a <details> element. <summary> is the clickable
 * header. Default browser marker hidden; custom chevron rotates 90° when open.
 * When the card is collapsed (no [open] attribute), the inner h3.glossary-term
 * inside <summary> drops its bottom margin so the card stays visually tight. */
.glossary-card > .glossary-summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    user-select: none;
    outline: none;
    /* Extend the clickable area to the card edges by absorbing the card's
     * padding into the summary itself. Without this, the 28px top/bottom
     * and 32px left/right padding around the title row belongs to .glossary-card
     * and clicks there do not toggle the details. */
    margin: -28px -32px 0;
    padding: 28px 32px 0;
}

/* When collapsed, the summary fills the entire card top-to-bottom. */
.glossary-card:not([open]) > .glossary-summary {
    margin-bottom: -28px;
    padding-bottom: 28px;
}

.glossary-card > .glossary-summary::-webkit-details-marker {
    display: none;
}

.glossary-card > .glossary-summary .glossary-term {
    margin: 0;
    flex: 1;
    /* Without this, some browsers absorb clicks on the h3 instead of
     * bubbling them to the parent <summary>, so only the arrow toggles
     * the card. pointer-events:none routes every click through to the
     * summary container itself. */
    pointer-events: none;
}

.glossary-card:not([open]) > .glossary-summary .glossary-term {
    margin-bottom: 0;
}

.glossary-card[open] > .glossary-summary .glossary-term {
    margin-bottom: 16px;
}

.glossary-chevron {
    width: 12px;
    height: 12px;
    flex-shrink: 0;
    position: relative;
    transition: transform 250ms var(--ease);
    opacity: 0.5;
}

.glossary-chevron::before {
    content: '';
    position: absolute;
    inset: 0;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(-45deg) translate(-2px, -2px);
}

.glossary-card[open] > .glossary-summary .glossary-chevron {
    transform: rotate(90deg);
    opacity: 0.85;
}

.glossary-card > .glossary-summary:hover .glossary-chevron {
    opacity: 0.85;
}

.glossary-card > .glossary-summary:focus-visible {
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.18);
    border-radius: 4px;
}

/* Expand-all / Collapse-all button row, sits just below the segmented control. */
.glossary-expand-row {
    max-width: 860px;
    width: 100%;
    margin: 14px auto 0;
    display: flex;
    justify-content: flex-end;
    padding: 0 4px;
}

.glossary-expand-btn {
    font-family: var(--font-oxanium);
    font-size: 11px;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--text-secondary);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    transition: color 400ms var(--ease);
}

.glossary-expand-btn:hover {
    color: var(--text-primary);
}

/* Brief-mode hides the expand button (there's only one card in brief mode). */
.brief-mode .glossary-expand-row {
    display: none;
}

.glossary-def {
    font-family: var(--font-ui);
    font-size: 14.5px;
    line-height: 1.7;
    color: var(--text-secondary);
    margin: 0 0 12px 0;
}

.glossary-def:last-child {
    margin-bottom: 0;
}

.glossary-def strong {
    color: var(--text-primary);
    font-weight: 500;
}

.glossary-def em {
    color: var(--text-primary);
    font-style: italic;
    opacity: 0.92;
}

.glossary-list {
    list-style: none;
    padding: 0;
    margin: 0 0 14px 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.glossary-list li {
    font-family: var(--font-ui);
    font-size: 14.5px;
    line-height: 1.6;
    color: var(--text-secondary);
    padding-left: 18px;
    position: relative;
}

.glossary-list li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.65em;
    width: 8px;
    height: 1px;
    background: rgba(255, 255, 255, 0.4);
}

.glossary-list li strong {
    color: var(--text-primary);
    font-weight: 500;
}

.glossary-sub {
    margin-top: 18px;
    padding: 18px 20px;
    border-left: 2px solid rgba(255, 255, 255, 0.14);
    background: rgba(255, 255, 255, 0.02);
    border-radius: 0 10px 10px 0;
    scroll-margin-top: 140px;
}

.glossary-sub:first-of-type {
    margin-top: 4px;
}

.glossary-subterm {
    font-family: var(--font-oxanium);
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-primary);
    margin: 0 0 10px 0;
}

@keyframes glossary-flash {
    0% {
        color: var(--text-primary);
        text-shadow: none;
    }
    10% {
        color: #ffffff;
        text-shadow:
            0 0 4px rgba(255, 255, 255, 1),
            0 0 16px rgba(255, 255, 255, 0.95),
            0 0 32px rgba(255, 255, 255, 0.6);
    }
    65% {
        color: #ffffff;
        text-shadow:
            0 0 4px rgba(255, 255, 255, 0.9),
            0 0 14px rgba(255, 255, 255, 0.7),
            0 0 26px rgba(255, 255, 255, 0.35);
    }
    100% {
        color: var(--text-primary);
        text-shadow: none;
    }
}

.glossary-subterm.flash {
    animation: glossary-flash 2.8s ease both;
    animation-delay: 450ms;
}

.glossary-meta {
    font-family: var(--font-ui);
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-tertiary);
    margin: 6px 0 0 0;
}

.glossary-meta-label {
    font-family: var(--font-oxanium);
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin-right: 6px;
}

.glossary-tiers {
    margin: 4px 0 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.tier-name {
    font-family: var(--font-oxanium);
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    margin: 0 0 4px 0;
    color: var(--text-primary);
}

.tier-name .tier-range {
    font-size: 11px;
    letter-spacing: 0.1em;
    color: var(--text-tertiary);
    margin-left: 6px;
}

.tier-desc {
    font-family: var(--font-ui);
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-secondary);
    margin: 0 0 0 0;
    padding-left: 14px;
    border-left: 1px solid rgba(255, 255, 255, 0.08);
}

.glossary-tagline {
    margin-top: 8px;
    padding-top: 14px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    color: var(--text-primary);
    font-style: normal;
}

/* Glossary back button — standalone glass-pill icon (same shape as the category one,
   but free-floating instead of sitting on a glass panel). */
#glossary-view .btn-back {
    position: fixed;
    top: 260px;
    left: 400px;
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 999px;
    color: var(--text-primary);
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 1px 0 rgba(255, 255, 255, 0.06);
    z-index: 5;
    transition: background 300ms var(--ease), border-color 300ms var(--ease), box-shadow 300ms var(--ease), transform 200ms var(--ease);
}

#glossary-view .btn-back svg {
    display: block;
    filter:
        drop-shadow(0 0 3px rgba(140, 185, 255, 0.4))
        drop-shadow(0 0 7px rgba(140, 185, 255, 0.2));
    transition: filter 300ms var(--ease);
}

#glossary-view .btn-back:hover {
    background: rgba(0, 0, 0, 0.12);
    border-color: rgba(255, 255, 255, 0.06);
    box-shadow:
        inset 0 3px 8px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05);
    transform: translateY(1px);
}

#glossary-view .btn-back:hover svg {
    filter:
        drop-shadow(0 0 4px rgba(140, 185, 255, 0.6))
        drop-shadow(0 0 10px rgba(140, 185, 255, 0.3));
}

.glossary-segmented {
    align-self: center;
    display: inline-flex;
    margin: 18px auto 4px;
    padding: 4px;
    background: rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 999px;
    box-shadow:
        inset 0 2px 6px rgba(0, 0, 0, 0.45),
        inset 0 -1px 0 rgba(255, 255, 255, 0.08),
        0 1px 0 rgba(255, 255, 255, 0.06);
}

.seg-btn {
    font-family: var(--font-oxanium);
    font-size: 11px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    padding: 9px 22px;
    background: transparent;
    border: none;
    border-radius: 999px;
    color: var(--text-tertiary);
    cursor: pointer;
    transition: background 250ms var(--ease), color 250ms var(--ease);
}

.seg-btn:hover {
    color: var(--text-primary);
}

.seg-btn.seg-active {
    background:
        linear-gradient(180deg,
            rgba(200, 222, 250, 0.16) 0%,
            rgba(170, 200, 235, 0.10) 60%,
            rgba(140, 175, 220, 0.07) 100%);
    color: #f0f6ff;
    text-shadow: 0 0 6px rgba(180, 210, 240, 0.30);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.16),
        inset 0 0 0 1px rgba(255, 255, 255, 0.04),
        inset 0 -1px 3px rgba(0, 30, 60, 0.18),
        0 0 16px rgba(180, 210, 255, 0.18);
}

.glossary-brief {
    display: none;
    flex-direction: column;
    max-width: 860px;
    width: 100%;
    margin: 32px auto 0;
}

#glossary-view.brief-mode .glossary-brief { display: flex; }
#glossary-view.brief-mode .glossary-flow  { display: none; }

.glossary-brief-card .glossary-brief-signals {
    margin: 6px 0 14px 0;
    gap: 10px;
}

.glossary-brief-card .glossary-brief-signals li::before {
    background: rgba(255, 255, 255, 0.55);
    width: 10px;
}

.glossary-brief-card .glossary-tagline {
    margin-top: 10px;
    padding-top: 14px;
}


/* Source-distinguished registry cards — Option A treatment.
   User-registered cards keep the same canvas/photo layout but get a small
   "Yours" badge so the investor sees their addition at a glance.
*/
.card-container.is-user-upload .card-name::after {
    content: "Yours";
    display: inline-block;
    margin-left: 10px;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.96);
    background: linear-gradient(135deg, rgba(255, 200, 64, 0.92), rgba(232, 96, 196, 0.92));
    padding: 3px 8px;
    border-radius: 999px;
    vertical-align: middle;
}

/* ════════════════════════════════════════════════════════════════════════
   MOBILE RESPONSIVE LAYER  ·  appended last, fully inside @media blocks
   ────────────────────────────────────────────────────────────────────────
   Every rule here lives inside a width-bounded media query, so the desktop
   layout is provably untouched — these rules never match at desktop widths.
   Where a desktop or earlier-mobile rule needs overriding, the selector
   below matches its specificity and wins on source order.

   Covers every view: registry · original · category · examine · glossary ·
   verdict — plus the iCO nav and its fan-out menu.
   ════════════════════════════════════════════════════════════════════════ */

@media (max-width: 768px) {

    /* Defensive: kill sideways scroll; stop mobile browsers auto-inflating copy. */
    body { overflow-x: hidden; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

    /* ─── iCO — docked bottom-centre on every content view ──────────────
       Same dock everywhere (registry + original + category + verdict).
       Spheres now sit above the artwork inside the scrollable original
       view, so the bottom-centre slot is free for the iCO again. */
    body:is(:has(#registry-view.active), :has(#original-view.active), :has(#category-view.active), :has(#verdict-view.active), :has(#examine-view.active)) .ico-container {
        width: 120px;
        height: 120px;
        top: auto;
        /* The iCO canvas carries ~27px of transparent padding around the
           orb, so a positive `bottom` leaves it visibly floating. Pull the
           container down by that padding to seat the orb on the screen edge;
           env() still lifts it clear of a home-indicator inset. */
        bottom: calc(-26px + env(safe-area-inset-bottom, 0px));
        left: 50%;
        right: auto;
        transform: translateX(-50%);
    }
    body:has(#glossary-view.active) .ico-container,
    body:has(#category-view.active) .ico-container,
    body:has(#verdict-view.active) .ico-container {
        display: none;
    }

    /* iCO fan-out menu — labels stack straight up from the docked sphere.
       Single fan-up pattern for every view that shows the iCO. */
    .ico-menu-arc { display: none; }
    /* When menu is open, cap label opacity to 0.5 so they blend in
       instead of asserting themselves. Wins over the desktop opacity:1
       rule via !important since both selectors target the open state. */
    /* Touch-only: scope the opacity cap to .menu-pinned ONLY (no :hover).
       iOS Safari makes :hover sticky after a tap, so if we kept :hover
       in this selector the menu would never visually close even after
       the JS auto-close timer removed .menu-pinned. */
    @media (hover: none) {
        body:is(:has(#registry-view.active), :has(#original-view.active), :has(#category-view.active), :has(#verdict-view.active), :has(#examine-view.active)) .ico-container.menu-pinned .ico-menu-item {
            opacity: 0.68 !important;
        }
    }
    /* Real-hover devices keep the hover-or-pinned trigger. */
    @media (hover: hover) {
        body:is(:has(#registry-view.active), :has(#original-view.active), :has(#category-view.active), :has(#verdict-view.active), :has(#examine-view.active)) .ico-container:is(:hover, .menu-pinned) .ico-menu-item {
            opacity: 0.68 !important;
        }
    }
    .ico-menu-item {
        top: auto;
        left: 50%;
        transform: translate(-50%, 10px);
        transform-origin: center;
        font-size: 10px;
        letter-spacing: 0.06em;
        /* Softer etched-gradient on mobile so labels blend into the
           background instead of reading as solid pills. */
        background-image: linear-gradient(170deg, rgba(255, 255, 255, 0.10) 0%, rgba(195, 220, 255, 0.06) 100%) !important;
        /* The base rule adds a dark drop-shadow behind the text which
           pulls readability up even at low gradient alphas — drop it
           entirely on mobile so labels fully blend with the bg. */
        filter: none !important;
    }
    /* Expand the invisible hit zone for thumb taps — desktop's -10/-16
       inset is fine for a mouse but the 10px ghosted text on mobile is
       almost impossible to land a finger on. Tight default so siblings
       and the orb area aren't swallowed; per-item overrides below grow
       the zone *outward* (away from the orb) for the triangle layout. */
    .ico-menu-item::before {
        inset: -14px -22px;
    }

    /* Triangle layout (examine + per-artwork): expand each label's hit
       zone OUTWARD only, so the orb's centre stays tappable and labels
       don't fight each other for overlapping taps. Glossary grows left,
       Test grows right, Home grows upward. */
    body:is(:has(#examine-view.active), :has(#original-view.active)) .ico-menu-glossary::before {
        inset: -22px 0 -22px -64px;
    }
    body:is(:has(#examine-view.active), :has(#original-view.active)) .ico-menu-test::before {
        inset: -22px -64px -22px 0;
    }
    body:is(:has(#examine-view.active), :has(#original-view.active)) .ico-menu-home::before {
        inset: -52px -28px 0 -28px;
    }
    .ico-menu-home     { bottom: calc(100% + 78px); }
    .ico-menu-test     { bottom: calc(100% + 42px); }
    .ico-menu-glossary { bottom: calc(100% + 6px); }
    .ico-container:is(:hover, .menu-pinned) .ico-menu-item {
        transform: translate(-50%, 0);
    }

    /* Triangle fan-out applied to test-an-image AND per-artwork
       (#original-view). Each label's near-edge anchored 18px from the
       container edge (~9px outside the orb's visible circumference) for
       symmetric clearance. Examine: Home above, Glossary left, Test
       right. Per-artwork: Glossary above (centred — keeps the longest
       label balanced over the orb), Home left, Test right. */
    body:has(#examine-view.active) .ico-menu-home,
    body:has(#original-view.active) .ico-menu-glossary {
        bottom: calc(100% - 18px);
        left: 50%;
        top: auto;
        right: auto;
        transform: translate(-50%, 10px);
    }
    body:has(#examine-view.active) .ico-container:is(:hover, .menu-pinned) .ico-menu-home,
    body:has(#original-view.active) .ico-container:is(:hover, .menu-pinned) .ico-menu-glossary {
        transform: translate(-50%, 0);
    }
    body:has(#examine-view.active) .ico-menu-glossary,
    body:has(#original-view.active) .ico-menu-home {
        top: 50%;
        bottom: auto;
        left: auto;
        right: calc(100% - 18px);
        transform: translate(10px, -50%);
    }
    body:has(#examine-view.active) .ico-container:is(:hover, .menu-pinned) .ico-menu-glossary,
    body:has(#original-view.active) .ico-container:is(:hover, .menu-pinned) .ico-menu-home {
        transform: translate(0, -50%);
    }
    body:is(:has(#examine-view.active), :has(#original-view.active)) .ico-menu-test {
        top: 50%;
        bottom: auto;
        right: auto;
        left: calc(100% - 18px);
        transform: translate(-10px, -50%);
    }
    body:is(:has(#examine-view.active), :has(#original-view.active)) .ico-container:is(:hover, .menu-pinned) .ico-menu-test {
        transform: translate(0, -50%);
    }

    /* On per-artwork and home pages, the full "Test an image" label is
       too wide and breaks the visual balance. Hide the rendered text
       via font-size:0 and inject a shorter "Test" via ::after — the
       existing ::before is reserved for the hit zone, so ::after
       handles the visible label here without conflicting. */
    body:is(:has(#original-view.active), :has(#registry-view.active)) .ico-menu-test {
        font-size: 0 !important;
        letter-spacing: 0 !important;
    }
    body:is(:has(#original-view.active), :has(#registry-view.active)) .ico-menu-test::after {
        content: "Test";
        font-family: var(--font-oxanium);
        font-size: 10px;
        font-weight: 300;
        letter-spacing: 0.06em;
        text-transform: uppercase;
        background-image: linear-gradient(170deg, rgba(255, 255, 255, 0.10) 0%, rgba(195, 220, 255, 0.06) 100%);
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
    }
    /* iOS Safari "sticky :hover" fix — after a tap, the touched element
       stays in :hover state until you tap elsewhere. Combined with the
       menu's :hover-or-pinned reveal rules, that means tapping the iCO
       opens the menu (via :hover) but tapping it again can't actually
       close it — the sticky :hover keeps it open even though .menu-pinned
       was toggled off. Neutralise the :hover trigger on touch-only
       devices so .menu-pinned (toggled by ico.js on tap) is the sole
       controller of menu visibility. */
    @media (hover: none) {
        .ico-container:hover .ico-menu-item {
            opacity: 0 !important;
            pointer-events: none !important;
        }
        .ico-container.menu-pinned .ico-menu-item {
            opacity: 1 !important;
            pointer-events: auto !important;
        }
    }

    .ico-menu::before {                                  /* hover bridge — points up */
        top: auto;
        bottom: 100%;
        left: -28px;
        right: -28px;
        width: auto;
        height: 120px;
    }
    /* Triangle layout doesn't need a tall upward bridge — labels sit at
       the orb's sides (Glossary/Test) and just above it (Home). Trim
       the bridge so it doesn't steal taps from the Run Detection button. */
    body:is(:has(#examine-view.active), :has(#original-view.active)) .ico-menu::before {
        height: 36px;
    }

    /* ─── Examine + Glossary Back button ─────────────────────────────────
       Desktop pins these with wide-screen pixel offsets that fall off-screen
       on a phone — re-dock top-left (no iCO there to collide with). */
    #examine-view .btn-back,
    #glossary-view .btn-back {
        top: calc(14px + env(safe-area-inset-top, 0px));
        left: 14px;
        right: auto;
    }

    /* Glass-panel back buttons run too large on mobile — shrink from
       44×44 to 34×34 across all four views (examine, glossary, category,
       verdict). SVG glyph proportional inside. */
    #examine-view .btn-back,
    #glossary-view .btn-back,
    .cat-page-glass > .btn-back,
    .verdict-glass .verdict-back {
        width: 34px;
        height: 34px;
    }
    #examine-view .btn-back svg,
    #glossary-view .btn-back svg,
    .cat-page-glass > .btn-back svg,
    .verdict-glass .verdict-back svg {
        width: 14px;
        height: 14px;
    }

    /* ─── Original view ───────────────────────────────────────────────────
       New mobile layout: spheres appear at the TOP (between NEYA header
       and the artwork), iCO is bottom-centre across all views. We make
       #original-view a flex column and reorder #original-sections so the
       sphere carousel flows above .original-hero — the DOM order keeps
       it after the hero (legacy from desktop where it pins to the bottom
       of the viewport), so we override visual order via `order`.
       padding-bottom reserves room for the bottom-docked iCO. */
    #original-view {
        padding: 14px 14px 172px 14px !important;
        overflow-x: hidden;
    }
    /* display:flex must be scoped to the ACTIVE state — otherwise it beats
       the `.view { display: none }` rule (lower specificity) and leaves the
       original-view as an invisible-but-tappable layer covering the entire
       viewport on every other view (home/category/verdict), eating taps. */
    #original-view.active {
        display: flex;
        flex-direction: column;
    }
    #original-view > .page-header { order: 0; flex-shrink: 0; }
    #original-view[data-original] #original-sections { order: 1; flex-shrink: 0; }
    #original-view[data-original] .original-hero { order: 2; }
    #original-view[data-original] .original-hero { margin-top: 8px; }
    /* Lift every original's artwork panel below the top sphere bar so the
       composition reads consistently across face / landscape / abstract /
       portrait — same gap, same panel proportions, same button trio. */
    #original-view[data-original] .artwork-clip { margin-top: 14px; }

    /* Full-content-width glass panel, centred by auto margins. */
    #original-view[data-original] .original-hero-imgwrap {
        width: 100% !important;
        margin-left: auto;
        margin-right: auto;
    }
    /* Trim the original-page label chip ("FACE" / "LANDSCAPE" / "ABSTRACT"
       / "PORTRAIT") to match the panel proportions. */
    #original-view[data-original] .original-hero-imgwrap::after {
        font-size: 11px;
        letter-spacing: 0.2em;
        padding: 5px 11px;
    }
    /* Tighten the gap between eye/fingerprint/control so the trio reads
       as a compact cluster instead of three spaced-out icons. */
    #original-view[data-original] .title-row {
        gap: 12px;
    }
    #original-view[data-original] .title-row .btn-eye,
    #original-view[data-original] .title-row .btn-fingerprint {
        width: 38px;
        height: 38px;
        padding: 8px;
    }
    #original-view[data-original] .title-row .btn-eye svg,
    #original-view[data-original] .title-row .btn-fingerprint svg {
        width: 22px;
        height: 22px;
    }
    /* Per-original-id selector list matches the desktop bottom-pinned rule's
       specificity (2,1,0) so the in-flow reset wins on source order. */
    #original-view[data-original="face"] #original-sections,
    #original-view[data-original="abstract"] #original-sections,
    #original-view[data-original="landscape"] #original-sections,
    #original-view[data-original="portrait"] #original-sections {
        position: static;
        bottom: auto;
        left: auto;
        right: auto;
        margin: 0;
        z-index: auto;
        pointer-events: auto;
    }
    /* Prev/next arrows sized to match the eye/fingerprint/control button
       trio on the face panel — same 32×32 frame, same 18px glyph — so
       all five circular UI elements on the face view read as one
       consistent button language. Nudged inward to overlay the left and
       right edges of the (now full-width) face panel and dropped slightly
       below vertical centre to sit at the face image's mid-height. */
    .orig-nav {
        width: 38px;
        height: 38px;
        top: 62%;
    }
    .orig-nav svg {
        width: 22px;
        height: 22px;
    }
    .orig-nav--prev { left: 24px; }
    .orig-nav--next { right: 24px; }

    /* Mobile: hide the registry (main page) prev/next arrows.
       Per-original arrows remain visible. */
    #registry-view #registry-nav-prev,
    #registry-view #registry-nav-next { display: none; }

    /* Floating back buttons hidden on mobile across reading/exploration
       views — the iCO sphere docked at the bottom carries Home, and the
       browser back gesture works natively, so these buttons were
       redundant and ate content space. Covers glossary, test-an-image
       (examine), and the category spheres view. */
    #glossary-view .btn-back,
    #examine-view .btn-back,
    .cat-page-glass > .btn-back {
        display: none;
    }

    /* Expand-all toggle hidden on mobile — tapping each card to open it
       reads naturally on touch, and the bulk-expand button added clutter
       to the slim mobile header. */
    .glossary-expand-btn {
        display: none;
    }

    /* ─── Category view — body-scrolled; reserve room for the floating iCO. */
    #category-view { padding-bottom: 172px; }
    /* Extra top padding clears the panel's absolutely-positioned Back button,
       which sits closer to the centred title once the panel is phone-width. */
    .cat-page-glass { padding-top: 60px !important; }
    /* Desktop centres the hero + cases vertically inside `min-height: 100vh`
       via flex auto-margins. On a phone the same rule pushes the content
       ~250 px below the header, so landing on this view from a fingerprint/
       control/sphere tap shows header + empty band + (offscreen) content —
       the user has to scroll down to find anything. Disable the centring
       on mobile so content sits flush below the header. */
    #category-view.active {
        display: block;
    }
    #category-view #category-hero { margin-top: 0; }
    #category-view #category-cases { margin-bottom: 0; }

    /* ─── Verdict view ───────────────────────────────────────────────────*/
    #verdict-view { padding: 16px 16px 172px 16px !important; overflow-x: hidden; }
    /* padding-top clears the panel's absolutely-positioned Back button. */
    .verdict-glass { max-width: 100%; margin: 16px auto 0; padding: 60px 18px 26px; }
    .verdict-glass .verdict-images { margin-bottom: 20px; }
    .signal-row { gap: 16px 22px; }
    /* The watermark-code hover overlay is a fixed 180px square on desktop —
       clamp it to the mobile thumbnail so it can't overflow sideways. */
    .verdict-img-slot { width: 126px; }
    .verdict-img-slot img { width: 126px; height: 126px; }
    .verdict-code-overlay { width: 126px; height: 126px; gap: 5px; padding: 8px; }
    .verdict-code-hex { font-size: 12px; }
    .verdict-code-overlay.is-absent .verdict-code-hex { font-size: 11px; }
    .verdict-code-bits { font-size: 7.5px; letter-spacing: 0.05em; }
    .verdict-code-label { font-size: 7px; }
    .analyzing-loader { width: 168px; height: 168px; }
    /* Trim the analyzing copy on small screens — desktop sizes read too
       loud beside the 168px orb. */
    .analyzing-heading { font-size: 10px; letter-spacing: 0.2em; }
    .analyzing-subline { font-size: 12px; }

    /* (The mobile mix-blend-mode hack that used to live here was retired
       once alpha-video.js shipped — face/abstract now have proper alpha
       on every browser including iOS Safari, so the desktop drop-shadow
       filter applies on mobile too.) */

    /* ─── Examine view ───────────────────────────────────────────────────
       One-viewport layout: header pinned top, image-pair centred, Run
       Detection pinned bottom. Slots sit side-by-side (mirroring the
       comparison) at ~46vw each so both fit a typical phone width. */
    #examine-view {
        padding: 16px 14px calc(20px + env(safe-area-inset-bottom, 0px)) !important;
        overflow-x: hidden;
        overflow-y: auto;
    }
    #examine-view.active {
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        min-height: 100vh;
        min-height: 100dvh;
    }
    .examine-header { margin-bottom: 0; flex-shrink: 0; }
    .registry-thumb img { width: 80px; height: 80px; }   /* registry-preview thumbs */

    /* Image pair — switch from stacked-column back to side-by-side row on
       mobile. Each slot ~46vw with a small gap. Centred vertically in the
       remaining viewport height by the parent's space-between. */
    #examine-view.active .image-pair {
        flex-direction: row;
        align-items: stretch;
        justify-content: center;
        gap: 10px;
        width: 100%;
        margin: 0;
    }
    #examine-view.active .image-slot {
        width: calc(50% - 5px);
        max-width: 46vw;
    }
    #examine-view.active .image-caption {
        font-size: 12px;
        letter-spacing: 0.18em;
        margin-bottom: 6px;
    }
    /* Slim the registry preview + upload affordance so two slots fit
       comfortably. Thumbs scroll horizontally instead of wrapping —
       4 showcase originals + any user uploads all live on one row,
       swipeable in place. Scrollbar hidden for clean glass look. */
    #examine-view.active .registry-preview {
        gap: 6px;
        padding: 6px;
        flex-wrap: nowrap;
        justify-content: flex-start;
        overflow-x: auto;
        overflow-y: hidden;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    #examine-view.active .registry-preview::-webkit-scrollbar { display: none; }
    #examine-view.active .registry-thumb { flex-shrink: 0; }

    /* Mobile-only row for user-uploaded originals — sits below the
       auto-scrolling carousel so user content doesn't get pulled into
       the loop. Empty unless the user has registered an image. */
    #examine-view.active .registry-uploads-row {
        display: flex;
        flex-wrap: wrap;
        gap: 6px;
        justify-content: center;
        padding: 8px 6px 0;
    }
    #examine-view.active .registry-uploads-row:empty { display: none; }

    /* When user uploads exist, let the registry frame grow taller than
       the square aspect-ratio so the carousel keeps its natural height
       instead of being squeezed by the uploads row sharing the same box.
       Scoped to :has(.registry-uploads-row:not(:empty)) so the frame
       only stretches when there's actually content below. */
    #examine-view.active .image-frame:has(.registry-uploads-row:not(:empty)) {
        aspect-ratio: auto;
        min-height: 46vw;
    }
    #examine-view.active .registry-thumb img { width: 38px; height: 38px; }
    /* Per-original labels (Face, Landscape, …) inside the thumb grid. */
    #examine-view.active .registry-thumb-label {
        font-size: 0.45rem;
        letter-spacing: 0.06em;
    }
    /* Shift the whole upload-row so every button state (idle upload
       icon, download pill, delete-armed pill, …) sits at the same spot. */
    #examine-view.active .registry-upload-row {
        transform: translateY(16px);
    }
    /* Idle state — circular icon button (48×48 on desktop). Shrunk
       proportionally for mobile registry panel. */
    #examine-view.active .btn-upload:not([data-state]) {
        width: 32px;
        height: 32px;
    }
    #examine-view.active .btn-upload:not([data-state]) .btn-upload-icon {
        width: 14px;
        height: 14px;
    }
    /* Data-state variants (loading / delete-armed / error) use a labeled
       pill — keep them readable but tighter than desktop. */
    #examine-view.active .btn-upload[data-state] {
        font-size: 8px;
        padding: 4px 7px;
        gap: 3px;
        letter-spacing: 0.08em;
    }
    #examine-view.active .upload-zone .upload-text {
        font-size: 10px;
        letter-spacing: 0.04em;
        padding: 0 6px;
        line-height: 1.4;
    }

    /* Pin the Run Detection action to the bottom. translateY lifts it
       above the iCO without disturbing the image-pair (which centres
       above via flex space-between). The earlier "tap-passes-to-iCO"
       bug was the iCO hover bridge eating the tap, not the transform —
       that bridge is now scoped down for triangle layout pages. */
    #examine-view.active .examine-action {
        flex-shrink: 0;
        margin-bottom: 0;
        margin-top: 0;
        width: 100%;
        transform: translateY(-160px);
    }
    /* Nudge the "Upload an image first" / "Test against NEYA" label down
       so it sits closer to the button instead of floating in the gap
       above. */
    #examine-view.active .case-label {
        margin-top: 40px;
    }

    /* ─── Glossary — had no mobile styling; size it for a phone. ──────────*/
    #glossary-view.active { padding: 16px 14px 76px; }
    /* +24px (16 → 40) compensates for the segmented bar's translateY(24px)
       — without it the brief / flow panel underlaps the visually-shifted
       button. */
    .glossary-flow,
    .glossary-brief { margin-top: 40px; gap: 14px; }
    .glossary-card { padding: 20px 17px; border-radius: 14px; }
    .glossary-term { font-size: 13.5px; letter-spacing: 0.1em; margin-bottom: 12px; }
    .glossary-def,
    .glossary-list li { font-size: 13.5px; line-height: 1.62; }
    .glossary-sub { padding: 14px 14px; margin-top: 14px; }
    .glossary-subterm { font-size: 12px; letter-spacing: 0.12em; }
    .glossary-meta { font-size: 12px; }
    .glossary-meta-label { font-size: 10px; }
    .glossary-tiers { gap: 12px; }
    .tier-name { font-size: 12px; }
    .tier-desc { font-size: 12.5px; }
    /* margin-top stays at 14px (original) so content below isn't pushed.
       translateY visually nudges just the segmented bar down without
       changing layout flow. */
    .glossary-segmented { margin-top: 14px; transform: translateY(24px); }
    .seg-btn { font-size: 9px; padding: 6px 14px; letter-spacing: 0.14em; }

    /* ─── Header — trim weight on small screens. ─────────────────────────*/
    /* Match the inner-view header to the home page: same logo height and
       subtitle size for a consistent brand-bar across every view. */
    .page-header--inner .brand-logo { height: 32px; }
    .page-header--inner .subtitle   { font-size: 8px; }
}

/* ─── Landscape phones — the registry's fixed-height carousel needs smaller
   cards and a smaller iCO so nothing clips in the short viewport. ──────────*/
@media (max-width: 768px) and (orientation: landscape) {
    #registry-view { padding: 10px 16px 70px 16px; }
    .registry-grid { height: 70vh; }
    .card-container { width: min(34vw, 210px); }
    .card-container[data-pos="1"]  { transform: translate(-50%, -50%) translateX(33vw)  scale(0.5); }
    .card-container[data-pos="-1"] { transform: translate(-50%, -50%) translateX(-33vw) scale(0.5); }
    .card-container[data-pos="2"]  { transform: translate(-50%, -50%) translateX(64vw)  scale(0.34); }
    .card-container[data-pos="-2"] { transform: translate(-50%, -50%) translateX(-64vw) scale(0.34); }
    .card-name { margin-top: 2px; }
    body:has(#registry-view.active) .ico-container { width: 92px; height: 92px; }
    body:is(:has(#original-view.active), :has(#category-view.active), :has(#verdict-view.active)) .ico-container {
        width: 88px; height: 88px;
    }
}

/* ─── Very small phones ─────────────────────────────────────────────────*/
@media (max-width: 380px) {
    .page-header--inner .brand-logo { height: 34px; }
    .verdict-label { font-size: 24px; }
    .verdict-img-slot,
    .verdict-img-slot img,
    .verdict-code-overlay { width: 112px; }
    .verdict-img-slot img,
    .verdict-code-overlay { height: 112px; }
    .glossary-card { padding: 17px 14px; }
}
