/* CSS Custom Properties - Exact from cleanUI.html */
:root {
    /* Core color tokens for consistent theming */
    --bg-primary: #000000;
    --bg-secondary: #1a1a1a;
    --bg-tertiary: #2a2a2a;
    --bg-light: #333333;

    --text-primary: #f8f9fa;
    --text-secondary: #a8a8a8;
    --text-muted: #606060;

    /* Animation timing tokens */
    --transition-fast: 0.15s;
    --transition-medium: 0.3s;
    --transition-slow: 0.4s;
    --easing-smooth: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

/* Reset and base styles - Exact from cleanUI.html */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    background: var(--bg-primary);
    color: white;
    /* Kills the double-tap-to-zoom gesture. Without it a hold-then-tap on
       the gallery could leave iOS zoomed into the page, which reads as the
       site having grown and gone unresponsive until you tap again. */
    touch-action: manipulation;
    font-family: "JetBrains Mono", monospace;
    font-weight: 100;
    line-height: 1.6;
    overflow: hidden;
    height: 100vh;
    /* 100vh on mobile Chrome is the height with the address/tab bar
       collapsed, so on load (bar expanded) the body is taller than the
       visible viewport and everything below the fold reads as "pushed
       down". dvh tracks the bar's actual state; vh above is just the
       fallback for browsers without dvh support. */
    height: 100dvh;
    font-size: 0.9rem;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none; /* Firefox */
    -ms-user-select: none; /* IE10+/Edge */
    user-select: none; /* Standard */
    /* Stops the iOS/Android long-press callout (Copy/Share/Save Image) from
       popping up over the tap-and-hold gallery reveal - user-select alone
       only blocks text selection, not this menu. */
    -webkit-touch-callout: none;
}

/* Allow selection in form fields and inputs */
input,
textarea,
[contenteditable="true"] {
    -webkit-user-select: text !important;
    -moz-user-select: text !important;
    -ms-user-select: text !important;
    user-select: text !important;
}

/* Prevent drag and drop of images and videos */
img,
video {
    -webkit-user-drag: none;
    -khtml-user-drag: none;
    -moz-user-drag: none;
    -o-user-drag: none;
    pointer-events: none; /* Prevents selection of the media elements */
    user-select: none; /* Standard way to prevent selection */
    -webkit-user-select: none; /* Safari */
    -ms-user-select: none; /* IE10 and IE11 */
}

/* Loading Overlay */
.loading-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    background: #000;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    transition: opacity 0.75s ease;
}

.loading-overlay.hidden {
    opacity: 0;
    pointer-events: none;
}

.text-wall {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    opacity: 0.5; /* Increased opacity for better visibility */
    font-size: 10px;
    line-height: 1.2;
    color: #8790de; /* Matches starfield palette */
    overflow: hidden;
    white-space: pre;
    pointer-events: none;
    z-index: 1;
    font-family: monospace;
    transition: opacity 0.225s ease;
}

/* The wall's characters are drawn into a single <canvas> child (see
   createTextWall in script.js), not per-character elements. The former
   .tw-cell/.tw-word rules that lived here - per-cell opacity reveal and a
   `filter: brightness()` flash on words - were removed with them: at ~18k
   elements that per-element style work could not hold frame rate, which is
   the whole reason rendering moved to canvas. The wall's own color, opacity
   and fade-out transition above still apply, since the canvas is a child of
   this element. */

/* Master Glitch Effects */
.glitch-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    background: #000;
    z-index: 2000;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.075s ease;
}

.glitch-overlay.active {
    opacity: 1;
    pointer-events: all;
}

.glitch-animation {
    animation: glitch 0.3s ease-in-out infinite;
}

@keyframes glitch {
    0% {
        transform: translate(0) scale(1);
        filter: blur(0px) hue-rotate(0deg);
    }
    10% {
        transform: translate(-15px, 5px) scale(1.05);
        filter: blur(2px) hue-rotate(30deg);
    }
    20% {
        transform: translate(10px, -8px) scale(0.95);
        filter: blur(1px) hue-rotate(-20deg);
    }
    30% {
        transform: translate(-8px, 3px) scale(1.02);
        filter: blur(1.5px) hue-rotate(45deg);
    }
    40% {
        transform: translate(12px, -5px) scale(0.98);
        filter: blur(0.5px) hue-rotate(-15deg);
    }
    50% {
        transform: translate(-5px, 8px) scale(1.01);
        filter: blur(1px) hue-rotate(25deg);
    }
    60% {
        transform: translate(8px, -3px) scale(0.99);
        filter: blur(0.8px) hue-rotate(-10deg);
    }
    70% {
        transform: translate(-3px, 5px) scale(1.03);
        filter: blur(1.2px) hue-rotate(35deg);
    }
    80% {
        transform: translate(6px, -2px) scale(0.97);
        filter: blur(0.3px) hue-rotate(-5deg);
    }
    90% {
        transform: translate(-2px, 3px) scale(1.01);
        filter: blur(0.7px) hue-rotate(15deg);
    }
    100% {
        transform: translate(0) scale(1);
        filter: blur(0px) hue-rotate(0deg);
    }
}

.noise {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background:
        radial-gradient(
            circle at 30% 30%,
            rgba(255, 255, 255, 0.05) 0%,
            transparent 50%
        ),
        radial-gradient(
            circle at 70% 70%,
            rgba(255, 255, 255, 0.03) 0%,
            transparent 50%
        );
    opacity: 0;
    animation: noise 1.5s ease-in-out;
}

@keyframes noise {
    0% {
        opacity: 0;
        transform: scale(1) rotate(0deg);
    }
    33% {
        opacity: 0.4;
        transform: scale(1.02) rotate(0.5deg);
    }
    66% {
        opacity: 0.6;
        transform: scale(0.98) rotate(-0.3deg);
    }
    100% {
        opacity: 0;
        transform: scale(1) rotate(0deg);
    }
}

