/* =========================================================================
   Lilac Sky
   - The soft palette dresses the chrome: background, header, buttons,
     keyboard, leaderboard, results.
   - The three tile states are deliberately NOT pastel. They stay saturated
     and far apart in lightness, and each one carries a glyph so the state
     survives red-green color vision deficiency (and grayscale, and glare on
     a phone outdoors). Color is the accelerator; the glyph is the signal.
   ========================================================================= */

:root {
  --bg: #f8f5ff;
  --surface: #e6defb;
  --surface-soft: #f1ecfe;
  --accent: #9b7fd4;
  --accent-dark: #6f52ac;
  --accent-ink: #ffffff;
  --text: #3d3450;
  --muted: #6c6386;
  --border: #d6ccf5;
  --danger: #a3324f;

  /* Tile states — high contrast, redundant glyph cue. */
  --correct-bg: #14653f;
  --correct-fg: #ffffff;
  --correct-edge: #0a3f26;
  --correct-glyph: "\2713"; /* ✓ */

  --present-bg: #f2b705;
  --present-fg: #2b2410;
  --present-edge: #9a7500;
  --present-glyph: "\25D0"; /* ◐ */

  --absent-bg: #6f667f;
  --absent-fg: #ffffff;
  --absent-edge: #4c4559;
  --absent-glyph: "\2715"; /* ✕ */

  --radius: 14px;
  --shadow: 0 2px 10px rgba(61, 52, 80, 0.09);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  overflow-x: hidden;
  overscroll-behavior-y: contain;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: ui-rounded, "SF Pro Rounded", "Segoe UI", system-ui, -apple-system, sans-serif;
  font-size: 16px;
  line-height: 1.45;
  /* House style: the whole interface is lowercase. This is presentational
     only — the underlying text is untouched, so scoring, the exact note-box
     wording and the stored player names are all unaffected. */
  text-transform: lowercase;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

/* Form controls don't inherit text-transform — the browser's own stylesheet
   sets it to none — so buttons need it applied explicitly. Text the player
   types is deliberately left alone: forcing their own words lowercase as they
   type a message to their daughter would read as a bug. Placeholders are our
   copy rather than theirs, so those do get lowercased. */
button,
select {
  text-transform: inherit;
}
::placeholder {
  text-transform: lowercase;
}

.app {
  width: 100%;
  max-width: 480px;
  margin-inline: auto;
  padding: max(14px, env(safe-area-inset-top)) 14px
    max(14px, env(safe-area-inset-bottom)) 14px;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: 8px;
  top: 8px;
  z-index: 10;
  background: var(--accent);
  color: var(--accent-ink);
  padding: 8px 12px;
  border-radius: 8px;
}

.screen[hidden] {
  display: none;
}

/* ------------------------------ typography ------------------------------ */

.hero {
  text-align: center;
  padding: 10px 0 18px;
}
.hero-eyebrow {
  margin: 0 0 6px;
  font-size: 0.78rem;
  letter-spacing: 0.11em;
  text-transform: lowercase;
  color: var(--accent-dark);
  font-weight: 700;
}
.hero-title {
  margin: 0 0 10px;
  font-size: clamp(1.5rem, 7vw, 1.95rem);
  line-height: 1.15;
  letter-spacing: -0.015em;
}
.hero-sub {
  margin: 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* --------------------------------- cards -------------------------------- */

.card {
  background: var(--surface-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 16px;
  box-shadow: var(--shadow);
}
.card-flush {
  padding: 6px;
}
.card-title {
  margin: 0 0 4px;
  font-size: 1.05rem;
}
.card-note {
  margin: 0 0 14px;
  color: var(--muted);
  font-size: 0.86rem;
}

/* --------------------------------- forms -------------------------------- */

.field {
  display: block;
  margin-bottom: 14px;
}
.field-label {
  display: block;
  font-weight: 650;
  font-size: 0.9rem;
  margin-bottom: 6px;
}
.field-hint {
  display: block;
  margin-top: 5px;
  font-size: 0.78rem;
  color: var(--muted);
}

input[type="text"],
textarea {
  width: 100%;
  font: inherit;
  /* 16px keeps iOS from zooming the viewport on focus. */
  font-size: 16px;
  color: var(--text);
  background: #fff;
  border: 2px solid var(--border);
  border-radius: 10px;
  padding: 12px;
  min-height: 48px;
}
textarea {
  resize: vertical;
  min-height: 110px;
  line-height: 1.5;
}
input[type="text"]:focus-visible,
textarea:focus-visible,
.btn:focus-visible,
.tab:focus-visible,
.key:focus-visible {
  outline: 3px solid var(--accent-dark);
  outline-offset: 2px;
}
.field-initial {
  max-width: 84px;
  text-align: center;
  text-transform: lowercase;
  font-weight: 700;
  letter-spacing: 0.08em;
}
input[aria-invalid="true"] {
  border-color: var(--danger);
}

.form-error {
  margin: 0 0 12px;
  color: var(--danger);
  font-size: 0.88rem;
  font-weight: 600;
}
.form-error[hidden] {
  display: none;
}

/* -------------------------------- buttons ------------------------------- */

.btn {
  font: inherit;
  font-weight: 700;
  border-radius: 12px;
  border: 2px solid transparent;
  padding: 13px 18px;
  min-height: 50px;
  cursor: pointer;
  transition: transform 0.08s ease, background-color 0.15s ease;
}
.btn:active {
  transform: translateY(1px);
}
.btn[disabled] {
  opacity: 0.55;
  cursor: default;
}
.btn-primary {
  background: var(--accent);
  color: var(--accent-ink);
}
.btn-primary:hover:not([disabled]) {
  background: var(--accent-dark);
}
.btn-secondary {
  background: #fff;
  color: var(--accent-dark);
  border-color: var(--accent);
}
.btn-ghost {
  background: transparent;
  color: var(--muted);
  border-color: transparent;
  font-weight: 600;
}
.btn-block {
  display: block;
  width: 100%;
}

/* --------------------------------- tabs --------------------------------- */

.tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 10px;
}
.tab {
  font: inherit;
  text-align: left;
  background: var(--surface-soft);
  border: 2px solid var(--border);
  border-radius: 12px;
  padding: 9px 11px;
  min-height: 52px;
  cursor: pointer;
  color: var(--muted);
}
.tab[aria-selected="true"] {
  background: var(--surface);
  border-color: var(--accent);
  color: var(--text);
  box-shadow: var(--shadow);
}
.tab-name {
  display: block;
  font-weight: 750;
  font-size: 0.92rem;
  line-height: 1.2;
}
.tab-meta {
  display: block;
  font-size: 0.74rem;
  margin-top: 2px;
}
.tab-done {
  font-weight: 700;
}

/* --------------------------------- board -------------------------------- */

/* The keyboard must never be pushed below the fold — it is the only way to
   play. The game screen is a full-height column with the keyboard pinned at
   the bottom; if a board is ever taller than the space left over, the board
   area scrolls rather than the keyboard leaving the screen. */
#screen-game:not([hidden]) {
  display: flex;
  flex-direction: column;
  height: calc(100dvh - 28px);
}
.play {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.panel[hidden] {
  display: none;
}
.panel-meta {
  margin: 0 0 8px;
  text-align: center;
  font-size: 0.84rem;
  color: var(--muted);
}

/* Tiles are sized by whichever runs out first, width or height, so a six-row
   board still leaves room for the keyboard on a short phone. --cols and --rows
   are set per puzzle in buildBoards(). The 430px allowance covers the tabs,
   meta line, toast, hint box and keyboard stacked around the board. */
.board {
  --tile: max(34px, min(56px, calc((100dvh - 430px) / var(--rows))));
  display: flex;
  flex-direction: column;
  gap: 5px;
  width: min(100%, calc(var(--cols) * var(--tile)));
  margin-inline: auto;
}
.board-row {
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  gap: 5px;
}

.tile {
  position: relative;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(1.1rem, 6.5vw, 1.8rem);
  font-weight: 800;
  text-transform: lowercase;
  border: 2px solid var(--border);
  border-radius: 8px;
  background: #fff;
  color: var(--text);
  transition: transform 0.22s ease-in, border-color 0.12s ease;
  will-change: transform;
}
.tile.is-filled {
  border-color: var(--accent);
  animation: pop 0.12s ease-out;
}
.tile.is-flipping {
  transform: rotateX(90deg);
}

/* Redundant, non-color state cue. */
.tile[data-state]::after {
  position: absolute;
  top: 2px;
  right: 4px;
  font-size: 0.6rem;
  font-weight: 700;
  line-height: 1;
  opacity: 0.92;
}
.tile[data-state="correct"] {
  background: var(--correct-bg);
  color: var(--correct-fg);
  border-color: var(--correct-edge);
  border-width: 3px;
}
.tile[data-state="correct"]::after {
  content: var(--correct-glyph);
}
.tile[data-state="present"] {
  background: var(--present-bg);
  color: var(--present-fg);
  border-color: var(--present-edge);
  border-width: 3px;
  border-style: dashed;
}
.tile[data-state="present"]::after {
  content: var(--present-glyph);
}
.tile[data-state="absent"] {
  background: var(--absent-bg);
  color: var(--absent-fg);
  border-color: var(--absent-edge);
}
.tile[data-state="absent"]::after {
  content: var(--absent-glyph);
}

.board-row.is-invalid {
  animation: shake 0.32s ease-in-out;
}

@keyframes pop {
  0% {
    transform: scale(0.92);
  }
  100% {
    transform: scale(1);
  }
}
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(4px); }
}

