/* ── reset & root ── */
:root {
    --orange: #FF9022;
    --green: #00AA00;
    --dark: #1a1a2e;
    /* 2D-UI axis colors (caption text + mouse diagram). Kept a touch darker than
       the 3D scene's AXIS_COLORS so they stay legible on the light panel. */
    --axis-x: #c0453a;
    --axis-y: #267326;
    --axis-z: #3a6fa8;
    /* Live info-panel height, kept current by a ResizeObserver in main.js. Used
       on small screens to stack the bottom controls above the panel bar. The
       148px here is only a pre-measure fallback. */
    --panel-h: 148px;
    --font: 'Lexend', sans-serif;
    --mono: 'DM Mono', monospace;

    /* ── fluid scale ──
       Sizes grow with the smaller viewport dimension (vmin), so the whole UI
       shrinks on both narrow AND short screens, then clamps at each end. This is
       what makes the chrome scale smoothly from phone to 4K, and it replaces the
       old max-width/max-height "trim" breakpoint. Calibrated so the mid-range
       lands on the original desktop sizes. */
    --edge: clamp(12px, 2.5vmin, 28px);
    /* screen-edge inset for the corner controls */
    --panel-w: clamp(300px, 34vw, 460px);
    --logo-h: clamp(22px, 3.4vmin, 34px);
    --fs-step: clamp(10px, 1.2vmin, 12px);
    --fs-title: clamp(16px, 2.1vmin, 23px);
    --fs-body: clamp(13px, 1.65vmin, 16px);
    --fs-btn: clamp(13px, 1.7vmin, 16px);
    --fs-ui: clamp(12px, 1.45vmin, 14.5px);
    /* badge, util + replay buttons */
    --pad-panel: clamp(16px, 2.2vmin, 24px) clamp(22px, 3.8vmin, 40px);
    --gap-panel: clamp(10px, 1.7vmin, 18px);
    --pad-btn: clamp(10px, 1.4vmin, 13px) clamp(18px, 3vmin, 26px);
}

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

html,
body {
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: #efefed;
    font-family: var(--font);
}

/* ── app shell ── */
#app {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
}

/* ── canvas window ── */
#canvas-wrap {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    background: radial-gradient(circle at center, #ffffff 0%, #efefed 100%);
    overflow: hidden;
}

#cv {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
}

/* progress bar */
#prog {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 5px;
    z-index: 20;
    background: rgba(28, 27, 34, .08);
}

#prog-fill {
    height: 100%;
    width: 0%;
    background: var(--orange);
    transition: width 1s cubic-bezier(.4, 0, .2, 1);
}

/* mode badge - fixed top center over canvas */
#status-badge {
    position: absolute;
    top: 14px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 30;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 18px;
    border-radius: 24px;
    font-family: var(--font);
    font-size: var(--fs-ui);
    font-weight: 600;
    letter-spacing: .01em;
    pointer-events: none;
    opacity: 0;
    transition: opacity .4s ease, background .4s, color .4s, box-shadow .4s,
        transform .5s cubic-bezier(0.34, 1.56, 0.64, 1),
        top .5s cubic-bezier(0.34, 1.56, 0.64, 1);
    white-space: nowrap;
}

#status-badge.on {
    opacity: 1;
}

#status-badge.watching {
    background: rgba(26, 26, 46, .92);
    color: #fff;
    box-shadow: 0 16px 48px rgba(0, 0, 0, .28);
    transform: translateX(-50%) scale(2.6);
    top: calc(10%);
}

#status-badge.interacting {
    background: var(--orange);
    color: #fff;
    box-shadow: 0 10px 32px rgba(255, 144, 34, .55);
    transform: translateX(-50%) scale(1.65);
    top: 22px;
}

.badge-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    transition: background .4s;
}

#status-badge.watching .badge-dot {
    background: rgba(255, 255, 255, .4);
}

#status-badge.interacting .badge-dot {
    background: rgba(255, 255, 255, .9);
    animation: badge-pulse 1.3s infinite;
}

@keyframes badge-pulse {

    0%,
    100% {
        transform: scale(1);
        opacity: 1;
    }

    50% {
        transform: scale(1.7);
        opacity: .5;
    }
}

/* replay-demo pill - sits under the "Your Turn" badge, top center.
   Only shown on beats that have a demo to replay, once the student's turn has
   begun (toggled on via .on from ui.js). */
