/* Rung — a daily word ladder. Shares Spectrum's palette so the two games read
   as one place. */

:root {
  --bg: #f6f7f9;
  --surface: #ffffff;
  --tile: #ffffff;
  --tile-border: #d9dee5;
  --ink: #131720;
  --ink-soft: #5c6673;
  --ink-faint: #97a1ae;
  --accent: #2f6df6;
  --correct: #2f9e5f;
  --correct-bg: #e6f5ec;
  --shadow: 0 1px 2px rgba(16, 22, 34, .08), 0 4px 14px rgba(16, 22, 34, .06);
  --radius: 12px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0e1116;
    --surface: #171c23;
    --tile: #1c222b;
    --tile-border: #2c3540;
    --ink: #eef2f7;
    --ink-soft: #9aa5b3;
    --ink-faint: #6b7684;
    --accent: #5c8dff;
    --correct: #43c17f;
    --correct-bg: #16342a;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4);
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: ui-rounded, "SF Pro Rounded", system-ui, -apple-system, "Segoe UI",
               Roboto, "Helvetica Neue", sans-serif;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

/* A fixed-height page: the ladder scrolls inside it, everything else holds
   still. Without this a long climb pushes the keyboard off the bottom. */
body {
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           0 env(safe-area-inset-left);
}

button { touch-action: manipulation; -webkit-user-select: none; user-select: none; }
button:focus { outline: none; }
button:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* ---------- top bar ---------- */
.topbar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  /* width is required: as a flex item, `margin: 0 auto` would otherwise cancel
     the default stretch and shrink this to its content. */
  width: 100%;
  max-width: 520px;
  margin: 0 auto;
  padding: 7px 14px;
  border-bottom: 1px solid var(--tile-border);
}
.topbar-side { display: flex; align-items: center; gap: 2px; }
.topbar-side.end { justify-self: end; }

.wordmark {
  margin: 0;
  text-align: center;
  font-size: 19px;
  font-weight: 800;
  letter-spacing: .24em;
  text-indent: .24em;
}
/* The game's own icon, sitting with the wordmark. letter-spacing is reset so
   the wordmark's tracking does not push the glyph away from the text. */
.mark {
  font-size: 17px;
  letter-spacing: 0;
  margin-right: 9px;
  vertical-align: -1px;
}

.icon-btn {
  width: 32px; height: 32px;
  border: 0; border-radius: 50%;
  background: transparent;
  color: var(--ink-soft);
  font-size: 17px;
  cursor: pointer;
}
.icon-btn:active { background: var(--tile-border); transform: scale(.88); }
a.icon-btn { display: grid; place-items: center; text-decoration: none; }

/* ---------- game ---------- */
.topbar { flex: none; }

#game {
  flex: 1 1 auto;
  min-height: 0;              /* lets the scroll area actually shrink */
  width: 100%;
  max-width: 520px;
  margin: 0 auto;
  padding: 12px 16px 0;
  display: flex;
  flex-direction: column;
}

.head { flex: none; }

.scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;   /* don't drag the page behind it */
  padding-bottom: 4px;
}

.puzzle-no {
  /* The theme label used to sit here and provide this gap; it left with the
     theme, so the number carried the spacing instead. */
  margin: 0 0 16px;
  text-align: center;
  font-size: 12px;
  letter-spacing: .1em;
  color: var(--ink-faint);
  text-transform: uppercase;
}