/* --------------------------------- toast -------------------------------- */

.toast {
  min-height: 1.4rem;
  margin: 8px 0 0;
  text-align: center;
  font-size: 0.9rem;
  font-weight: 650;
  color: var(--accent-dark);
}

/* --------------------------------- hint --------------------------------- */

.hint-zone {
  margin: 8px 0 2px;
}
.hint-box {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 12px;
}
.hint-status {
  margin: 0;
  font-size: 0.85rem;
  color: var(--muted);
  text-align: center;
}
.hint-title {
  margin: 0 0 6px;
  font-size: 0.9rem;
  font-weight: 750;
}
.hint-warning {
  margin: 0 0 10px;
  font-size: 0.83rem;
  color: var(--muted);
}
.hint-actions {
  display: grid;
  gap: 8px;
}
.hint-text {
  margin: 6px 0 0;
  font-size: 0.92rem;
  font-style: italic;
}
.hint-revealed {
  border-left: 4px solid var(--accent);
}

/* ------------------------------- keyboard ------------------------------- */

.keyboard {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 10px;
  padding-top: 6px;
  touch-action: manipulation;
}
.kb-row {
  display: flex;
  gap: 5px;
  justify-content: center;
}
.key {
  flex: 1 1 0;
  min-width: 0;
  min-height: 52px;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 700;
  text-transform: lowercase;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  padding: 0;
  transition: transform 0.06s ease;
  touch-action: manipulation;
  user-select: none;
}
.key:active {
  transform: translateY(1px);
}
.key-wide {
  flex: 1.7 1 0;
  font-size: 0.74rem;
  letter-spacing: 0.02em;
}
.kb-spacer {
  flex: 0.5 1 0;
}
.key[data-state="correct"] {
  background: var(--correct-bg);
  color: var(--correct-fg);
  border-color: var(--correct-edge);
}
.key[data-state="present"] {
  background: var(--present-bg);
  color: var(--present-fg);
  border-color: var(--present-edge);
  border-style: dashed;
  border-width: 2px;
}
.key[data-state="absent"] {
  background: var(--absent-bg);
  color: var(--absent-fg);
  border-color: var(--absent-edge);
}
.key[data-state]::after {
  font-size: 0.58rem;
  vertical-align: super;
  margin-left: 1px;
  opacity: 0.9;
}
.key[data-state="correct"]::after {
  content: var(--correct-glyph);
}
.key[data-state="present"]::after {
  content: var(--present-glyph);
}
.key[data-state="absent"]::after {
  content: var(--absent-glyph);
}