#btn-replay {
    position: absolute;
    top: 72px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 30;
    display: none;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: 20px;
    border: 1px solid rgba(0, 0, 0, 0.08);
    background: rgba(255, 255, 255, 0.94);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.10), 0 1px 4px rgba(0, 0, 0, 0.05);
    font-family: var(--font);
    font-size: var(--fs-ui);
    font-weight: 600;
    letter-spacing: .01em;
    color: #1a1a2e;
    cursor: pointer;
    white-space: nowrap;
    transition: background .2s, border-color .2s, color .2s, transform .15s, box-shadow .2s;
}

#btn-replay.on {
    display: inline-flex;
    animation: replayIn .4s ease .55s backwards;
}

/* like continueIn but keeps the translateX(-50%) centering, so the pill fades
   up in place instead of starting off-center and snapping to the middle */
@keyframes replayIn {
    from {
        opacity: 0;
        transform: translateX(-50%) translateY(8px);
    }

    to {
        opacity: 1;
        transform: translateX(-50%) translateY(0);
    }
}

#btn-replay svg {
    opacity: 0.75;
}

#btn-replay:hover {
    color: var(--orange);
    border-color: var(--orange);
    box-shadow: 0 8px 22px rgba(255, 144, 34, 0.20), 0 1px 4px rgba(0, 0, 0, 0.06);
    transform: translateX(-50%) translateY(-2px);
}

#btn-replay:hover svg {
    opacity: 1;
}

/* hint pill - top center of canvas, below badge */
#hint {
    position: absolute;
    top: 60px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 30;
    pointer-events: none;
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 300;
    color: #ffffff;
    letter-spacing: .06em;
    padding: 5px 12px;
    border: 1px solid rgba(255, 255, 255, .1);
    border-radius: 20px;
    background: #1a1a2e;
    backdrop-filter: blur(6px);
    opacity: 0;
    transition: opacity .6s ease;
    white-space: nowrap;
}

#hint.on {
    opacity: 1;
}

/* ── info panel ── */
#panel {
    /* Permanently docked to the bottom-left corner so it never covers Gizmobot
       (a centered panel buried the model on shorter screens) and can't be
       dragged out of place. */
    position: absolute;
    bottom: var(--edge);
    left: var(--edge);
    transform: none;
    width: min(92vw, var(--panel-w));
    /* Solid (was rgba .96 + blur). The blur was invisible at that opacity but
       forced a full backdrop-filter recomposite every frame the 3D scene moved
       behind it - the main source of jank during the camera sweeps in Watch
       demos. Dropping it keeps the look and smooths every camera move. */
    background: #fbfbfa;
    border: 1px solid rgba(0, 0, 0, 0.06);
    border-radius: 14px;
    box-shadow:
        0 12px 32px rgba(0, 0, 0, 0.06),
        0 4px 12px rgba(0, 0, 0, 0.03);
    padding: var(--pad-panel);
    display: flex;
    flex-direction: column;
    gap: var(--gap-panel);
    z-index: 50;
    pointer-events: auto;
    cursor: default;
    transition: box-shadow .4s ease, border-color .4s ease;
}

#panel.panel-watching {
    border-color: rgba(26, 26, 46, .55);
    box-shadow:
        inset 0 0 0 1px rgba(26, 26, 46, .55),
        0 12px 32px rgba(0, 0, 0, .06),
        0 4px 12px rgba(0, 0, 0, .03);
}

#panel.panel-interacting {
    border-color: var(--orange);
    box-shadow:
        inset 0 0 0 1px var(--orange),
        0 12px 32px rgba(0, 0, 0, .06),
        0 4px 12px rgba(0, 0, 0, .03);
}

/* panel is fixed in place now - the drag grip is gone */
#drag-handle {
    display: none;
}

#panel * {
    pointer-events: auto;
}

.home-btn {
    position: fixed;
    top: var(--edge);
    left: var(--edge);
    z-index: 1000;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    background: rgba(23, 30, 53, 0.7);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 8px;
    color: #fff;
    text-decoration: none;
    font-family: 'Lexend', sans-serif;
    font-size: var(--fs-ui);
    font-weight: 500;
    transition: all 0.3s ease;
}

.home-btn:hover {
    background: rgba(23, 30, 53, 0.95);
    border-color: var(--orange);
    color: var(--orange);
    transform: translateX(-4px);
}

.panel-header {
    display: flex;
    flex-direction: column;
    gap: 0;
}

