/* 으스스 프렌즈 — pastel-on-midnight cute-horror UI */
:root {
  --ink: #0b0b16;
  --card: rgba(16, 15, 30, 0.82);
  --line: rgba(255, 190, 214, 0.28);
  --pink: #ff9bb8;
  --mint: #9be8c2;
  --cream: #ffe9c9;
  --lav: #b9a8ff;
  --text: #f3ecff;
  --dim: #b9aecf;
  /* the menu palette — colder and far darker than the in-game HUD, which stays
     pastel on purpose. Nothing in here is used by the HUD. */
  --void: #04050a;
  --bone: #ece6da;
  --dust: #9a94a6;
  --mute: #6a6474;
  --hair: rgba(236, 230, 218, 0.14);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; }
body {
  background: var(--ink);
  color: var(--text);
  font-family: 'Gowun Dodum', sans-serif;
  overflow: hidden;
  user-select: none;
}
#app, #app canvas { position: fixed; inset: 0; width: 100%; height: 100%; display: block; }

/* ---------- HUD ---------- */
#hud { position: fixed; inset: 0; pointer-events: none; z-index: 5; }

#vignette {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at center, transparent 52%, rgba(4, 3, 12, 0.62) 100%);
  transition: opacity 0.8s ease;
}
#vignette.fear {
  background: radial-gradient(ellipse at center, transparent 38%, rgba(8, 2, 14, 0.85) 100%);
}
#vignette.pulse { animation: vignette-pulse 1.3s ease-in-out 2; }
@keyframes vignette-pulse { 50% { opacity: 0.55; transform: scale(1.02); } }
/* Cold breath creeping in from the frame edge as something closes in behind you.
   Separate from #vignette so scripted dread and stalker dread can stack. */
#dread {
  position: absolute; inset: 0; opacity: 0; transition: opacity 0.5s ease;
  background:
    radial-gradient(ellipse 130% 90% at 50% 120%, rgba(10, 4, 20, 0.75), transparent 55%),
    radial-gradient(ellipse at center, transparent 26%, rgba(6, 2, 12, 0.72) 96%);
  animation: dread-breathe 4.6s ease-in-out infinite;
}
@keyframes dread-breathe { 50% { transform: scale(1.035); } }
#blink {
  position: absolute; inset: 0; background: #000; opacity: 0;
  transition: opacity 0.06s linear;
}
/* The shader pass owns most of the grain now — this is the dirty-lens layer. */
#grain {
  position: absolute; inset: -8px; opacity: 0.045; pointer-events: none;
  background-repeat: repeat; animation: grain-jitter 0.42s steps(3) infinite;
}
@keyframes grain-jitter {
  0% { transform: translate(0, 0); }
  33% { transform: translate(-5px, 3px); }
  66% { transform: translate(4px, -6px); }
  100% { transform: translate(0, 0); }
}
#flash {
  position: absolute; inset: 0; background: #fff; opacity: 0; transition: opacity 0.12s ease-out;
}

.panel {
  background: var(--card);
  border: 1.5px dashed var(--line);
  border-radius: 14px;
  backdrop-filter: blur(4px);
}

#objectives {
  position: absolute; top: 16px; left: 16px; padding: 12px 16px; max-width: 320px;
}
#stage-label {
  font-family: 'Jua', sans-serif; font-size: 11px; letter-spacing: 3px; color: var(--lav); opacity: 0.9;
}
#stage-title { font-family: 'Jua', sans-serif; font-size: 20px; color: var(--cream); margin: 2px 0 8px; }
#objective-list { list-style: none; }
#objective-list li {
  font-size: 13.5px; color: var(--dim); padding: 3px 0 3px 24px; position: relative; line-height: 1.35;
}
#objective-list li::before {
  content: ''; position: absolute; left: 2px; top: 6px; width: 12px; height: 12px;
  border: 1.5px solid var(--lav); border-radius: 4px; opacity: 0.75;
}
#objective-list li.done { color: var(--mint); text-decoration: line-through; text-decoration-color: rgba(155,232,194,0.5); }
#objective-list li.done::before { content: '✓'; border-color: var(--mint); color: var(--mint); font-size: 10px; line-height: 12px; text-align: center; }
#objective-list li .count { color: var(--pink); font-weight: bold; }
#objective-list li.pop { animation: obj-pop 0.5s ease; }
@keyframes obj-pop { 30% { transform: translateX(4px) scale(1.04); } }

/* Sub-lines under a count objective — which friend, and which room they are
   locked in. A dot, not a checkbox: these are not three objectives, they are
   one objective saying where to go, and a second column of checkboxes made the
   panel read as six tasks. */
#objective-list .obj-hints { list-style: none; margin: 1px 0 3px; }
#objective-list .obj-hints li {
  font-size: 12px; color: var(--dim); opacity: 0.82; padding: 1px 0 1px 14px;
}
#objective-list .obj-hints li::before {
  content: ''; left: 3px; top: 8px; width: 5px; height: 5px;
  border: none; border-radius: 50%; background: var(--lav); opacity: 0.6;
}
#objective-list .obj-hints li.done {
  color: var(--mint); opacity: 0.62;
  text-decoration: line-through; text-decoration-color: rgba(155, 232, 194, 0.45);
}
#objective-list .obj-hints li.done::before { content: ''; background: var(--mint); opacity: 0.85; }

#friends { position: absolute; top: 16px; right: 16px; padding: 9px 14px; display: flex; gap: 10px; }
.friend-slot { font-size: 22px; filter: grayscale(1) brightness(0.45); transition: all 0.6s ease; transform: scale(0.92); }
.friend-slot.found { filter: none; transform: scale(1.08); animation: friend-pop 0.8s ease; }
@keyframes friend-pop { 40% { transform: scale(1.45) rotate(-8deg); } 70% { transform: scale(0.95) rotate(4deg); } }

/* ---------- 아파트: 층 · 일행 · 무궁화꽃 ----------
   The floor number is the tower night's CLOCK — the only thing on screen that
   says how much of the level is left — so it is the largest readout in the
   game and it sits top-right where the eye already goes. It is set in the
   serif rather than the round display face on purpose: everything else in this
   HUD is pastel and friendly, and this one number is neither. */
