/* griffinland's own desktop. main.css is mocial's stylesheet copied as-is,
   so windows, the taskbar and the fonts match; everything here belongs to
   this desktop alone. */

/* Back to mocial: second column at griffinland's spot on mocial (181px,
   right 81px), so the two icons trade you back and forth from one place */
#mocial-icon-group {
    top: 181px;
    right: 81px;
}

/* 64x81 pixel-art gif - sized by height to sit level with the 44px icons */
#mocial-icon {
    -webkit-user-drag: none;
    user-drag: none;
    user-select: none;
    position: absolute;
    top: 0;
    right: 31px; /* centers the ~38px-wide icon within the 100px group */
    height: 48px;
    width: auto;
    image-rendering: pixelated;
}

#mocial-icon-label {
    position: absolute;
    right: 0;
    width: 100px;
    text-align: center;
    font-family: 'W95FA', sans-serif;
    font-size: 13px;
    line-height: 1.2;
    top: 52px;
}

#mocial-icon-label a {
    color: #fff;
    text-decoration: none;
}

/* ===== Gate with hangman ==================================================
   The password dialog stays dead center, exactly where it sits on mocial;
   the two games that win the password hang off its sides, centered on it -
   hangman on the right, dice on the left. The wrapper is the dialog's width,
   so the games are placed against the dialog rather than the screen edges.
   Where there's no room beside it, they drop below it and the gate scrolls. */
#password-gate {
    overflow-y: auto;
}

/* Auto margins rather than the gate's own centering: they center the same,
   but a too-tall stack starts at the top where it can be scrolled to, not
   pushed off the top of the screen */
#gate-windows {
    position: relative;
    margin: auto;
    width: 100%;
    max-width: 560px;   /* the dialog's own max-width */
}

#hangman-window,
#dice-window {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 320px;
    text-align: left;
}
#hangman-window {
    left: calc(100% + 24px);
}
#dice-window {
    right: calc(100% + 24px);
}

/* Beside the dialog needs 560 + 2 x (24 + 320) across, and the hangman's
   height down. Short of that, both stack under the dialog. */
@media screen and (max-width: 1279px), screen and (max-height: 659px) {
    #gate-windows {
        padding-top: 90px;   /* with the gate's 20px, clears the ~105px typed title */
    }
    #hangman-window,
    #dice-window {
        position: static;
        transform: none;
        width: 100%;
        max-width: 360px;
        margin: 20px auto 0;
    }
}

.hangman-inner {
    padding: 14px 16px 16px;
    box-sizing: border-box;
}

/* A ? button's pop-up: a Win95 "What's This?" tip, pale yellow with a
   hard black border, hanging just under the title bar's buttons */
.title-tip {
    position: absolute;
    top: calc(100% + 4px);
    right: 4px;
    z-index: 1;
    padding: 4px 8px;
    background: #ffffe1;
    border: 1px solid #000;
    box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.35);
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    font-weight: normal;
    color: #000;
    white-space: nowrap;
}
.title-tip[hidden] {
    display: none;
}
#hangman-help,
#dice-help {
    cursor: url('cursor-pointer.png') 8 0, pointer;
}

/* The drawing sits in a white inset well, like a Paint canvas */
#hangman-drawing {
    display: block;
    width: 100%;
    height: 180px;   /* the drawing letterboxes to fit, centered */
    background: #fff;
    border: 2px inset #d8d8d8;
    box-sizing: border-box;
}
#hangman-drawing .hm-gallows rect {
    fill: #a89a86;
    stroke: #000;
    stroke-width: 2;
}
#hangman-drawing path,
#hangman-drawing circle {
    fill: none;
    stroke: #000;
    stroke-width: 3;
    stroke-linecap: round;
}
#hangman-drawing .hm-gallows path:not(.hm-rope) {
    stroke-width: 6;
    stroke: #6f6455;
}
#hangman-drawing .hm-part,
#hangman-drawing .hm-face {
    visibility: hidden;
}
#hangman-drawing .hm-part.shown,
#hangman-drawing.lost .hm-face {
    visibility: visible;
}
#hangman-drawing .hm-face {
    stroke-width: 2;
}

#hangman-word,
#dice-word {
    margin: 12px 0 10px;
    text-align: center;
    font-family: 'W95FA', monospace;
    font-size: 26px;
    letter-spacing: 4px;
    white-space: pre;
}

#hangman-letters {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 4px;
}

/* Raised Win95 keys; played ones go flat and get the screenshot's marks -
   a green ring for a hit, a red cross for a miss */
#hangman-letters button {
    position: relative;
    font-family: 'W95FA', Tahoma, sans-serif;
    font-size: 16px;
    padding: 4px 0;
    background: #d8d8d8;
    border: 2px outset #f0f0f0;
    border-radius: 0;
    color: #000;
    cursor: url('cursor-pointer.png') 8 0, pointer;
}
#hangman-letters button:active {
    border-style: inset;
}
#hangman-letters button:disabled {
    border-style: inset;
    background: #c8c8c8;
    cursor: default;
}
#hangman-letters button.hit::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 24px;
    height: 24px;
    transform: translate(-50%, -50%);
    border: 3px solid #1a8a1a;
    border-radius: 50%;
}
#hangman-letters button.miss {
    color: #555;
}
#hangman-letters button.miss::before,
#hangman-letters button.miss::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 24px;
    height: 3px;
    background: #d01010;
    transform: translate(-50%, -50%) rotate(45deg);
}
#hangman-letters button.miss::after {
    transform: translate(-50%, -50%) rotate(-45deg);
}

#hangman-status {
    min-height: 18px;
    margin: 10px 0 8px;
    font-size: 13px;
}

.hangman-buttons {
    flex-direction: row;
    justify-content: flex-end;
}

/* ===== Dice ================================================================
   Two white dice on a green felt well, the green of Win95's Solitaire */
.dice-inner {
    padding: 14px 16px 16px;
    box-sizing: border-box;
}

.dice-felt {
    display: flex;
    justify-content: center;
    gap: 24px;
    padding: 26px 0;
    background: #008000;
    border: 2px inset #d8d8d8;
}

/* A 3x3 grid of spots; main.js marks which ones carry a pip */
.die {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(3, 1fr);
    width: 64px;
    height: 64px;
    padding: 8px;
    box-sizing: border-box;
    background: #fff;
    border: 2px solid #000;
    border-radius: 9px;
    box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.45);
}
.die span {
    align-self: center;
    justify-self: center;
    width: 11px;
    height: 11px;
    border-radius: 50%;
}
.die span.pip {
    background: #000;
}
/* Sixes are the ones that count, so they land red */
.die[data-face="6"] span.pip {
    background: #c00000;
}

#dice-status {
    min-height: 34px;
    font-size: 13px;
}

.dice-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 8px;
    font-size: 13px;
}

.dice-buttons {
    flex-direction: row;
}
.password-buttons button:disabled {
    color: #808080;
    text-shadow: 1px 1px 0 #fff;
    border-style: outset;
    cursor: default;
}

/* ===== Welcome =============================================================
   The pop-up that greets visitors on the desktop: griffinland as the far side
   of the pearly gates. A sky scene on top - sun rays turning, clouds drifting,
   the gates swinging open and the spinning world rising out as an angel -
   under gold WordArt, then a grey Win95 body with a fake progress bar.
   Everything plays once the window gets .welcome-play (see main.js). */
#welcome-window {
    display: none;
    top: 70px;
    width: min(560px, calc(100vw - 32px));
    text-align: left;
}

.welcome-inner {
    background: #d8d8d8;
}