@keyframes decompose {
    0% {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
    50% {
        opacity: 0.3;
        transform: translateY(-20px) scale(0.9);
    }
    100% {
        opacity: 0;
        transform: translateY(-40px) scale(0.8);
    }
}

@keyframes compose {
    0% {
        opacity: 0;
        transform: translateY(40px) scale(0.8);
    }
    50% {
        opacity: 0.7;
        transform: translateY(10px) scale(0.95);
    }
    100% {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

.glitch-reveal {
    animation: glitchReveal 1.5s ease-out forwards;
}

@keyframes glitchReveal {
    0% {
        opacity: 0;
        transform: scale(1.1) translateZ(0);
        filter: hue-rotate(0deg) brightness(1);
    }
    10% {
        opacity: 1;
        transform: scale(1.05) translateZ(0);
        filter: hue-rotate(90deg) brightness(1.5);
    }
    20% {
        transform: scale(0.98) translateZ(0);
        filter: hue-rotate(180deg) brightness(0.8);
    }
    30% {
        transform: scale(1.02) translateZ(0);
        filter: hue-rotate(270deg) brightness(1.2);
    }
    40% {
        transform: scale(0.99) translateZ(0);
        filter: hue-rotate(360deg) brightness(1.1);
    }
    50% {
        transform: scale(1.01) translateZ(0);
        filter: hue-rotate(45deg) brightness(0.9);
    }
    60% {
        transform: scale(1) translateZ(0);
        filter: hue-rotate(90deg) brightness(1);
    }
    100% {
        opacity: 1;
        transform: scale(1) translateZ(0);
        filter: hue-rotate(0deg) brightness(1);
    }
}

.boot-container {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    max-width: 80%;
    text-align: left;
    z-index: 10;
}

@media (min-width: 769px) {
    .boot-container {
        top: 58%;
    }
}

.boot-text {
    font-size: 1.1rem;
    line-height: 1.6;
    margin-bottom: 2rem;
    color: #ffffff;
}

.boot-line {
    margin: 0.5rem 0;
    opacity: 0;
    transform: translateY(5px);
    transition: all 0.3s ease;
    position: relative;
}

.boot-line.visible {
    opacity: 1;
    transform: translateY(0);
}

.awareness-container {
    position: fixed;
    bottom: 60px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 0.7rem;
    z-index: 15;
    text-align: center;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.awareness-container.visible {
    opacity: 1;
}

.awareness-label {
    margin-bottom: 5px;
    color: #fff;
}

.progress-bar {
    width: 300px;
    max-width: 90vw;
    height: 4px;
    background: #1a1a1a;
    overflow: hidden;
    border-radius: 2px;
}

.progress-fill {
    height: 100%;
    background: #fff;
    width: 0%;
    transition: width 0.225s ease;
}

/* Ensure scene receives pointer events */
.gallery-3d-scene,
.gallery-3d-grid {
    pointer-events: auto;
}

/* AI Button */
.ai-button {
    position: fixed;
    top: 2rem;
    right: 2rem;
    z-index: 150;
    padding: calc(0.6rem + 0.5px) calc(0.9rem - 0.5px) calc(0.6rem - 0.5px) calc(0.9rem + 0.5px);
    font-size: 0.9rem;
    font-family: "JetBrains Mono", monospace;
    font-weight: 100;
    background: rgba(248, 249, 250, 0.95);
    color: var(--bg-primary);
    border: 1px solid white;
    border-radius: 2px;
    cursor: pointer;
    transition: all var(--transition-medium) ease;
    backdrop-filter: blur(10px);
    letter-spacing: 0.02em;
    text-decoration: none !important;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    white-space: nowrap;
}

.ai-button:hover {
    background: black;
    color: white;
    border-color: white;
}

@keyframes colorFlicker {
    0%,
    100% {
        color: var(--text-primary);
        text-shadow: 0 0 3px rgba(255, 255, 255, 0.15);
    }
    20% {
        color: #ff6b6b;
        text-shadow: 0 0 8px rgba(255, 107, 107, 0.4);
    }
    40% {
        color: #4ecdc4;
        text-shadow: 0 0 8px rgba(78, 205, 196, 0.4);
    }
    60% {
        color: #45b7d1;
        text-shadow: 0 0 8px rgba(69, 183, 209, 0.4);
    }
    80% {
        color: #f9ca24;
        text-shadow: 0 0 8px rgba(249, 202, 36, 0.4);
    }
}

/* Ensure all fonts are JetBrains Mono */
* {
    font-family: "JetBrains Mono", monospace !important;
}

.display-1,
.display-2,
.hero-text,
.section-title,
.section-subtitle,
.timeline-paragraph,
.brand,
.nav-text,
.form-input,
.form-select,
.form-textarea,
.btn-primary {
    font-family: "JetBrains Mono", monospace;
}

/* Move Send button in contact form down by 0.25px */
.slide[data-slide="5"] .btn-primary {
    position: relative;
    top: 0.25px;
}

/* Clean content reveal */
/* Home slide reveal classes removed - now handled by JavaScript for consistency */

/* Layout containers */
.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 2rem;
}

/* Fixed UI Elements */
.sound-control {
    position: fixed;
    top: 2rem;
    right: 2rem;
    z-index: 200;
    font-size: 24px;
    cursor: pointer;
    color: white;
}

.brand {
    position: fixed !important;
    bottom: 2rem !important;
    right: 2rem !important;
    top: auto !important;
    left: auto !important;
    z-index: 200;
    background: rgba(248, 249, 250, 0.08);
    padding: 0.5rem 0.75rem;
    border-radius: 2px;
    font-size: 0.75rem;
    color: var(--text-secondary);
    backdrop-filter: blur(10px);
    height: 29px;
    display: flex;
    align-items: center;
    padding-top: calc(0.5rem + 0.25px);
    padding-bottom: calc(0.5rem - 0.25px);
    transition: none;
    transform: none !important;
}

.brand:hover {
    background: rgba(248, 249, 250, 0.08);
    transform: none;
}

/* FPS Display (also cycles/reveals the CO2 line on hover or, on touch, on a timer) */
.fps-display {
    position: fixed;
    top: 2rem;
    left: 2rem;
    z-index: 200;
    color: var(--text-secondary);
    font-family: "Courier New", monospace;
    font-size: 14px;
    font-weight: bold;
    height: 18px;
    overflow: hidden;
}

/* The line window. It is a separate element from .fps-display because the
   mobile pill carries padding, and overflow clips at the padding box - the
   neighbouring lines showed through in that 6px band. */
.stats-viewport {
    height: 18px;
    overflow: hidden;
}

.stats-track {
    display: flex;
    flex-direction: column;
    transition: transform 0.5s ease;
}

.stats-line {
    height: 18px;
    line-height: 18px;
    white-space: nowrap;
}

.stats-line.stats-co2 {
    font-family: inherit;
    font-size: inherit;
    font-weight: bold;
    color: var(--text-secondary);
}

.fps-display[data-stats-step="1"] .stats-track {
    transform: translateY(-18px);
}

/* Navigation system with reduced spacing */
.nav-sections {
    position: fixed;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 200;
    display: flex;
    flex-direction: column;
    gap: 0;
}

.nav-item {
    position: absolute;
    width: 92px;
    height: 29px;
    padding: 0.5rem;
    font-size: 0.9rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    text-align: right;
    opacity: 0.5;
    border-radius: 2px;
    transition: all var(--transition-fast) var(--easing-smooth);
    overflow: hidden;
    white-space: nowrap;
    backdrop-filter: blur(10px);
    z-index: 1;
}

.nav-item.active {
    z-index: 10;
}

.nav-item.transitioning {
    z-index: 50;
    transition:
        z-index 0s linear 0s,
        background 300ms var(--easing-smooth),
        opacity 300ms var(--easing-smooth),
        transform 300ms var(--easing-smooth);
}

/* Distance-based background lightness with better visibility */
.nav-item[data-distance="0"] {
    background: rgba(248, 249, 250, 0.12);
}
.nav-item[data-distance="1"] {
    background: rgba(248, 249, 250, 0.08);
}
.nav-item[data-distance="2"] {
    background: rgba(248, 249, 250, 0.05);
}
.nav-item[data-distance="3"] {
    background: rgba(248, 249, 250, 0.03);
}

.nav-text {
    opacity: 0;
    transition: opacity 150ms var(--easing-smooth);
    filter: brightness(0.5);
}

.nav-item:hover {
    opacity: 1 !important;
    background: rgba(248, 249, 250, 0.15) !important;
    transform: translateY(-1px);
    transition: all var(--transition-medium) var(--easing-smooth);
}

.nav-item:hover .nav-text,
.nav-item.active.show-text .nav-text {
    opacity: 1;
    filter: brightness(1);
}

.nav-item:focus-visible {
    opacity: 1 !important;
    outline: 2px solid #4ade80;
    outline-offset: 2px;
}

.nav-item:focus-visible .nav-text {
    opacity: 1;
    filter: brightness(1);
}

.nav-item.active {
    opacity: 1;
}

/* Slide system */
.slides-container {
    position: relative;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    z-index: 100;
}

.slide {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
    height: 100dvh;
    display: flex;
    align-items: center;
    opacity: 0;
    pointer-events: none;
}

.slide.active {
    opacity: 1;
    pointer-events: all;
}

/* Typography scale */
.display-1 {
    font-size: clamp(2rem, 6vw, 4rem);
    font-weight: 400;
    line-height: 1.1;
    letter-spacing: -0.01em;
    margin-bottom: 2rem;
    opacity: 0; /* Start hidden for animations */
    text-shadow: 0 0 3px rgba(255, 255, 255, 0.15);
}

.display-2 {
    font-size: clamp(1.5rem, 4vw, 2.5rem);
    font-weight: 400;
    line-height: 1.2;
    margin-bottom: 2rem;
    opacity: 0; /* Start hidden for animations */
}

.hero-text {
    font-size: 1.5rem;
    color: #b8b8b8;
    margin: 2rem 0;
    opacity: 0; /* Start hidden for animations */
    text-shadow: 0 0 2px rgba(184, 184, 184, 0.3);
}

.focus-line {
    font-family: "JetBrains Mono", monospace;
    font-size: 0.75rem;
    font-weight: 400;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #8a8a8a;
    margin: 0 0 2rem;
    text-shadow: none;
}

/* Work showcase layout */
.work-content {
    position: absolute;
    right: 15%;
    top: 50%;
    transform: translateY(-50%);
    text-align: right;
    max-width: 600px;
    z-index: 50;
}

/* About and Game slides get wider text */
.slide[data-slide="4"] .work-content,
.slide[data-slide="1"] .work-content {
    max-width: 800px;
}

.section-title {
    font-size: 3.5rem;
    margin-bottom: 1.5rem;
    font-weight: 400;
    line-height: 1.1;
    letter-spacing: -0.01em;
    opacity: 0; /* Start hidden for animations */
    text-shadow: 0 0 3px rgba(255, 255, 255, 0.15);
}

/* Desktop wraps the home subtitle naturally; the forced break is mobile-only. */
.subtitle-break {
    display: none;
}

.section-subtitle {
    font-size: 1.2rem;
    margin-bottom: 0.5rem;
    font-weight: 100;
    color: #ffffff;
    opacity: 0; /* Start hidden for animations */
    text-shadow: 0 0 3px rgba(255, 255, 255, 0.15);
}

.timeline-paragraph {
    color: #a8a8a8;
    margin-bottom: 1.5rem;
    max-width: 600px;
    font-weight: 100;
    line-height: 1.6;
    font-size: 0.9rem;
    opacity: 0; /* Start hidden for animations */
    text-shadow: 0 0 2px rgba(168, 168, 168, 0.3);
}

/* Consecutive paragraphs (same type) sit closer together than the
   subtitle-to-content gap above them. */
.timeline-paragraph:has(+ .timeline-paragraph) {
    margin-bottom: 0.45rem;
}

.timeline-paragraph strong {
    color: #ffffff;
    font-weight: 700;
}

/* About and Game slides get wider paragraphs */
.slide[data-slide="4"] .timeline-paragraph,
.slide[data-slide="1"] .timeline-paragraph {
    max-width: 800px;
}

/* Core/Tested/Base list paragraph sits a touch lower than the tight
   consecutive-paragraph spacing above it, like the subtitle-to-paragraph gap. */
.slide[data-slide="4"] .timeline-paragraph:last-child {
    margin-top: 0.5rem;
}

/* Pulsing brightness hint (DRAG APPS, CLICK/TAP AND HOLD) */
@keyframes pulseHint {
    0%,
    100% {
        filter: brightness(0.6);
    }
    50% {
        filter: brightness(1.5);
    }
}

.pulse-hint {
    display: inline-block;
    animation: pulseHint 1.8s ease-in-out infinite;
    transform: translateY(0.9rem);
}

/* 50% faster pulse - used by the CLICK/TAP AND HOLD hint */
.pulse-hint-fast {
    animation-duration: 0.9s;
}

/* Scroll-down hint: pulsing "SCROLL" label, bottom-center, slide 0 only */
.scroll-hint {
    display: none;
    position: fixed;
    left: 50%;
    bottom: calc(2rem + 8px);
    transform: translateX(-50%);
    z-index: 200;
    color: rgba(248, 249, 250, 0.6);
    font-size: 0.75rem;
    letter-spacing: 0.15em;
    margin-right: -0.15em;
    animation: pulseHint 1.8s ease-in-out infinite;
    pointer-events: none;
}

body:has(.slide[data-slide="0"].active) .scroll-hint {
    display: block;
}

@media (hover: none), (pointer: coarse) {
    .scroll-hint {
        left: 50%;
        bottom: 2.5rem;
    }
}

/* Click/tap to start hint pulses at the same frequency as Spatial Psychology's
   CLICK/TAP AND HOLD hint, but brighter at its peak since it's the slide's
   call to action rather than a secondary hint. */
@keyframes pulseHintBright {
    0%,
    100% {
        filter: brightness(0.6);
    }
    50% {
        filter: brightness(2.4);
    }
}

.slide[data-slide="1"] .hint-desktop:not(.hint-sub),
.slide[data-slide="1"] .hint-mobile:not(.hint-sub) {
    animation: pulseHintBright 0.9s ease-in-out infinite;
}

.work-visual {
    position: absolute;
    right: 50%;
    top: 50%;
    transform: translate(50%, -50%);
    width: 55%;
    aspect-ratio: 16/9;
    background: #080808;
    border-radius: 2px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
    font-size: 0.9rem;
    z-index: 1;
}

/* Form components */
.form-container {
    max-width: 500px;
    margin: 1rem 0;
}

.form-input,
.form-select,
.form-textarea {
    width: 100%;
    padding: 0.65rem 1rem;
    background: rgba(248, 249, 250, 0.95);
    border: none;
    border-radius: 2px;
    color: var(--bg-primary);
    font-size: 1rem;
    margin-bottom: 0.6rem;
    font-family: inherit;
    transition: all var(--transition-medium) ease;
    backdrop-filter: blur(10px);
    opacity: 0; /* Start hidden to prevent flash on first load */
}

/* Text cursor for email and textarea fields */
.form-input,
.form-textarea {
    caret-color: black;
    cursor: text;
}

/* Keep pointer cursor for select and button */
.form-select,
.btn-primary {
    cursor: pointer;
}

.form-input:focus,
.form-select:focus,
.form-textarea:focus {
    outline: none;
    background: rgba(248, 249, 250, 1);
}

.form-input:focus-visible,
.form-select:focus-visible,
.form-textarea:focus-visible {
    outline: 2px solid #4ade80;
    outline-offset: 2px;
}

.form-select {
    cursor: pointer;
    appearance: none;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%23a8a8a8' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M8 6l4 4 -4 4' transform='rotate(0 10 10)'/%3e%3c/svg%3e");
    background-position: right 1rem center;
    background-repeat: no-repeat;
    background-size: 1rem;
    padding-right: 3rem;
}

.form-textarea {
    resize: none;
    min-height: 74px;
    max-height: 150px;
    overflow-y: auto;
}

.btn-primary {
    width: 100%;
    padding: 0.65rem 2rem;
    background: white;
    color: black;
    font-size: 1rem;
    font-family: inherit;
    font-weight: 400;
    border: 1px solid white;
    border-radius: 2px;
    cursor: pointer;
    transition: all var(--transition-medium) ease;
    opacity: 0; /* Start hidden to prevent flash on first load */
}

/* Style the select dropdown arrow */
.form-select {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000000'%3e%3cpath d='M10 17l5-5-5-5v10z'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    background-size: 1.5em;
    padding-right: 2.5rem;
}

.btn-primary:hover {
    background: black;
    color: white;
    border-color: white;
    /* Removed translateY and scale transforms */
    transform: none;
}

/* Social links (contact form) */
.social-links {
    display: flex;
    gap: 0.4rem;
    margin-top: 4rem;
}

.social-link {
    width: 80px;
    height: 80px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(248, 249, 250, 0.95);
    border: none;
    border-radius: 2px;
    color: var(--bg-primary);
    backdrop-filter: blur(10px);
    cursor: pointer;
    transition: all var(--transition-medium) ease;
    opacity: 0; /* Start hidden to prevent flash on first load */
}

.social-link svg {
    width: 32px;
    height: 32px;
}

.social-link-text {
    width: auto;
    padding: 0 1.5rem;
    font-family: "JetBrains Mono", monospace;
    font-size: 0.85rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none !important;
    white-space: nowrap;
}

.social-link:hover {
    background: black;
    color: white;
    outline: 1px solid white;
}

/* Game Container Styles for Slide 3 (Game Dev) */
.game-container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    z-index: 75; /* Between slides (100) and parallax (50) */
    opacity: 1;
    display: none;
    overflow: hidden;
    background: transparent; /* Let Three.js canvas handle background */
    cursor: none;
    pointer-events: auto;
    /* Prevent layout interference */
    contain: strict;
}

/* Remove any CSS interference with canvas */
.game-container canvas {
    /* Let the canvas handle its own positioning via JS */
    pointer-events: auto;
}

/* Game container positioning relative to slide content */
.slide[data-slide="1"] {
    position: relative;
}

.slide[data-slide="1"] .work-content {
    z-index: 100; /* Above game canvas to be visible */
    pointer-events: none; /* Allow game interactions through text */
    position: absolute; /* Match other slides */
    right: 15%; /* Match other slides */
    top: 50%; /* Match other slides */
    transform: translateY(-50%); /* Match other slides */
    text-align: right; /* Match other slides */
    max-width: 800px; /* Wider text for game slide */
}

/* Ensure game slide text elements are visible */
.slide[data-slide="1"] .section-title,
.slide[data-slide="1"] .section-subtitle,
.slide[data-slide="1"] .timeline-paragraph {
    position: relative;
    z-index: 101; /* Above everything */
    pointer-events: none;
}

/* Hide game container on non-game slides */
.slide:not([data-slide="1"]) .game-container {
    display: none !important;
}

/* HYPER THRILL HUD - score, control hints, fullscreen (Slide 3) */
.slide[data-slide="1"] .score-container {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    margin-top: 0.6rem;
    position: relative;
    z-index: 101;
    pointer-events: none;
    opacity: 0; /* Start hidden for animations */
}

.slide[data-slide="1"] .score-current {
    font-size: clamp(1.4rem, 2.2vw, 1.9rem);
    font-weight: 300;
    color: var(--text-primary);
    letter-spacing: 0.02em;
}

.slide[data-slide="1"] .score-best {
    font-size: clamp(1.1rem, 1.6vw, 1.4rem);
    font-weight: 300;
    color: var(--text-secondary);
    letter-spacing: 0.02em;
    min-height: 1em;
}

.slide[data-slide="1"] .control-hints {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    margin-top: 0.9rem;
    position: relative;
    z-index: 101;
    pointer-events: none;
    opacity: 0; /* Start hidden for animations */
}

.slide[data-slide="1"] .hint-desktop,
.slide[data-slide="1"] .hint-mobile {
    font-size: clamp(1.1rem, 1.6vw, 1.4rem);
    font-weight: 300;
    color: rgba(248, 249, 250, 0.5);
    letter-spacing: 0.04em;
}

.slide[data-slide="1"] .hint-sub {
    color: rgba(248, 249, 250, 0.3);
}

/* Desktop/mobile hint toggle - shared by Game and Spatial Psychology slides */
.hint-desktop {
    display: none;
}
.hint-mobile {
    display: none;
}

@media (hover: hover) and (pointer: fine) {
    .hint-desktop {
        display: inline-block;
    }
}

@media (hover: none), (pointer: coarse) {
    .hint-mobile {
        display: inline-block;
    }
}

.slide[data-slide="1"] .fullscreen-hint {
    display: none; /* shown only on pointer:fine via media query below */
    margin-top: 0.4rem;
    font-size: 0.85rem;
    font-weight: 300;
    color: rgba(248, 249, 250, 0.3);
    letter-spacing: 0.04em;
    position: relative;
    z-index: 101;
    pointer-events: none;
    opacity: 0; /* Start hidden for animations */
}

@media (hover: hover) and (pointer: fine) {
    .slide[data-slide="1"] .fullscreen-hint {
        display: block;
    }
}

.fullscreen-btn {
    display: none; /* shown only on touch via media query below */
    position: fixed;
    bottom: 2rem;
    left: 2rem;
    z-index: 9000;
    background: none;
    border: none;
    padding: 0.4rem;
    line-height: 0;
    color: rgba(248, 249, 250, 0.4);
    -webkit-tap-highlight-color: transparent;
}

.portrait-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: #000;
    z-index: 99999;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    color: #fff;
    font-size: 0.75rem;
    font-weight: 300;
    letter-spacing: 0.08em;
    pointer-events: none;
}

.rotate-icon {
    animation: rotate-icon-spin 1.6s ease-in-out infinite;
}

@keyframes rotate-icon-spin {
    0%,
    20% {
        transform: rotate(0deg);
    }
    50%,
    70% {
        transform: rotate(-90deg);
    }
    100% {
        transform: rotate(-90deg);
    }
}

/* Touch/mobile: show fullscreen button, hide the desktop hints */
@media (hover: none), (pointer: coarse) {
    .fullscreen-btn {
        display: block;
    }
}

/* Portrait on touch: show rotate overlay */
@media (hover: none) and (pointer: coarse) and (orientation: portrait) {
    .portrait-overlay {
        display: flex;
    }
}

/* Responsive game container */

/* 3D Gallery Styles for Slide 4 (3D Motion / Spatial Psychology) */
.gallery-3d-container {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100vh;
    height: 100dvh;
    pointer-events: auto; /* allow hover events for gallery items */
    z-index: 20;
    opacity: 0;
    filter: blur(15px);
    /* No CSS transition - GSAP handles all opacity changes */
    perspective: 1000px;
    transform-style: preserve-3d;
}

.gallery-3d-scene {
    position: relative;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
    perspective-origin: 50% 50%;
    will-change: transform;
    transform-style: preserve-3d;
    backface-visibility: hidden;
}

.gallery-3d-grid {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 90%;
    max-width: 1200px;
    height: 75%;
    max-height: 700px;
    transform-style: preserve-3d;
    margin: 0 auto;
    will-change: transform;
    backface-visibility: hidden;
    contain: layout style;
}

/* Unified grid for all images - justified height layout */
.unified-images-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 3px;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
    padding: 20px 0;
    align-items: center;
    align-content: center;
    justify-content: center;
}