#floor {
  position: absolute; top: 16px; right: 16px;
  display: flex; align-items: baseline; gap: 4px;
  padding: 6px 16px 8px;
  font-family: 'Nanum Myeongjo', serif;
  transition: color 0.6s ease, border-color 0.6s ease;
}
#floor b { font-size: 40px; line-height: 1; font-weight: 800; color: var(--cream); letter-spacing: -0.02em; }
#floor span { font-size: 13px; color: var(--dim); }
/* one storey down: a small settle, so the number reads as having MOVED */
#floor.tick b { animation: floor-tick 0.5s ease; }
@keyframes floor-tick {
  0% { transform: translateY(-9px); opacity: 0.25; }
  60% { transform: translateY(2px); }
  100% { transform: none; opacity: 1; }
}
/* …and the twelfth floor you have already walked. The number goes the WRONG
   WAY, holds, and then stays that colour for the rest of the night. No sting,
   no shake — a readout you have trusted for four minutes quietly disagreeing
   with you is worth more than any of that. */
#floor.wrong b { color: #d2707c; }
#floor.wrong { border-color: rgba(150, 32, 46, 0.5); }
#floor.up b { animation: floor-up 1.5s ease; }
@keyframes floor-up {
  0% { transform: translateY(16px); opacity: 0; }
  22% { transform: none; opacity: 1; }
  34%, 50%, 66% { opacity: 0.35; }
  42%, 58%, 100% { opacity: 1; }
}

/* ---------- 지하철: 종점까지 · 스친 횟수 ----------
   The subway night's clock is a DISTANCE, top-right in the same serif and at
   the same weight as the tower's floor number, for the same reason: it is the
   one thing on screen that says how much dark is left. The last two hundred
   metres let it warm — the only readout in the game that is ever allowed to
   promise anything. */
#dist {
  position: absolute; top: 16px; right: 16px;
  display: flex; align-items: baseline; gap: 5px;
  padding: 6px 16px 8px;
  font-family: 'Nanum Myeongjo', serif;
  transition: color 0.6s ease, border-color 0.6s ease;
}
#dist b { font-size: 34px; line-height: 1; font-weight: 800; color: var(--cream); letter-spacing: -0.02em; }
#dist span { font-size: 13px; color: var(--dim); }
#dist .dist-label { font-size: 12px; margin-right: 2px; }
#dist.near b { color: #e8c28a; }
#dist.near { border-color: rgba(190, 150, 70, 0.4); }

/* 스친 횟수: the times the last train went through the place you were
   standing. It counts UP, like the school's hugs, and the pop is the same
   pop, because it is the same kind of number — a cost you survived. */
#passes {
  position: absolute; top: 84px; right: 16px;
  display: flex; align-items: center; gap: 7px;
  padding: 6px 13px;
}
#passes .pass-icon { font-size: 16px; filter: grayscale(0.4) brightness(0.9); }
#passes .pass-label { font-size: 12px; color: var(--dim); }
#passes b { font-size: 19px; color: var(--cream); }
#passes.pop { animation: pass-pop 0.7s ease; }
@keyframes pass-pop {
  30% { transform: scale(1.12); border-color: rgba(190, 200, 226, 0.75); }
}

/* The health bar, and it is a row of faces. Five pips is a number you spend;
   아기 여우 going grey is not. */
#party {
  position: absolute; top: 84px; right: 16px;
  display: flex; align-items: center; gap: 8px; padding: 8px 13px;
}
.party-slot {
  font-size: 20px; transform: scale(1);
  transition: filter 1.4s ease, opacity 1.4s ease, transform 0.8s ease;
}
/* the drain is SLOW on purpose — about as long as noticing takes */
.party-slot.gone { filter: grayscale(1) brightness(0.35); opacity: 0.4; transform: scale(0.8); }
/* 얼음. NOT the same read as gone, and the difference has to be legible at a
   glance mid-chase: a frozen friend is still on this floor and you can still go
   back for them, so the chip goes cold and BREATHES rather than draining out. */
.party-slot.frozen {
  filter: grayscale(0.55) brightness(0.8) drop-shadow(0 0 7px rgba(126, 196, 240, 0.9));
  opacity: 0.85; transform: scale(0.92);
  animation: party-ice 1.9s ease-in-out infinite;
}
@keyframes party-ice {
  0%, 100% { filter: grayscale(0.55) brightness(0.78) drop-shadow(0 0 5px rgba(126, 196, 240, 0.7)); }
  50% { filter: grayscale(0.4) brightness(1) drop-shadow(0 0 12px rgba(150, 214, 255, 1)); }
}
.party-slot.losing { animation: party-lose 1.6s ease forwards; }
@keyframes party-lose {
  0% { transform: scale(1.25); filter: none; }
  30% { transform: scale(0.92) rotate(-9deg); }
  100% { transform: scale(0.8); filter: grayscale(1) brightness(0.35); opacity: 0.4; }
}
#party b { font-family: 'Jua', sans-serif; font-size: 13px; color: var(--dim); margin-left: 2px; }

/* 무궁화꽃이 피었습니다. A line of text and a bar that fills while you hold
   still, and nothing else — the only thing the player should be looking at
   while this runs is the corridor. */
#counting {
  position: absolute; left: 50%; bottom: 21%; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  opacity: 0; transition: opacity 0.35s ease;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.95);
}
#counting.show { opacity: 1; }
#counting span {
  font-family: 'Nanum Myeongjo', serif; font-size: 19px; letter-spacing: 0.22em;
  color: #efe2e6;
}
#counting i { display: block; width: 190px; height: 2px; background: rgba(236, 230, 218, 0.16); }
#count-bar { display: block; height: 100%; width: 0; background: var(--cream); transition: width 0.12s linear; }

#crosshair {
  position: absolute; left: 50%; top: 50%; width: 5px; height: 5px; margin: -2.5px;
  background: rgba(255, 255, 255, 0.8); border-radius: 50%;
  /* dark ring, not a glow: a bare white dot disappeared inside the torch pool */
  box-shadow: 0 0 0 1.5px rgba(8, 6, 16, 0.75), 0 0 5px rgba(0, 0, 0, 0.6);
  transition: all 0.12s ease;
}
#crosshair.hit {
  width: 11px; height: 11px; margin: -5.5px;
  background: transparent; border: 2px solid var(--pink);
  box-shadow: 0 0 10px rgba(255, 155, 184, 0.6);
}
#crosshair.carry {
  width: 9px; height: 9px; margin: -4.5px;
  background: transparent; border: 1.5px dashed var(--cream);
}