/* ---------- the ladder ---------- */
.ladder {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  width: fit-content;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

.rung { display: flex; gap: 6px; }

/* Only a rung that has just been added animates. Every render rebuilds the
   whole ladder, so animating .rung itself replayed the entry on every tap. */
.rung.enter { animation: rungIn .3s cubic-bezier(.2, .8, .3, 1) backwards; }
@keyframes rungIn { from { opacity: 0; transform: translateY(-8px); } }

.slot {
  position: relative;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  font-size: 21px;
  font-weight: 800;
  letter-spacing: .02em;
  background: var(--tile);
  border: 1.5px solid var(--tile-border);
  border-radius: var(--radius);
  color: var(--ink);
}

/* the fixed ends of the ladder */
.rung.anchor .slot {
  background: transparent;
  border-style: dashed;
  color: var(--ink-soft);
}
.rung.target .slot {
  border-color: var(--correct);
  color: var(--correct);
  border-style: solid;
  background: var(--correct-bg);
}

/* steps already taken */
.rung.done .slot { color: var(--ink-soft); }
.rung.done .slot.changed { color: var(--ink); border-color: var(--ink-faint); }

/* A letter that matches the target is green wherever it appears, so the ladder
   shows the rung on which each letter fell into place. Listed after .changed
   and at equal specificity, so a change that lands on target reads as green
   rather than merely altered. */
.rung.done .slot.matched,
.rung.live .slot.matched {
  color: var(--correct);
  border-color: var(--correct);
  background: var(--correct-bg);
}
.rung.done .slot.matched { opacity: .72; }   /* history, quieter than the live row */

/* The word you are standing on: blue border and blue letters, which is the
   whole affordance — the hint below says "tap a blue letter". */
.rung.live .slot {
  cursor: pointer;
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: var(--shadow);
}
.rung.live .slot:active { transform: scale(.93); }

/* The slot being edited carries a slow blinking caret rather than a fill, so
   it reads as "typing here" instead of "selected". currentColor so it follows
   the slot — blue normally, green once that letter matches. */
.rung.live .slot.picked::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 6px;
  width: 18px;
  height: 2.5px;
  margin-left: -9px;
  border-radius: 2px;
  background: currentColor;
  animation: caret 1.15s step-end infinite;
}
@keyframes caret {
  0%, 49%   { opacity: 1; }
  50%, 100% { opacity: 0; }
}

.gap {
  width: 2px;
  height: 10px;
  background: var(--tile-border);
  border-radius: 2px;
}

/* ---------- docked keyboard ---------- */
.dock {
  flex: none;
  width: 100%;
  max-width: 520px;
  margin: 0 auto;
  padding: 6px 10px calc(10px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--tile-border);
  background: var(--bg);
}

.keyboard {
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  max-width: 460px;
}
.kb-row { display: flex; gap: 5px; justify-content: center; }

.key {
  min-width: 30px;
  height: 44px;
  padding: 0 4px;
  flex: 1 1 auto;
  border: 0;
  border-radius: 7px;
  background: var(--tile-border);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  font-weight: 800;
  cursor: pointer;
}
.key:active { transform: scale(.9); }
.key:disabled { opacity: .35; cursor: default; }

/* The slot being edited, and the row shaking off a word that is not one. */
.rung.live.reject { animation: rejectShake .42s ease; }
@keyframes rejectShake {
  0%, 100% { transform: translateX(0); }
  15%      { transform: translateX(-7px); }
  32%      { transform: translateX(6px); }
  50%      { transform: translateX(-5px); }
  68%      { transform: translateX(4px); }
  85%      { transform: translateX(-2px); }
}

/* ---------- feedback + actions ---------- */
/* Status row: the two controls flank the count, so the text stays centred
   however wide the buttons get. Sits in the dock, above the keyboard. */
/* Count left, button right. Centring the count squeezed the button, and the
   button is the thing with a number on it worth reading. */
.statusbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.statusbar .feedback { flex: 1; text-align: left; }
.statusbar #btn-undo { flex: none; }

.feedback {
  margin: 0;
  min-height: 17px;
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
}
.feedback b { color: var(--ink); }

/* The only control on the board, so it takes the primary treatment. */
#btn-undo {
  padding: 7px 16px;
  border: 0;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .02em;
  cursor: pointer;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
#btn-undo:active { transform: scale(.92); }
#btn-undo:disabled {
  background: transparent;
  border: 1.5px solid var(--tile-border);
  color: var(--ink-faint);
  cursor: default;
  transform: none;
}

