/* One column on a phone, grid beside clues once there is room. The grid sizes
   itself from the level's own dimensions — a level is 8x8 or 16x16 depending on
   the rung, and a fixed cell size would either overflow the small screens or
   waste the large ones. */

:root {
  --ink: #14161a;
  --paper: #fbfbf9;
  --cell: #ffffff;
  --line: #b9bdc5;
  --void: #aab1bb;
  --lit: #dbe8fb;
  --cursor: #ffe38a;
  --accent: #1f5fd0;
  --muted: #6b7280;
  color-scheme: light;

  /* The header does not move, so anything scrolled into view has to clear it —
     the clue list is scrolled for the player every time the selection moves. */
  scroll-padding-top: 84px;

  /* One column down the middle of the page, and the gutter beside it. The bar
     and the footer run edge to edge — a sticky bar that stopped short of the
     screen would look like a mistake — but what is *in* them lines up with the
     puzzle rather than with the window. */
  --column: 1100px;
  --gutter: 16px;
  --margin: max(var(--gutter), calc((100% - var(--column)) / 2 + var(--gutter)));
}

/* One dark palette, not one for the system preference and a second for the
   switch. `data-theme` is on the element before the first paint — see
   `app/theme.js` — so the stylesheet never has to ask the system itself. */
:root[data-theme="dark"] {
  --ink: #e9ebef;
  --paper: #15171b;
  --cell: #2b313a;
  --line: #454c58;
  --void: #0b0d10;
  --lit: #2d4a73;
  --cursor: #6b5a1f;
  --accent: #7aa7f5;
  --muted: #9aa1ad;
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 16px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* Fixed to the top: the clock and the ladder are what a player glances at, and
   on a phone the clue list is long enough that both would otherwise be gone by
   the time they matter. Sticky rather than fixed, so the layout below it needs
   no offset and nothing has to know how tall it is. */
.bar {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  gap: 12px 20px;
  align-items: center;
  justify-content: space-between;
  padding-block: 12px;
  padding-inline: var(--margin);
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}

h1 {
  margin: 0;
  font-size: 20px;
  letter-spacing: -0.01em;
}

.ladder {
  display: flex;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.rung {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 12px;
  color: var(--muted);
}

.rung.done {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--paper);
}

.rung.current {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  color: var(--ink);
  font-weight: 700;
}

/* Dissolved at any width with room for one row, so the ladder and the clocks
   sit directly in the bar as they always did. */
.status {
  display: contents;
}

.controls {
  display: flex;
  align-items: center;
  gap: 8px;
}

.icon {
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--cell);
  color: var(--ink);
  font-size: 17px;
  line-height: 1;
}

.lang {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 4px 6px;
  background: var(--cell);
  color: var(--ink);
  font: inherit;
  /* 16px for the same reason as the cells: a menu is a field iOS focuses too. */
  font-size: 16px;
}

.timers {
  display: flex;
  gap: 18px;
  margin: 0;
}