#collect {
  position: absolute; top: 66px; right: 16px; padding: 7px 14px; display: flex; gap: 14px;
  font-size: 13px; color: var(--dim);
}
#collect b { color: var(--cream); font-family: 'Jua', sans-serif; }

#note-modal {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(6, 5, 14, 0.72); pointer-events: auto; cursor: pointer;
}
#note-card {
  background: linear-gradient(160deg, #f5ecd8, #efe2c8);
  color: #4a3c30; border-radius: 6px 18px 8px 20px;
  padding: 26px 30px; max-width: 420px; width: 88vw;
  max-height: 84vh; display: flex; flex-direction: column;
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.65);
  transform: rotate(-1.6deg);
  border: 1px solid rgba(120, 96, 60, 0.25);
}
/* a long letter scrolls inside the card instead of running off a short screen */
#note-body { overflow-y: auto; min-height: 0; overscroll-behavior: contain; }
#note-face { font-size: 34px; }
#note-title { font-family: 'Jua', sans-serif; font-size: 19px; margin: 6px 0 10px; color: #6b4a35; }
#note-body { font-size: 14.5px; line-height: 1.7; white-space: pre-line; }
.note-hint { margin-top: 16px; font-size: 11.5px; color: rgba(107, 74, 53, 0.6); text-align: right; }
#prompt {
  position: absolute; left: 50%; top: calc(50% + 30px); transform: translateX(-50%);
  font-family: 'Jua', sans-serif; font-size: 15px; color: var(--cream);
  background: var(--card); border: 1.5px solid var(--line); border-radius: 999px;
  padding: 6px 16px; white-space: nowrap;
  max-width: 92vw; overflow: hidden; text-overflow: ellipsis;
}
#prompt b, #carry-hint b { color: var(--pink); }
#carry-hint {
  position: absolute; left: 50%; bottom: 132px; transform: translateX(-50%);
  font-size: 12.5px; color: var(--dim);
}

#subtitle {
  position: absolute; left: 50%; bottom: 26px; transform: translateX(-50%);
  display: flex; align-items: center; gap: 12px;
  background: var(--card); border: 1.5px dashed var(--line); border-radius: 16px;
  padding: 10px 20px 12px 14px; max-width: min(640px, 86vw); pointer-events: none;
}
#subtitle-face { font-size: 30px; }
#subtitle-name { font-family: 'Jua', sans-serif; font-size: 12.5px; color: var(--pink); margin-bottom: 2px; }
#subtitle-text { font-size: 15.5px; line-height: 1.45; }

#titlecard {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: rgba(5, 4, 12, 0.55); text-align: center; opacity: 0; transition: opacity 0.7s ease;
}
#titlecard.show { opacity: 1; }
#titlecard-label { font-family: 'Jua', sans-serif; letter-spacing: 6px; font-size: 15px; color: var(--lav); }
#titlecard-title {
  font-family: 'Jua', sans-serif; font-size: clamp(34px, 6vw, 56px); color: var(--cream);
  margin: 8px 0 10px; text-shadow: 0 4px 30px rgba(255, 155, 184, 0.35);
}
#titlecard-sub { font-size: 16px; color: var(--dim); }

#reveal-card {
  position: absolute; left: 50%; top: 34%; transform: translate(-50%, -50%) scale(0.6); text-align: center;
  opacity: 0; transition: all 0.45s cubic-bezier(0.2, 1.6, 0.4, 1);
}
#reveal-card.show { opacity: 1; transform: translate(-50%, -50%) scale(1); }
#reveal-emoji { font-size: 74px; animation: reveal-bounce 1.2s ease infinite; }
@keyframes reveal-bounce { 50% { transform: translateY(-10px) rotate(4deg); } }
#reveal-name {
  font-family: 'Jua', sans-serif; font-size: 42px; color: var(--pink);
  text-shadow: 0 3px 24px rgba(255, 155, 184, 0.5);
}
#reveal-note { font-family: 'Jua', sans-serif; font-size: 18px; color: var(--cream); margin-top: 4px; }

#toast {
  position: absolute; left: 50%; top: 88px; transform: translateX(-50%);
  font-family: 'Jua', sans-serif; font-size: 16px; color: var(--cream);
  background: var(--card); border: 1.5px dashed var(--line); border-radius: 999px; padding: 8px 22px;
  max-width: 86vw; text-align: center;
  animation: toast-in 0.4s ease;
}
@keyframes toast-in { from { opacity: 0; transform: translateX(-50%) translateY(-10px); } }

/* ---------- the autosave's corner mark ----------
   Deliberately the quietest thing on the HUD. It has to be legible enough that
   a player who is about to close the tab can confirm the night is written down,
   and faint enough that a stage which fires six milestones in a minute does not
   flash at them six times. Bottom-right, under the dread vignette, no motion
   but the fade. */
#saveflag {
  position: absolute; right: 16px; bottom: 14px;
  display: flex; align-items: center; gap: 7px;
  font-size: 11px; letter-spacing: 0.16em; color: var(--mute);
  animation: saveflag 2.6s ease forwards;
}
#saveflag b { font-weight: 400; }
.save-dot {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--cream); box-shadow: 0 0 7px rgba(255, 246, 217, 0.6);
}
@keyframes saveflag {
  0% { opacity: 0; }
  14% { opacity: 0.85; }
  62% { opacity: 0.85; }
  100% { opacity: 0; }
}

/* ====================================================================
   THE NIGHT SCREENS — level select and the two briefings.
   The old menu was a dashed pastel card on a purple gradient: a birthday
   invitation for a horror game. It is now a full-bleed painted night with
   the building you are about to walk into standing behind the type, graded
   down until only its lit windows survive. Every screen is the same layer
   stack (menu.js injects it off data-plate):
       plate → haze → fog ×2 → rain → flash → grain → vignette → content
   Nothing here uses backdrop-filter: the app canvas is live behind these
   and blurring it costs a full readback every frame for no visible gain.
   ==================================================================== */
.overlay {
  position: fixed; inset: 0; z-index: 10; display: flex; align-items: center; justify-content: center;
  background: var(--void);
}
/* pause and the two endings are not night screens — they sit over a live game,
   and seeing the room dimly through them is the point */