.welcome-sky {
    position: relative;
    height: 320px;
    overflow: hidden;
    container-type: inline-size;
    background: linear-gradient(180deg, #6fb7ff 0%, #a9d8ff 45%, #ffe7f3 80%, #fff6d6 100%);
    border-bottom: 2px solid #808080;
}

/* Sun rays fanning out from behind the gates, slowly turning */
.welcome-rays {
    position: absolute;
    left: 50%;
    top: 74%;
    width: 900px;
    height: 900px;
    margin: -450px 0 0 -450px;
    background: repeating-conic-gradient(rgba(255, 250, 210, 0.75) 0deg 8deg, rgba(255, 250, 210, 0) 8deg 20deg);
    -webkit-mask: radial-gradient(circle, #000 8%, transparent 52%);
    mask: radial-gradient(circle, #000 8%, transparent 52%);
    animation: welcome-spin 40s linear infinite;
}

/* The floor of cloud: a row of white puffs, scrolling sideways. Two layers,
   one behind the gates and one in front of their feet. */
.welcome-cloudbank {
    position: absolute;
    left: 0;
    right: 0;
    bottom: -18px;
    height: 70px;
    background: radial-gradient(circle at 34px 40px, #fff 30px, transparent 31px) repeat-x;
    background-size: 68px 70px;
    animation: welcome-bank 14s linear infinite;
}
.welcome-cloudbank-back {
    bottom: 14px;
    opacity: 0.75;
    background-size: 90px 70px;
    animation-duration: 22s;
    animation-direction: reverse;
}

/* Loose clouds drifting across the sky, each its own speed and size */
.welcome-cloud {
    position: absolute;
    left: -160px;
    top: var(--top);
    width: 110px;
    height: 34px;
    background: #fff;
    border-radius: 34px;
    opacity: 0.92;
    animation: welcome-drift var(--dur) linear var(--delay) infinite;
}
.welcome-cloud::before,
.welcome-cloud::after {
    content: "";
    position: absolute;
    background: #fff;
    border-radius: 50%;
}
.welcome-cloud::before {
    left: 18px;
    top: -20px;
    width: 44px;
    height: 44px;
}
.welcome-cloud::after {
    left: 50px;
    top: -30px;
    width: 52px;
    height: 52px;
}

.welcome-sparkle {
    position: absolute;
    color: #fff8c0;
    font-size: 18px;
    text-shadow: 0 0 6px #fff;
    animation: welcome-twinkle 1.8s ease-in-out var(--delay) infinite;
}

/* The light pouring out between the gates as they open */
.welcome-glow {
    position: absolute;
    left: 50%;
    bottom: 30px;
    width: 220px;
    height: 170px;
    margin-left: -110px;
    background: radial-gradient(ellipse at 50% 70%, #fff 0%, rgba(255, 246, 190, 0.9) 35%, rgba(255, 246, 190, 0) 70%);
    transform: scale(0.3);
    opacity: 0;
}

.welcome-gates {
    position: absolute;
    left: 50%;
    bottom: 34px;
    width: 200px;
    height: 150px;
    margin-left: -100px;
    display: flex;
    perspective: 500px;
}
.welcome-gate {
    width: 100px;
    height: 150px;
    overflow: visible;
}
.welcome-gate path {
    fill: none;
    stroke: #c9a227;
    stroke-width: 5;
    stroke-linecap: round;
}
.welcome-gate circle {
    fill: #fffdf4;
    stroke: #c9a227;
    stroke-width: 1.5;
}
.welcome-gate-left {
    transform-origin: left center;
}
.welcome-gate-right {
    transform-origin: right center;
}

/* The angel rises up out of the gates and then hovers there, flapping */
.welcome-angel {
    position: absolute;
    left: 50%;
    bottom: 40px;
    width: 140px;
    height: 100px;
    margin-left: -70px;
    opacity: 0;
}
/* Out-specifies `.popup-window .popup-inner-wrapper img`, which stretches
   window images to full width */
#welcome-window .popup-inner-wrapper .welcome-angel img {
    position: absolute;
    left: 50%;
    top: 30px;
    width: 58px;
    margin-left: -29px;
    image-rendering: pixelated;
}
.welcome-halo {
    position: absolute;
    left: 50%;
    top: 12px;
    width: 46px;
    height: 12px;
    margin-left: -23px;
    border: 4px solid #ffd700;
    border-radius: 50%;
    box-shadow: 0 0 10px #fff3a0, inset 0 0 6px #fff3a0;
    animation: welcome-halo 1.6s ease-in-out infinite alternate;
}
.welcome-wing {
    position: absolute;
    top: 30px;
    width: 52px;
    height: 38px;
    overflow: visible;
}
.welcome-wing path {
    fill: #fff;
    stroke: #9aa7b8;
    stroke-width: 2;
    stroke-linejoin: round;
}
.welcome-wing-left {
    left: 18px;
    transform-origin: right 60%;
    animation: welcome-flap-left 0.32s ease-in-out infinite alternate;
}
.welcome-wing-right {
    right: 18px;
    transform-origin: left 60%;
    animation: welcome-flap-right 0.32s ease-in-out infinite alternate;
}

/* Gold WordArt, each letter riding its own wave. Sized off the window's
   width so "GRIFFINLAND" always fits on one line. */
.welcome-wordart {
    position: absolute;
    left: 0;
    right: 0;
    top: 12px;
    text-align: center;
    font-family: "Times New Roman", Times, serif;
    font-weight: 900;
    line-height: 1;
    filter: drop-shadow(3px 3px 0 #7a3d00) drop-shadow(0 0 8px rgba(255, 255, 255, 0.85));
}
.welcome-wordart-line {
    display: block;
    white-space: nowrap;
}
.welcome-wordart-line:first-child {
    font-size: clamp(22px, 6cqw, 32px);
    margin-bottom: 2px;
}
.welcome-wordart-line + .welcome-wordart-line {
    font-size: clamp(30px, 9.4cqw, 54px);
}
.welcome-wordart .letter {
    display: inline-block;
    color: transparent;
    background: linear-gradient(180deg, #fffbe0 0%, #ffd700 42%, #d98a00 58%, #ffe680 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-stroke: 1px #8a4b00;
    animation: welcome-wave 1.4s ease-in-out calc(var(--i) * 0.07s) infinite;
}

.welcome-body {
    padding: 14px 16px;
    font-family: Tahoma, Geneva, sans-serif;
}
.welcome-buttons {
    flex-direction: row;
    justify-content: center;
}

/* ----- What plays when the window opens ----- */
.welcome-play .welcome-gate-left {
    animation: welcome-gate-left 1.6s ease-in-out 0.5s both;
}
.welcome-play .welcome-gate-right {
    animation: welcome-gate-right 1.6s ease-in-out 0.5s both;
}
.welcome-play .welcome-glow {
    animation: welcome-glow-open 1.6s ease-out 0.6s forwards,
               welcome-glow-pulse 2.2s ease-in-out 2.2s infinite alternate;
}
.welcome-play .welcome-angel {
    animation: welcome-ascend 1.6s cubic-bezier(0.22, 1, 0.36, 1) 1.3s both,
               welcome-hover 2.4s ease-in-out 2.9s infinite alternate;
}
.welcome-play .welcome-wordart {
    animation: welcome-pop 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

@keyframes welcome-spin {
    to { transform: rotate(360deg); }
}
@keyframes welcome-bank {
    to { background-position-x: -680px; }
}
@keyframes welcome-drift {
    to { transform: translateX(900px); }
}
@keyframes welcome-twinkle {
    0%, 100% { transform: scale(0.4) rotate(0deg); opacity: 0.2; }
    50% { transform: scale(1.2) rotate(45deg); opacity: 1; }
}
@keyframes welcome-gate-left {
    to { transform: rotateY(-62deg); }
}
@keyframes welcome-gate-right {
    to { transform: rotateY(62deg); }
}
@keyframes welcome-glow-open {
    to { transform: scale(1); opacity: 1; }
}
@keyframes welcome-glow-pulse {
    from { transform: scale(1); opacity: 1; }
    to { transform: scale(1.12); opacity: 0.8; }
}
@keyframes welcome-ascend {
    from { transform: translateY(40px) scale(0.3); opacity: 0; }
    to { transform: translateY(-84px) scale(1); opacity: 1; }
}
@keyframes welcome-hover {
    from { transform: translateY(-84px); opacity: 1; }
    to { transform: translateY(-94px); opacity: 1; }
}
@keyframes welcome-halo {
    from { transform: translateY(0); }
    to { transform: translateY(-4px); }
}
@keyframes welcome-flap-left {
    from { transform: rotate(14deg); }
    to { transform: rotate(-26deg); }
}
@keyframes welcome-flap-right {
    from { transform: rotate(-14deg); }
    to { transform: rotate(26deg); }
}
@keyframes welcome-wave {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-6px); }
}
@keyframes welcome-pop {
    from { transform: scale(0) rotate(-8deg); }
    to { transform: scale(1) rotate(0deg); }
}

/* No motion wanted: skip straight to the gates open and the angel up */
@media (prefers-reduced-motion: reduce) {
    .welcome-sky *,
    .welcome-sky *::before,
    .welcome-sky *::after {
        animation: none !important;
    }
    .welcome-gate-left { transform: rotateY(-62deg); }
    .welcome-gate-right { transform: rotateY(62deg); }
    .welcome-glow { transform: none; opacity: 1; }
    .welcome-angel { transform: translateY(-84px); opacity: 1; }
}

/* ===== Theme ===============================================================
   griffinland's desktop is forest green where mocial's is teal - the one
   change that tells you the desktop moved. The gate and the header follow
   it so nothing flashes teal on the way in. */
:root {
    --gl-forest: #22743a;
}
body,
header,
html.gated body > header,
html.gated body.dark-mode > header,
#password-gate {
    background: var(--gl-forest);
}

/* The typed "griffinland", a size up from mocial's title */
#title {
    font-size: 2.5em;
    line-height: 1.2;
}

/* Icons stay above the horizon drawn behind them */
.desktop-icon-group {
    z-index: 2;
}

/* ===== Desktop icons ======================================================== */
.gl-icon img {
    position: absolute;
    top: 0;
    right: 28px;
    width: 44px;
    height: 44px;
    image-rendering: pixelated;
    -webkit-user-drag: none;
    user-select: none;
}
.gl-icon-label {
    position: absolute;
    top: 48px;
    right: 0;
    width: 100px;
    text-align: center;
    font-family: 'W95FA', sans-serif;
    font-size: 13px;
    line-height: 1.2;
}
.gl-icon-label a {
    color: #fff;
    text-decoration: none;
}

/* Two columns down the right edge, on the same 107px rows mocial uses */
#chat-icon-group       { top: 74px; right: 81px; }
#virus-icon-group      { top: 181px; right: 10px; }
#guestbook-icon-group  { top: 288px; right: 81px; }
#calculator-icon-group { top: 288px; right: 10px; }
#screensaver-icon-group { top: 395px; right: 10px; }
#cam-icon-group        { top: 395px; right: 81px; }   /* local copies only */
#desk-cam-icon-group   { top: 502px; right: 81px; }   /* local copies only */

/* ===== Window kit =========================================================== */
.gl-window {
    display: none;
    text-align: left;
    background: #fff;   /* a solid back, so no gap ever shows the desktop through */
}
/* The shell splits the title bar 75/25, which wraps the buttons onto a second
   line in a narrow window. griffinland's windows flex instead: buttons keep
   their size and a long title trails off. */
.gl-window .windows-header-wrapper {
    display: flex;
    align-items: center;
}
.gl-window .window-title {
    float: none;
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.gl-window .window-icons {
    float: none;
    flex: 0 0 auto;
    width: auto;
}

/* Undo the shell's full-width window images for griffinland's own windows */
.gl-window .popup-inner-wrapper img {
    width: auto;
    max-width: 100%;
    display: inline-block;
}

.gl-btn {
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    min-width: 84px;
    padding: 4px 12px;
    background: #d8d8d8;
    color: #000;
    border: 2px outset #f0f0f0;
    border-radius: 0;
    cursor: url('cursor-pointer.png') 8 0, pointer;
}
.gl-btn:active {
    border-style: inset;
}

.gl-buttons {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}

/* The ASCII-box call to action. Box-drawing characters only line up in a
   monospace font, so this one button is Courier rather than Tahoma. */
.gl-ascii-btn {
    display: inline-block;
    margin: 0;
    padding: 2px 4px;
    font-family: "Courier New", Courier, monospace;
    font-size: 13px;
    font-weight: bold;
    line-height: 1.05;
    white-space: pre;
    color: #000080;
    background: none;
    border: none;
    cursor: url('cursor-pointer.png') 8 0, pointer;
}
.gl-ascii-btn:hover,
.gl-ascii-btn:focus-visible {
    color: #fff;
    background: #000080;
    outline: none;
}

/* ===== Menu bars ============================================================ */
.gl-menubar {
    display: flex;
    gap: 2px;
    padding: 2px 4px;
    background: #ececec;
    border-bottom: 1px solid #b8b8b8;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    color: #000;
    text-align: left;
    user-select: none;
}
.gl-menubar-item {
    position: relative;
    padding: 1px 8px;
    cursor: default;
}
.gl-menubar-item:hover,
.gl-menubar-item.open {
    background: rgb(51, 78, 165);
    color: #fff;
}
.gl-menubar-item:focus-visible {
    outline: 1px dotted #000;
}

.gl-menu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 5;
    min-width: 190px;
    padding: 2px;
    background: #f2f2f2;
    border: 2px outset #f8f8f8;
    box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.35);
    color: #000;
}
.gl-menu[hidden] {
    display: none;
}
.gl-menu-row {
    display: flex;
    align-items: center;
    width: 100%;
    padding: 3px 10px 3px 2px;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    text-align: left;
    color: #000;
    background: none;
    border: none;
    cursor: default;
}
.gl-menu-row:hover:not([disabled]),
.gl-menu-row:focus-visible {
    background: rgb(51, 78, 165);
    color: #fff;
    outline: none;
}
.gl-menu-row[disabled] {
    color: #8a8a8a;
    text-shadow: 1px 1px 0 #fff;
}
.gl-menu-check {
    width: 18px;
    flex: 0 0 auto;
    text-align: center;
}
.gl-menu-label {
    flex: 1 1 auto;
}
.gl-menu-hint {
    margin-left: 14px;
    font-size: 11px;
    font-style: italic;
}
.gl-menu-divider {
    margin: 3px 2px;
    border-top: 1px solid #a8a8a8;
    border-bottom: 1px solid #fff;
}

/* ===== About ================================================================ */
#about-window {
    width: 360px;
}
.gl-about {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    padding: 16px;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    line-height: 1.5;
}
#about-window .popup-inner-wrapper img.gl-about-icon {
    width: 48px;
    height: 48px;
    flex: 0 0 auto;
    image-rendering: pixelated;
}
.gl-about-text {
    flex: 1 1 200px;
}
.gl-about-name {
    font-family: 'W95FA', sans-serif;
    font-size: 22px;
    line-height: 1.2;
}
.gl-about hr {
    border: none;
    border-top: 1px solid #c0c0c0;
    margin: 8px 0;
}
.gl-about .gl-buttons {
    flex: 1 1 100%;
}