/* -------------------------------- results ------------------------------- */

.reveal-card {
  background: linear-gradient(160deg, var(--surface) 0%, #fff 100%);
  border: 2px solid var(--accent);
  border-radius: 18px;
  padding: 22px 16px;
  text-align: center;
  margin-bottom: 16px;
  box-shadow: var(--shadow);
  position: relative;
}

/* ---------------------------- celebration ------------------------------- */

/* Particles burst from the middle of the card and are allowed outside it,
   while the layer itself stays unclickable and out of the accessibility tree.
   Nothing here can push the page sideways: the layer has no size of its own
   and body already clips horizontal overflow. */
.celebration {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: visible;
  /* Behind the text. Confetti drifting across the name is the one thing this
     must never do — the name is the whole point of the screen. */
  z-index: 0;
}
.celebration:empty {
  display: none;
}

.spark {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--size);
  height: var(--size);
  background: var(--color);
  border-radius: 2px;
  opacity: 0;
  animation: spark-fly var(--dur) cubic-bezier(0.18, 0.7, 0.35, 1) var(--delay) forwards;
}
.spark-round {
  border-radius: 50%;
}

@keyframes spark-fly {
  0% {
    transform: translate(-50%, -50%) scale(0.3) rotate(0deg);
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  70% {
    opacity: 1;
  }
  100% {
    transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy) + 26px))
      scale(1) rotate(var(--rot));
    opacity: 0;
  }
}