.overlay:not(.screen) { background: rgba(4, 5, 10, 0.93); }
/* screens crossfade through each other rather than cutting: picking a night
   dissolves the card art into the same plate at full bleed */
.screen { transition: opacity 0.45s ease; }
.screen.veiled { opacity: 0; }

/* ---------- the atmosphere stack ---------- */
.fx { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.fx > * { position: absolute; }

/* The building. JS owns its transform (slow push-in + pointer parallax), so
   nothing here may set one — it would be overwritten on the next frame. */
/* The plates are painted dim already — the grade's job is to cool and crush
   the EDGES, not the building. Everything here was originally about half this
   brightness and the school simply was not there: a backdrop you cannot make
   out is not scary, it is off. */
.fx-plate {
  inset: -5%;
  background-position: center 44%; background-size: cover; background-repeat: no-repeat;
  filter: brightness(1.5) contrast(1.12) saturate(0.6);
  opacity: 0; transition: opacity 1.6s ease, filter 1.2s ease;
  will-change: transform;
}
.fx-plate.on { opacity: 1; }

/* A cold cast, dark closing in from every edge, and the ground pulled to true
   black so the type below has somewhere to sit. */
.fx-haze {
  inset: 0;
  background:
    radial-gradient(ellipse 124% 90% at 50% 42%, rgba(6, 8, 16, 0) 0%, rgba(5, 6, 13, 0.24) 60%, rgba(3, 4, 9, 0.8) 100%),
    linear-gradient(180deg, rgba(3, 4, 9, 0.62) 0%, rgba(4, 5, 11, 0) 28%, rgba(3, 4, 9, 0.5) 74%, rgba(3, 4, 9, 0.84) 100%),
    linear-gradient(0deg, rgba(9, 13, 28, 0.26), rgba(9, 13, 28, 0.26));
}
/* the briefings put their column on the left, so the dark is weighted there */
.brief-screen .fx-haze::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(3, 4, 9, 0.94) 0%, rgba(3, 4, 9, 0.8) 28%, rgba(3, 4, 9, 0.2) 60%, transparent 78%);
}
/* On the level select the crossroads is scenery, not the subject — the two
   cards are. It sits back, and the sky behind the wordmark gets its own well
   of dark so the lamp and the signpost cannot crowd the type. */
#start .fx-plate { filter: brightness(1.14) contrast(1.14) saturate(0.5); }
#start .fx-haze::after {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(ellipse 52% 36% at 50% 18%, rgba(3, 4, 9, 0.78) 0%, rgba(3, 4, 9, 0.35) 55%, transparent 76%);
}

.fx-fog, .fx-fog2 { inset: -25%; will-change: transform; }
.fx-fog {
  background:
    radial-gradient(ellipse 44% 24% at 24% 76%, rgba(152, 166, 196, 0.11), transparent 70%),
    radial-gradient(ellipse 56% 28% at 62% 88%, rgba(140, 156, 190, 0.1), transparent 72%);
  animation: fog-a 54s ease-in-out infinite alternate;
}
.fx-fog2 {
  background:
    radial-gradient(ellipse 38% 20% at 74% 68%, rgba(150, 164, 196, 0.085), transparent 70%),
    radial-gradient(ellipse 50% 22% at 34% 94%, rgba(146, 160, 192, 0.1), transparent 72%);
  animation: fog-b 78s ease-in-out infinite alternate;
}
@keyframes fog-a { to { transform: translate3d(7%, -3%, 0) scale(1.14); } }
@keyframes fog-b { to { transform: translate3d(-8%, 2%, 0) scale(1.1); } }

/* Rain: a seamless canvas tile (menu.js) scrolled exactly one tile per cycle
   in BOTH axes, which is the only way a repeating streak field loops without
   a visible seam. Two layers at different speeds read as depth. */
.fx-rain, .fx-rain2 { inset: 0; opacity: 0; transition: opacity 2s ease; background-repeat: repeat; }
/* kept low on purpose — the plates are painted with their own rain, and a
   second, harder CSS layer on top read as scratches on the film */
.storm .fx-rain { opacity: 0.3; animation: rain-near 0.62s linear infinite; }
.storm .fx-rain2 { opacity: 0.16; animation: rain-far 1.15s linear infinite; }
@keyframes rain-near { to { background-position: -128px 384px; } }
@keyframes rain-far { to { background-position: -64px 192px; } }

/* Lightning. `screen` over a near-black plate lifts the shadows instead of
   washing a white sheet over them, so a strike REVEALS the building. */