/* Responsive unified grid for flexbox */
@media (max-width: 1200px) {
    .unified-images-grid {
        gap: 3px;
    }
    .gallery-item {
        height: 100px;
    }
    .gallery-item[data-media-type="video"] {
        width: calc(100px * 16 / 9);
    }
}

.br-mobile {
    display: none;
}

@media (max-width: 768px) {
    .unified-images-grid {
        gap: 3px;
    }
    .gallery-item {
        height: 80px;
    }
    .gallery-item[data-media-type="video"] {
        width: calc(80px * 16 / 9);
    }
    .br-mobile {
        display: inline;
    }
    .br-desktop {
        display: none;
    }
}

@media (max-width: 576px) {
    .unified-images-grid {
        gap: 3px;
    }
    .gallery-item {
        height: 60px;
    }
    .gallery-item[data-media-type="video"] {
        width: calc(60px * 16 / 9);
    }
}

/* Gallery Item Base Styles */
.gallery-item {
    position: relative;
    background: transparent !important; /* transparent background */
    display: flex;
    align-items: center;
    justify-content: center;
    transform-origin: center center;
    will-change: transform, z-index;
    transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
    width: 100%;
    height: 100%;
    contain: layout style;
    overflow: hidden;
    border-radius: 2px !important;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    transform-style: preserve-3d;
    -webkit-transform-style: preserve-3d;
    pointer-events: auto;
    box-shadow: none; /* no shadow */
    opacity: 0; /* container invisible */
    /* Prevent container blur during transforms */
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
    -webkit-font-smoothing: antialiased;
    /* Enhanced 3D container quality */
    -webkit-perspective: 1000px;
    perspective: 1000px;
}

/* Gallery Image Styles */
.gallery-image {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
    border-radius: 2px !important;
    background: #000 !important; /* solid black background */
    box-shadow: none;
    transform-origin: center center;
    filter: none; /* no filters */
    transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
    pointer-events: auto; /* Enable click events for images */
    opacity: 1 !important; /* images always visible */
    /* High-quality photo rendering - preserve detail */
    image-rendering: -webkit-optimize-contrast;
    image-rendering: high-quality;
    image-rendering: -moz-crisp-edges;
    /* Force GPU acceleration without blur */
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
    -webkit-font-smoothing: antialiased;
}

/* Gallery Video Styles */
.gallery-video {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
    border-radius: 2px !important; /* keep same rounding as pictures */
    background: #000 !important; /* solid black background */
    box-shadow: none;
    transform-origin: center center;
    pointer-events: none; /* Disable all interactions including controls */
    transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
    opacity: 1 !important; /* videos always visible */
    /* High-quality video rendering - prevent CSS blur */
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
    -webkit-font-smoothing: antialiased;
}

