/* =====================================================================
   Big-TV pixel-art styling for the kiosk. Mirrors the game's medieval
   theme (src/MedievalInnovation/wwwroot/css/theme.css): same palette,
   'Press Start 2P' pixel font and chunky 4px frames.
   ===================================================================== */

html, body {
    margin: 0;
    padding: 0;
    background: #241408;
    overflow: hidden;
}

.kiosk {
    /* Palette copied from the game's theme.css. */
    --ink: #1b1410;
    --parch: #e6d4a8;
    --parch-dk: #cdb684;
    --wood: #3a2416;
    --wood-dk: #241408;
    --gold: #e8b923;
    --gold-dk: #9c7710;
    --blood: #8c2f22;
    --stone: #6b6157;
    --pixel: 'Press Start 2P', 'Courier New', monospace;
    --body-font: 'Courier New', Consolas, monospace;
    /* House colors, matching the shield gradients in the game. */
    --akstark: #5b7a95;
    --vaultister: #b23a44;
    --blobaryen: #7a3464;
    --functionoy: #1f8f73;

    width: 100vw;
    height: 100dvh;
    padding: clamp(12px, 2vw, 40px) clamp(14px, 3vw, 56px) clamp(16px, 2vw, 32px);
    box-sizing: border-box;
    overflow: hidden;

    background: var(--wood-dk);
    background-image:
        repeating-linear-gradient(90deg, rgba(0, 0, 0, .25) 0 2px, rgba(255, 255, 255, .02) 2px 14px),
        repeating-linear-gradient(0deg, rgba(0, 0, 0, .18) 0 3px, transparent 3px 9px);
    color: var(--ink);
    font-family: var(--body-font);
    image-rendering: pixelated;

    display: flex;
    flex-direction: column;
    gap: clamp(12px, 1.6vw, 28px);
}

/* ---- banner ---- */
.tv-banner {
    background: var(--blood);
    background-image: repeating-linear-gradient(135deg, rgba(0, 0, 0, .12) 0 8px, transparent 8px 16px);
    border: 4px solid var(--ink);
    box-shadow: 0 0 0 4px var(--wood), 4px 4px 0 4px rgba(0, 0, 0, .45), inset 0 0 0 2px rgba(255, 255, 255, .25);
    padding: clamp(10px, 1.6vw, 26px) 16px;
    text-align: center;
}

.tv-banner h1 {
    font-family: var(--pixel);
    font-size: clamp(18px, 3.4vw, 54px);
    color: var(--gold);
    margin: 0 0 .4em;
    letter-spacing: 2px;
    text-shadow: 4px 4px 0 #000;
}

.tv-banner-sub {
    margin: 0;
    font-family: var(--pixel);
    font-size: clamp(9px, 1.1vw, 18px);
    color: var(--parch);
    letter-spacing: 3px;
}

/* ---- two-column grid on wide (TV) screens ---- */
.tv-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: clamp(12px, 1.6vw, 28px);
    flex: 1;
    align-items: stretch;
}

@media (min-width: 1100px) {
    .tv-grid {
        grid-template-columns: 11fr 9fr;
    }
}

/* ---- parchment panels with the chunky pixel frame ---- */
.tv-panel {
    background: var(--parch);
    background-image:
        radial-gradient(circle at 20% 15%, rgba(140, 100, 40, .13), transparent 45%),
        radial-gradient(circle at 85% 70%, rgba(140, 100, 40, .13), transparent 40%);
    border: 4px solid var(--ink);
    box-shadow: 0 0 0 4px var(--wood), 4px 4px 0 4px rgba(0, 0, 0, .45), inset 0 0 0 2px rgba(255, 255, 255, .25);
    padding: clamp(14px, 1.8vw, 32px);
    display: flex;
    flex-direction: column;
}

.tv-panel h2 {
    font-family: var(--pixel);
    font-size: clamp(11px, 1.3vw, 22px);
    margin: 0 0 clamp(12px, 1.5vw, 26px);
    color: var(--wood);
    letter-spacing: 2px;
    border-bottom: 4px solid var(--wood);
    padding-bottom: .6em;
}

.tv-empty,
.tv-loading {
    font-family: var(--pixel);
    font-size: clamp(10px, 1.2vw, 18px);
    color: var(--parch);
    line-height: 1.8;
}