.balloon {
  position: absolute;
  left: var(--left);
  bottom: 10%;
  width: 22px;
  height: 28px;
  background: var(--color);
  border-radius: 50% 50% 46% 46%;
  opacity: 0;
  transform-origin: 50% 120%;
  animation: balloon-rise var(--dur) ease-in var(--delay) forwards;
}
/* The string. */
.balloon::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 100%;
  width: 1px;
  height: 16px;
  background: rgba(61, 52, 80, 0.35);
}

@keyframes balloon-rise {
  0% {
    transform: translate(-50%, 20px) scale(var(--scale));
    opacity: 0;
  }
  15% {
    opacity: 0.95;
  }
  80% {
    opacity: 0.95;
  }
  100% {
    transform: translate(calc(-50% + var(--drift)), -190px) scale(var(--scale));
    opacity: 0;
  }
}
.reveal-card-compact {
  padding: 14px;
}
.reveal-label {
  position: relative;
  z-index: 1;
  margin: 0 0 6px;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: lowercase;
  color: var(--accent-dark);
  font-weight: 700;
}
.reveal-name {
  position: relative;
  z-index: 1;
  margin: 0;
  font-size: clamp(1.6rem, 8vw, 2.2rem);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

.score-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.score-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.92rem;
}
.score-list li:last-child {
  border-bottom: 0;
}
.score-label {
  font-weight: 650;
}
.score-value {
  font-weight: 700;
  white-space: nowrap;
}

/* ------------------------------ leaderboard ----------------------------- */

.lb-head,
.lb-row {
  display: grid;
  grid-template-columns: 26px 1fr 46px 46px;
  gap: 6px;
  align-items: center;
  padding: 9px 8px;
}
.lb-head {
  font-size: 0.72rem;
  text-transform: lowercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  font-weight: 700;
}
.lb-col-score {
  text-align: center;
}
.lb-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.lb-row {
  border-top: 1px solid var(--border);
  font-size: 0.92rem;
}
.lb-row.is-you {
  background: var(--surface);
  border-radius: 10px;
  font-weight: 700;
}
.lb-rank {
  color: var(--muted);
  font-size: 0.82rem;
  font-weight: 700;
}
.lb-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lb-you-tag {
  font-size: 0.7rem;
  color: var(--accent-dark);
  margin-left: 4px;
}
.lb-empty {
  padding: 16px 10px;
  text-align: center;
  margin: 0;
}

.chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  height: 26px;
  padding: 0 6px;
  border-radius: 8px;
  font-size: 0.8rem;
  font-weight: 800;
  border: 2px solid transparent;
}
.chip-win {
  background: var(--correct-bg);
  color: var(--correct-fg);
  border-color: var(--correct-edge);
}
.chip-loss {
  background: var(--absent-bg);
  color: var(--absent-fg);
  border-color: var(--absent-edge);
}
.chip-hint {
  background: var(--present-bg);
  color: var(--present-fg);
  border-color: var(--present-edge);
  border-style: dashed;
}

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 14px;
  justify-content: center;
  font-size: 0.78rem;
  color: var(--muted);
  margin: 4px 0 20px;
}
.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* ------------------------------ reveal gate ----------------------------- */

.reveal-gate-card {
  text-align: center;
}
.reveal-gate-note {
  margin-bottom: 12px;
  font-size: 0.95rem;
}

/* ------------------------------ demo banner ----------------------------- */

.demo-banner {
  margin: 0;
  padding: 9px 14px;
  text-align: center;
  font-size: 0.8rem;
  font-weight: 750;
  letter-spacing: 0.02em;
  color: #2b2410;
  background: var(--present-bg);
  border-bottom: 3px dashed var(--present-edge);
}
.demo-banner[hidden] {
  display: none;
}

/* --------------------------- reaction overlay --------------------------- */

.reaction-layer {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(61, 52, 80, 0.55);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity 0.16s ease;
  cursor: pointer;
}
.reaction-layer[hidden] {
  display: none;
}
.reaction-layer.is-open {
  opacity: 1;
}

.reaction-card {
  width: min(100%, 340px);
  background: var(--bg);
  border: 2px solid var(--accent);
  border-radius: 18px;
  padding: 12px 12px 10px;
  box-shadow: 0 12px 32px rgba(61, 52, 80, 0.32);
  text-align: center;
  transform: scale(0.94);
  transition: transform 0.18s cubic-bezier(0.2, 0.9, 0.3, 1.3);
  cursor: default;
}
.reaction-layer.is-open .reaction-card {
  transform: scale(1);
}

.reaction-media {
  border-radius: 12px;
  overflow: hidden;
  background: var(--surface);
  /* No fixed aspect ratio and no cropping: memes come in every shape and
     cutting off the caption or a face defeats the point of the clip. The box
     takes the clip's own proportions; min-height only stops the card
     collapsing while one loads. */
  min-height: 120px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  position: relative;
}
.reaction-clip {
  width: 100%;
  height: auto;
  /* Tall clips are bounded so the card always fits a phone screen. */
  max-height: 58dvh;
  object-fit: contain;
  display: block;
}

/* Pause badge, so a paused clip doesn't just look like a frozen download. */
.reaction-media.is-paused::after {
  content: "\25B6"; /* ▶ */
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.6rem;
  color: #fff;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.6);
  background: rgba(61, 52, 80, 0.3);
}

.reaction-caption {
  margin: 10px 0 0;
  font-size: 0.98rem;
  font-weight: 750;
}
.reaction-caption:empty {
  display: none;
}
.reaction-skip {
  margin: 6px 0 0;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: lowercase;
  color: var(--muted);
}
.reaction-skip:empty {
  display: none;
}

.reaction-actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}
.reaction-actions .btn {
  flex: 1 1 0;
  min-height: 46px;
  padding: 10px 12px;
  font-size: 0.92rem;
}
.reaction-next[hidden] {
  display: none;
}

/* ----------------------------- motion opt-out --------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* Narrow phones: claw back a few pixels so nothing overflows at 320-375px. */
@media (max-width: 380px) {
  .app {
    padding-inline: 10px;
  }
  .kb-row {
    gap: 4px;
  }
  .key {
    font-size: 0.9rem;
    border-radius: 7px;
  }
  .key-wide {
    font-size: 0.68rem;
  }
}