.gallery-video::-webkit-media-controls {
    display: none !important;
}

.gallery-video::-webkit-media-controls-enclosure {
    display: none !important;
}

/* Remove any thin borders around video items */
.gallery-item:has(.gallery-video) {
    border: none !important;
    background: #000; /* solid background behind videos too */
}

/* Keep loaded state clean */
.gallery-item:has(.gallery-video.loaded) {
    border: none !important;
    background: #000;
}

/* Video play indicator overlay - no shadow */
.gallery-item:has(.gallery-video)::after {
    content: "▶";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: rgba(255, 255, 255, 0.6);
    font-size: 24px;
    font-weight: bold;
    text-shadow: none;
    opacity: 0.8;
    transition: opacity 0.3s ease;
    pointer-events: none;
    z-index: 2;
}

/* Hide play indicator while video is playing */
.gallery-item.is-playing::after {
    opacity: 0 !important;
}

/* Hide play indicator for brought forward videos */
.gallery-item.brought-forward::after {
    opacity: 0 !important;
}

/* Ensure brought forward items maintain proper scaling */
.gallery-item.brought-forward {
    transform-origin: center center;
}

/* Ensure high quality scaling for brought forward images */
.gallery-item.brought-forward .gallery-image {
    /* Maximum quality rendering for brought forward images */
    image-rendering: -webkit-optimize-contrast;
    image-rendering: high-quality;
    image-rendering: -moz-crisp-edges;
    transform-origin: center center;
    filter: none; /* Remove any filters that might degrade quality */
    /* Force hardware acceleration for crisp scaling */
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
}

.gallery-item.brought-forward .gallery-video {
    transform-origin: center center;
    filter: none; /* Remove any filters that might degrade quality */
    /* Force hardware acceleration for crisp scaling */
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
}

/* Video loading state */
.gallery-item:has(.gallery-video) {
    background: rgba(0, 0, 0, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.1);
}

/* Video loaded state */
.gallery-item:has(.gallery-video.loaded) {
    background: transparent;
    border: none;
}

/* Video failed state - hide completely */
.gallery-item.failed {
    display: none !important;
}

/* Justified height layout - all items same height, variable width */
.gallery-item {
    height: 120px; /* Reduced height to fit better on screen */
    width: auto; /* Width will be calculated based on aspect ratio */
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    overflow: hidden;
}

/* Videos get width based on 16:9 aspect ratio */
.gallery-item[data-media-type="video"] {
    width: calc(120px * 16 / 9); /* ~213px width for 16:9 at 120px height */
}

/* Images will get width dynamically set by JavaScript based on their aspect ratio */
.gallery-item[data-media-type="image"] {
    width: auto; /* Width will be set dynamically */
}

/* Mobile responsive */
@media (max-width: 1200px) {
    .gallery-3d-grid {
        /* left stays 50% from the base rule - it pairs with that rule's
           translate(-50%, -50%) to center regardless of width. Overriding
           left to 2% here without also touching the transform shifted the
           whole grid ~46% of the screen off to the left. */
        width: 96%;
        grid-template-columns: repeat(10, 1fr);
        grid-template-rows: repeat(7, 1fr);
    }
}

@media (max-width: 768px) {
    .work-visual {
        position: relative;
        right: auto;
        top: auto;
        transform: none;
        width: 100%;
        margin-top: 1rem;
    }

    /* Active nav item (distance 0) sits flush with the container's own top
       edge and is 29px tall, so top: var(--m-gutter) puts its vertical
       center within half a pixel of GET IN TOUCH's - same gutter, same
       row. Spacing/behavior otherwise matches desktop (config.navSpacing
       is unconditional again). */
    .nav-sections {
        top: var(--m-gutter);
        transform: translateY(0);
    }

    .gallery-3d-scene {
        perspective: 600px;
    }

    .gallery-item {
        min-height: 40px;
    }
}

@media (max-width: 576px) {
    .gallery-item {
        min-height: 30px;
    }
}

/* Performance Optimizations */
.gallery-3d-container,
.gallery-3d-scene,
.gallery-3d-grid,
.gallery-item,
.gallery-image,
.gallery-video {
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    transform-style: preserve-3d;
    -webkit-transform-style: preserve-3d;
    will-change: transform, opacity;
    contain: layout style;
}

/* Gallery Item Styling */
.gallery-item {
    position: relative;
    overflow: hidden;
    border-radius: 2px;
    pointer-events: auto;
    border: none; /* no borders */
}

.gallery-item img,
.gallery-item video {
    border: none; /* no borders */
    filter: none; /* no filters */
    box-shadow: none; /* no shadows */
}

.gallery-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    border-radius: 2px;
}

/* Ensure proper stacking context */
.gallery-3d-container {
    isolation: isolate;
}

/* Hide gallery on non-3D Motion slides */
.slide:not([data-slide="2"]) .gallery-3d-container {
    display: none;
}

/* MARKET DATA DASHBOARD - SLIDE 5 ONLY (Adaptive Solutions) */
.market-dashboard {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%) scale(var(--app-scale, 1));
    display: flex;
    gap: 0;
    width: 175px;
    height: 491px;
    font-family: "JetBrains Mono", monospace;
    z-index: 10;
    user-select: none;
    opacity: 0;
    transition: transform var(--transition-medium) var(--easing-smooth);
    /* Without this, touch browsers claim the gesture for page panning
       before dashboard.js's pointer-drag handlers see it, so a drag on
       mobile/tablet reads as a swipe and changes slide instead. */
    touch-action: none;
}

/* Once dragged, left/top hold the literal top-left corner instead of a
   center point, so the centering translate is dropped - only the hover/
   drag scale remains. transform-origin has to move to that same corner:
   left/top by themselves only set the box's pre-transform position, and
   the default center origin would still grow the box symmetrically around
   its middle, shifting the rendered top-left corner away from (left, top)
   by half the scale growth (~3.5px at scale 1.04) the instant hover/drag
   scale kicks in. The drag math in dashboard.js assumes left/top IS the
   rendered corner, so that shift read as the widget jumping right as you
   picked it up while hovering. */
.market-dashboard.positioned {
    transform-origin: top left;
    transform: scale(var(--app-scale, 1));
}

.market-dashboard:hover,
.market-dashboard:active,
.market-dashboard.dragging {
    --app-scale: 1.04;
}

.market-dashboard:active {
    cursor: none !important;
}
.market-dashboard.dragging {
    cursor: none !important;
    transition: none;
}

.market-dashboard.dragging * {
    cursor: none !important;
}

.market-feed-container,
.analytics-container {
    background: #141414;
    border: 1px solid #333333;
    font-size: 0.75rem;
    color: var(--text-primary);
    overflow: hidden;
    transition: all 0.3s ease;
    animation: fadeInDashboard 0.8s ease-out;
}

@keyframes fadeInDashboard {
    0% {
        opacity: 0;
        transform: translate(-50%, -50%) translateY(30px);
    }
    38% {
        opacity: 0;
        transform: translate(-50%, -50%) translateY(30px);
    }
    100% {
        opacity: 1;
        transform: translate(-50%, -50%) translateY(0);
    }
}

.market-feed-container {
    width: 175px;
    border-radius: 2px;
}

.analytics-container.active {
    opacity: 1;
}

.dashboard-header {
    padding: 12px 16px;
    background: #1f1f1f;
    border-bottom: 1px solid #333333;
    font-weight: 500;
    font-size: 0.9rem;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: #ffffff;
    text-align: center;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    height: 45px;
    box-sizing: border-box;
    padding-top: 11.75px; /* Reduced by 4px to move text higher */
}

.timespan-controls {
    display: flex;
    gap: 4px;
}

.timespan-btn {
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.2);
    color: rgba(255, 255, 255, 0.7);
    padding: 4px 8px;
    border-radius: 2px;
    font-size: 0.6rem;
    font-family: "JetBrains Mono", monospace;
    cursor: none !important;
    transition: all 0.2s ease;
    transform: translateY(4px);
}

.timespan-btn:hover {
    background: rgba(255, 255, 255, 0.15);
    color: rgba(255, 255, 255, 0.9);
}

.timespan-btn.active {
    background: rgba(74, 222, 128, 0.2);
    border-color: #4ade80;
    color: #4ade80;
}

/* Market Feed Stock List */
.stock-list {
    height: calc(100% - 45px);
    overflow: visible;
    padding: 12px;
}

.stock-item {
    display: flex;
    flex-direction: column;
    padding: 12px 10px;
    margin-bottom: 3px;
    background: #101010;
    border-radius: 2px;
    transition: all 0.2s ease;
    border-left: 3px solid transparent;
}

.stock-item:hover {
    background: #1c1c1c;
}

.stock-info {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 4px;
    transform: translateY(2px);
}

.stock-symbol {
    font-weight: 600;
    color: #fff;
    font-size: 0.8rem;
}

.stock-price {
    font-weight: 500;
    font-size: 0.75rem;
    color: #e0e0e0;
}

.stock-data {
    display: flex;
    justify-content: space-between;
    align-items: center;
    transform: translateY(2px);
}

.stock-change {
    font-size: 0.65rem;
    font-weight: 500;
}

.stock-change.positive {
    color: #4ade80;
}

.stock-change.negative {
    color: #f87171;
}

.loading-text {
    text-align: center;
    color: #999999;
    padding: 30px 20px;
    font-size: 0.7rem;
}

/* Responsive Design for Market Dashboard */
@media (max-width: 1200px) {
    .market-dashboard {
        width: 85%;
        height: 55%;
    }

    .market-feed-container {
        width: 320px;
    }
}

@media (max-width: 768px) {
    .dashboard-header {
        padding: 10px 12px;
        font-size: 0.65rem;
    }

    .stock-item {
        padding: 8px;
        margin-bottom: 4px;
    }

    .stock-symbol {
        font-size: 0.75rem;
    }

    .stock-price {
        font-size: 0.7rem;
    }

    .stock-change {
        font-size: 0.6rem;
    }
}

@media (max-width: 480px) {
    .stock-item {
        padding: 6px;
    }

    .stock-symbol {
        font-size: 0.7rem;
    }

    .stock-price {
        font-size: 0.65rem;
    }

    .stock-change {
        font-size: 0.55rem;
    }
}

/* Metrics grid */
.metrics-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    padding: 12px;
    height: calc(100% - 45px);
}

.metric-item {
    background: rgba(255, 255, 255, 0.03);
    border-radius: 3px;
    padding: 12px 8px;
    text-align: center;
    transition: background 0.2s ease;
}