#cap-step {
    font-size: var(--fs-step);
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--green);
    font-family: var(--mono);
    margin-bottom: 5px;
    opacity: 0;
    max-height: 0;
    overflow: hidden;
    transition: opacity .4s ease, max-height .4s ease;
}

#cap-step.on {
    opacity: 1;
    max-height: 24px;
}

#cap-title {
    font-size: var(--fs-title);
    font-weight: 500;
    color: #111;
    line-height: 1.25;
    letter-spacing: -.02em;
    margin-bottom: 5px;
    opacity: 0;
    transition: opacity .45s ease;
}

#cap-body {
    font-size: var(--fs-body);
    font-weight: 300;
    color: #555;
    line-height: 1.72;
    opacity: 0;
    transition: opacity .45s ease .06s;
}

#cap-title.on {
    opacity: 1;
}

#cap-body.on {
    opacity: 1;
}

#cap-body b {
    color: #222;
    font-weight: 400;
}

#cap-body .co {
    color: var(--orange);
}

#cap-body .cx {
    color: var(--axis-x);
}

#cap-body .cy {
    color: var(--axis-y);
}

#cap-body .cz {
    color: var(--axis-z);
}

/* small muted follow-up tip inside a caption (e.g. the reset-tool callout) */
#cap-body .cap-tip {
    display: inline-block;
    margin-top: 8px;
    font-size: 13px;
    color: #8a8a8a;
}

#cap-body .cap-tip b {
    color: var(--orange);
    font-weight: 500;
}

/* loading state */
#loading {
    position: absolute;
    inset: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--dark);
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 300;
    color: rgba(255, 255, 255, .35);
    letter-spacing: .1em;
    transition: opacity .8s ease;
}

#loading.fade {
    opacity: 0;
    pointer-events: none;
}

/* action side */
.panel-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 6px;
}

/* continue button - display:none while locked so the panel doesn't reserve a
   big empty footer; fades/slides in via keyframes when it unlocks */
#btn-continue {
    display: none;
    align-items: center;
    gap: 7px;
    padding: var(--pad-btn);
    background: var(--orange);
    border: none;
    border-radius: 7px;
    font-family: var(--font);
    font-size: var(--fs-btn);
    font-weight: 500;
    color: #fff;
    cursor: pointer;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: transform .15s ease, background .15s;
}

#btn-continue.on {
    display: inline-flex;
    opacity: 1;
    pointer-events: all;
    /* 'backwards' (not 'both') so the finished animation releases transform -
       otherwise it would pin translateY(0) and break the hover lift */
    animation: continueIn .45s cubic-bezier(.34, 1.3, .64, 1) backwards;
}

@keyframes continueIn {
    from {
        opacity: 0;
        transform: translateY(8px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

#btn-continue:hover {
    background: #e07010;
    transform: translateY(-1px);
}

#btn-continue:active {
    transform: translateY(0);
}

.continue-side {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 5px;
    margin-left: auto;
}

#kbd-hint {
    display: none;
    font-family: var(--mono);
    font-size: 10px;
    color: var(--green);
    opacity: 0;
    pointer-events: none;
    letter-spacing: .02em;
}

#kbd-hint.on {
    display: block;
    opacity: 1;
    animation: continueIn .45s ease .1s backwards;
}

#kbd-hint kbd {
    display: inline-block;
    background: rgba(0, 0, 0, .05);
    border: 1px solid rgba(0, 0, 0, .12);
    border-bottom-width: 2px;
    border-radius: 4px;
    padding: 1px 5px;
    font-family: var(--mono);
    font-size: 10px;
    color: var(--green);
}

/* demo cursor */
#demo-cursor {
    position: absolute;
    z-index: 200;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.3s;
    transform: translate(0, 0);
    display: flex;
    align-items: flex-start;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.3));
}

#demo-cursor.on {
    opacity: 1;
}

#cursor-arrow {
    display: block;
}

/* press feedback: a glow around the pointer - orange for left-click drags,
   green for right-click (pan) drags */
#demo-cursor.down {
    filter: drop-shadow(0 0 5px rgba(255, 144, 34, 0.95)) drop-shadow(0 0 14px rgba(255, 144, 34, 0.55));
}

#demo-cursor.down.right {
    filter: drop-shadow(0 0 5px rgba(0, 170, 0, 0.95)) drop-shadow(0 0 14px rgba(0, 170, 0, 0.55));
}