.fx-flash { inset: 0; background: #b9c8e8; opacity: 0; mix-blend-mode: screen; }

.fx-grain { inset: -8px; opacity: 0.05; background-repeat: repeat; animation: grain-jitter 0.42s steps(3) infinite; }
.fx-vig {
  inset: 0;
  background: radial-gradient(ellipse 96% 84% at 50% 48%, transparent 38%, rgba(2, 3, 7, 0.5) 76%, rgba(1, 2, 5, 0.84) 100%);
  animation: vig-breathe 11s ease-in-out infinite;
}
@keyframes vig-breathe { 50% { transform: scale(1.035); } }

/* ---------- level select ---------- */
.menu {
  position: relative; z-index: 2; text-align: center;
  width: min(1040px, 92vw); max-height: 100vh;
  /* never sideways. `overflow-y: auto` alone computes overflow-x to auto too,
     so any transform that pokes a pixel past the column (the floating crest,
     a hovered card) summoned a horizontal scrollbar, which made the box 15px
     taller and shoved the whole centred page up — then vanished on the next
     beat of the animation, and the page bobbed with it. */
  overflow-x: hidden; overflow-y: auto;
  padding: 5vh 0 4vh;
}
/* inline-block: it rotates as it floats, and a full-width block rotated by 4°
   is 2px wider than the column it sits in — that was the scrollbar above */
.menu-crest { display: inline-block; font-size: 34px; opacity: 0.58; filter: drop-shadow(0 4px 14px rgba(0, 0, 0, 0.9)); animation: ghost-float 4.5s ease-in-out infinite; }
@keyframes ghost-float { 50% { transform: translateY(-9px) rotate(-4deg); } }
.menu-title {
  font-family: 'Nanum Myeongjo', serif; font-weight: 800;
  font-size: clamp(38px, 6.6vw, 76px); letter-spacing: 0.06em; line-height: 1.15;
  color: var(--bone); margin: 4px 0 0;
  text-shadow: 0 0 46px rgba(150, 172, 220, 0.2), 0 2px 1px rgba(0, 0, 0, 0.95);
  animation: lamp-flicker 11s ease-in-out infinite;
}
/* a failing lamp, not a strobe: it holds, stutters twice, holds again */
@keyframes lamp-flicker {
  0%, 37%, 39.5%, 41.5%, 68%, 69.5%, 100% { opacity: 1; }
  38% { opacity: 0.5; }
  40.5% { opacity: 0.76; }
  68.7% { opacity: 0.38; }
}
.menu-title-en {
  font-family: 'Nanum Myeongjo', serif; font-size: 11.5px; letter-spacing: 0.62em;
  color: var(--mute); margin: 12px 0 0; text-indent: 0.62em;
}
.rule { display: flex; align-items: center; gap: 18px; margin: 26px auto 30px; max-width: 520px; }
.rule i { flex: 1; height: 1px; background: linear-gradient(90deg, transparent, var(--hair)); }
.rule i:last-child { background: linear-gradient(270deg, transparent, var(--hair)); }
.rule span { font-size: 13px; letter-spacing: 0.14em; color: var(--dust); white-space: nowrap; }

/* Four nights now. Four across on a wide screen, and the whole row narrows
   rather than the cards stacking — the point of this page is that you are
   standing at a crossroads looking at all of them at once, and a card that has
   dropped onto its own line has stopped being a choice. (13.0's card shipped
   on a grid that still said three, and the scariest night in the game
   rendered as a lone third-width card below the fold.) */
#level-list { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.level-card {
  position: relative; overflow: hidden; isolation: isolate;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: min(54vh, 430px); padding: 0; margin: 0; text-align: left;
  font-family: 'Gowun Dodum', sans-serif; color: var(--bone); cursor: pointer;
  background: #06070d; border: 1px solid rgba(236, 230, 218, 0.12); border-radius: 3px;
  box-shadow: 0 26px 64px rgba(0, 0, 0, 0.62);
  transition: transform 0.55s cubic-bezier(0.2, 0.7, 0.2, 1), border-color 0.5s ease,
              box-shadow 0.5s ease, opacity 0.5s ease;
}
.level-art {
  position: absolute; inset: 0; z-index: 0;
  background-size: cover; background-position: center 44%;
  filter: brightness(1.02) contrast(1.04) saturate(0.44);
  transform: scale(1.05);
  transition: filter 1s ease, transform 1.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.level-card::after {   /* the scrim the copy is legible against */
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(4, 5, 10, 0) 0%, rgba(4, 5, 10, 0.34) 42%, rgba(4, 5, 10, 0.9) 84%, rgba(4, 5, 10, 0.97) 100%);
}
/* the night you are not pointing at recedes */
#level-list:hover .level-card, #level-list:focus-within .level-card { opacity: 0.5; }
#level-list .level-card:hover, #level-list .level-card:focus-visible {
  opacity: 1; transform: translateY(-6px);
  border-color: rgba(236, 230, 218, 0.34); box-shadow: 0 34px 80px rgba(0, 0, 0, 0.78);
  outline: none;
}
.level-card:hover .level-art, .level-card:focus-visible .level-art {
  filter: brightness(1.45) contrast(1.0) saturate(0.78); transform: scale(1.13);
}
.level-seal {
  position: absolute; top: 13px; right: 15px; z-index: 3; font-size: 19px;
  opacity: 0.42; filter: grayscale(0.7); transition: opacity 0.5s ease, filter 0.5s ease;
}
.level-card:hover .level-seal { opacity: 0.95; filter: none; }
/* Something standing in the school's front doorway, only once you lean toward
   it. Pinned to the card's exact CENTRE on purpose: the art is `cover`, so the
   crop slides around as the card's aspect changes, and dead centre is the one
   point that maps to the same place in the painting at every size — and the
   scale-up on hover is anchored there too, so the eyes never drift off the
   door. Anywhere else and they end up on a wall at some viewport. */