.tv-empty {
    color: var(--wood);
}

.tv-loading {
    text-align: center;
    padding: 3em 0;
    animation: tv-blink 1.2s steps(2, start) infinite;
}

@keyframes tv-blink {
    50% { opacity: .35; }
}

.tv-alert {
    font-family: var(--pixel);
    font-size: clamp(10px, 1.2vw, 18px);
    background: var(--blood);
    color: var(--parch);
    border: 4px solid var(--ink);
    box-shadow: 4px 4px 0 rgba(0, 0, 0, .45);
    padding: 1em;
    line-height: 1.8;
}

/* ---- house bar chart ---- */
.tv-bar-chart {
    display: flex;
    align-items: stretch;
    justify-content: space-around;
    gap: clamp(10px, 1.5vw, 32px);
    flex: 1;
    min-height: clamp(220px, 42vh, 560px);
}

.tv-bar-column {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    flex: 1;
    min-width: 0;
}

.tv-bar-crown {
    font-size: clamp(18px, 2.2vw, 40px);
    line-height: 1;
    filter: drop-shadow(3px 3px 0 rgba(0, 0, 0, .5));
}

.tv-bar-sigil {
    filter: drop-shadow(3px 3px 0 rgba(0, 0, 0, .45));
    image-rendering: pixelated;
}

.tv-bar-value {
    font-family: var(--pixel);
    font-size: clamp(11px, 1.4vw, 26px);
    color: var(--wood);
    text-shadow: 2px 2px 0 rgba(255, 255, 255, .35);
}

/* The track is invisible: it only reserves vertical space and pins the bar to the
   bottom, so the bar reads as a freestanding tower rather than a gauge to fill. */
.tv-bar-track {
    flex: 1;
    width: 100%;
    max-width: clamp(70px, 8vw, 160px);
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
}

.tv-bar {
    width: 100%;
    min-height: 0;
    border: 4px solid var(--ink);
    background-image: repeating-linear-gradient(0deg, rgba(0, 0, 0, .22) 0 6px, transparent 6px 12px);
    box-shadow: 4px 4px 0 rgba(0, 0, 0, .4), inset 0 0 0 2px rgba(255, 255, 255, .25);
    transition: height .6s steps(12);
}

.tv-bar-label {
    font-family: var(--pixel);
    /* Small enough that even "VAULTISTER" / "FUNCTIONOY" (10 chars) fit on one line. */
    font-size: clamp(7px, .7vw, 12px);
    letter-spacing: 0;
    color: var(--parch);
    padding: 8px 4px;
    border: 3px solid var(--ink);
    box-shadow: 3px 3px 0 rgba(0, 0, 0, .45);
    text-align: center;
    width: 100%;
    box-sizing: border-box;
    /* Names must stay fully readable on the TV: wrap instead of clipping. */
    white-space: normal;
    overflow-wrap: break-word;
    line-height: 1.6;
}

.tv-bar[data-house="akstark"], .tv-bar-label[data-house="akstark"] { background-color: var(--akstark); }
.tv-bar[data-house="vaultister"], .tv-bar-label[data-house="vaultister"] { background-color: var(--vaultister); }
.tv-bar[data-house="blobaryen"], .tv-bar-label[data-house="blobaryen"] { background-color: var(--blobaryen); }
.tv-bar[data-house="functionoy"], .tv-bar-label[data-house="functionoy"] { background-color: var(--functionoy); }

/* ---- champions leaderboard ---- */
.tv-leaderboard {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: clamp(6px, .7vw, 12px);
    flex: 1;
    justify-content: space-between;
}

.tv-row {
    display: grid;
    grid-template-columns: auto auto 1fr auto auto;
    align-items: center;
    gap: clamp(10px, 1.2vw, 24px);
    background: var(--parch-dk);
    border: 3px solid var(--ink);
    box-shadow: 3px 3px 0 rgba(0, 0, 0, .35);
    padding: clamp(8px, 1vw, 20px) clamp(10px, 1.2vw, 24px);
}