/* mouse interaction diagram */
.mouse-rig {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
    margin-top: 10px;
}

/* Scale the diagram with the rest of the UI. The SVG ships with fixed 65x80
   attributes from mouseDiagram.js, but its viewBox lets CSS resize it; height
   auto keeps the aspect ratio. */
.mouse-rig svg {
    width: clamp(52px, 7vmin, 74px);
    height: auto;
}

.mouse-label {
    font-family: var(--mono);
    font-size: 9px;
    letter-spacing: .13em;
    color: #9b9799;
    text-transform: uppercase;
}

/* Arrow bob animations - applied to SVG <g> elements */
@keyframes arrBobUp {

    0%,
    100% {
        transform: translateY(0);
        opacity: .6;
    }

    50% {
        transform: translateY(-5px);
        opacity: 1;
    }
}

@keyframes arrBobDown {

    0%,
    100% {
        transform: translateY(0);
        opacity: .6;
    }

    50% {
        transform: translateY(5px);
        opacity: 1;
    }
}

@keyframes arrBobLeft {

    0%,
    100% {
        transform: translateX(0);
        opacity: .6;
    }

    50% {
        transform: translateX(-5px);
        opacity: 1;
    }
}

@keyframes arrBobRight {

    0%,
    100% {
        transform: translateX(0);
        opacity: .6;
    }

    50% {
        transform: translateX(5px);
        opacity: 1;
    }
}

@keyframes arrBobArcL {

    0%,
    100% {
        transform: translateX(0);
        opacity: .6;
    }

    50% {
        transform: translateX(-4px);
        opacity: 1;
    }
}

@keyframes arrBobArcR {

    0%,
    100% {
        transform: translateX(0);
        opacity: .6;
    }

    50% {
        transform: translateX(4px);
        opacity: 1;
    }
}

.arr-up {
    animation: arrBobUp 1.4s ease-in-out infinite;
    transform-box: fill-box;
    transform-origin: center;
}

.arr-down {
    animation: arrBobDown 1.4s ease-in-out infinite .7s;
    transform-box: fill-box;
    transform-origin: center;
}

.arr-left {
    animation: arrBobLeft 1.4s ease-in-out infinite;
    transform-box: fill-box;
    transform-origin: center;
}

.arr-right {
    animation: arrBobRight 1.4s ease-in-out infinite .7s;
    transform-box: fill-box;
    transform-origin: center;
}

.arr-arc-l {
    animation: arrBobArcL 1.6s ease-in-out infinite;
    transform-box: fill-box;
    transform-origin: center;
}

.arr-arc-r {
    animation: arrBobArcR 1.6s ease-in-out infinite .8s;
    transform-box: fill-box;
    transform-origin: center;
}

/* free play widget */
#free-play-widget {
    position: absolute;
    bottom: var(--edge);
    left: 50%;
    transform: translateX(-50%);
    z-index: 60;
    background: rgba(255, 255, 255, 0.97);
    backdrop-filter: blur(16px);
    padding: 8px;
    border-radius: 16px;
    box-shadow: 0 12px 36px rgba(0, 0, 0, 0.14), 0 2px 8px rgba(0, 0, 0, 0.06);
    border: 1px solid rgba(0, 0, 0, 0.06);
    display: none;
    gap: 6px;
}

.fp-btn {
    background: transparent;
    border: none;
    padding: clamp(11px, 1.7vmin, 15px) clamp(20px, 3.4vmin, 30px);
    border-radius: 10px;
    font-family: var(--font);
    font-size: var(--fs-btn);
    font-weight: 500;
    color: #555;
    cursor: pointer;
    transition: all 0.2s;
    letter-spacing: -.01em;
}

.fp-btn.active {
    background: var(--orange);
    color: #fff;
    box-shadow: 0 4px 14px rgba(255, 144, 34, .45);
}

.fp-btn:hover:not(.active) {
    background: rgba(0, 0, 0, 0.05);
    color: #222;
}

.logo-top-right {
    position: fixed;
    top: var(--edge);
    right: var(--edge);
    z-index: 1000;
    height: var(--logo-h);
    width: auto;
    object-fit: contain;
    pointer-events: none;
    opacity: 0.9;
}

/* utility bar */
#util-bar {
    position: absolute;
    bottom: var(--edge);
    right: var(--edge);
    display: flex;
    flex-direction: row;
    gap: 8px;
    z-index: 100;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.4s ease, transform 0.4s ease;
    transform: translateY(10px);
}