/* ===== Snow trail ========================================================== */
.gl-sparkle {
    position: fixed;
    z-index: 300000;
    pointer-events: none;
    line-height: 1;
    color: #fff;
    text-shadow: 0 0 3px rgba(255, 255, 255, 0.6);
    transform: translate(-50%, -50%);
    animation: gl-snow-fall 4s linear forwards;   /* duration set per flake */
}
.gl-sparkle span {
    display: inline-block;
    animation: gl-snow-sway 1.4s ease-in-out infinite alternate;
}
@keyframes gl-snow-fall {
    0%   { opacity: 0; transform: translate(-50%, -50%); }
    12%  { opacity: var(--alpha); }
    70%  { opacity: var(--alpha); }
    100% { opacity: 0; transform: translate(-50%, calc(-50% + var(--fall))); }
}
@keyframes gl-snow-sway {
    from { transform: translateX(calc(var(--sway) * -1)) rotate(-25deg); }
    to { transform: translateX(var(--sway)) rotate(25deg); }
}

/* ===== not-a-virus.exe: the spam storm ====================================== */
.gl-spam {
    width: 260px;
}
.gl-spam .gl-body {
    padding: 10px 12px 12px;
    text-align: center;
    background: #fffbe6;
}
.gl-spam-head {
    font-family: "Times New Roman", Times, serif;
    font-weight: 900;
    font-style: italic;
    font-size: 22px;
    line-height: 1.05;
    animation: gl-spam-flash 0.8s steps(1, end) infinite;
}
.gl-spam .popup-inner-wrapper img.gl-spam-img {
    display: block;
    max-width: 150px;
    max-height: 90px;
    margin: 8px auto;
    image-rendering: auto;
}
.gl-spam-text {
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    line-height: 1.35;
}
.gl-spam-btn {
    margin-top: 10px;
    padding: 5px 14px;
    font-family: 'W95FA', sans-serif;
    font-size: 15px;
    color: #fff;
    background: #d81b1b;
    border: 3px outset #ff8a8a;
    cursor: url('cursor-pointer.png') 8 0, pointer;
    animation: gl-blink 0.7s steps(1, end) infinite;
}
.gl-spam-btn:active {
    border-style: inset;
}
@keyframes gl-spam-flash {
    0% { color: #d81b1b; }
    50% { color: #1b3cd8; }
}
@keyframes gl-blink {
    0% { background: #d81b1b; color: #fff; }
    50% { background: #ffe14a; color: #d81b1b; }
}

/* On a phone the shell stacks windows in the page; the storm floats instead */
@media screen and (max-width: 960px) {
    body.mobile-stacked .popup-window.gl-spam {
        position: fixed !important;
        width: min(260px, 86vw) !important;
        margin: 0 !important;
    }
}

#antivirus-window {
    width: 340px;
}
.gl-antivirus {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
    padding: 16px;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    line-height: 1.5;
}
.gl-shield {
    width: 48px;
    flex: 0 0 auto;
}
.gl-antivirus-text {
    flex: 1 1 180px;
}
.gl-antivirus-head {
    font-weight: bold;
    font-size: 15px;
}
.gl-antivirus-buttons {
    flex: 1 1 100%;
    display: flex;
    justify-content: center;
}

/* ===== The parked spam ad =================================================== */
#promo-window {
    width: 240px;
}
.gl-promo .gl-body {
    text-align: center;
    padding-bottom: 12px;
    background: #fff;
}
.gl-promo-marquee {
    overflow: hidden;
    background: #000;
    color: #ffde59;
    font-family: 'W95FA', sans-serif;
    font-size: 13px;
    padding: 3px 0;
}
.gl-promo-marquee span {
    display: inline-block;
    white-space: nowrap;
    animation: gl-marquee 10s linear infinite;
}
@keyframes gl-marquee {
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}
#promo-window .popup-inner-wrapper img.gl-promo-fire {
    display: block;
    width: 150px;
    margin: 10px auto 4px;
}
.gl-promo-text {
    padding: 0 12px;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    line-height: 1.35;
}
.gl-promo-btn {
    margin-top: 10px;
    padding: 6px 16px;
    font-family: 'W95FA', sans-serif;
    font-size: 18px;
    border: 3px outset #ff8a8a;
    cursor: url('cursor-pointer.png') 8 0, pointer;
    animation: gl-blink 0.6s steps(1, end) infinite;
}
.gl-promo-btn:active {
    border-style: inset;
}

/* ===== Screensaver ========================================================== */
.gl-saver {
    position: fixed;
    inset: 0;
    z-index: 200000;
    overflow: hidden;
    background: #000 url('gifs/space.png') repeat;
    animation: gl-stars 40s linear infinite;
    cursor: none;
}
@keyframes gl-stars {
    to { background-position: -288px 144px; }
}
.gl-saver-sprite {
    position: absolute;
    left: 0;
    top: 0;
    height: auto;
    will-change: transform;
    pointer-events: none;
}
.gl-saver-logo {
    position: absolute;
    left: 0;
    top: 0;
    font-family: "Times New Roman", Times, serif;
    font-weight: 900;
    font-style: italic;
    font-size: 52px;
    line-height: 1;
    white-space: nowrap;
    color: #ffd84a;
    text-shadow: 3px 3px 0 #000, 0 0 14px rgba(255, 255, 255, 0.5);
    will-change: transform;
}
.gl-saver-corner {
    position: absolute;
    left: 50%;
    top: 40%;
    transform: translate(-50%, -50%);
    font-family: 'W95FA', sans-serif;
    font-size: 64px;
    color: #fff;
    text-shadow: 4px 4px 0 #d81b1b;
    opacity: 0;
    pointer-events: none;
}
.gl-saver-corner.show {
    animation: gl-corner 1.8s ease-out;
}
@keyframes gl-corner {
    0% { opacity: 1; transform: translate(-50%, -50%) scale(0.4); }
    20% { transform: translate(-50%, -50%) scale(1.2); }
    80% { opacity: 1; }
    100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
}

/* ===== Tip of the Day ======================================================= */
#tips-window {
    width: 440px;
}
.gl-tips .gl-body {
    background: #d8d8d8;
}
.gl-tips-main {
    display: flex;
    gap: 14px;
    padding: 16px 16px 10px;
}
#tips-window .popup-inner-wrapper img.gl-tips-bulb {
    width: 52px;
    height: auto;
    flex: 0 0 auto;
    align-self: flex-start;
    image-rendering: pixelated;
}
.gl-tips-card {
    flex: 1 1 auto;
    min-height: 96px;
    padding: 10px 12px;
    background: #ffffe1;
    border: 2px inset #d8d8d8;
    font-family: Tahoma, Geneva, sans-serif;
}
.gl-tips-heading {
    margin-bottom: 6px;
    font-family: "Times New Roman", Times, serif;
    font-size: 19px;
    font-weight: bold;
}
.gl-tips-text {
    font-size: 14px;
    line-height: 1.45;
}
.gl-tips-footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 4px 16px 14px;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
}
.gl-tips-startup {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* ===== Hit counter and web badges =========================================== */
#gl-badges {
    position: fixed;
    left: 14px;
    bottom: 46px;
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
}