/* Gold, silver and bronze podium rows. */
.tv-row[data-rank="1"] { background: var(--gold); }
.tv-row[data-rank="2"] { background: #c7c3ba; }
.tv-row[data-rank="3"] { background: #c98f4e; }

.tv-rank {
    font-family: var(--pixel);
    font-size: clamp(12px, 1.4vw, 26px);
    color: var(--wood);
    min-width: 2.2em;
    text-align: right;
}

.tv-avatar {
    display: flex;
    align-items: center;
    filter: drop-shadow(2px 2px 0 rgba(0, 0, 0, .4));
}

.tv-name {
    font-family: var(--pixel);
    font-size: clamp(10px, 1.2vw, 22px);
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1.6;
}

.tv-house {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--pixel);
    font-size: clamp(8px, .9vw, 15px);
    color: var(--parch);
    padding: 5px 9px;
    border: 2px solid var(--ink);
    background-color: var(--stone);
    white-space: nowrap;
}

.tv-house[data-house="akstark"] { background-color: var(--akstark); }
.tv-house[data-house="vaultister"] { background-color: var(--vaultister); }
.tv-house[data-house="blobaryen"] { background-color: var(--blobaryen); }
.tv-house[data-house="functionoy"] { background-color: var(--functionoy); }

.tv-points {
    font-family: var(--pixel);
    font-size: clamp(12px, 1.4vw, 26px);
    color: var(--wood);
    min-width: 3.5em;
    text-align: right;
}

/* ---- buttons (only on the sign-in page; the TV audience never touches the kiosk) ---- */
.tv-backlink {
    font-family: var(--pixel);
    font-size: 9px;
    color: var(--parch);
    background: var(--stone);
    border: 3px solid var(--ink);
    box-shadow: 3px 3px 0 rgba(0, 0, 0, .45);
    padding: 9px 14px;
    cursor: pointer;
    text-decoration: none;
    letter-spacing: 1px;
    transition: transform .05s;
}

.tv-backlink:hover { filter: brightness(1.18); }
.tv-backlink:active { transform: translate(3px, 3px); box-shadow: none; }
.tv-backlink:disabled { filter: saturate(.3) brightness(.8); cursor: default; }

.tv-detail {
    display: block;
    font-size: .5em;
    margin-top: .5em;
    color: var(--stone);
}

/* ---- the admin's status message ---- */
.tv-status {
    flex: 0 0 auto;
    font-family: var(--pixel);
    font-size: clamp(12px, 1.6vw, 30px);
    line-height: 1.5;
    text-align: center;
    padding: clamp(8px, 1vw, 18px) 16px;
    border: 4px solid var(--ink);
    box-shadow: 0 0 0 4px var(--wood);
}

.tv-status-info {
    color: var(--ink);
    background: var(--gold);
}

.tv-status-warning {
    color: #fff;
    background: var(--blood);
}

/* ---- the loop ---- */
.kiosk-page,
.kiosk-stage {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: clamp(12px, 1.6vw, 28px);
}

.kiosk-panel {
    flex: 1;
    min-height: 0;
}

.kiosk-centered {
    margin: auto;
    text-align: center;
}

/* The remaining time on screen: a thin bar along the bottom edge that runs out with the slide. */
.kiosk-timer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    height: 6px;
    background: rgba(0, 0, 0, .35);
}

.kiosk-timer-fill {
    height: 100%;
    background: var(--gold);
    opacity: .7;
    transform-origin: left;
    animation-name: kiosk-countdown;
    animation-timing-function: linear;
    animation-fill-mode: forwards;
}

@keyframes kiosk-countdown {
    from { transform: scaleX(1); }
    to { transform: scaleX(0); }
}

.pixel-icon {
    display: grid;
    image-rendering: pixelated;
}

.pixel-icon > div {
    width: 100%;
    height: 100%;
}

/* ---- text slides ---- */
.kiosk-markdown {
    font-family: var(--body-font);
    font-size: clamp(16px, 2vw, 40px);
    line-height: 1.5;
    overflow: hidden;
}

.kiosk-markdown h1,
.kiosk-markdown h2,
.kiosk-markdown h3 {
    font-family: var(--pixel);
    color: var(--wood);
    line-height: 1.5;
    letter-spacing: 2px;
}

.kiosk-markdown h1 { font-size: clamp(18px, 3vw, 56px); }
.kiosk-markdown h2 { font-size: clamp(14px, 2.2vw, 40px); }
.kiosk-markdown h3 { font-size: clamp(12px, 1.6vw, 30px); }

.kiosk-markdown strong { color: var(--blood); }

.kiosk-markdown img {
    max-width: 100%;
    max-height: 60vh;
    image-rendering: auto;
}