.level-eyes {
  position: absolute; z-index: 2; left: 50%; top: 50%; transform: translate(-50%, -50%);
  display: flex; gap: 11px; opacity: 0; transition: opacity 1.3s ease;
}
.level-eyes i { width: 5px; height: 5px; border-radius: 50%; background: #d02231; box-shadow: 0 0 11px 3px rgba(208, 34, 49, 0.45); }
.level-card.scary:hover .level-eyes, .level-card.scary:focus-visible .level-eyes { opacity: 0.9; animation: eye-blink 4.5s 1.4s ease-in-out infinite; }
@keyframes eye-blink { 0%, 92%, 100% { opacity: 0.9; } 94%, 97% { opacity: 0; } }

.level-copy { position: relative; z-index: 2; display: flex; flex-direction: column; gap: 5px; padding: 22px 22px 20px; }
.level-index { font-size: 10.5px; letter-spacing: 0.3em; color: var(--mute); }
.level-name {
  font-family: 'Nanum Myeongjo', serif; font-weight: 800; font-size: 34px; line-height: 1.1;
  color: var(--bone); text-shadow: 0 2px 18px rgba(0, 0, 0, 0.9);
}
.level-en { font-size: 10px; letter-spacing: 0.42em; color: var(--mute); margin: -2px 0 3px; }
.level-sub { font-size: 12.5px; line-height: 1.5; color: var(--dust); }
.level-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.level-tags i {
  font-style: normal; font-size: 10px; letter-spacing: 0.05em; color: var(--dust);
  border: 1px solid var(--hair); border-radius: 2px; padding: 3px 8px;
}
.level-best { font-size: 10.5px; color: var(--mute); margin-top: 7px; }
.level-best b { color: var(--dust); font-weight: normal; }
.level-go {
  font-size: 11.5px; letter-spacing: 0.24em; color: var(--bone);
  margin-top: 12px; opacity: 0; transform: translateY(6px);
  transition: opacity 0.45s ease, transform 0.45s ease;
}
.level-go b { display: inline-block; transition: transform 0.45s ease; }
.level-card:hover .level-go, .level-card:focus-visible .level-go { opacity: 0.9; transform: none; }
.level-card:hover .level-go b { transform: translateX(6px); }

.level-card.scary { border-color: rgba(150, 32, 46, 0.34); }
.level-card.scary:hover, .level-card.scary:focus-visible {
  border-color: rgba(196, 42, 60, 0.75); box-shadow: 0 34px 80px rgba(0, 0, 0, 0.78), 0 0 34px rgba(150, 24, 40, 0.22);
}
.level-card.scary .level-tags i:last-child { color: #d2707c; border-color: rgba(150, 32, 46, 0.5); }

/* the third night. It gets a colder red than the school's and its two eyes sit
   lower and closer together, because what is in that building is not a doll. */
.level-card.worst { border-color: rgba(122, 20, 34, 0.42); }
.level-card.worst:hover, .level-card.worst:focus-visible { border-color: rgba(160, 26, 42, 0.75); }
.level-card.worst .level-eyes { top: 40%; gap: 8px; }
.level-card.worst .level-eyes i { background: #eae4d6; box-shadow: 0 0 9px 2px rgba(234, 228, 214, 0.3); }
.level-card.worst .level-name { color: #efe4e2; }

/* the fourth night. Its two eyes are a HEADLIGHT pair — warm, close together,
   dead level, low — because what looks back from this card is not standing. */
.level-card.last { border-color: rgba(38, 46, 66, 0.66); }
.level-card.last:hover, .level-card.last:focus-visible { border-color: rgba(96, 116, 158, 0.7); }
.level-card.last .level-eyes { top: 56%; gap: 7px; }
.level-card.last .level-eyes i { background: #ffe9c2; box-shadow: 0 0 12px 3px rgba(255, 226, 178, 0.4); }
.level-card.last .level-name { color: #dfe6f2; }
.level-card.last .level-tags i:last-child { color: #d2707c; border-color: rgba(150, 32, 46, 0.5); }

/* where everyone was, when the lights came on */
.ending-missing {
  margin: 14px auto 4px; max-width: 460px; text-align: left;
  font-size: 13px; line-height: 1.9; color: var(--dust);
  border-left: 2px solid rgba(255, 190, 214, 0.24); padding-left: 14px;
}

.menu-foot { display: flex; flex-direction: column; align-items: center; gap: 12px; margin-top: 28px; }

/* ---------- briefing ---------- */
/* The column is pinned left so the building keeps the rest of the frame. */
.brief-screen { justify-content: flex-start; }
.brief {
  position: relative; z-index: 2; display: flex; align-items: center;
  width: min(600px, 100%); height: 100%; padding: 0 clamp(20px, 4.5vw, 60px);
}
.brief-scroll { width: 100%; max-height: 94vh; overflow-x: hidden; overflow-y: auto; padding: 26px 0; text-align: left; }
.brief-index { font-size: 10.5px; letter-spacing: 0.32em; color: var(--mute); }
.brief-title {
  font-family: 'Nanum Myeongjo', serif; font-weight: 800; font-size: clamp(42px, 5.6vw, 64px);
  line-height: 1.08; color: var(--bone); margin: 6px 0 0; letter-spacing: 0.03em;
  text-shadow: 0 0 40px rgba(150, 172, 220, 0.16), 0 2px 1px rgba(0, 0, 0, 0.95);
}
.brief-en { font-size: 10.5px; letter-spacing: 0.52em; color: var(--mute); margin: 10px 0 0; }
.brief-sheet {
  border: 1px solid var(--hair); border-radius: 2px; padding: 13px 16px 15px;
  background: rgba(6, 7, 13, 0.55); margin: 0 0 20px;
}
.sheet-head {
  font-size: 10px; letter-spacing: 0.3em; color: var(--mute);
  padding-bottom: 9px; margin-bottom: 11px; border-bottom: 1px solid var(--hair);
}
.brief-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 0 0 14px; }

/* ---------- resume ----------
   The line above the buttons says what is actually in the save — which stage,
   how far in, how long ago — because "이어서 하기" on its own asks the player to
   trust a black box with forty minutes in it. It is also where a save that the
   server retired says so, in the same place they would have looked for it. */
.resume-line {
  margin: 0 0 12px; padding: 10px 14px;
  border: 1px solid var(--hair); border-left: 2px solid var(--pink);
  background: rgba(9, 9, 16, 0.55);
  font-size: 12.5px; line-height: 1.7; color: var(--dim);
}
.resume-line b { color: var(--cream); font-family: 'Jua', sans-serif; }
.resume-line.retired { border-left-color: var(--mute); }
.pause-saves { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-top: 12px; }
#save-status { min-height: 1.6em; }

/* ---------- shared type + controls ---------- */
.title-ghost { font-size: 54px; animation: ghost-float 4.5s ease-in-out infinite; }
.overlay-card {
  text-align: center; max-width: 560px; width: min(560px, 92vw);
  background: rgba(9, 9, 16, 0.94); border: 1px solid var(--hair); border-radius: 3px;
  padding: 34px 34px 26px;
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.78);
}
.overlay-card h1, .overlay-card h2 {
  font-family: 'Nanum Myeongjo', serif; font-weight: 800; color: var(--bone); letter-spacing: 0.03em;
}
.overlay-card h1 { font-size: 38px; margin: 8px 0 0; }
.overlay-card h2 { font-size: 27px; }
.title-en { font-size: 11px; letter-spacing: 0.5em; color: var(--mute); margin: 10px 0 16px; }
.story { font-size: 14.5px; line-height: 1.78; color: var(--dust); margin: 16px 0 20px; }
.story b { color: var(--bone); font-weight: normal; border-bottom: 1px solid rgba(236, 230, 218, 0.2); }
.controls-grid {
  display: grid; grid-template-columns: 1fr; gap: 7px; text-align: left;
  font-size: 12.5px; line-height: 1.5; color: var(--dust);
}
.controls-grid b { color: var(--bone); font-weight: normal; }
.controls-grid > span { padding-left: 13px; position: relative; }
.controls-grid > span::before {
  content: ''; position: absolute; left: 0; top: 8px; width: 4px; height: 1px; background: var(--hair);
}
.story b.danger, .controls-grid b.danger { color: #d2707c; border-color: rgba(196, 42, 60, 0.45); }

/* A pressed brass plate rather than a bubblegum pill. The sweep is a single
   translated gradient — no filters, so it stays cheap over a live canvas. */
button {
  position: relative; overflow: hidden;
  font-family: 'Nanum Myeongjo', serif; font-weight: 700; font-size: 16px; letter-spacing: 0.04em;
  color: var(--bone);
  background: linear-gradient(180deg, rgba(32, 30, 42, 0.92), rgba(12, 12, 20, 0.94));
  border: 1px solid rgba(236, 230, 218, 0.24); border-radius: 2px;
  padding: 13px 28px; cursor: pointer;
  transition: border-color 0.35s ease, background 0.35s ease, color 0.35s ease, transform 0.25s ease;
}
button::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(105deg, transparent 34%, rgba(236, 230, 218, 0.14) 50%, transparent 66%);
  transform: translateX(-120%); transition: transform 0.75s ease;
}
button:hover { border-color: rgba(236, 230, 218, 0.6); background: linear-gradient(180deg, rgba(46, 43, 60, 0.95), rgba(17, 16, 27, 0.95)); }
button:hover::after { transform: translateX(120%); }
button:active { transform: translateY(1px); }
button.ghost-btn {
  font-family: 'Gowun Dodum', sans-serif; font-weight: normal; font-size: 13px; letter-spacing: 0.06em;
  color: var(--mute); background: none; border-color: transparent; padding: 12px 8px;
}
button.ghost-btn:hover { color: var(--dust); background: none; border-color: transparent; }
button.ghost-btn::after { display: none; }
button.danger-btn {
  color: #f2dde0; border-color: rgba(178, 38, 58, 0.62);
  background: linear-gradient(180deg, rgba(58, 18, 26, 0.94), rgba(20, 9, 13, 0.95));
  box-shadow: 0 0 26px rgba(150, 24, 40, 0.14);
}
button.danger-btn:hover {
  border-color: rgba(212, 52, 74, 0.95);
  background: linear-gradient(180deg, rgba(82, 24, 36, 0.96), rgba(28, 11, 17, 0.96));
  box-shadow: 0 0 40px rgba(168, 26, 44, 0.3);
}
/* the pause/ending cards still stack their buttons down the middle */
.overlay-card button { display: block; margin: 0 auto 10px; }

.start-note { font-size: 11.5px; line-height: 1.6; color: var(--mute); margin-top: 12px; }
#ending-stats {
  display: flex; justify-content: center; gap: 20px; margin: 6px 0 18px; flex-wrap: wrap;
  font-size: 11px; letter-spacing: 0.08em; color: var(--mute);
}
#ending-stats b { display: block; font-family: 'Nanum Myeongjo', serif; font-size: 21px; color: var(--bone); letter-spacing: 0; }
#ending-rank { font-family: 'Nanum Myeongjo', serif; font-size: 18px; color: var(--dust); margin: 14px 0 4px; }
#ending-rank .rank-tier {
  display: inline-block; font-size: 26px; font-weight: 800; color: var(--bone);
  border: 1px solid var(--hair); border-radius: 2px; padding: 2px 14px; margin-right: 10px;
}
#ending-unlock {
  font-size: 12.5px; color: var(--dust); margin: 0 0 16px;
  border: 1px solid var(--hair); border-radius: 2px; padding: 9px 14px;
}

/* ---------- controls: sliders and the midnight switch ---------- */
/* the level-select footer spaces its own children, but the pause card stacks
   this straight on top of a button and needs the gap */
.slider-row { display: flex; align-items: center; justify-content: center; gap: 24px; font-size: 13px; margin: 0 0 18px; }
.menu-foot .slider-row { margin: 0; }
.slider-row label { display: flex; align-items: center; gap: 9px; cursor: pointer; opacity: 0.75; transition: opacity 0.3s ease; }
.slider-row label:hover { opacity: 1; }
.slider-row input[type="range"] {
  -webkit-appearance: none; appearance: none; width: 112px; height: 1px;
  background: rgba(236, 230, 218, 0.22); outline: none; cursor: pointer;
}
.slider-row input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 10px; height: 10px; border-radius: 50%;
  background: var(--bone); box-shadow: 0 0 0 3px var(--void), 0 0 10px rgba(236, 230, 218, 0.4); cursor: pointer;
}
.slider-row input[type="range"]::-moz-range-thumb {
  width: 10px; height: 10px; border: none; border-radius: 50%;
  background: var(--bone); box-shadow: 0 0 0 3px var(--void), 0 0 10px rgba(236, 230, 218, 0.4); cursor: pointer;
}
#midnight-row {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 12.5px; line-height: 1.5; color: var(--dust); margin: 0 0 18px; cursor: pointer;
  border: 1px solid var(--hair); border-radius: 2px; padding: 11px 14px;
  transition: border-color 0.35s ease, color 0.35s ease;
}
#midnight-row:hover { border-color: rgba(236, 230, 218, 0.28); color: var(--bone); }
#midnight-row input { accent-color: #8f86c8; margin-top: 2px; }
#midnight-row b { color: var(--bone); font-weight: normal; }
#best-line, #school-best-line { font-size: 11.5px; letter-spacing: 0.04em; color: var(--mute); margin: 0 0 18px; }
#best-line b, #school-best-line b { color: var(--dust); font-weight: normal; }