.gl-counter {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 6px;
    background: #000;
    border: 2px inset #d8d8d8;
    font-family: 'W95FA', sans-serif;
    font-size: 12px;
    color: #9fff9f;
}
.gl-counter[hidden] {
    display: none;
}
.gl-counter-digits {
    display: inline-flex;
    gap: 1px;
}
/* Each digit is a window onto a strip of 0-9 that slides up into place */
.gl-digit {
    display: inline-block;
    width: 0.72em;
    height: 1em;
    overflow: hidden;
    background: #0f2a12;
    font-family: "Courier New", Courier, monospace;
    font-size: 18px;
    font-weight: bold;
    line-height: 1em;
    text-align: center;
    color: #3dff6a;
}
.gl-digit-strip {
    display: block;
    white-space: pre;
    transition: transform 1.4s cubic-bezier(0.2, 0.9, 0.3, 1.05);
}

.gl-badge-row {
    display: flex;
    gap: 6px;
}
/* 88x31: the one true size of a web badge */
.gl-badge {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 88px;
    height: 31px;
    box-sizing: border-box;
    overflow: hidden;
    border: 1px solid #000;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 8px;
    line-height: 1.05;
    text-align: center;
}
.gl-badge b {
    font-size: 11px;
}
/* A raised silver button with a tiny CRT on it, the cursor blinking */
.gl-badge.gl-badge-viewed {
    flex-direction: row;
    gap: 4px;
    padding: 0 5px 0 4px;
    background: linear-gradient(180deg, #fafafa 0%, #dcdcdc 55%, #c4c4c4 100%);
    box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #808080;
    color: #000;
}
.gl-mini-crt {
    width: 22px;
    height: 20px;
    flex: 0 0 auto;
    shape-rendering: crispEdges;
}
.gl-mini-crt-cursor {
    animation: gl-beacon 1s steps(1, end) infinite;
}
.gl-badge-viewed-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1;
}
.gl-badge-viewed-text small {
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 7px;
    letter-spacing: 0.2px;
    text-transform: uppercase;
    color: #333;
}
.gl-badge-viewed-text b {
    margin-top: 1px;
    font-family: 'W95FA', sans-serif;
    font-size: 14px;
    font-weight: normal;
    color: #000080;
}
.gl-badge-construction {
    background: repeating-linear-gradient(-45deg, #ffd400 0 7px, #111 7px 14px);
    background-size: 200% 100%;
    animation: gl-stripes 1.2s linear infinite;
}
.gl-badge-construction b {
    padding: 1px 4px;
    font-size: 8px;
    font-weight: 900;
    color: #000;
    background: #ffd400;
    border: 1px solid #000;
}
@keyframes gl-stripes {
    to { background-position: -40px 0; }
}
.gl-beacon {
    position: absolute;
    top: 2px;
    left: 3px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #ff6a00;
    box-shadow: 0 0 6px 2px #ffae00;
    animation: gl-beacon 0.9s steps(1, end) infinite;
}
@keyframes gl-beacon {
    50% { opacity: 0.15; box-shadow: none; }
}
.gl-badge-webring {
    background: #fff;
    color: #000;
}
.gl-badge-webring b {
    font-size: 9px;
    letter-spacing: 0.5px;
}
.gl-badge-webring span {
    white-space: nowrap;
}
.gl-badge-webring a {
    color: #0000ee;
    font-size: 9px;
}

/* ===== The horizon ========================================================== */
#gl-horizon {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 38px;
    height: 170px;
    z-index: 1;
    pointer-events: none;
}
/* The dino and the birds sit back a touch; the chairs don't, which is why
   the fade is here rather than on #gl-horizon itself. */
.gl-dino,
.gl-birds {
    opacity: 0.85;
}
html.gated #gl-horizon {
    display: none;
}
/* The forest: one image, drawn by drawTrees in griffinland.js */
.gl-trees {
    position: absolute;
    left: 0;
    top: 0;
}
.gl-trees img {
    display: block;
}
/* The towers sit between the treeline and the chairs, at full strength */
.gl-towers {
    position: absolute;
    left: 0;
    top: 0;
}
.gl-towers svg {
    display: block;
    overflow: visible;
    position: absolute;
    left: 0;
    top: 0;
}
/* The ropes: no fill, and the far one paler, like its chairs */
.gl-rope path {
    fill: none;
}
.gl-rope-down {
    opacity: 0.82;
}
/* The glints along each rope slide one repeat (ROPE_LAY in griffinland.js)
   per cycle; griffinland.js sets each cycle's length so they keep pace with
   the chairs. The up rope runs left to right, the down rope back. */
.gl-rope-up .gl-rope-lay {
    animation: gl-rope-up 1s linear infinite;
}
.gl-rope-down .gl-rope-lay {
    animation: gl-rope-down 1s linear infinite;
}
@keyframes gl-rope-up {
    from { stroke-dashoffset: 0; }
    to { stroke-dashoffset: -7px; }
}
@keyframes gl-rope-down {
    from { stroke-dashoffset: 0; }
    to { stroke-dashoffset: 7px; }
}
/* The dino, out for his walk along the line - one slow lap, bobbing */
.gl-dino {
    position: absolute;
    bottom: 9px;
    left: -60px;
    height: 40px;
    width: auto;
    animation: gl-walk 90s linear infinite, gl-bob 0.5s steps(2, end) infinite;
}
@keyframes gl-walk {
    from { left: -60px; }
    to { left: 100%; }
}
@keyframes gl-bob {
    50% { transform: translateY(-2px); }
}
.gl-birds {
    position: absolute;
    top: 50px;
    left: 0;
    animation: gl-birds 45s linear infinite;
    color: #fff;
    font-family: 'W95FA', sans-serif;
    font-size: 14px;
    letter-spacing: 10px;
}
/* The chairlift. Each chair rides the cable from off the left edge to off
   the right, climbing with it (34px down at the left, 16px at the right,
   less a few px so the hanger grips it), and swings gently as it goes. */
.gl-lift {
    position: absolute;
    inset: 0;
}
.gl-chair {
    position: absolute;
    left: -80px;
    top: 32px;
    animation: gl-ride 70s linear infinite;
}
/* Every chair is griffin's chair art: its hanger clamp (49% across, 5% down
   the 84px picture) is what sits on the cable */
.gl-chair-swing {
    transform-origin: 50% 0;
    margin-left: -41px;
    margin-top: -4px;
    animation: gl-swing 3.2s ease-in-out infinite alternate;
}
.gl-chair-empty {
    display: block;
    width: 84px;
    height: 89px;
}
@keyframes gl-ride {
    from { left: -80px; top: 32px; }
    to { left: calc(100% + 80px); top: 12px; }
}
/* The downhill side: the far rope, 11px higher (BACK_UP in griffinland.js),
   so 21px down at the left and 3px at the right once the hanger grips it.
   Behind the towers, smaller, paler, mirrored to face downhill, and riding
   right to left at the same rope speed. */
.gl-lift-back {
    position: absolute;
    inset: 0;
}
.gl-chair-back {
    animation-name: gl-ride-back;
}
.gl-chair-back .gl-chair-swing {
    margin-left: -30px;
    margin-top: -3px;
}
.gl-chair-back .gl-chair-empty,
.gl-chair-back .gl-crew {
    width: 60px;
    height: 64px;
    transform: scaleX(-1);
    filter: saturate(0.55) brightness(1.08);
    opacity: 0.82;
}
@keyframes gl-ride-back {
    from { left: calc(100% + 60px); top: 3px; }
    to { left: -60px; top: 21px; }
}
@keyframes gl-swing {
    from { transform: rotate(-3deg); }
    to { transform: rotate(3deg); }
}

.gl-birds span:nth-child(2) {
    position: relative;
    top: -6px;
}
@keyframes gl-birds {
    from { transform: translateX(-80px); }
    to { transform: translateX(100vw); }
}

/* On a phone the horizon gives way to the content, and the badges sit at the
   end of the page instead of floating over it */
@media screen and (max-width: 960px) {
    #gl-horizon {
        display: none;
    }
    body.mobile-stacked #gl-badges {
        position: static;
        order: 9999;
        margin: 16px 10px;
    }
}

/* ===== Calculator =========================================================== */
#calculator-window {
    width: 300px;
}
/* Padding, not the display's margin: a first child's top margin escapes
   its parent, which left a see-through strip under the menu bar */