.kiosk-markdown table {
    border-collapse: collapse;
}

.kiosk-markdown th,
.kiosk-markdown td {
    border: 3px solid var(--ink);
    padding: .3em .6em;
}

/* ---- sign-in ---- */
.kiosk-login {
    gap: 18px;
    min-width: min(420px, 90vw);
}

.kiosk-login h1 {
    font-family: var(--pixel);
    font-size: clamp(16px, 2vw, 28px);
    color: var(--wood);
    margin: 0;
}

.kiosk-login form {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.kiosk-login label {
    font-family: var(--pixel);
    font-size: 11px;
    color: var(--wood);
}

.kiosk-login input {
    font-family: var(--pixel);
    font-size: 16px;
    padding: 10px;
    border: 3px solid var(--ink);
    background: var(--parch-dk);
}

/* =====================================================================
   Joust instant replay (tech demo, /joust-replay).
   The world is a 32em x 18em field: its font-size is 1/32 of the scene's
   width, so every position below is in "field units" and the whole battle
   screen scales with the TV. One sprite pixel is .2em.
   Every part runs on the same clock: --jr-dur is the length of one pass and
   --jr-delay how far into it the take starts (the replay starts late and runs
   slow). The lances meet at 50%.
   ===================================================================== */

.jr-screen {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: clamp(10px, 1.4vw, 24px);
}

.jr-viewport {
    flex: 1;
    min-height: 0;
    container-type: size;
    display: grid;
    place-items: center;
}

.jr-scene {
    position: relative;
    width: min(100cqw, 100cqh * 16 / 9);
    aspect-ratio: 16 / 9;
    box-sizing: border-box;
    container-type: inline-size;
    overflow: hidden;
    background: #000;
    border: 4px solid #f2f2f2;
    border-radius: 8px;
    box-shadow: 0 0 0 4px var(--ink), 6px 6px 0 4px rgba(0, 0, 0, .45);
}

.jr-world {
    position: absolute;
    inset: 0;
    font-size: calc(100cqw / 32);
    animation: jr-shake var(--jr-dur) linear var(--jr-delay) both;
}

.jr-scene[data-phase="Replay"] .jr-world {
    transform-origin: 72% 72%;
    filter: saturate(.75) contrast(1.1) sepia(.15);
    animation: jr-zoom 1.2s ease-out both, jr-shake var(--jr-dur) linear var(--jr-delay) both;
}

/* Scanlines over the replay, like a tape being played back. */
.jr-scene[data-phase="Replay"]::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        repeating-linear-gradient(to bottom, rgba(0, 0, 0, .2) 0 2px, transparent 2px 4px),
        radial-gradient(ellipse at center, transparent 55%, rgba(0, 0, 0, .45));
}