.timers dt {
  color: var(--muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.timers dd {
  margin: 0;
  font-size: 18px;
  font-variant-numeric: tabular-nums;
}

/* A phone. The header was 111px of a 664px screen with two rungs and taller
   with ten, so the puzzle began below the fold: the ladder becomes a bar on its
   own line and everything else fits on one short row. Nothing is dropped — the
   date moved down to the line above the grid, which was empty anyway. */
@media (max-width: 639px) {
  :root {
    scroll-padding-top: 100px;
  }

  .bar {
    gap: 8px 12px;
    padding-block: 10px;
  }

  h1 {
    font-size: 17px;
  }

  /* Row one is the title and the controls, row two is what the player is
     watching. The wrapper is what makes that hold at any phone width, rather
     than depending on four loose items wrapping where they happen to. */
  .controls {
    order: 1;
  }

  .status {
    order: 2;
    display: flex;
    flex-basis: 100%;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
  }

  /* The last resort if a long title and a long language name ever meet on a
     narrow phone: the title gives way rather than the row breaking in three. */
  h1 {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .ladder {
    flex: 1;
    gap: 3px;
  }

  /* One segment a level: done behind you, the current one lit, the rest to
     come. The number each rung carries is what the line above the grid says in
     words, so nothing is lost by hiding it. */
  .rung {
    flex: 1;
    width: auto;
    height: 6px;
    border: 0;
    border-radius: 3px;
    background: var(--line);
    font-size: 0;
  }

  .rung.done {
    background: var(--accent);
  }

  .rung.current {
    outline: 0;
    background: var(--cursor);
  }

  .timers {
    gap: 14px;
  }

  .timers div {
    display: flex;
    align-items: baseline;
    gap: 5px;
  }

  .timers dd {
    font-size: 15px;
  }
}

main {
  display: grid;
  gap: 24px;
  padding: var(--gutter);
  max-width: var(--column);
  margin: 0 auto;
}

@media (min-width: 860px) {
  main {
    grid-template-columns: minmax(0, 1fr) 340px;
    align-items: start;
  }
}

.difficulty {
  margin: 0 0 10px;
  color: var(--muted);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.difficulty time {
  font-size: inherit;
  color: inherit;
  font-variant-numeric: tabular-nums;
}

.difficulty time::before {
  content: "·";
  margin: 0 0.6em;
}

.grid {
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  gap: 2px;
  width: min(100%, calc(var(--cols) * 42px));
  aspect-ratio: var(--cols) / var(--rows);
}

.cell {
  position: relative;
  background: var(--cell);
  border: 1px solid var(--line);
  border-radius: 2px;
}

.cell.void {
  background: var(--void);
  border-color: var(--void);
}

.cell.lit {
  background: var(--lit);
}

.cell.cursor {
  background: var(--cursor);
}

.number {
  position: absolute;
  top: 1px;
  left: 2px;
  font-size: 9px;
  line-height: 1;
  color: var(--muted);
  pointer-events: none;
}

.letter {
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  text-align: center;
  text-transform: uppercase;
  font: inherit;
  font-weight: 600;
  /* Never below 16px. iOS zooms the page in when it focuses a field whose text
     is smaller than that, and nothing zooms it back out — so a player was left
     pinching out after every word. `line-height: 1` is what lets 16px fit the
     tightest rung, whose cells are about 20px across on a narrow phone. */
  font-size: clamp(16px, 3.4vw, 22px);
  line-height: 1;
}

.letter:focus {
  outline: none;
}

.banner {
  margin-top: 16px;
  padding: 12px 14px;
  border: 1px solid var(--accent);
  border-radius: 8px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
}

.banner p {
  margin: 0;
}

.actions {
  display: flex;
  gap: 8px;
}

/* A row of its own under the message, however narrow the banner gets: these
   are five proper nouns and none of them shortens. */
.targets {
  flex-basis: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Quieter than the banner's own action — the player has already pressed the
   button that matters, and this is only where it goes. */
/* `inline-block` so the links sit in a box the size of a button rather than on
   their own baseline, which left the one real button in the row lower than the
   five links beside it. */
.target {
  display: inline-block;
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
}

/* The link off the not-found page is a link and not a button — it goes
   somewhere — but it is the one thing to do on that page, so it looks like the
   one thing to do. */
button,
.button {
  padding: 8px 14px;
  border: 0;
  border-radius: 6px;
  background: var(--accent);
  color: var(--paper);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.button {
  display: inline-block;
  text-decoration: none;
}

/* Across and Down side by side at every width the clues run full-bleed, phones
   included: stacked, Down starts below a whole list of Across, so half the
   clues are off screen and the selection jumping between the two directions
   scrolls the page each time. Narrower lines are the price, and a clue is a
   phrase — it wraps. The one place they stack is the 340px sidebar. */
.clues {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

@media (min-width: 860px) {
  .clues {
    grid-template-columns: 1fr;
  }
}

.clue-list h2 {
  margin: 0 0 6px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.clue-list ol {
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 40vh;
  overflow-y: auto;
}

.clue {
  display: flex;
  gap: 8px;
  padding: 5px 8px;
  border-radius: 5px;
  font-size: 14px;
  cursor: pointer;
}

.clue b {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 1.6em;
  text-align: right;
}

/* A clue with a letter in every cell of its answer. Written in rather than
   right — nothing here knows which until the whole level is — so it recedes
   instead of being marked off, and what is left stands out by contrast. A tint
   would have been the other way round, and `.current` already owns the
   background. */
.clue.filled {
  color: var(--muted);
}

.clue.current {
  background: var(--lit);
}

/* Two columns of a phone's width wrap a clue over three or four lines, so the
   gutters give up what they can: every pixel taken out of the padding is a
   pixel of clue, and a tighter leading is worth a line back on the long ones.
   Below the rules it overrides, or the later ones win. */
@media (max-width: 639px) {
  .clues {
    gap: 12px;
  }

  .clue {
    gap: 6px;
    padding: 5px 6px;
    line-height: 1.35;
  }
}

[hidden] {
  display: none !important;
}

/* Below everything, and quiet: the version is what a bug report needs, not
   something a player is meant to read. */
.footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 16px;
  padding-block: 24px 32px;
  padding-inline: var(--margin);
  color: var(--muted);
}
