* {
    margin: 0;
    padding: 0;
}

html,
body {
    overflow: hidden;
    /**
     * The wall behind the machine. This cannot be the renderer's clear colour:
     * an opaque canvas would cover the CSS3D desktop entirely. Sampled from the
     * outer edge of the monitor shell so wall and casing meet without a seam.
     */
    background-color: #9d989b;
}

#webgl {
    pointer-events: none;
}

#css {
    cursor: pointer;
}

#monitor-videos {
    pointer-events: none;
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    top: 0;
    left: 0;
}

video {
    position: absolute;
    top: 0;
    pointer-events: none;
}

/**
 * Film grain over the whole scene. This used to be a second WebGL context
 * rendering a noise shader; an SVG turbulence tile with a stepped drift is
 * visually equivalent and costs no GPU context.
 */
#grain {
    position: fixed;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    opacity: 0.12;
    mix-blend-mode: soft-light;
    background-image: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%27160%27 height=%27160%27%3E%3Cfilter id=%27n%27%3E%3CfeTurbulence type=%27fractalNoise%27 baseFrequency=%270.85%27 numOctaves=%273%27 stitchTiles=%27stitch%27/%3E%3C/filter%3E%3Crect width=%27160%27 height=%27160%27 filter=%27url%28%23n%29%27/%3E%3C/svg%3E");
    animation: grain-drift 0.6s steps(1) infinite;
}

@keyframes grain-drift {
    0% { background-position: 0 0; }
    25% { background-position: -37px 19px; }
    50% { background-position: 23px -41px; }
    75% { background-position: -13px -29px; }
    100% { background-position: 31px 11px; }
}

/* Boot overlay: black until the scene is ready, then it fades and is removed. */
#boot {
    position: fixed;
    inset: 0;
    z-index: 10;
    background: #9d989b;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 0.45s ease-out;
}

#boot-track {
    width: 180px;
    height: 2px;
    background: #7b7779;
    overflow: hidden;
}

#boot-bar {
    width: 0%;
    height: 100%;
    background: #0052ff;
    transition: width 0.25s ease-out;
}

#boot-error {
    font-family: monospace;
    font-size: 13px;
    letter-spacing: 0.08em;
    color: #4a4749;
    text-transform: uppercase;
}

/* Sub-pixel wobble on the screen plane so the CRT never looks perfectly still */
.jitter {
    animation-duration: 0.3s;
    animation-timing-function: ease-in-out;
    animation-fill-mode: forwards;
    animation-iteration-count: infinite;
    animation-name: jittery;
    z-index: -10;
}

@keyframes jittery {
    10% { transform: translate(-0.1px, -0.15px) scale(1, 1); }
    20% { transform: translate(0.15px, 0.1px) scale(1, 1); }
    30% { transform: translate(-0.2px, -0.25px) scale(1, 1); }
    40% { transform: translate(0.05px, 0.1px) scale(1, 1); }
    50% { transform: translate(-0.025px, -0.05px) scale(1, 1); }
    60% { transform: translate(0px, 0.075px) scale(1, 1); }
    70% { transform: translate(-0.075px, -0.1px) scale(1, 1); }
    80% { transform: translate(0.075px, 0.125px) scale(1, 1); }
    90% { transform: translate(-0.125px, -0.075px) scale(1, 1); }
    100% { transform: translate(0.075px, 0.025px) scale(1, 1); }
}

/* =====================================================================
   Mobile shell
   The 3D scene is never constructed on a phone, so its layers come off
   the page too: a full-screen blended grain overlay repainting every
   0.6s is pure cost with nothing on screen to justify it. The monitor's
   video textures are not listed here at all -- the CRT creates those
   itself, so a phone never fetches or decodes them.
   ===================================================================== */

.layout-mobile #webgl,
.layout-mobile #css,
.layout-mobile #grain {
    display: none;
}

.layout-mobile,
.layout-mobile body {
    /* Behind the shell during rubber-banding, and under the safe-area inset */
    background-color: #000000;
    /* Kills the 300ms double-tap zoom delay while leaving pinch zoom alone */
    touch-action: manipulation;
    overscroll-behavior: none;
    -webkit-text-size-adjust: 100%;
}

.layout-mobile #boot {
    background: #000000;
}

#mobile-shell {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    /* dvh tracks the iOS URL bar; vh is the fallback for older WebKit */
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
    box-sizing: border-box;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
    background-color: #000000;
}

.layout-mobile #desktop-root {
    width: 100%;
    height: 100%;
    position: relative;
}

/**
 * What is left of the CRT once the monitor is gone: scanlines and a corner
 * vignette. Both are static gradients, so they composite once on load and
 * then cost nothing per frame -- unlike the grain layer they replace.
 */
#mobile-glass {
    position: absolute;
    inset: 0;
    z-index: 5;
    pointer-events: none;
    background-image:
        repeating-linear-gradient(
            to bottom,
            rgba(0, 0, 0, 0.055) 0px,
            rgba(0, 0, 0, 0.055) 1px,
            rgba(0, 0, 0, 0) 1px,
            rgba(0, 0, 0, 0) 3px
        ),
        radial-gradient(
            125% 105% at 50% 50%,
            rgba(0, 0, 0, 0) 55%,
            rgba(0, 0, 0, 0.3) 100%
        );
}

@media (prefers-reduced-motion: reduce) {
    #grain,
    .jitter {
        animation: none;
    }
}


/*# sourceMappingURL=main.css.map*/