.primary, .secondary {
  display: block;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  border-radius: 999px;
  font-family: inherit;
  font-weight: 700;
  cursor: pointer;
}
.primary {
  padding: 13px 30px;
  border: 0;
  background: var(--accent);
  color: #fff;
  font-size: 16px;
}
.secondary {
  padding: 11px 26px;
  margin-top: 10px;
  border: 1.5px solid var(--tile-border);
  background: transparent;
  color: var(--ink-soft);
  font-size: 15px;
  font-weight: 600;
}
.primary:active, .secondary:active { transform: scale(.94); }
.primary:disabled, .secondary:disabled {
  opacity: .45; cursor: default; transform: none;
}

.primary.press, .secondary.press, #btn-undo.press { animation: press .26s cubic-bezier(.2, .8, .3, 1); }
@keyframes press {
  0%   { transform: scale(.94); }
  55%  { transform: scale(1.035); }
  100% { transform: scale(1); }
}

/* ---------- sheets ---------- */
.sheet-wrap[hidden] { display: none; }
.sheet-wrap {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(8, 11, 16, .55);
  animation: fade .18s ease;
}
@keyframes fade { from { opacity: 0; } }

.sheet {
  position: relative;
  width: 100%;
  max-width: 520px;
  max-height: 90dvh;
  overflow-y: auto;
  padding: 26px 20px calc(26px + env(safe-area-inset-bottom));
  background: var(--surface);
  border-radius: 20px 20px 0 0;
  animation: rise .26s cubic-bezier(.2, .8, .3, 1);
}
@keyframes rise { from { transform: translateY(24px); } }

@media (min-width: 560px) {
  .sheet-wrap { align-items: center; }
  .sheet { border-radius: 20px; }
}

.sheet h2 { margin: 0 0 6px; font-size: 22px; text-align: center; }

.close {
  position: absolute;
  top: 12px; right: 12px;
  width: 34px; height: 34px;
  border: 0; border-radius: 50%;
  background: transparent;
  color: var(--ink-soft);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}

.result-sub {
  margin: 0 0 14px;
  text-align: center;
  color: var(--ink-soft);
  font-size: 15px;
}

.chain {
  margin: 0 0 18px;
  text-align: center;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.9;
  color: var(--ink-soft);
  word-spacing: .1em;
}

.statrow {
  display: flex;
  justify-content: center;
  align-items: start;      /* one label wraps to two lines; keep the numbers level */
  gap: 18px;
  margin: 20px 0 0;
}
.stat { text-align: center; }
.stat b { display: block; font-size: 26px; font-weight: 800; }
.stat span {
  display: block;
  max-width: 74px;
  margin-inline: auto;
  font-size: 11px; color: var(--ink-soft);
  text-transform: uppercase; letter-spacing: .06em;
  line-height: 1.25;
}

.countdown {
  margin: 18px 0 0;
  text-align: center;
  font-size: 13px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.dist-title {
  margin: 22px 0 10px;
  font-size: 13px;
  text-align: center;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: .09em;
}
.dist { display: flex; flex-direction: column; gap: 6px; }
.dist-row { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.dist-row .track { flex: 1; min-width: 0; display: flex; }
.dist-row .lab {
  width: 88px;            /* fits '−3 or better' on one line */
  flex: none;
  font-weight: 700;
  font-size: 12px;
  color: var(--ink-soft);
}
.dist-row .bar {
  background: var(--accent);
  color: #fff;
  padding: 3px 8px;
  border-radius: 5px;
  font-weight: 700;
  font-size: 12px;
  min-width: 26px;
  text-align: right;
}

.help-list { margin: 16px 0; padding-left: 20px; line-height: 1.65; font-size: 15px; }
.help-list li { margin-bottom: 8px; }
.help-foot {
  margin: 18px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--tile-border);
  text-align: center;
  font-size: 14px;
  color: var(--ink-soft);
  font-style: italic;
}

/* short screens */
@media (max-height: 740px) {
  .topbar { padding: 5px 12px; }
  #game { padding: 8px 14px 0; }
  @media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