/* ---- the field: banded sky, stepped mountains and hills, striped grass ---- */
.jr-sky {
    position: absolute;
    inset: 0 0 auto 0;
    height: 10em;
    background: linear-gradient(to bottom,
        #141a4e 0 2em, #1f2f7a 2em 4em, #2f4fa6 4em 6em, #4f7fd0 6em 7.6em, #8fb6ea 7.6em 8.8em, #cfe2f6 8.8em 10em);
}

.jr-cloud {
    position: absolute;
    height: 1.4em;
    background: #f4f8ff;
    clip-path: polygon(0 100%, 0 60%, 10% 60%, 10% 40%, 25% 40%, 25% 20%, 40% 20%, 40% 0, 60% 0, 60% 20%,
        75% 20%, 75% 40%, 90% 40%, 90% 60%, 100% 60%, 100% 100%);
    animation: jr-drift 14s ease-in-out infinite alternate;
}

.jr-cloud-1 { left: 4em; top: 1.6em; width: 5em; }
.jr-cloud-2 { left: 21em; top: 3.4em; width: 4em; animation-direction: alternate-reverse; }

.jr-mountains {
    position: absolute;
    left: 0;
    right: 0;
    top: 6.4em;
    height: 3.6em;
    background: #5d6b95;
    clip-path: polygon(0 100%, 0 60%, 4% 60%, 4% 40%, 8% 40%, 8% 15%, 12% 15%, 12% 0, 15% 0, 15% 20%, 19% 20%,
        19% 45%, 24% 45%, 24% 30%, 28% 30%, 28% 10%, 32% 10%, 32% 35%, 37% 35%, 37% 60%, 42% 60%, 42% 40%, 47% 40%,
        47% 20%, 52% 20%, 52% 5%, 56% 5%, 56% 25%, 61% 25%, 61% 50%, 66% 50%, 66% 35%, 71% 35%, 71% 15%, 75% 15%,
        75% 30%, 80% 30%, 80% 55%, 85% 55%, 85% 35%, 90% 35%, 90% 20%, 95% 20%, 95% 45%, 100% 45%, 100% 100%);
}

.jr-hills {
    position: absolute;
    left: 0;
    right: 0;
    top: 8.6em;
    height: 1.6em;
    background: #2f6b3a;
    clip-path: polygon(0 100%, 0 50%, 6% 50%, 6% 20%, 14% 20%, 14% 0, 24% 0, 24% 30%, 32% 30%, 32% 60%, 40% 60%,
        40% 30%, 48% 30%, 48% 10%, 60% 10%, 60% 40%, 70% 40%, 70% 20%, 80% 20%, 80% 0, 90% 0, 90% 40%, 100% 40%, 100% 100%);
}

/* The dirt of the lists runs from 14.6em to 15.8em; the hooves land at 15.4em. */
.jr-grass {
    position: absolute;
    inset: 10em 0 0 0;
    background: linear-gradient(to bottom,
        #6fae4c 0 .6em, #5d9c40 .6em 1.5em, #4f8c36 1.5em 2.8em, #437d2f 2.8em 4.6em,
        #a37a45 4.6em 5.8em, #8a6538 5.8em 6.1em, #3a6e2a 6.1em 8em);
}

.jr-pennant {
    position: absolute;
    top: 9.2em;
    width: .2em;
    height: 4.4em;
    background: #3d2b1f;
}

.jr-pennant::after {
    content: "";
    position: absolute;
    left: .2em;
    top: 0;
    width: 1.4em;
    height: .8em;
    background: var(--jr-flag);
    clip-path: polygon(0 0, 100% 50%, 0 100%);
    transform-origin: left center;
    animation: jr-flutter .6s steps(1, end) infinite;
}

/* The tilt: the barrier the knights ride along, a rail on posts behind the horses. */
.jr-tilt {
    position: absolute;
    left: 0;
    right: 0;
    top: 13em;
    height: 1.6em;
    background:
        linear-gradient(to bottom, #e8d6a0 0 .15em, #a9743f .15em .5em, #5c3d22 .5em .6em, transparent .6em),
        repeating-linear-gradient(to right, #7a5230 0 .3em, transparent .3em 3em);
}

/* ---- the knights ---- */
.jr-part {
    position: absolute;
    animation-duration: var(--jr-dur);
    animation-delay: var(--jr-delay);
    animation-timing-function: linear;
    animation-fill-mode: both;
}

/* PixelIcon sizes itself in px; here the field units decide. */
.jr-part .pixel-icon {
    width: 100% !important;
    height: 100% !important;
}

.jr-horse { width: 6.4em; height: 4em; top: 11.4em; z-index: 1; }
.jr-rider { width: 3.2em; height: 3.2em; top: 10.8em; z-index: 2; }
.jr-lance { width: 7.2em; height: 1em; top: 12.2em; z-index: 3; }

.jr-gallop-a,
.jr-gallop-b {
    position: absolute;
    inset: 0;
    animation: jr-gallop calc(var(--jr-dur) * .06) steps(1, end) infinite;
}

.jr-gallop-b {
    animation-delay: calc(var(--jr-dur) * -.03);
}

.jr-part[data-side="left"] { animation-name: jr-charge-right; }
.jr-horse[data-side="left"] { left: 9.1em; }
.jr-rider[data-side="left"] { left: 10.5em; }
.jr-lance[data-side="left"] { left: 12.1em; }

.jr-part[data-side="right"] { scale: -1 1; animation-name: jr-charge-left; }
.jr-horse[data-side="right"] { left: 16.5em; }
.jr-rider[data-side="right"] { left: 18.3em; }
.jr-lance[data-side="right"] { left: 12.7em; }
.jr-rider[data-outcome="unhorsed"] { animation-name: jr-unhorse; }
.jr-lance[data-outcome="unhorsed"] { animation-name: jr-lance-fly; }
.jr-part[data-side="left"][data-outcome="unhorsed"] { --jr-fall-direction: -1; }
.jr-lance[data-attack="Low"] { top: 12.9em; }
.jr-scene[data-winner="2"][data-phase="Replay"] .jr-world { transform-origin: 28% 72%; --jr-zoom-x: 22%; }
.jr-scene[data-winner="2"] .jr-impact { left: 11.3em; }

/* ---- the hit ---- */
.jr-impact {
    position: absolute;
    left: 19.3em;
    top: 12.7em;
    z-index: 4;
}

.jr-burst {
    position: absolute;
    left: -1.2em;
    top: -1.2em;
    width: 2.4em;
    height: 2.4em;
    background: #fff6c0;
    clip-path: polygon(50% 0, 60% 35%, 100% 50%, 60% 65%, 50% 100%, 40% 65%, 0 50%, 40% 35%);
    animation: jr-burst var(--jr-dur) linear var(--jr-delay) both;
}

.jr-splinter {
    position: absolute;
    width: .4em;
    height: .2em;
    background: #a9743f;
    animation: jr-splinter var(--jr-dur) linear var(--jr-delay) both;
}

/* ---- on-screen graphics, outside the field so the zoom leaves them alone ---- */
.jr-live,
.jr-replay-badge {
    position: absolute;
    top: 4%;
    font-family: var(--pixel);
    color: #fff;
    letter-spacing: 2px;
    z-index: 5;
}

.jr-live {
    left: 3%;
    font-size: clamp(10px, 1.3vw, 24px);
    text-shadow: 3px 3px 0 #000;
    animation: tv-blink 1.2s steps(2, start) infinite;
}

.jr-live::before {
    content: "";
    display: inline-block;
    width: .8em;
    height: .8em;
    margin-right: .6em;
    background: #e33;
    box-shadow: 3px 3px 0 #000;
}

.jr-replay-badge {
    right: 3%;
    font-size: clamp(12px, 2vw, 36px);
    text-align: right;
    background: var(--blood);
    border: 4px solid #f2f2f2;
    box-shadow: 0 0 0 4px var(--ink), 4px 4px 0 4px rgba(0, 0, 0, .5);
    padding: .5em .7em;
    animation: jr-badge-in .4s steps(4) both;
}

.jr-replay-badge small {
    display: block;
    margin-top: .6em;
    font-size: .5em;
    color: var(--gold);
    animation: tv-blink 1s steps(2, start) infinite;
}

.jr-flash {
    position: absolute;
    inset: 0;
    z-index: 6;
    background: #fff;
    pointer-events: none;
    animation: jr-flash .5s steps(5) forwards;
}

/* Final Fantasy style windows: a blue gradient with a white rounded frame. */
.jr-message,
.jr-window {
    background: linear-gradient(to bottom, #3a4fc8, #10186a);
    border: 4px solid #f2f2f2;
    border-radius: 8px;
    box-shadow: 0 0 0 4px var(--ink), 4px 4px 0 4px rgba(0, 0, 0, .45);
    color: #fff;
    font-family: var(--pixel);
}

.jr-message {
    position: absolute;
    left: 50%;
    bottom: 5%;
    translate: -50% 0;
    z-index: 5;
    padding: .9em 1.2em;
    font-size: clamp(8px, 1.1vw, 20px);
    white-space: nowrap;
}

/* Typed out letter by letter; the pixel font is monospaced, so a letter is 1ch. */
.jr-message span {
    display: inline-block;
    vertical-align: bottom;
    overflow: hidden;
    width: 0;
    animation: jr-type 1.2s steps(var(--jr-chars)) forwards;
}

.jr-window {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .6em 3em;
    padding: clamp(10px, 1.2vw, 22px) clamp(14px, 2vw, 36px);
}

.jr-party {
    display: grid;
    grid-template-columns: 1.2em auto 1fr auto auto;
    align-items: center;
    gap: .8em;
    min-width: 0;
    font-size: clamp(10px, 1.2vw, 22px);
}

.jr-cursor { animation: tv-blink .8s steps(2, start) infinite; }

.jr-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1.6;
}

.jr-house { display: flex; }
.jr-status { color: var(--gold); }
.jr-party[data-outcome="unhorsed"] .jr-status { color: #ff8a80; }

/* ---- keyframes ---- */
@keyframes jr-charge-right {
    from { translate: -25em 0; }
    to { translate: 25em 0; }
}

@keyframes jr-charge-left {
    from { translate: 25em 0; }
    to { translate: -25em 0; }
}

/* Struck in the chest, the rider tips backwards out of the saddle while the horse runs on. */
@keyframes jr-unhorse {
    0% { translate: calc(25em * var(--jr-fall-direction, 1)) 0; rotate: 0deg; }
    50% { translate: 0 0; rotate: 0deg; }
    56% { translate: calc(1.8em * var(--jr-fall-direction, 1)) -2em; rotate: calc(35deg * var(--jr-fall-direction, 1)); }
    64% { translate: calc(3.8em * var(--jr-fall-direction, 1)) -2.6em; rotate: calc(80deg * var(--jr-fall-direction, 1)); }
    72% { translate: calc(5.2em * var(--jr-fall-direction, 1)) 1em; rotate: calc(100deg * var(--jr-fall-direction, 1)); }
    76% { translate: calc(5.6em * var(--jr-fall-direction, 1)) 1.8em; rotate: calc(90deg * var(--jr-fall-direction, 1)); }
    80% { translate: calc(5.9em * var(--jr-fall-direction, 1)) 1.4em; rotate: calc(95deg * var(--jr-fall-direction, 1)); }
    84%, 100% { translate: calc(6.1em * var(--jr-fall-direction, 1)) 1.8em; rotate: calc(90deg * var(--jr-fall-direction, 1)); }
}

@keyframes jr-lance-fly {
    0% { translate: calc(25em * var(--jr-fall-direction, 1)) 0; rotate: 0deg; }
    50% { translate: 0 0; rotate: 0deg; }
    60% { translate: calc(1em * var(--jr-fall-direction, 1)) -4em; rotate: calc(200deg * var(--jr-fall-direction, 1)); }
    70% { translate: calc(2em * var(--jr-fall-direction, 1)) -5.5em; rotate: calc(400deg * var(--jr-fall-direction, 1)); }
    82% { translate: calc(2.8em * var(--jr-fall-direction, 1)) 2.3em; rotate: calc(720deg * var(--jr-fall-direction, 1)); }
    86% { translate: calc(2.9em * var(--jr-fall-direction, 1)) 1.9em; rotate: calc(712deg * var(--jr-fall-direction, 1)); }
    90%, 100% { translate: calc(3em * var(--jr-fall-direction, 1)) 2.3em; rotate: calc(720deg * var(--jr-fall-direction, 1)); }
}

@keyframes jr-burst {
    0%, 49.5% { opacity: 0; scale: .2; }
    50% { opacity: 1; scale: .6; }
    53% { opacity: 1; scale: 1.3; }
    57%, 100% { opacity: 0; scale: 1.6; }
}

@keyframes jr-splinter {
    0%, 49.5% { opacity: 0; translate: 0 0; rotate: 0deg; }
    50% { opacity: 1; translate: 0 0; rotate: 0deg; }
    66% { opacity: 1; translate: var(--jr-dx) var(--jr-dy); rotate: 360deg; }
    72%, 100% { opacity: 0; translate: var(--jr-dx) calc(var(--jr-dy) + 1.5em); rotate: 420deg; }
}

@keyframes jr-shake {
    0%, 49.5%, 56%, 100% { transform: none; }
    51% { transform: translate(.3em, -.2em); }
    52.5% { transform: translate(-.3em, .2em); }
    54% { transform: translate(.2em, .1em); }
}

/* The camera pushes in towards the falling knight. */
@keyframes jr-zoom {
    from { scale: 1; translate: 0 0; }
    to { scale: 1.8; translate: var(--jr-zoom-x, -22%) -22%; }
}

@keyframes jr-gallop {
    0% { opacity: 1; }
    50% { opacity: 0; }
}

@keyframes jr-drift {
    to { translate: 1.5em 0; }
}

@keyframes jr-flutter {
    50% { scale: 1 .7; }
}

@keyframes jr-badge-in {
    from { translate: 120% 0; }
    to { translate: 0 0; }
}

@keyframes jr-flash {
    from { opacity: 1; }
    to { opacity: 0; }
}

@keyframes jr-type {
    to { width: calc(var(--jr-chars) * 1ch); }
}