.metric-item:hover {
    background: rgba(255, 255, 255, 0.08);
}

.metric-label {
    display: block;
    font-size: 0.6rem;
    color: rgba(255, 255, 255, 0.7);
    margin-bottom: 4px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.metric-value {
    display: block;
    font-size: 0.85rem;
    font-weight: 600;
    color: #fff;
}

/* Control panel */
.control-panel {
    padding: 12px;
    height: calc(100% - 45px);
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.dashboard-btn {
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 3px;
    color: #fff;
    padding: 8px 12px;
    font-family: "JetBrains Mono", monospace;
    font-size: 0.7rem;
    font-weight: 500;
    cursor: none !important;
    transition: all 0.2s ease;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.dashboard-btn:hover {
    background: rgba(255, 255, 255, 0.2);
    border-color: rgba(255, 255, 255, 0.4);
    transform: translateY(-1px);
}

.dashboard-btn:active {
    transform: translateY(0);
}

.status-indicator {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: auto;
    padding: 8px;
    background: rgba(255, 255, 255, 0.03);
    border-radius: 3px;
}

.status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #4ade80;
    animation: pulse 2s infinite;
}

@keyframes pulse {
    0%,
    100% {
        opacity: 1;
    }
    50% {
        opacity: 0.5;
    }
}

.status-text {
    font-size: 0.65rem;
    color: rgba(255, 255, 255, 0.8);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* Dark theme variations */
.dashboard-overlay.dark-theme .corner-box {
    background: rgba(15, 15, 15, 0.95);
    border-color: rgba(255, 255, 255, 0.1);
}

.dashboard-overlay.dark-theme .box-header {
    background: rgba(255, 255, 255, 0.02);
}

.dashboard-overlay.dark-theme .stock-item,
.dashboard-overlay.dark-theme .metric-item {
    background: rgba(255, 255, 255, 0.02);
}

.dashboard-overlay.dark-theme .dashboard-btn {
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.1);
}

/* Responsive design */
@media (max-width: 1200px) {
    .corner-box {
        width: 240px;
        height: 180px;
    }

    .top-left,
    .top-right,
    .bottom-left,
    .bottom-right {
        top: 15px;
        left: 15px;
        right: 15px;
        bottom: 15px;
    }
}

@media (max-width: 768px) {
    .corner-box {
        width: 200px;
        height: 160px;
    }

    .top-left,
    .top-right,
    .bottom-left,
    .bottom-right {
        top: 10px;
        left: 10px;
        right: 10px;
        bottom: 10px;
    }

    .box-header {
        padding: 8px 12px;
        font-size: 0.65rem;
    }

    .metrics-grid {
        gap: 6px;
        padding: 8px;
    }

    .metric-item {
        padding: 8px 6px;
    }
}

@media (max-width: 480px) {
    .corner-box {
        width: 160px;
        height: 140px;
    }

    .stock-symbol {
        font-size: 0.65rem;
    }

    .stock-price,
    .stock-change {
        font-size: 0.6rem;
    }

    .dashboard-btn {
        padding: 6px 8px;
        font-size: 0.65rem;
    }
}

/* CODE EXPLAINER STYLES */
.code-explainer-app {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 300px;
    height: 420px;
    background: #000000;
    border: 1px solid #333333;
    border-radius: 2px;
    font-family: "JetBrains Mono", monospace;
    z-index: 10;
    user-select: none;
    animation: fadeInCodeExplainer 0.8s ease-out;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}

@keyframes fadeInCodeExplainer {
    from {
        opacity: 0;
        transform: translate(-50%, -50%) translateY(30px);
    }
    to {
        opacity: 1;
        transform: translate(-50%, -50%) translateY(0);
    }
}

/* Integration with existing slide content */
.slide[data-slide="2"] .work-content {
    z-index: 5; /* Lower than gallery so gallery receives hover/click */
    right: 15%;
    top: 50%;
    transform: translateY(-50%) translateZ(100px);
    pointer-events: none; /* text not interactive, allow underlying gallery interactions */
}

.slide[data-slide="2"] .section-title {
    color: #ffffff;
}

.slide[data-slide="2"] .section-subtitle {
    color: #ffffff;
}

.slide[data-slide="2"] .timeline-paragraph {
    color: #a8a8a8; /* Grey color matching other slides */
}

/* CLICK/TAP AND HOLD sits inline right after the Clients line, and
   .pulse-hint's own line box is shorter than the paragraph's line-height -
   without this the hint's un-transformed position already overlaps the line
   above it, and only the pulse animation's translateY happens to push it
   just clear (by well under a pixel at some widths). Give it a real margin
   so the gap doesn't depend on the animation transform. */
.slide[data-slide="2"] .pulse-hint {
    margin-top: 0.6rem;
}

.slide[data-slide="2"] .work-visual {
    z-index: 1; /* Below gallery but above background */
}

/* Slide 0: Main - align hero content like other sections' work-content.
   Wider than the 600px default so the large display-1 title has enough
   horizontal room and doesn't wrap outside its intended <br> points. */
.slide[data-slide="0"] .content {
    position: absolute;
    right: 8%;
    top: 50%;
    transform: translateY(-50%);
    text-align: right;
    max-width: 1300px;
    z-index: 50;
}

.slide[data-slide="0"] .hero-text {
    max-width: 950px;
    margin-left: auto;
    font-size: 0.9rem;
    font-weight: 100;
    line-height: 1.6;
    color: #a8a8a8;
    margin-top: 0;
    margin-bottom: 1.5rem;
}

.slide[data-slide="0"] .section-title {
    text-align: right;
}

.slide[data-slide="0"] .display-1 {
    font-size: 3.5rem;
    margin-bottom: 1.5rem;
}

.slide[data-slide="0"] .section-subtitle {
    text-align: right;
    margin-bottom: 0.5rem;
}

/* Make gallery items clickable */
.gallery-item {
    cursor: pointer;
    transition: cursor 0.2s ease;
}

/* COLOR FAMILY PICKER STYLES */
.color-picker-app {
    position: absolute;
    right: 20%;
    top: 50%;
    transform: translateY(-50%) scale(var(--app-scale, 1));
    width: 240px;
    background: #141414;
    border: 1px solid #333333;
    border-radius: 2px;
    font-family: "JetBrains Mono", monospace;
    z-index: 15;
    user-select: none;
    opacity: 0;
    animation: fadeInColorPicker 0.8s ease-out;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
    transition: transform var(--transition-medium) var(--easing-smooth);
    /* See matching comment on .market-dashboard - keeps touch drag from
       being read as a page-swipe/slide-change gesture. */
    touch-action: none;
}

/* Once dragged, left/top hold the literal top-left corner instead of a
   center point, so the centering translate is dropped - only the hover/
   drag scale remains. transform-origin moves to that same corner - see the
   matching rule/comment on .market-dashboard.positioned for why (default
   center origin shifts the rendered corner away from left/top by half the
   scale growth, which the drag math in color-picker.js doesn't expect). */
.color-picker-app.positioned {
    transform-origin: top left;
    transform: scale(var(--app-scale, 1));
}

.color-picker-app:hover,
.color-picker-app:active,
.color-picker-app.dragging {
    --app-scale: 1.04;
}

@keyframes fadeInColorPicker {
    0% {
        opacity: 0;
        transform: translateY(-50%) translateX(30px);
    }
    62.5% {
        opacity: 0;
        transform: translateY(-50%) translateX(30px);
    }
    100% {
        opacity: 1;
        transform: translateY(-50%) translateX(0);
    }
}

.color-picker-app.dragging {
    transition: none;
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
}

.color-picker-header {
    padding: 12px 16px;
    background: #1f1f1f;
    border-bottom: 1px solid #333333;
    font-weight: 500;
    font-size: 0.9rem; /* Increased to match market feed */
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: #ffffff;
    text-align: center;
    user-select: none;
    position: relative;
    top: 1px; /* Moved 0.5px higher from 1.5px to 1px */
}

.color-picker-content {
    padding: 16px;
    font-size: 0.9rem; /* Increased to match market feed */
}

/* Ensure all text in color picker has consistent font size */
.color-picker-app {
    font-size: 0.9rem; /* Increased base font size to match market feed */
}

/* Adjust specific elements if they have different font sizes */
.color-picker-app input,
.color-picker-app button,
.color-picker-app select {
    font-size: 0.75rem;
}

/* Main Color Section */
.main-color-section {
    margin-bottom: 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.main-color-display {
    width: 100%;
    height: 60px;
    border-radius: 2px;
    border: 1px solid #333333;
    background: #f044a4;
    transition: all 0.3s ease;
    position: relative;
}

.random-color-btn {
    width: 100%;
    padding: 8px 12px;
    background: #1c1c1c;
    border: 1px solid #3d3d3d;
    border-radius: 2px;
    color: #fff;
    font-family: inherit;
    font-size: 0.75rem;
    font-weight: 500;
    cursor: pointer;
    transition: all var(--transition-medium) var(--easing-smooth);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.random-color-btn:hover {
    background: #f8f9fa;
    color: var(--bg-primary);
    border-color: #f8f9fa;
    transform: translateY(-1px);
}

.random-color-btn:active {
    background: #c7c8ca;
    transform: translateY(0);
}

.current-color-display {
    width: 100%;
    height: 40px;
    border-radius: 2px;
    border: 1px solid #333333;
    margin-bottom: 12px;
    background: #f044a4;

    transition: all 0.2s ease;
    position: relative;
}

.current-color-display:hover {
    border-color: #555555;
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1);
}

.color-controls {
    display: flex;
    gap: 12px;
    align-items: flex-end;
}

.rgb-inputs {
    display: flex;
    gap: 8px;
    flex: 1;
}

.input-group {
    display: flex;
    flex-direction: column;
    flex: 1;
}

.input-group input {
    width: 100%;
    padding: 6px 4px;
    background: rgba(248, 249, 250, 0.95);
    border: none;
    border-radius: 2px;
    color: var(--bg-primary);
    font-size: 0.75rem;
    font-family: inherit;
    text-align: center;
    transition: all 0.2s ease;
}

/* Hide arrows in Chrome, Safari, Edge */
.input-group input::-webkit-outer-spin-button,
.input-group input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.input-group input:focus {
    outline: none;
    background: rgba(248, 249, 250, 1);
    box-shadow: 0 0 0 2px rgba(248, 249, 250, 0.3);
}

.input-group input:hover {
    background: rgba(248, 249, 250, 1);
    box-shadow: 0 0 0 1px rgba(248, 249, 250, 0.5);
}

.control-buttons {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.control-btn {
    width: 32px;
    height: 20px;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 2px;
    color: #fff;
    font-family: inherit;
    font-size: 0.8rem;
    transition: all 0.2s ease;
    display: flex;
    align-items: center;
    justify-content: center;
}

.control-btn:hover {
    background: rgba(255, 255, 255, 0.2);
    border-color: rgba(255, 255, 255, 0.4);
    transform: translateY(-1px);
}

.control-btn .btn-icon {
    font-size: 12px;
    line-height: 1;
}

/* Section Labels */
.section-label {
    font-size: 0.7rem;
    color: #ffffff;
    margin-bottom: 8px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-weight: 500;
}

/* Color Harmonies Section */
.color-harmonies-section {
    margin-bottom: 16px;
}

.harmony-group {
    margin-bottom: 16px;
}

.harmony-label {
    font-size: 0.7rem;
    color: #ffffff;
    margin-bottom: 8px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-weight: 500;
}

.harmony-colors-row {
    display: flex;
    gap: 4px;
}

.color-swatch {
    width: 24px;
    height: 24px;
    border-radius: 2px;
    border: 1px solid #333333;
    transition: all 0.2s ease;
    position: relative;
    cursor: pointer;
}

.color-swatch:hover {
    filter: brightness(1.3);
    border-color: #666666;
    z-index: 10;
}

.color-swatch:active {
    filter: brightness(0.8);
    transition: filter 0.1s ease;
}

.color-swatch.large {
    width: 32px;
    height: 32px;
}

/* Adjacent Colors Section */
.adjacent-colors-section {
    margin-bottom: 3px;
}

.adjacent-colors {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
}

/* Notification */
.color-picker-notification {
    position: absolute;
    top: -30px;
    left: 50%;
    transform: translateX(-50%);
    background: rgba(74, 222, 128, 0.9);
    color: #000;
    padding: 6px 12px;
    border-radius: 2px;
    font-size: 0.7rem;
    font-weight: 500;
    white-space: nowrap;
    z-index: 100;
    animation: notificationSlide 0.3s ease-out;
}

@keyframes notificationSlide {
    from {
        opacity: 0;
        transform: translateX(-50%) translateY(10px);
    }
    to {
        opacity: 1;
        transform: translateX(-50%) translateY(0);
    }
}

/* Responsive Design for Color Picker */
@media (max-width: 1200px) {
    .color-picker-app {
        right: 5%;
        width: 220px;
    }
}

@media (max-width: 768px) {
    .color-controls {
        flex-direction: column;
        gap: 8px;
    }

    .control-buttons {
        flex-direction: row;
        justify-content: center;
    }

    .control-btn {
        width: 36px;
        height: 36px;
    }
}

@media (max-width: 480px) {
    .color-picker-content {
        padding: 12px;
    }

    .current-color-display {
        height: 50px;
    }

    .color-swatch {
        width: 20px;
        height: 20px;
    }

    .color-swatch.large {
        width: 28px;
        height: 28px;
    }
}

/* ==================================================================
   Commercial Site Preview Windows (draggable, sandboxed, Apps slide)
================================================================== */
.site-preview-app {
    position: absolute;
    width: 260px;
    background: #141414;
    border: 1px solid #333333;
    border-radius: 2px;
    font-family: "JetBrains Mono", monospace;
    z-index: 12;
    user-select: none;
    opacity: 0;
    animation: fadeInSitePreview 0.8s ease-out;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
    transition:
        transform var(--transition-medium) var(--easing-smooth),
        border-color var(--transition-medium) var(--easing-smooth),
        box-shadow var(--transition-medium) var(--easing-smooth);
    /* See matching comment on .market-dashboard - keeps touch drag from
       being read as a page-swipe/slide-change gesture. */
    touch-action: none;
}

.site-preview-app:hover,
.site-preview-app:active,
.site-preview-app.dragging {
    transform: scale(1.04);
    border-color: #666666;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
}

#sitePreviewOradin {
    left: 6%;
    top: 9%;
}

#sitePreviewMetamorph {
    left: 6%;
    top: 40%;
}

#sitePreviewMetamorph .site-preview-thumb {
    aspect-ratio: 1600 / 1000;
}

@keyframes fadeInSitePreview {
    0%,
    50% {
        opacity: 0;
        transform: translateX(-30px);
    }
    100% {
        opacity: 1;
        transform: translateX(0);
    }
}

.site-preview-app.dragging {
    transition: none;
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
    cursor: none !important;
}

.site-preview-app.dragging * {
    cursor: none !important;
}

.site-preview-header {
    padding: 7px 12px;
    background: #1f1f1f;
    border-bottom: 1px solid #333333;
    font-weight: 500;
    font-size: 0.65rem;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.75);
    text-align: center;
}