/* 안긴 횟수 — five pips that FILL as she gets her hugs in. A bar that drains
   says "you are dying"; a row that fills says "she is getting there", which is
   the actual stake of this night. Round, not heart-shaped: at 11px a heart is a
   blob, and a blob that is trying to be a heart is worse than a clean dot. */
#hugs {
  position: absolute; left: 16px; bottom: 26px; padding: 7px 12px;
  display: flex; align-items: center; gap: 9px;
}
.hug-icon { font-size: 15px; }
#hug-pips { display: flex; gap: 5px; }
#hug-pips i {
  width: 11px; height: 11px; border-radius: 50%;
  border: 1.5px solid var(--line); background: rgba(6, 5, 14, 0.6);
  transition: background 0.35s ease, border-color 0.35s ease, transform 0.35s ease;
}
#hug-pips i.on {
  background: radial-gradient(circle at 34% 30%, #ffd9e6, var(--pink) 62%, #d4587f);
  border-color: rgba(255, 190, 214, 0.75);
  transform: scale(1.12);
}
#hugs b { font-family: 'Jua', sans-serif; font-size: 12.5px; color: var(--cream); }
/* one hug from being carried off to the nurse's office */
#hugs.nearly .hug-icon { animation: hug-fuss 1.5s ease-in-out infinite; }
#hugs.pop .hug-icon { animation: hug-pop 0.55s ease; }
@keyframes hug-fuss { 50% { transform: scale(1.14) rotate(-6deg); } }
@keyframes hug-pop { 35% { transform: scale(1.45) rotate(-12deg); } 65% { transform: scale(0.94) rotate(7deg); } }

