* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* <button> doesn't inherit color/font from its ancestors by default (UA
   stylesheet), so without this reset button text renders in the browser's
   default black regardless of the dark page background. */
button { font: inherit; color: inherit; }

html, body {
  width: 100%;
  height: 100%;
  background: #000;
  color: #fff;
  font-family: "Pretendard", "Apple SD Gothic Neo", "Noto Sans KR", -apple-system, sans-serif;
  overscroll-behavior: none;
  overflow: hidden;
}

.hidden { display: none; }

/* idle/select/confirm are stacked full-screen siblings, shown/hidden via
   .visible (opacity) rather than display:none, so app.js can crossfade
   between any two of them instead of jump-cutting. */
.screen {
  position: fixed;
  inset: 0;
  background: #000;
  opacity: 0;
  pointer-events: none;
  transition: opacity .5s ease;
}
.screen.visible {
  opacity: 1;
  pointer-events: auto;
}

/* ---------------------------------------------------------------------
   Idle screen — mirrors the display's own waiting-media rotation (same
   pool of images) rather than a dedicated tablet-only asset, so the
   tablet and LED wall feel like one connected surface while idle. */

.idle-screen { cursor: pointer; }

.idle-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  transition: opacity 1.2s ease;
}
.idle-bg.active { opacity: 1; }

/* ---------------------------------------------------------------------
   Select screen (tb02-style: fixed proportions, 6 rows baked into the
   design). #select-frame is sized in px by app.js's fitFrame() to
   exactly match the source image's aspect ratio at the largest size that
   fits the viewport — this keeps the tap-zone percentages pixel-accurate
   no matter the screen size. */

.frame {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* width/height set inline by app.js */
}

.frame-image {
  display: block;
  width: 100%;
  height: 100%;
}

.tap-zones {
  position: absolute;
  inset: 0;
}
.tap-zone {
  position: absolute;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
}
.tap-zone:active { background: rgba(255, 255, 255, .12); }
/* Briefly ignore taps while a submission is in flight, so a fast double
   tap can't fire two participations. */
.tap-zones.submitting { pointer-events: none; }

/* ---------------------------------------------------------------------
   Confirm screen — the same bg_image_path + image_path the display
   shows for the tapped message, held for CONFIRM_MS. */

/* The display's background photos are shot for a much wider LED-wall
   aspect ratio than the tablet screen. Fit to width (contain, not cover)
   instead of cropping to fill — any leftover height just shows the
   screen's own black background rather than cutting off the image. */
.confirm-bg {
  position: absolute;
  inset: 0;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}
.confirm-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,.2) 0%, rgba(0,0,0,.45) 100%);
}
.confirm-image {
  /* Fit to width (like .confirm-bg) — height:auto follows the image's own
     aspect ratio, so it's never taller than its natural proportional
     height. object-fit/max-height would instead let the box's height
     become the binding constraint on a narrow/tall screen, shrinking the
     image down and leaving it visually adrift instead of full-width. */
  position: absolute;
  left: 8vw;
  right: 8vw;
  top: 50%;
  transform: translateY(-50%);
  width: calc(100% - 16vw);
  height: auto;
  filter: drop-shadow(0 10px 30px rgba(0,0,0,.5));
}

/* ---------------------------------------------------------------------
   Warp transition — a white circle that grows from the exact point the
   user tapped until it fills the screen ("빨려 들어가듯 하얗게"), then
   (after app.js swaps the screen underneath) shrinks back down from that
   same point to reveal what's now there. */

.warp {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: #fff;
  pointer-events: none;
  clip-path: circle(0% at var(--warp-x, 50%) var(--warp-y, 50%));
  transition: clip-path .5s cubic-bezier(.65, 0, .35, 1);
}
.warp.covering { clip-path: circle(80% at var(--warp-x, 50%) var(--warp-y, 50%)); }

/* Sparkle burst — a handful of small glowing sparks flying outward from
   the tap point, right as the warp starts closing in. Purely decorative;
   app.js creates/removes .sparkle-burst instances on the fly. */
.sparkle-burst {
  position: fixed;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  z-index: 45;
  pointer-events: none;
}
.spark {
  position: absolute;
  left: 0;
  top: 0;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, #ffe89a 45%, rgba(255,232,154,0) 75%);
  box-shadow: 0 0 10px 2px rgba(255, 255, 255, .85);
  transform: rotate(var(--angle)) translateX(0) scale(1);
  animation: spark-fly .5s cubic-bezier(.2, .8, .3, 1) forwards;
}
@keyframes spark-fly {
  0%   { transform: rotate(var(--angle)) translateX(0) scale(1); opacity: 1; }
  100% { transform: rotate(var(--angle)) translateX(70px) scale(.15); opacity: 0; }
}

/* ---------------------------------------------------------------------
   Fallback grid (used until the designed select image is configured, or
   when the active message count isn't exactly 6). */

.fallback {
  width: 100%;
  min-height: 100%;
}

.topbar {
  padding: 2rem 1.5rem 1rem;
  text-align: center;
}
.topbar h1 { font-size: 1.6rem; font-weight: 800; letter-spacing: .02em; }
.topbar p { margin-top: .4rem; opacity: .7; font-size: 1rem; }

.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
  padding: 1rem 1.25rem 2.5rem;
}
@media (min-width: 700px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
}
.grid.submitting { pointer-events: none; opacity: .7; }

.card {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: 1.2rem;
  overflow: hidden;
  border: none;
  background: #1a1d29;
  background-size: cover;
  background-position: center;
  cursor: pointer;
  transition: transform .15s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
.card:active { transform: scale(.96); }
.card .overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0) 40%, rgba(0,0,0,.55) 100%);
}
.card .card-image {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}
.card .label {
  position: relative;
  z-index: 1;
  padding: 1rem;
  font-size: 1.15rem;
  font-weight: 700;
  text-align: center;
  word-break: keep-all;
  line-height: 1.35;
}

.thanks {
  position: fixed;
  inset: 0;
  z-index: 20;
  background: #0d0f16;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  transition: opacity .25s ease;
}
.thanks.hidden { opacity: 0; pointer-events: none; display: flex; }
.thanks-emoji { font-size: 4rem; margin-bottom: 1rem; animation: pop .5s ease; }
.thanks-text { font-size: 1.5rem; font-weight: 800; }
.thanks-sub { margin-top: .5rem; opacity: .7; }

@keyframes pop {
  0% { transform: scale(.4); opacity: 0; }
  70% { transform: scale(1.15); opacity: 1; }
  100% { transform: scale(1); }
}