.site-preview-thumb {
    width: 100%;
    overflow: hidden;
    cursor: pointer;
}

#sitePreviewOradin .site-preview-thumb {
    aspect-ratio: 900 / 562;
}

.site-preview-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
    display: block;
    pointer-events: none;
    transition: filter var(--transition-medium) var(--easing-smooth);
    filter: brightness(0.92);
}

.site-preview-app:hover .site-preview-thumb img {
    filter: brightness(1.05);
}

/* Lightbox - enlarged sandboxed view */
.site-preview-lightbox {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.85);
    backdrop-filter: blur(6px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 500;
    opacity: 0;
    visibility: hidden;
    transition:
        opacity 0.3s ease,
        visibility 0.3s ease;
}

.site-preview-lightbox.active {
    opacity: 1;
    visibility: visible;
}

.site-preview-lightbox-frame {
    width: 90vw;
    height: 88vh;
    max-width: 1600px;
    background: #141414;
    border: 1px solid #333333;
    border-radius: 2px;
    box-shadow: 0 10px 60px rgba(0, 0, 0, 0.6);
    display: flex;
    flex-direction: column;
    transform: scale(0.96);
    transition: transform 0.3s ease;
}

.site-preview-lightbox.active .site-preview-lightbox-frame {
    transform: scale(1);
}

.site-preview-lightbox-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    background: #1f1f1f;
    border-bottom: 1px solid #333333;
    font-family: "JetBrains Mono", monospace;
    font-size: 0.75rem;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: #ffffff;
    flex-shrink: 0;
}

.site-preview-lightbox-actions {
    display: flex;
    align-items: center;
    gap: 16px;
}

.site-preview-lightbox-newtab {
    color: rgba(255, 255, 255, 0.6);
    text-decoration: none;
    font-size: 0.65rem;
    letter-spacing: 0.5px;
    transition: color 0.2s ease;
}

.site-preview-lightbox-newtab:hover {
    color: #4ade80;
}

.site-preview-lightbox-close {
    background: none;
    border: none;
    color: rgba(255, 255, 255, 0.7);
    font-size: 1.4rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 4px;
    transition: color 0.2s ease;
}

.site-preview-lightbox-close:hover {
    color: #f87171;
}

.site-preview-lightbox-body {
    flex: 1;
    min-height: 0;
    position: relative;
    overflow: hidden;
    background: #ffffff;
}

/*
 * The iframe is rendered at a fixed desktop width and scaled down to fit -
 * not sized to the lightbox's own (often narrower/shorter) box. Embedded
 * sites read their own window/viewport size, so sizing the iframe directly
 * to the lightbox would hand them a squeezed viewport and trigger layout
 * meant for tablet/mobile widths. This keeps them seeing a normal desktop
 * viewport, just visually scaled.
 */
#sitePreviewLightboxIframe {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 1600px;
    height: 900px;
    border: none;
    background: #ffffff;
    transform-origin: top left;
}

@media (max-width: 1200px) {
    .site-preview-app {
        width: 220px;
    }
}

/* ==================================================================
   Video Preview Widgets (Shapeshift / Biomass, draggable, Apps slide)
   Idle: small muted looping clip. Click the frame: swaps to the
   higher-res source, unmutes, shows native controls, and the widget
   itself grows via the width transition below - "expand size of
   widget on click" rather than the site-preview lightbox's separate
   overlay, since these are clips to watch in place, not pages to browse.
================================================================== */
.video-preview-app {
    position: absolute;
    width: var(--vp-width, 150px);
    background: #141414;
    border: 1px solid #333333;
    border-radius: 2px;
    font-family: "JetBrains Mono", monospace;
    z-index: 12;
    user-select: none;
    opacity: 0;
    animation: fadeInSitePreview 0.8s ease-out;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
    transition:
        width var(--transition-medium) var(--easing-smooth),
        transform var(--transition-medium) var(--easing-smooth),
        border-color var(--transition-medium) var(--easing-smooth),
        box-shadow var(--transition-medium) var(--easing-smooth);
    /* See matching comment on .market-dashboard - keeps touch drag from
       being read as a page-swipe/slide-change gesture. */
    touch-action: none;
}

.video-preview-app:hover,
.video-preview-app:active,
.video-preview-app.dragging {
    transform: scale(1.04);
    border-color: #666666;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
}

.video-preview-app.dragging {
    transition: none;
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
    cursor: none !important;
}

.video-preview-app.dragging * {
    cursor: none !important;
}

/* Expanded state overrides the hover/drag scale - the width swap already
   grows it, scaling on top would compound and overshoot. */
.video-preview-app.expanded {
    width: var(--vp-width-expanded, 320px);
    z-index: 90;
}

.video-preview-app.expanded:hover,
.video-preview-app.expanded:active,
.video-preview-app.expanded.dragging {
    transform: none;
}

#videoPreviewShapeshift {
    --vp-width: 140px;
    --vp-width-expanded: 320px;
    left: 6%;
    top: 60%;
}

#videoPreviewBiomass {
    --vp-width: 165px;
    --vp-width-expanded: 340px;
    left: 30%;
    top: 15%;
}

.video-preview-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 7px 10px 7px 12px;
    background: #1f1f1f;
    border-bottom: 1px solid #333333;
    font-weight: 500;
    font-size: 0.62rem;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.75);
}

.video-preview-close {
    display: none;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: rgba(255, 255, 255, 0.6);
    font-size: 2rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 8px;
    /* Negative margin cancels the header's own padding on those edges so
       the button's hit area (and hover background) fills the full bar
       height instead of just the glyph's line-height. */
    margin: -7px -10px -7px 0;
    transition: color 0.2s ease, background-color 0.2s ease;
}

.video-preview-close:hover {
    color: #f87171;
    background-color: rgba(255, 255, 255, 0.06);
}

.video-preview-app.expanded .video-preview-close {
    display: flex;
}

.video-preview-thumb {
    position: relative;
    width: 100%;
    overflow: hidden;
    cursor: pointer;
    background: #000000;
}

#videoPreviewShapeshift .video-preview-thumb {
    aspect-ratio: 432 / 960;
}

#videoPreviewBiomass .video-preview-thumb {
    aspect-ratio: 436 / 802;
}