#pages {
  position: absolute; top: 66px; right: 16px; padding: 7px 14px;
  font-size: 13px; color: var(--dim);
}
#pages b { color: var(--cream); font-family: 'Jua', sans-serif; }

/* the hug: the frame closes in like arms going round it, warm and soft, and
   then lets go. It EASES in over a fifth of a second — a slam here is what made
   the old crimson version read as a wound. */
#squeeze {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background:
    radial-gradient(ellipse at center, transparent 26%, rgba(255, 146, 186, 0.30) 70%, rgba(196, 84, 128, 0.52) 100%),
    radial-gradient(ellipse 60% 40% at 50% 50%, rgba(255, 226, 238, 0.14), transparent 70%);
}
#squeeze.show { animation: hug-squeeze 1.5s cubic-bezier(0.32, 0, 0.2, 1); }
@keyframes hug-squeeze {
  0%   { opacity: 0; transform: scale(1.14); }
  22%  { opacity: 1; transform: scale(1); }
  46%  { opacity: 0.78; transform: scale(1.02); }
  100% { opacity: 0; transform: scale(1.06); }
}

/* NOTHING HERE PAINTS THE FRAME ON HER FLARE TIMER. Two vignette states used
   to: a crimson "rage" border in 9.1 and the rose "longing" wash that replaced
   it in 10.0. Both fired on the same 16-42s schedule, which runs while she is
   nowhere in the building — so the screen kept tinting itself in an empty
   corridor with nothing on it to explain why. Recolouring that only changed
   which wrong thing it said. Her flare now lives where you can go and find it:
   a positioned sound, and lit eyes if she is actually in the room with you.
   See hunter.flare() and the note in hud.js. */

[hidden] { display: none !important; }

/* Narrow viewports: the objectives panel and the friends/collect panels would
   otherwise collide head-on somewhere under ~700px. */
@media (max-width: 760px) {
  #objectives { max-width: 44vw; padding: 9px 12px; top: 12px; left: 12px; }
  #stage-title { font-size: 16px; }
  #objective-list li { font-size: 12px; padding-left: 20px; }
  #objective-list .obj-hints li { font-size: 11px; padding-left: 13px; }
  #friends { padding: 7px 10px; gap: 7px; top: 12px; right: 12px; }
  .friend-slot { font-size: 18px; }
  #collect { top: 56px; right: 12px; gap: 10px; font-size: 11.5px; padding: 5px 10px; }
  #subtitle { max-width: 92vw; padding: 8px 14px 10px 10px; }
  #subtitle-text { font-size: 14px; }
  .controls-grid { grid-template-columns: 1fr; }
  /* the subtitle box goes near-full-width down here and would sit on top of it */
  #hugs { bottom: 108px; left: 12px; }
  #pages { top: 56px; right: 12px; font-size: 11.5px; padding: 5px 10px; }

  /* the nights stack, and the briefing gives the frame back to the building:
     the copy drops to the bottom and the scrim turns bottom-weighted with it,
     because a left-weighted one over a full-width column hides everything */
  .menu { padding: 3vh 0; }
  .menu-title { font-size: clamp(30px, 9.5vw, 50px); }
  .rule { margin: 20px auto 22px; }
  #level-list { grid-template-columns: 1fr; gap: 14px; }
  #dist { top: 10px; right: 10px; padding: 4px 12px 6px; }
  #dist b { font-size: 26px; }
  #dist .dist-label { font-size: 10px; }
  #passes { top: 62px; right: 10px; padding: 5px 10px; }
  #passes b { font-size: 16px; }
  #floor { top: 10px; right: 10px; padding: 4px 12px 6px; }
  #floor b { font-size: 30px; }
  #party { top: 62px; right: 10px; gap: 6px; padding: 6px 10px; }
  .party-slot { font-size: 17px; }
  #counting span { font-size: 15px; letter-spacing: 0.16em; }
  .level-card { min-height: 190px; }
  .level-name { font-size: 27px; }
  .level-copy { padding: 16px 18px 15px; }
  .menu-foot { margin-top: 20px; }
  .slider-row { gap: 16px; }

  .brief { width: 100%; padding: 0 20px; align-items: flex-end; }
  .brief-scroll { max-height: 82vh; padding: 18px 0 22px; }
  .brief-title { font-size: clamp(34px, 11vw, 48px); }
  .brief-screen .fx-haze::after {
    background: linear-gradient(0deg, rgba(3, 4, 9, 0.96) 0%, rgba(3, 4, 9, 0.88) 40%, rgba(3, 4, 9, 0.42) 70%, transparent 92%);
  }
}
/* Short landscape windows — a 1366×768 laptop, or a 1080p screen once the
   browser's own chrome has taken its share — are the COMMON case, and at the
   full spacing the four nights ran ~60px past the fold, so the level select
   opened on a scrollbar with the sliders cut off. The spacing gives way first;
   the cards keep their proportion. */
@media (max-height: 860px) and (min-width: 761px) {
  .menu { padding: 3vh 0 2.5vh; }
  .menu-crest { font-size: 26px; }
  .menu-title { font-size: clamp(34px, 5.4vw, 64px); }
  .menu-title-en { margin-top: 8px; }
  .rule { margin: 14px auto 18px; }
  .level-card { min-height: min(50vh, 430px); }
  .menu-foot { margin-top: 16px; gap: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  #grain, #dread { animation: none; }
  #vignette.pulse { animation: none; }
  #hugs.nearly .hug-icon, #hugs.pop .hug-icon { animation: none; }
  /* the menu's weather stops; menu.js separately skips parallax, the push-in
     and the lightning, so the night just holds still */
  .fx-fog, .fx-fog2, .fx-grain, .fx-vig, .storm .fx-rain, .storm .fx-rain2,
  .menu-title, .menu-crest, .title-ghost, .level-card.scary:hover .level-eyes { animation: none; }
  .level-card:hover, .level-card:focus-visible { transform: none; }
  .level-card:hover .level-art, .level-card:focus-visible .level-art { transform: scale(1.05); }
}