#util-bar.on {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

/* draw the eye to the reset buttons when a step calls them out */
#util-bar.callout .util-btn {
    animation: utilCallout 1.1s cubic-bezier(.34, 1.56, .64, 1) 3;
}

@keyframes utilCallout {

    0%,
    100% {
        transform: translateY(0);
        box-shadow: 0 6px 20px rgba(0, 0, 0, 0.10), 0 1px 4px rgba(0, 0, 0, 0.06);
    }

    45% {
        transform: translateY(-6px);
        box-shadow: 0 12px 30px rgba(255, 144, 34, 0.35), 0 2px 8px rgba(0, 0, 0, 0.10);
        border-color: var(--orange);
    }
}

.util-btn {
    background: #ffffff;
    /* was rgba .97 + blur - blur invisible but costly per-frame */
    border: 1.5px solid rgba(0, 0, 0, 0.12);
    border-radius: 10px;
    padding: var(--pad-btn);
    font-family: var(--font);
    font-size: var(--fs-ui);
    font-weight: 600;
    color: #222;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.10), 0 1px 4px rgba(0, 0, 0, 0.06);
    transition: all 0.25s cubic-bezier(0.2, 0.8, 0.2, 1);
    white-space: nowrap;
}

.util-btn:hover {
    background: #fff;
    border-color: var(--orange);
    color: var(--orange);
    transform: translateY(-4px);
    box-shadow: 0 10px 28px rgba(255, 144, 34, 0.22), 0 2px 8px rgba(0, 0, 0, 0.08);
}

.util-btn svg {
    opacity: 0.8;
}

.util-btn:hover svg {
    opacity: 1;
}

/* ── finish / back-to-home button (beat 11) ── */
#btn-finish {
    display: none;
    align-items: center;
    gap: 8px;
    padding: var(--pad-btn);
    background: var(--dark);
    border: none;
    border-radius: 7px;
    font-family: var(--font);
    font-size: var(--fs-btn);
    font-weight: 500;
    color: #fff;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
    transition: background .2s, transform .15s;
}

#btn-finish.on {
    display: inline-flex;
}

#btn-finish:hover {
    background: var(--orange);
    transform: translateY(-2px);
}

#btn-finish svg {
    opacity: 0.8;
}

/* ── celebration panel (beat 11) ── */
#panel.panel-celebrate {
    border-color: rgba(255, 144, 34, 0.25);
    box-shadow:
        0 0 0 3px rgba(255, 144, 34, 0.12),
        0 20px 60px rgba(0, 0, 0, 0.10),
        0 6px 16px rgba(0, 0, 0, 0.05);
}

#panel.panel-celebrate #cap-title {
    background: linear-gradient(120deg, #FF9022, #e07010);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    font-size: clamp(19px, 2.5vmin, 26px);
}

/* star burst / pop animation for celebration emoji */
@keyframes celebPop {
    0% {
        transform: scale(0) rotate(-10deg);
        opacity: 0;
    }

    60% {
        transform: scale(1.15) rotate(4deg);
        opacity: 1;
    }

    100% {
        transform: scale(1) rotate(0deg);
        opacity: 1;
    }
}

.cap-celebrate-icon {
    display: inline-block;
    animation: celebPop .55s cubic-bezier(.34, 1.56, .64, 1) both;
    margin-right: 6px;
}

/* The old max-width:1000px / max-height:720px "trim" query is gone - the fluid
   --fs-* / --pad-panel tokens (vmin-based clamps) now shrink the panel smoothly
   on narrow and short screens without a hard breakpoint. */

/* ── very small screens: dock the panel as a full-width bottom bar ──
   Frees the corners on phones. The reset buttons and free-play widget stack
   just above the bar via --panel-h (its real height, tracked in main.js).
   Kept last so it wins over the trim rules above. */
@media (max-width: 640px) {
    #panel {
        left: 0;
        right: 0;
        bottom: 0;
        width: 100%;
        max-width: none;
        border-radius: 14px 14px 0 0;
        border-left: none;
        border-right: none;
        border-bottom: none;
        padding: 14px 20px calc(16px + env(safe-area-inset-bottom, 0px));
    }

    #util-bar {
        right: 12px;
        bottom: calc(var(--panel-h) + 12px);
    }

    #free-play-widget {
        bottom: calc(var(--panel-h) + 12px);
    }
}