.gl-calc .gl-body {
    background: #d8d8d8;
    padding: 10px 0 12px;
}
.gl-calc-display {
    margin: 0 10px 10px;
    padding: 6px 10px;
    overflow: hidden;
    background: #c9dcb5;
    border: 2px inset #d8d8d8;
    font-family: "Courier New", Courier, monospace;
    font-size: 26px;
    font-weight: bold;
    text-align: right;
    white-space: nowrap;
    color: #203018;
}
.gl-calc-display.lucky {
    animation: gl-lucky 0.9s ease-out;
}
@keyframes gl-lucky {
    0% { background: #ffe680; }
    100% { background: #c9dcb5; }
}
.gl-calc-keys {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 5px;
    padding: 0 10px;
}
.gl-calc-key {
    padding: 7px 0;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 15px;
    color: #000080;
    background: #e8e8e8;
    border: 2px outset #f8f8f8;
    border-radius: 0;
    cursor: url('cursor-pointer.png') 8 0, pointer;
}
.gl-calc-key:active {
    border-style: inset;
}
.gl-calc-red {
    color: #c00000;
}
.gl-calc-gold {
    background: #ffe680;
    color: #8a4b00;
}
.gl-calc-wide {
    grid-column: span 2;
}

/* ===== DJ cam ============================================================= */
/* One window per camera, border-box so split screen tiles them exactly.
   Club colours: a dark booth, hot pink and cyan neon, and the frame and
   logo kick with the music (griffinland.js sets --gl-cam-kick, 0 to 1,
   every frame). */
@property --gl-cam-spin {
    syntax: "<angle>";
    inherits: false;
    initial-value: 0deg;
}
.gl-window.gl-cam {
    --gl-cam-pink: #ff2bd6;
    --gl-cam-cyan: #18d8ff;
    width: 480px;
    box-sizing: border-box;
}
.gl-cam .gl-body {
    background: #0e0b16;
    padding: 10px;
}
/* Split screen: the windows tile the desktop and griffinland.js fits each
   viewfinder to its picture, centred on black; the clips list steps aside */
.gl-cam-split .gl-body {
    background: #000;
}
.gl-cam-split .gl-cam-screen {
    box-sizing: border-box;
    aspect-ratio: auto;
    margin-left: auto;
    margin-right: auto;
}
/* Padding, not margin, above the controls: the viewfinder's margins centre
   it, and a margin here would merge with them and throw the sum off */
.gl-cam-split .gl-cam-controls {
    margin-top: 0;
    padding-top: 10px;
}
.gl-cam-split .gl-cam-clips {
    display: none;
}
/* Phone-sized screens stack every window anyway, so there's nothing to split */
@media screen and (max-width: 960px) {
    .gl-cam-split-btn {
        display: none;
    }
}

/* A 16:9 viewfinder in a spinning neon frame that glows on every kick
   while the camera's live */
.gl-cam-screen {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border: 3px solid transparent;
    background:
        linear-gradient(#000, #000) padding-box,
        conic-gradient(from var(--gl-cam-spin), var(--gl-cam-pink), #7a2bff, var(--gl-cam-cyan), #2bff8c, #ffe14a, var(--gl-cam-pink)) border-box;
    animation: gl-cam-spin 6s linear infinite;
    font-family: "Courier New", Courier, monospace;
    font-weight: bold;
    color: #fff;
    text-shadow: 1px 1px 0 #000;
}
.gl-cam-live .gl-cam-screen {
    box-shadow:
        0 0 calc(6px + 22px * var(--gl-cam-kick, 0)) calc(2px * var(--gl-cam-kick, 0)) rgba(255, 43, 214, calc(0.25 + 0.55 * var(--gl-cam-kick, 0))),
        0 0 4px rgba(24, 216, 255, 0.6);
}
@keyframes gl-cam-spin {
    to { --gl-cam-spin: 360deg; }
}
/* Neon corner marks */
.gl-cam-screen::before {
    content: "";
    position: absolute;
    inset: 10px;
    z-index: 1;
    pointer-events: none;
    --mark: linear-gradient(var(--gl-cam-cyan), var(--gl-cam-cyan));
    background:
        var(--mark) top left / 18px 2px, var(--mark) top left / 2px 18px,
        var(--mark) top right / 18px 2px, var(--mark) top right / 2px 18px,
        var(--mark) bottom left / 18px 2px, var(--mark) bottom left / 2px 18px,
        var(--mark) bottom right / 18px 2px, var(--mark) bottom right / 2px 18px;
    background-repeat: no-repeat;
    filter: drop-shadow(0 0 3px var(--gl-cam-cyan));
}
/* Faint scanlines over the picture */
.gl-cam-screen::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: repeating-linear-gradient(rgba(0, 0, 0, 0.18) 0 1px, transparent 1px 3px);
}
/* Specific enough to beat the window kit's img rule */
.gl-window.gl-cam .gl-cam-feed {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}
.gl-cam-rec,
.gl-cam-stamp,
.gl-cam-logo,
.gl-cam-viz,
.gl-cam-fs-rec {
    position: absolute;
    z-index: 2;
    font-size: 15px;
}
/* A hot red chip so it reads over any picture; only the dot blinks */
.gl-cam-rec {
    top: 16px;
    left: 18px;
    padding: 2px 8px;
    background: #ff1f4b;
    border-radius: 3px;
    letter-spacing: 1px;
    text-shadow: none;
    box-shadow: 0 0 10px rgba(255, 31, 75, 0.8);
}
.gl-cam-rec:empty {
    display: none;
}
.gl-cam-rec::before {
    content: "● ";
    color: #fff;
    animation: gl-cam-blink 1s steps(1) infinite;
}
@keyframes gl-cam-blink {
    50% { color: transparent; }
}
.gl-cam-stamp {
    top: 18px;
    right: 18px;
    white-space: pre;
    font-size: 13px;
    color: #e8defa;
}
/* The DJ CAM logo, split pink and cyan, bumping on every kick */
.gl-cam-logo {
    top: 12px;
    left: 50%;
    transform: translateX(-50%) scale(calc(1 + 0.14 * var(--gl-cam-kick, 0)));
    font-family: Impact, "Arial Black", sans-serif;
    font-style: italic;
    font-weight: normal;
    font-size: 22px;
    letter-spacing: 3px;
    white-space: nowrap;
    text-shadow: -2px 0 var(--gl-cam-pink), 2px 0 var(--gl-cam-cyan), 0 0 14px rgba(255, 43, 214, 0.9);
}
/* The visualizer across the bottom of the picture, fading out at its top
   so the picture shows through */
.gl-cam-viz {
    display: none;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 34%;
    pointer-events: none;
    -webkit-mask-image: linear-gradient(to top, #000 55%, transparent);
    mask-image: linear-gradient(to top, #000 55%, transparent);
}
.gl-cam-live .gl-cam-viz {
    display: block;
}
/* No picture: a neon sign in a dark purple room */
.gl-cam-nosignal {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 20px;
    padding-top: 40px;
    background: radial-gradient(ellipse at center, #2a0838, #07020c 75%);
    text-align: center;
}
.gl-cam-live .gl-cam-nosignal {
    display: none;
}
.gl-cam-nosignal-title {
    font-family: Impact, "Arial Black", sans-serif;
    font-weight: normal;
    font-size: 34px;
    letter-spacing: 5px;
    color: #ffd6f7;
    text-shadow: 0 0 6px var(--gl-cam-pink), 0 0 18px var(--gl-cam-pink), 0 0 34px var(--gl-cam-pink);
    animation: gl-cam-flicker 5s infinite;
}
/* An old sign that catches every few seconds - a dip, never a strobe */
@keyframes gl-cam-flicker {
    0%, 90%, 94%, 100% { opacity: 1; }
    92% { opacity: 0.45; }
}
.gl-cam-nosignal-why {
    font-size: 13px;
    font-weight: normal;
    white-space: pre-line;
    color: #c9b6ff;
}
.gl-cam-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
}
/* Two cameras' windows side by side are narrow: the buttons keep to one
   line and the camera's name gives way instead */
.gl-cam-controls .gl-btn {
    flex: 0 0 auto;
    min-width: 0;
    padding: 4px 8px;
    white-space: nowrap;
    color: #f0e6ff;
    background: #241c35;
    border-color: #5a4a80;
}
/* The record button: a red dot that turns into a stop square */
.gl-cam-shutter {
    position: relative;
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    padding: 0;
    background: #241c35;
    border: 2px outset #5a4a80;
    border-radius: 50%;
    cursor: url('cursor-pointer.png') 8 0, pointer;
}
.gl-cam-shutter::after {
    content: "";
    position: absolute;
    inset: 8px;
    background: #ff1f4b;
    border: 1px solid #600;
    border-radius: 50%;
    box-shadow: 0 0 8px rgba(255, 31, 75, 0.8);
}
.gl-cam-shutter:active {
    border-style: inset;
}
.gl-cam-shutter:disabled {
    cursor: default;
}
.gl-cam-shutter:disabled::after {
    background: #5a4a58;
    border-color: #3a2a38;
    box-shadow: none;
}
.gl-cam-recording .gl-cam-shutter::after {
    inset: 11px;
    border-radius: 0;
}
.gl-cam-shutter-label {
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    font-weight: bold;
    color: #fff;
}
.gl-cam-recording .gl-cam-shutter-label {
    color: #ff4b6e;
}
.gl-cam-said {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 12px;
    color: #b9a8d8;
}
/* The ON AIR switch: an unlit studio sign until it's on */
.gl-cam-air {
    flex: 0 0 auto;
    padding: 4px 10px;
    font-family: "Courier New", Courier, monospace;
    font-size: 13px;
    font-weight: bold;
    letter-spacing: 1px;
    color: #7a3a3a;
    background: #3a2020;
    border: 2px outset #5a4a80;
    border-radius: 0;
    cursor: url('cursor-pointer.png') 8 0, pointer;
}
.gl-cam-air:active {
    border-style: inset;
}
.gl-cam-air-on {
    color: #fff;
    background: #e02020;
    text-shadow: 0 0 6px #ffb0b0;
    box-shadow: 0 0 8px rgba(255, 40, 40, 0.7);
}
/* SOUND: lit cyan while the visualizer's hearing the laptop */
.gl-cam-sound {
    flex: 0 0 auto;
    padding: 4px 8px;
    font-family: "Courier New", Courier, monospace;
    font-size: 13px;
    font-weight: bold;
    letter-spacing: 1px;
    color: #4a6a78;
    background: #102028;
    border: 2px outset #5a4a80;
    border-radius: 0;
    cursor: url('cursor-pointer.png') 8 0, pointer;
}
.gl-cam-sound:active {
    border-style: inset;
}
.gl-cam-sound-on {
    color: #001a20;
    background: var(--gl-cam-cyan);
    box-shadow: 0 0 8px rgba(24, 216, 255, 0.7);
}
/* Full screen: four corner marks */
.gl-cam-controls .gl-cam-full-btn {
    width: 30px;
    align-self: stretch;
    --mark: linear-gradient(#f0e6ff, #f0e6ff);
    background:
        var(--mark) 8px 7px / 5px 2px, var(--mark) 8px 7px / 2px 5px,
        var(--mark) right 8px top 7px / 5px 2px, var(--mark) right 8px top 7px / 2px 5px,
        var(--mark) left 8px bottom 7px / 5px 2px, var(--mark) left 8px bottom 7px / 2px 5px,
        var(--mark) right 8px bottom 7px / 5px 2px, var(--mark) right 8px bottom 7px / 2px 5px,
        #241c35;
    background-repeat: no-repeat;
}
.gl-cam-controls .gl-cam-full-btn[hidden] {
    display: none;
}

/* Full screen is just the picture: it fills the screen (beating the sizes
   split screen sets), the overlays grow, and the pointer and the record
   button hide while the mouse rests */
.gl-cam-screen:fullscreen {
    width: 100vw !important;
    height: 100vh !important;
    margin: 0 !important;
    aspect-ratio: auto;
    border: 0;
}
.gl-cam-screen:fullscreen::before {
    inset: 28px;
}
.gl-cam-screen:fullscreen .gl-cam-logo {
    top: 30px;
    font-size: 48px;
    letter-spacing: 6px;
}
.gl-cam-screen:fullscreen .gl-cam-rec,
.gl-cam-screen:fullscreen .gl-cam-stamp {
    top: 42px;
    font-size: 22px;
}
.gl-cam-screen:fullscreen .gl-cam-rec {
    left: 46px;
}
.gl-cam-screen:fullscreen .gl-cam-stamp {
    right: 46px;
}
.gl-cam-screen.gl-cam-idle:fullscreen {
    cursor: none;
}
.gl-cam-fs-rec {
    display: none;
    right: 46px;
    bottom: 46px;
    padding: 10px 18px;
    font-family: "Courier New", Courier, monospace;
    font-size: 20px;
    font-weight: bold;
    letter-spacing: 2px;
    color: #fff;
    background: rgba(255, 31, 75, 0.85);
    border: 2px solid #fff;
    border-radius: 4px;
    box-shadow: 0 0 16px rgba(255, 31, 75, 0.8);
    cursor: url('cursor-pointer.png') 8 0, pointer;
    transition: opacity 0.3s;
}
.gl-cam-screen:fullscreen .gl-cam-fs-rec {
    display: block;
}
.gl-cam-screen.gl-cam-idle .gl-cam-fs-rec {
    opacity: 0;
    pointer-events: none;
}
.gl-cam-recording .gl-cam-fs-rec {
    background: rgba(0, 0, 0, 0.6);
    border-color: #ff1f4b;
}
.gl-cam-fs-rec:disabled {
    opacity: 0.4;
    cursor: default;
}

/* Visitors only get the caption under the picture */
.gl-cam-public .gl-cam-said {
    text-align: center;
    color: var(--gl-cam-pink);
    text-shadow: 0 0 6px rgba(255, 43, 214, 0.6);
}

.gl-cam-clips {
    margin: 10px 0 0;
    padding: 0;
    list-style: none;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 12px;
}
.gl-cam-clips:empty {
    display: none;
}
.gl-cam-clips li {
    display: flex;
    justify-content: space-between;
    padding: 3px 6px;
    color: #e8defa;
    background: #17121f;
    border-bottom: 1px solid #2a2238;
}
.gl-cam-clips li::before {
    content: "▶";
    margin-right: 6px;
    color: var(--gl-cam-pink);
}
.gl-cam-clip-size {
    margin-left: auto;
    color: #7a6a98;
}
@media (prefers-reduced-motion: reduce) {
    .gl-cam-screen,
    .gl-cam-nosignal-title {
        animation: none;
    }
}

/* ===== Desk cam ============================================================= */
/* The same windows in plain clothes: Win95 grey, an inset viewfinder with
   camcorder marks, and a VCR-blue screen when there's no picture */
.gl-cam-desk .gl-body {
    background: #d8d8d8;
}
.gl-cam-desk.gl-cam-split .gl-body {
    background: #000;
}
.gl-cam-desk .gl-cam-screen {
    background: #000;
    border: 2px inset #d8d8d8;
    animation: none;
}
.gl-cam-desk.gl-cam-live .gl-cam-screen {
    box-shadow: none;
}
.gl-cam-desk.gl-cam-split .gl-cam-screen {
    border-color: #000;
}
.gl-cam-desk .gl-cam-screen::before {
    --mark: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8));
    filter: none;
}
.gl-cam-desk .gl-cam-screen::after {
    display: none;
}
.gl-cam-desk .gl-cam-rec {
    padding: 1px 6px;
    background: rgba(0, 0, 0, 0.6);
    border-radius: 0;
    letter-spacing: 0;
    box-shadow: none;
}
.gl-cam-desk .gl-cam-rec::before {
    color: #ff3030;
}
.gl-cam-mode {
    position: absolute;
    z-index: 2;
    top: 16px;
    right: 18px;
    font-size: 15px;
}
.gl-cam-desk .gl-cam-stamp {
    top: auto;
    bottom: 16px;
    font-size: 15px;
    color: #fff;
}
.gl-cam-desk .gl-cam-nosignal {
    padding: 20px;
    background: #0000a8;
}
.gl-cam-desk .gl-cam-nosignal-title {
    font-family: inherit;
    font-weight: bold;
    font-size: 28px;
    letter-spacing: 4px;
    color: #fff;
    text-shadow: 1px 1px 0 #000;
    animation: none;
}
.gl-cam-desk .gl-cam-nosignal-why {
    color: #fff;
}
.gl-cam-desk .gl-cam-controls .gl-btn {
    color: #000;
    background: #d8d8d8;
    border-color: #f0f0f0;
}
.gl-cam-desk .gl-cam-shutter {
    background: #e8e8e8;
    border-color: #f8f8f8;
}
.gl-cam-desk .gl-cam-shutter::after {
    background: #e02020;
    box-shadow: none;
}
.gl-cam-desk .gl-cam-shutter:disabled::after {
    background: #b0a0a0;
    border-color: #807070;
}
.gl-cam-desk .gl-cam-shutter-label {
    color: #000;
}
.gl-cam-desk.gl-cam-split .gl-cam-shutter-label {
    color: #fff;
}
.gl-cam-desk.gl-cam-recording .gl-cam-shutter-label {
    color: #c00000;
}
.gl-cam-desk .gl-cam-said {
    color: #404040;
    text-shadow: none;
}
.gl-cam-desk.gl-cam-split .gl-cam-said {
    color: #a0a0a0;
}
.gl-cam-desk .gl-cam-air {
    border-color: #f0f0f0;
}
.gl-cam-desk .gl-cam-controls .gl-cam-full-btn {
    --mark: linear-gradient(#000, #000);
    background:
        var(--mark) 8px 7px / 5px 2px, var(--mark) 8px 7px / 2px 5px,
        var(--mark) right 8px top 7px / 5px 2px, var(--mark) right 8px top 7px / 2px 5px,
        var(--mark) left 8px bottom 7px / 5px 2px, var(--mark) left 8px bottom 7px / 2px 5px,
        var(--mark) right 8px bottom 7px / 5px 2px, var(--mark) right 8px bottom 7px / 2px 5px,
        #d8d8d8;
    background-repeat: no-repeat;
}
.gl-cam-desk .gl-cam-clips li {
    color: #000;
    background: #fff;
    border-bottom-color: #e0e0e0;
}
.gl-cam-desk .gl-cam-clips li::before {
    color: #000080;
}
.gl-cam-desk .gl-cam-clip-size {
    color: #808080;
}
/* Full screen: the date moves left, clear of the record button */
.gl-cam-desk .gl-cam-screen:fullscreen {
    border: 0;
}
.gl-cam-desk .gl-cam-screen:fullscreen .gl-cam-stamp {
    top: auto;
    right: auto;
    bottom: 46px;
    left: 46px;
}
.gl-cam-screen:fullscreen .gl-cam-mode {
    top: 42px;
    right: 46px;
    font-size: 22px;
}

/* ===== Chat room ============================================================ */
#chat-window {
    width: 440px;
}
/* The join screen, the room and the log's buttons all have display rules
   of their own, which would otherwise beat the hidden attribute */
.gl-chat [hidden] {
    display: none !important;
}
.gl-chat .gl-body {
    display: flex;
    flex-direction: column;
    background: #fff;
}
/* The way in: a name, the rules, the door */
.gl-chat-join {
    padding: 14px;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 12px;
}
.gl-chat-hero {
    margin: -14px -14px 12px;
    padding: 14px 12px 12px;
    text-align: center;
    background: #170a35 url('gifs/space.png') repeat;
    color: #fff;
}
.gl-chat-title {
    font-family: "Times New Roman", Times, serif;
    font-weight: 900;
    font-style: italic;
    font-size: 28px;
    line-height: 1.1;
    color: transparent;
    background: linear-gradient(180deg, #e9fbff 0%, #5ad1ff 45%, #ffd84a 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-stroke: 1px #0b2a5a;
    filter: drop-shadow(2px 2px 0 #000);
}
.gl-chat-sub {
    margin-top: 4px;
    font-size: 12px;
}
.gl-chat-join label {
    display: block;
    font-weight: bold;
}
.gl-chat input:not([type=radio]) {
    display: block;
    width: 100%;
    margin-top: 3px;
    padding: 3px 5px;
    box-sizing: border-box;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    background: #fff;
    border: 2px inset #d8d8d8;
    border-radius: 0;
}
.gl-chat-rules {
    margin: 8px 0 4px;
    color: #555;
    font-style: italic;
}
.gl-chat-error {
    min-height: 16px;
    color: #a00000;
}

/* The room: a status strip, the log in a sunken box, and the say line */
.gl-chat-room {
    display: flex;
    flex-direction: column;
    padding: 6px;
    background: #c0c0c0;
}
.gl-chat-top {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 4px;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 11px;
}
.gl-chat-where {
    font-weight: bold;
}
.gl-chat-status {
    color: #333;
}
.gl-chat-status.is-off {
    color: #a00000;
}
.gl-chat-log {
    position: relative;
    height: min(340px, 50vh);
    overflow-y: auto;
    padding: 4px 6px;
    background: #fff;
    border: 2px inset #d8d8d8;
    font-family: "Courier New", Courier, monospace;
    font-size: 13px;
    line-height: 1.45;
}
.gl-chat-lines {
    margin: 0;
    padding: 0;
    list-style: none;
}
.gl-chat-line {
    overflow-wrap: anywhere;
}
.gl-chat-time {
    margin-right: 4px;
    color: #888;
    font-size: 11px;
}
.gl-chat-name {
    font-weight: bold;
}
.gl-chat-day {
    margin: 6px 0 2px;
    text-align: center;
    color: #888;
    font-size: 11px;
}
.gl-chat-empty {
    padding: 30px 10px;
    text-align: center;
    color: #888;
    font-style: italic;
}
.gl-chat-older {
    display: block;
    margin: 2px auto 6px;
    font-size: 11px;
}
.gl-chat-new {
    position: sticky;
    bottom: 0;
    display: block;
    margin: 4px auto 0;
    font-size: 11px;
}
.gl-chat-say {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 6px;
}
.gl-chat-say input[name=message] {
    flex: 1;
    margin-top: 0;
}
.gl-chat-me {
    max-width: 30%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: "Courier New", Courier, monospace;
    font-size: 13px;
    font-weight: bold;
}

/* griffin's own messages: his face, a crown, a name in moving rainbow and
   a soft gold glow on the line, so you know it's really him */
.gl-chat-griffin {
    margin: 2px -4px;
    padding: 2px 4px;
    background: linear-gradient(90deg, #fff6c9, #fffdf2 70%);
    border-left: 3px solid #ffcf3a;
}
.gl-chat-face {
    display: inline-block;
    width: 22px;
    height: 22px;
    margin-right: 3px;
    vertical-align: -6px;
    border-radius: 50%;
    background: #9bd2f0 url('gifs/griffin/head.png?v=2') no-repeat;
    background-size: 126px 133px;
    background-position: -42px -36px;
    box-shadow: 0 0 0 1.5px #000;
}
.gl-chat-griffin .gl-chat-name,
.gl-chat-me.is-griffin {
    color: transparent;
    background: linear-gradient(90deg, #ff3b3b, #ff9a1f, #ffd400, #2fcf5a, #2f8bff, #9b4dff, #ff3b3b);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    animation: gl-chat-rainbow 3s linear infinite;
}
@keyframes gl-chat-rainbow {
    to { background-position: -200% 0; }
}
.gl-chat-crown {
    margin-left: 2px;
    color: #e0a400;
    text-shadow: 0 0 4px #ffe680;
}
@media (prefers-reduced-motion: reduce) {
    .gl-chat-griffin .gl-chat-name,
    .gl-chat-me.is-griffin {
        animation: none;
    }
}
@media screen and (max-width: 960px) {
    .gl-chat-log {
        height: 60vh;
    }
}

/* ===== Guestbook ============================================================ */
#guestbook-window {
    width: 460px;
}
.gl-guestbook .gl-body {
    max-height: min(560px, 68vh);
    overflow-y: auto;
    background: #fff;
}
@media screen and (max-width: 960px) {
    .gl-guestbook .gl-body {
        max-height: none;
    }
}
.gl-gb-hero {
    padding: 14px 12px 10px;
    text-align: center;
    background: #170a35 url('gifs/space.png') repeat;
    color: #fff;
}
.gl-gb-title-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}
#guestbook-window .gl-gb-title-row img {
    height: 46px;
}
.gl-gb-title {
    font-family: "Times New Roman", Times, serif;
    font-weight: 900;
    font-style: italic;
    font-size: 30px;
    line-height: 1.1;
    color: transparent;
    background: linear-gradient(180deg, #fff1fb 0%, #ff7ad9 45%, #ffd84a 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-stroke: 1px #5a0b3a;
    filter: drop-shadow(2px 2px 0 #000);
}
.gl-gb-sub {
    margin: 6px 0 8px;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
}
.gl-gb-cta .gl-ascii-btn {
    color: #ffde59;
}
.gl-gb-cta .gl-ascii-btn:hover,
.gl-gb-cta .gl-ascii-btn:focus-visible {
    color: #2a0b4a;
    background: #ffde59;
}

.gl-gb-form {
    padding: 12px 14px;
    background: #fffbe6;
    border-bottom: 2px dashed #e0c080;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 12px;
}
.gl-gb-form label {
    display: block;
    margin-bottom: 8px;
    font-weight: bold;
}
.gl-gb-form input:not([type=radio]),
.gl-gb-form textarea {
    display: block;
    width: 100%;
    margin-top: 3px;
    padding: 3px 5px;
    box-sizing: border-box;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 13px;
    background: #fff;
    border: 2px inset #d8d8d8;
    border-radius: 0;
}
.gl-gb-form textarea {
    resize: vertical;
}
.gl-gb-moods {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 0 0 8px;
    padding: 6px;
    border: 2px groove #f0e0c0;
}
.gl-gb-moods legend {
    padding: 0 4px;
    font-weight: bold;
}
.gl-gb-mood-pick input {
    position: absolute;
    opacity: 0;
}
#guestbook-window .gl-gb-mood-pick img {
    display: block;
    width: 34px;
    height: 34px;
    object-fit: contain;
    padding: 3px;
    border: 2px solid transparent;
    cursor: url('cursor-pointer.png') 8 0, pointer;
}
.gl-gb-mood-pick input:checked + img {
    border: 2px dashed #a3133f;
    background: #fff;
}
.gl-gb-mood-pick input:focus-visible + img {
    outline: 1px dotted #000;
}
/* The bot trap: off-screen, so people never see it */
.gl-gb-honey {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    opacity: 0;
}
.gl-gb-error {
    min-height: 16px;
    color: #a00000;
}

.gl-gb-count {
    padding: 8px;
    text-align: center;
    font-family: Tahoma, Geneva, sans-serif;
    font-size: 12px;
    font-style: italic;
    color: #555;
}
.gl-gb-entries {
    list-style: none;
    margin: 0;
    padding: 0 12px 14px;
}
.gl-gb-entry {
    display: flex;
    gap: 10px;
    margin-top: 8px;
    padding: 10px;
    background: #fff;
    border: 2px ridge #c8b8e0;
}
.gl-gb-entry:nth-child(even) {
    background: #f7f1ff;
}
#guestbook-window .popup-inner-wrapper img.gl-gb-mood {
    width: 44px;
    height: 44px;
    object-fit: contain;
    flex: 0 0 auto;
}
.gl-gb-entry-text {
    flex: 1 1 auto;
    min-width: 0;
    font-family: Tahoma, Geneva, sans-serif;
}
.gl-gb-name {
    font-size: 14px;
    font-weight: bold;
    color: #a3133f;
}
.gl-gb-from {
    font-size: 12px;
    font-weight: normal;
    font-style: italic;
    color: #555;
}
.gl-gb-date {
    font-size: 11px;
    color: #888;
}
.gl-gb-msg {
    margin: 4px 0 0;
    font-size: 13px;
    line-height: 1.4;
    overflow-wrap: anywhere;
}
.gl-gb-home {
    display: inline-block;
    margin-top: 4px;
    font-size: 12px;
    color: #0000ee;
    overflow-wrap: anywhere;
}

/* Less motion asked for: the desktop holds still */
@media (prefers-reduced-motion: reduce) {
    .gl-dino,
    .gl-birds,
    .gl-chair,
    .gl-chair-swing,
    .gl-rope-lay,
    .gl-promo-marquee span,
    .gl-badge-construction,
    .gl-beacon,
    .gl-spam-head,
    .gl-spam-btn,
    .gl-promo-btn,
    .gl-saver {
        animation: none;
    }
    .gl-dino {
        left: 30%;
    }
}

/* ===== griffin, on the lift =================================================
   His chairlift art, cut into layers that all share one canvas (see
   tools/griffin-rig.py): the chair and his body, each leg with its ski, his
   head, the shaka arm and the hand holding the beer. Each part turns on its
   own joint - the transform-origins are those joints, as a share of the
   canvas - and moves in % of it, so the poses hold at any size.

   Each part is a wrapper holding his pose, around an image that can wiggle
   on top of it. Resting is the default: arm draped on the chair back, beer
   in hand. griffinland.js adds a class for a few seconds at a time - sip,
   shaka (sometimes both), look-left, look-right, or cheers on hover - and
   every pose eases in and back out, so he never snaps. */
.gl-rider {
    position: relative;
    width: 84px;
    height: 89px;
    pointer-events: auto;
}
.gl-rider img,
.glr-part {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}
.glr-part {
    transition: transform 0.7s ease-in-out;
}

/* The joints, shared by each wrapper and the image inside it */
.glr-head, .glr-head img { transform-origin: 43.1% 43.3%; }
.glr-arm, .glr-arm img   { transform-origin: 54% 43.5%; }
.glr-beer, .glr-beer img { transform-origin: 33.5% 51.5%; }
.glr-leg-left, .glr-leg-left img   { transform-origin: 50.6% 55.6%; }
.glr-leg-right, .glr-leg-right img { transform-origin: 69% 54.4%; }

/* Resting: arm down on the chair back */
.glr-arm { transform: rotate(48deg); }

/* Skis dangle the whole time, out of step with each other */
.glr-leg-left img  { animation: glr-leg-left 1.9s ease-in-out infinite alternate; }
.glr-leg-right img { animation: glr-leg-right 2.3s ease-in-out infinite alternate; }
@keyframes glr-leg-left {
    from { transform: rotate(-7deg); }
    to { transform: rotate(10deg); }
}
@keyframes glr-leg-right {
    from { transform: rotate(7deg); }
    to { transform: rotate(-10deg); }
}

/* Looking around */
.gl-rider.look-left .glr-head  { transform: translateX(-0.5%) rotate(-8deg); }
.gl-rider.look-right .glr-head { transform: translateX(0.4%) rotate(6deg); }

/* Shaka: the arm comes up off the chair back, then gives it a shake */
.gl-rider.shaka .glr-arm { transform: none; }
.gl-rider.shaka .glr-arm img { animation: glr-shake 0.45s ease-in-out 0.7s 4 alternate; }
@keyframes glr-shake {
    from { transform: none; }
    to { transform: rotate(-12deg); }
}

/* Sip: bottle to his mouth, head back, a few gulps */
.gl-rider.sip .glr-beer { transform: translate(4.5%, -4.3%) rotate(38deg); }
.gl-rider.sip .glr-head { transform: rotate(-6deg); }
.gl-rider.sip .glr-beer img { animation: glr-gulp 0.45s ease-in-out 0.8s 4 alternate; }
@keyframes glr-gulp {
    from { transform: none; }
    to { transform: rotate(7deg); }
}

/* Cheers, on hover: the beer goes up and bobs, and he leans in */
.gl-rider.cheers .glr-beer { transform: translate(-0.5%, -5.4%) rotate(-12deg); }
.gl-rider.cheers .glr-head { transform: rotate(4deg); }
.gl-rider.cheers .glr-beer img { animation: glr-bob 0.8s ease-in-out 0.7s infinite alternate; }
@keyframes glr-bob {
    from { transform: none; }
    to { transform: translateY(-1.2%) rotate(6deg); }
}

@media (prefers-reduced-motion: reduce) {
    .glr-part {
        transition: none;
    }
    .gl-rider img {
        animation: none !important;
    }
}

/* The other riders (buildCrew in griffinland.js): layers on the same canvas
   as griffin's, stacked with no offsets. The transform-origins are the
   joints, as a share of the canvas: his shoulder for the wave, the front
   binding for the board. */
.gl-crew {
    position: relative;
    width: 84px;
    height: 89px;
    pointer-events: auto;
}
.gl-crew img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}
/* The couple: steam curling off her cocoa, and every so often he waves */
.glc-steam {
    animation: glc-steam 2.6s ease-in-out infinite;
}
@keyframes glc-steam {
    0% { opacity: 0; transform: translateY(1.5%); }
    30% { opacity: 1; }
    100% { opacity: 0; transform: translateY(-3%); }
}
.glc-wave {
    transform-origin: 67.3% 45.8%;
    animation: glc-wave 7s ease-in-out infinite;
}
@keyframes glc-wave {
    0%, 62%, 94%, 100% { transform: none; }
    68% { transform: rotate(-12deg); }
    74% { transform: rotate(8deg); }
    80% { transform: rotate(-12deg); }
    86% { transform: rotate(8deg); }
}
/* The snowboarder: the board swings off his front foot, the phone records */
.glc-board {
    transform-origin: 73.8% 76.6%;
    animation: glc-board 2.6s ease-in-out infinite alternate;
}
/* Small enough that the back boot stays resting on the board */
@keyframes glc-board {
    from { transform: rotate(-4deg); }
    to { transform: rotate(2.5deg); }
}
.glc-rec {
    animation: glc-rec 1.2s steps(1, end) infinite;
}
@keyframes glc-rec {
    50% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .gl-crew img {
        animation: none !important;
    }
}

/* ===== Shop 2.0 =============================================================
   Tees on a rail in a sunken box the colour of the desktop, grey Win95 controls
   round it. griffinland.js works out every tee's position and size. */
#shop-icon-group { top: 502px; right: 10px; }
/* Phones stack windows just under the fourth row of icons, which would cover a
   fifth, so that row becomes a third column (below the griffinland title) */
@media screen and (max-width: 960px) {
    #shop-icon-group     { top: 181px; right: 152px; }
    #desk-cam-icon-group { top: 288px; right: 152px; }
}

.gl-shop2 {
    width: min(780px, 94vw);
}
.gl-shop2 .gl-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 0;
    padding: 6px;
    background: #c0c0c0;
    font-family: Tahoma, Geneva, sans-serif;
    color: #000;
}
.s2-stage {
    position: relative;
    height: min(520px, calc(100vh - 210px));
    min-height: 430px;
    overflow: hidden;
    background: var(--gl-forest, #22743a);
    border: 2px inset #d8d8d8;
    user-select: none;
}
/* Only where a click does something: on a tee, or anywhere once one's chosen */
.s2-stage.is-hot,
.s2-stage.is-detail {
    cursor: url('cursor-pointer.png') 8 0, pointer;
}
.s2-stage .gl-btn {
    min-width: 0;
    font-size: 12px;
}
.s2-back {
    position: absolute;
    top: 8px;
    left: 8px;
    z-index: 30;
    visibility: hidden;
}
.is-detail .s2-back {
    visibility: visible;
}
.s2-rail {
    position: absolute;
    height: 5px;
    margin-top: -2px;
    background: linear-gradient(#fff, #c0c0c0 45%, #6d6d6d);
    border: 1px solid #000;
    box-sizing: content-box;
    box-shadow: 0 4px 5px rgba(0, 0, 0, .35);
    transition: filter .45s, opacity .45s;
}
.is-detail .s2-rail {
    filter: blur(6px);
    opacity: .4;
}

.s2-tee {
    position: absolute;
    top: 0;
    left: 0;
    width: 440px;
    height: 400px;
    transform-origin: 220px 15px;
    pointer-events: none;
    outline: none;
    transition: transform .65s cubic-bezier(.2, .75, .2, 1), filter .45s, opacity .45s;
}
.is-settling .s2-tee {
    transition: none;
}
.is-detail .s2-tee:not(.is-chosen) {
    filter: blur(8px);
    opacity: .4;
}
/* Only the flip is really 3D. The tee itself turns as one flat picture, so the
   hanger, cloth and print can't fight over which one is in front mid-turn. */
.s2-swing {
    position: absolute;
    inset: 0;
    transform-origin: 220px 15px;
    perspective: 1600px;
    opacity: 0;
    transition: opacity .3s;
}
.is-ready .s2-swing {
    opacity: 1;
}
.s2-sway {
    animation: s2-sway 1s ease-out;
}
@keyframes s2-sway {
    25% { transform: rotateZ(1.6deg); }
    55% { transform: rotateZ(-.9deg); }
    80% { transform: rotateZ(.35deg); }
}
.s2-flip,
.s2-face {
    position: absolute;
    inset: 0;
}
.s2-flip {
    transform-style: preserve-3d;
    transition: transform .7s cubic-bezier(.3, .7, .2, 1);
}
.is-back .s2-flip {
    transform: rotateY(-180deg);
}
.s2-face {
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}
.s2-face-back {
    transform: rotateY(180deg);
}
.s2-stage .s2-swing img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    -webkit-user-drag: none;
}
/* Where mocial's shop puts the print: centred on the chest, under the collar */
.s2-stage .s2-swing img.s2-print {
    top: 30.25%;
    left: 38.8%;
    width: 22.4%;
    height: auto;
}
.s2-tee:focus-visible .s2-flip {
    outline: 1px dotted #fff;
    outline-offset: -40px;
}

/* Slides up out of the bottom of the box when a tee's chosen */
.s2-info {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 30;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
    padding: 8px 8px 10px;
    background: #c0c0c0;
    border-top: 2px outset #f0f0f0;
    visibility: hidden;
    transform: translateY(100%);
    transition: transform .4s cubic-bezier(.2, .75, .2, 1), visibility .4s;
    cursor: default;
}
.is-detail .s2-info {
    visibility: visible;
    transform: none;
}
.s2-heading {
    display: flex;
    gap: 10px;
    font-size: 13px;
    font-weight: bold;
}
.s2-price {
    font-weight: normal;
}
.s2-options {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 4px 14px;
}
.s2-group {
    display: flex;
    align-items: center;
    gap: 2px;
}
.s2-group-label {
    margin-right: 4px;
    font-size: 12px;
}
.s2-sides .gl-btn {
    min-width: 54px;
}
.s2-size.gl-btn {
    min-width: 36px;
    padding: 4px 6px;
}
/* A pressed-in toggle, the way a Win95 toolbar holds one down */
.s2-stage .gl-btn.is-on {
    background: #e8e8e8;
    border-style: inset;
    font-weight: bold;
}
.s2-buy.gl-btn {
    min-width: 170px;
    font-weight: bold;
    outline: 1px solid #000;
}
.s2-buy.gl-btn:disabled {
    color: #808080;
    text-shadow: 1px 1px 0 #fff;
    font-weight: normal;
    outline: none;
    cursor: default;
}
.s2-stage .gl-btn:focus-visible {
    outline: 1px dotted #000;
    outline-offset: -4px;
}

.s2-status {
    display: flex;
    gap: 2px;
    font-size: 11px;
}
.s2-status > div {
    padding: 2px 6px;
    border: 1px inset #d8d8d8;
}
.s2-status-text {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The inspiration reel: a phone recording, so the window is tall and narrow */
.gl-inspiration {
    width: calc(min(600px, 100vh - 230px) * 540 / 1174);   /* tall enough, and clear of the taskbar */
    min-width: 240px;
}
.gl-inspiration .gl-body {
    margin: 0;
    padding: 0;
    background: #000;
}
.s2-reel {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 540 / 1174;
}
@media (prefers-reduced-motion: reduce) {
    .s2-tee,
    .s2-swing,
    .s2-flip,
    .s2-info,
    .s2-rail {
        transition: none;
    }
    .s2-sway {
        animation: none;
    }
}