.video-preview-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    pointer-events: none;
    filter: brightness(0.92);
    transition: filter var(--transition-medium) var(--easing-smooth);
}

.video-preview-app.expanded .video-preview-video {
    pointer-events: auto;
    filter: none;
}

.video-preview-app:hover .video-preview-video {
    filter: brightness(1.05);
}

.video-preview-play-icon {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.6rem;
    color: rgba(255, 255, 255, 0.85);
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.6);
    pointer-events: none;
    transition: opacity 0.2s ease;
}

.video-preview-app.expanded .video-preview-play-icon {
    opacity: 0;
}

/* Hero starfield (slide 0)
   Sits behind the hero copy inside the slide's own stacking context - a
   body-level overlay would be trapped under .slides-container's z-index 100.
   z-index 0 is enough to stay behind the text: .slide[data-slide="0"] .content
   is already positioned at z-index 50. Nothing else on the slide is touched -
   giving .container a position would re-anchor that absolutely positioned
   .content (right: 8%) to the container box and move the hero copy. */
.starfield {
    position: absolute;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
    opacity: 0;
    /* Starts hidden so the boot sequence's reveal (see startBootSequence in
       script.js) triggers a real 0->1 fade instead of the field just sitting
       at full brightness under the loading overlay the whole time and
       popping into view the instant the overlay clears. Shaped to track the
       game's own dimming curve (fadeFactor += diff * 0.05
       per frame, i.e. 0.95^frames) over the window that is actually on screen:
       ~0.84 vs the game's 0.63 at 150ms, 0.48 vs 0.46 at 250ms. It then drops
       away faster than the game's long tail on purpose, so the field is
       effectively gone before goToSlide's hard opacity cut lands and the cut
       is not the thing you notice. Duration is paired with the slide-0
       swapDelay in script.js - changing one without the other either
       reintroduces the snap or stalls the transition. */
    transition: opacity 1000ms cubic-bezier(0.4, 0, 0.2, 1);
}

.starfield-canvas {
    position: absolute;
    top: 0;
    left: 0;
    display: block;
}

/* Keeps the hero text off the busiest part of the field without dimming the
   streaks at the edges. */
.starfield-veil {
    position: absolute;
    inset: 0;
    background: radial-gradient(
        ellipse 55% 50% at center,
        rgba(0, 0, 0, 0.5) 0%,
        rgba(0, 0, 0, 0.28) 45%,
        rgba(0, 0, 0, 0) 80%
    );
}

/* ==================================================================
   MOBILE / TOUCH LAYOUT
   Lives at the end of the file on purpose: the per-slide rules above
   (.slide[data-slide="1"] .work-content, .slide[data-slide="2"]
   .work-content, ...) carry three classes of specificity, so anything
   that has to beat them must either match that weight or come later.
   Every selector below is written at the same weight and wins on order.
================================================================== */

/* ---- Fixed chrome (any touch device, either orientation) ---------- */
@media (max-width: 768px), (hover: none) and (pointer: coarse) {
    :root {
        /* Shared right edge for GET IN TOUCH and every slide's copy. */
        --m-gutter: 1rem;
        /* The stats/brand pill sits a little further into the corner. */
        --m-corner: 0.75rem;
    }

    .ai-button {
        top: var(--m-gutter);
        right: var(--m-gutter);
        font-size: 0.72rem;
        padding: 0.5rem 0.7rem;
    }

    /* The brand line is folded into the stats pill below, so the standalone
       bar would just be a duplicate sitting in the same corner. */
    .brand {
        display: none !important;
    }

    /* Home slide 0 subtitle only: force the line break after "&" instead of
       whatever the natural wrap happens to land on at a given width. */
    .subtitle-break {
        display: block;
    }

    /* Live FPS/heap/xfer readout - no cycling, no CO2 sentence. Where it
       sits depends on which slide is active: hidden on Home (nothing to
       read it against), bottom-right by default (Spatial Psychology /
       Adaptive Solutions / About / Contact, portrait), and top-left on
       Hyper Thrill instead since that slide is landscape-only and its
       copy sits on the right - see the landscape override below and the
       per-slide rules that follow this block. */
    .fps-display {
        top: auto;
        left: auto;
        bottom: var(--m-corner);
        right: var(--m-corner);
        width: auto;
        max-width: 55vw;
        height: auto;
        font-size: clamp(0.5rem, 2.3vw, 0.62rem);
        font-weight: 400;
        display: flex;
        align-items: center;
        justify-content: flex-end;
        overflow: visible;
        color: var(--text-secondary);
        transition: opacity 0.5s ease;
    }

    .stats-viewport {
        display: inline-block;
        height: auto;
        overflow: visible;
    }

    .stats-track {
        position: static;
        display: inline-block;
    }

    .stats-line {
        display: none;
    }

    .stats-line:not(.stats-co2) {
        display: inline-block;
        position: static;
        height: auto;
        line-height: 1.3;
        white-space: nowrap;
    }

    /* Home has no readout - it's the introduction, not the workbench. */
    body:has(.slide[data-slide="0"].active) .fps-display {
        opacity: 0;
        pointer-events: none;
    }

    /* Fullscreen toggle follows the brand into the opposite corner. */
    .fullscreen-btn {
        bottom: var(--m-corner);
        left: var(--m-corner);
    }
}

/* Hyper Thrill is landscape-only (see .portrait-overlay), and its copy
   already sits right-aligned there - the readout moves to the top-left
   corner, clear of both, instead of following the default bottom-right. */
@media (max-width: 768px) and (orientation: landscape),
    (hover: none) and (pointer: coarse) and (orientation: landscape) {
    body:has(.slide[data-slide="1"].active) .fps-display {
        top: var(--m-gutter);
        left: var(--m-corner);
        bottom: auto;
        right: auto;
        justify-content: flex-start;
    }
}

/* Every other slide is portrait-only - this is the "please rotate back"
   prompt that appears the moment you leave Hyper Thrill still sideways.
   Without it the layout below assumes portrait and GET IN TOUCH/the copy
   end up out of view in landscape on every other slide. */
.landscape-lock-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: #000;
    z-index: 99999;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    color: rgba(248, 249, 250, 0.45);
    font-size: 0.75rem;
    font-weight: 300;
    letter-spacing: 0.08em;
    pointer-events: none;
}

@media (hover: none) and (pointer: coarse) and (orientation: landscape) {
    body:has(.slide:not([data-slide="1"]).active) .landscape-lock-overlay {
        display: flex;
    }
}

/* ---- Portrait phone copy ----------------------------------------- */
@media (max-width: 768px) {
    :root {
        --m-title: clamp(1.7rem, 8.5vw, 2.6rem);
        --m-sub: clamp(0.85rem, 3.9vw, 1.1rem);
        --m-body: clamp(0.72rem, 3.15vw, 0.9rem);
    }

    /* .container is a flex item, so without an explicit width it shrinks to
       its content and `margin: 0 auto` centres it - the copy then never
       reaches the gutter it is supposed to share with GET IN TOUCH. */
    .container {
        width: 100%;
        padding: 0 var(--m-gutter);
    }

    /* Nothing on a slide is allowed to grow the document - the hold-to-zoom
       gallery in particular. */
    .slide {
        overflow: hidden;
    }

    /* All copy right-aligned against the same gutter as GET IN TOUCH,
       matching how the Home slide already reads. */
    .slide[data-slide="0"] .content,
    .slide[data-slide="1"] .work-content,
    .slide[data-slide="2"] .work-content,
    .slide[data-slide="3"] .work-content,
    .slide[data-slide="4"] .work-content {
        position: absolute;
        left: var(--m-gutter);
        right: var(--m-gutter);
        top: 50%;
        transform: translateY(-50%);
        max-width: none;
        width: auto;
        text-align: right;
    }

    /* Keeps this slide's copy in front of the 3D gallery, as on desktop. */
    .slide[data-slide="2"] .work-content {
        transform: translateY(-50%) translateZ(100px);
    }

    /* Adaptive Solutions is the one slide with floating widgets underneath
       the copy, so the text is anchored under the top chrome instead of
       centred, leaving the lower half of the screen to the widgets. */
    .slide[data-slide="3"] .work-content {
        top: 4rem;
        transform: none;
    }

    /* Manual <br> line breaks are tuned for a ~1200px column and produce the
       ragged, mid-word-looking wraps seen on a phone. Let the text reflow. */
    .slide[data-slide="0"] .hero-text br,
    .slide[data-slide="1"] .timeline-paragraph br,
    .slide[data-slide="2"] .timeline-paragraph br,
    .slide[data-slide="3"] .timeline-paragraph br,
    .slide[data-slide="4"] .timeline-paragraph br {
        display: none;
    }

    /* Except the Core / Tested / Base list, where the breaks are the
       structure rather than hand-wrapping. */
    .slide[data-slide="4"] .timeline-paragraph:last-child br {
        display: inline;
    }

    /* ...except the one that puts a CLICK/TAP AND HOLD style hint on its own
       line. Forcing `display: block` on .pulse-hint instead would fight the
       .hint-desktop / .hint-mobile toggle, which is also a display switch.
       Needs the [data-slide] prefix to actually out-specificity the blanket
       hide rule above (bare .timeline-paragraph br:has(...) was losing to
       it and never applied). */
    .slide[data-slide="1"] .timeline-paragraph br:has(+ .pulse-hint),
    .slide[data-slide="2"] .timeline-paragraph br:has(+ .pulse-hint) {
        display: inline;
    }

    /* Mobile-only manual breaks in the Spatial Psychology paragraphs
       (BRAW HAUS / CLSTL) need to survive the blanket br hide above,
       and the desktop-only break they replace needs to actually go away. */
    .slide[data-slide="2"] .timeline-paragraph br.br-mobile {
        display: inline;
    }
    .slide[data-slide="2"] .timeline-paragraph br.br-desktop {
        display: none;
    }

    .slide[data-slide="0"] .display-1,
    .slide[data-slide="1"] .section-title,
    .slide[data-slide="2"] .section-title,
    .slide[data-slide="3"] .section-title,
    .slide[data-slide="4"] .section-title {
        font-size: var(--m-title);
        margin-bottom: 0.9rem;
    }

    .slide[data-slide="0"] .section-subtitle,
    .slide[data-slide="1"] .section-subtitle,
    .slide[data-slide="2"] .section-subtitle,
    .slide[data-slide="3"] .section-subtitle,
    .slide[data-slide="4"] .section-subtitle {
        font-size: var(--m-sub);
        margin-bottom: 0.6rem;
        line-height: 1.35;
    }

    .slide[data-slide="0"] .hero-text,
    .slide[data-slide="1"] .timeline-paragraph,
    .slide[data-slide="2"] .timeline-paragraph,
    .slide[data-slide="3"] .timeline-paragraph,
    .slide[data-slide="4"] .timeline-paragraph {
        font-size: var(--m-body);
        max-width: none;
        margin-left: auto;
        margin-bottom: 0.9rem;
    }

    .slide[data-slide="2"] .timeline-paragraph:has(+ .timeline-paragraph),
    .slide[data-slide="4"] .timeline-paragraph:has(+ .timeline-paragraph) {
        margin-bottom: 0.5rem;
    }

    /* Hyper Thrill HUD scales with the rest of the copy. */
    .slide[data-slide="1"] .score-current {
        font-size: 1rem;
    }
    .slide[data-slide="1"] .score-best,
    .slide[data-slide="1"] .hint-desktop,
    .slide[data-slide="1"] .hint-mobile {
        font-size: 0.78rem;
    }

    /* Contact: title follows the same right edge; the form keeps the full
       gutter-to-gutter width so its fields end on that edge too. */
    .slide[data-slide="5"] .display-2 {
        text-align: right;
        font-size: clamp(1.3rem, 6.5vw, 2.5rem);
        margin-bottom: 1.5rem;
    }
    .slide[data-slide="5"] .form-container {
        max-width: none;
    }
    .slide[data-slide="5"] .social-links {
        justify-content: flex-end;
        margin-top: 2.5rem;
    }

    /* Sized so the longest line (EMPATHY CREATIVITY GRATITUDE, 28 chars)
       reads close to the progress bar's own width below it, while staying
       on one line - nowrap is what makes that safe to size up. */
    /* Anchored low, just above the progress bar, instead of vertically
       centered - the text-wall hole in script.js is measured from this
       box's real position, so pushing the sentences down here is what
       frees up the upper two-thirds of the screen for the wall to grow
       into on mobile. */
    .boot-container {
        top: auto;
        bottom: 110px;
        left: 50%;
        transform: translateX(-50%);
        max-width: 94%;
    }
    .boot-text {
        font-size: clamp(0.8rem, 4.3vw, 1.4rem);
        margin-bottom: 1rem;
    }
    .boot-line {
        white-space: nowrap;
        margin: 0.35rem 0;
    }
    .progress-bar {
        width: 240px;
    }
}

/* Short portrait screens (iPhone SE and friends) need one more notch down
   so the longest slide - About - still clears the top and bottom chrome. */
@media (max-width: 768px) and (max-height: 720px) {
    :root {
        --m-title: clamp(1.4rem, 7.5vw, 2.2rem);
        --m-sub: clamp(0.78rem, 3.5vw, 1rem);
        --m-body: clamp(0.66rem, 2.9vw, 0.82rem);
    }
}

/* ---- Adaptive Solutions widgets, small screens ------------------- */
@media (max-width: 768px), (orientation: landscape) and (max-height: 520px) {
    /* Those widgets are sized for a desktop column - on a phone they
       cover the copy outright. Shrink them here and let PositionUtils drop
       them into the band under the text (see _buildAdaptiveLayout, which
       reads this same scale). --app-scale stays the hover/drag multiplier
       so picking a widget up still nudges it. */
    .market-dashboard,
    .color-picker-app,
    .site-preview-app,
    .video-preview-app {
        --app-base-scale: 0.6;
    }

    /* Each widget's baked-in transform is a contract with its own init code
       (dashboard.js / color-picker.js pre-compensate for the translate when
       they hand PositionUtils a coordinate), so the translates stay exactly
       as they are and the scale is only multiplied in. The origins are set
       to the point each translate holds fixed, so shrinking the widget does
       not also slide it away from where it was placed. */
    .market-dashboard {
        transform: translate(-50%, -50%)
            scale(calc(var(--app-base-scale) * var(--app-scale, 1)));
        transform-origin: center;
    }
    .color-picker-app {
        transform: translateY(-50%)
            scale(calc(var(--app-base-scale) * var(--app-scale, 1)));
        transform-origin: left center;
    }
    .market-dashboard.positioned,
    .color-picker-app.positioned {
        transform: scale(calc(var(--app-base-scale) * var(--app-scale, 1)));
        transform-origin: top left;
    }
    .site-preview-app,
    .video-preview-app {
        transform: scale(var(--app-base-scale));
        transform-origin: top left;
    }
    .site-preview-app:hover,
    .site-preview-app:active,
    .site-preview-app.dragging,
    .video-preview-app:hover,
    .video-preview-app:active,
    .video-preview-app.dragging {
        transform: scale(calc(var(--app-base-scale) * 1.04));
    }
    /* Expanded already grows via its own width var - the base-scale
       transform still applies (so it grows from the same shrunken
       footprint the rest of the widget uses on a phone), but not the
       extra hover/drag bump on top of it. */
    .video-preview-app.expanded,
    .video-preview-app.expanded:hover,
    .video-preview-app.expanded:active,
    .video-preview-app.expanded.dragging {
        transform: scale(var(--app-base-scale));
    }

    /* The <=1200px rules size the dashboard as a percentage of the viewport
       (85% x 55%) and pin the feed to a fixed 320px. On a phone that is a
       widget wider than the screen with a feed sticking out of its own
       frame - put both back on the dashboard's own geometry. */
    .market-dashboard {
        width: 175px;
        height: 491px;
    }
    .market-feed-container {
        width: 100%;
    }
}

/* ---- Landscape phone (the game slide is the reason this exists) --- */
@media (orientation: landscape) and (max-height: 520px) {
    .slide[data-slide="0"] .content,
    .slide[data-slide="1"] .work-content,
    .slide[data-slide="2"] .work-content,
    .slide[data-slide="3"] .work-content,
    .slide[data-slide="4"] .work-content {
        right: var(--m-gutter, 1rem);
        left: auto;
        max-width: 68%;
        text-align: right;
    }

    .slide[data-slide="0"] .display-1,
    .slide[data-slide="1"] .section-title,
    .slide[data-slide="2"] .section-title,
    .slide[data-slide="3"] .section-title,
    .slide[data-slide="4"] .section-title {
        font-size: 1.9rem;
        margin-bottom: 0.6rem;
    }

    .slide[data-slide="0"] .section-subtitle,
    .slide[data-slide="1"] .section-subtitle,
    .slide[data-slide="2"] .section-subtitle,
    .slide[data-slide="3"] .section-subtitle,
    .slide[data-slide="4"] .section-subtitle {
        font-size: 0.85rem;
        margin-bottom: 0.4rem;
    }

    .slide[data-slide="0"] .hero-text,
    .slide[data-slide="1"] .timeline-paragraph,
    .slide[data-slide="2"] .timeline-paragraph,
    .slide[data-slide="3"] .timeline-paragraph,
    .slide[data-slide="4"] .timeline-paragraph {
        font-size: 0.68rem;
        margin-bottom: 0.4rem;
        max-width: none;
        margin-left: auto;
    }

    .slide[data-slide="0"] .hero-text br,
    .slide[data-slide="1"] .timeline-paragraph br,
    .slide[data-slide="2"] .timeline-paragraph br,
    .slide[data-slide="3"] .timeline-paragraph br,
    .slide[data-slide="4"] .timeline-paragraph br {
        display: none;
    }
    .slide[data-slide="4"] .timeline-paragraph:last-child br,
    .slide[data-slide="1"] .timeline-paragraph br:has(+ .pulse-hint),
    .slide[data-slide="2"] .timeline-paragraph br:has(+ .pulse-hint) {
        display: inline;
    }
    .slide[data-slide="2"] .timeline-paragraph br.br-mobile {
        display: inline;
    }
    .slide[data-slide="2"] .timeline-paragraph br.br-desktop {
        display: none;
    }

    /* Hyper Thrill's intro is the one paragraph long enough in this cramped
       landscape column to want a deliberate break rather than the reflow -
       land it right after "solo developer," instead of wherever the text
       happens to wrap. */
    .slide[data-slide="1"] .timeline-paragraph br.landscape-break {
        display: inline;
    }

    /* About is by far the longest slide; at the shared landscape scale its
       title sits under GET IN TOUCH and its last line under the stats pill.
       It gets its own notch down so the whole block clears both corners. */
    .slide[data-slide="4"] .section-title {
        font-size: 1.4rem;
        margin-bottom: 0.4rem;
    }
    .slide[data-slide="4"] .section-subtitle {
        font-size: 0.72rem;
        margin-bottom: 0.3rem;
        text-wrap: balance;
    }
    .slide[data-slide="4"] .timeline-paragraph {
        font-size: 0.6rem;
        margin-bottom: 0.3rem;
        text-wrap: pretty;
    }

    /* Contact has to fit a five-field form between the two corners, and
       follows the same right edge as every other slide. */
    .container {
        width: 100%;
        padding: 0 var(--m-gutter, 1rem);
    }
    .slide[data-slide="5"] .display-2 {
        font-size: 1.5rem;
        margin-bottom: 0.7rem;
        text-align: right;
    }
    .slide[data-slide="5"] .content {
        max-width: 500px; /* matches .form-container's own max-width */
        margin-left: auto;
    }
    .slide[data-slide="5"] .form-container {
        margin: 0;
    }
    .slide[data-slide="5"] .social-links {
        justify-content: flex-end;
    }
    .form-input,
    .form-select,
    .form-textarea,
    .btn-primary {
        padding: 0.4rem 0.7rem;
        font-size: 0.8rem;
        margin-bottom: 0.4rem;
    }
    .form-textarea {
        min-height: 48px;
    }
    .social-links {
        margin-top: 1.2rem;
    }

    .slide[data-slide="1"] .score-container {
        margin-top: 0.4rem;
    }
    .slide[data-slide="1"] .score-current {
        font-size: 0.95rem;
    }
    .slide[data-slide="1"] .control-hints {
        margin-top: 0.5rem;
    }
    .slide[data-slide="1"] .score-best,
    .slide[data-slide="1"] .hint-desktop,
    .slide[data-slide="1"] .hint-mobile {
        font-size: 0.72rem;
    }

    .boot-text {
        font-size: 0.85rem;
    }
    .boot-line {
        white-space: nowrap;
        margin: 0.3rem 0;
    }
}

/* Hide the nav wheel on phones in any orientation - phones don't have room
   for it alongside the other UI, even when rotated to landscape for the
   game. Tablets (any orientation) and desktop keep it. Phones are
   identified by their short dimension staying <=767px even when the long
   dimension (width in landscape) grows past the phone breakpoint. */
@media (hover: none) and (pointer: coarse) and (max-width: 767px),
       (hover: none) and (pointer: coarse) and (max-height: 767px) {
    .nav-sections {
        display: none;
    }
}
