/* =========================================================================
   Guess the City — game screens
   Depends on css/game-tokens.css for the palette. Everything here is scoped
   under .gtc so it cannot reach the landmark pages.
   ========================================================================= */

/* The one rule here that is not scoped under .gtc, and it has to be.
   css/site.css resets the body margin for the landmark pages; the game page
   loads only game-tokens.css and this file, so it kept the browser's default
   8px on all four sides. That is 16px of vertical margin outside a layout
   built to fill exactly 100dvh — so the game screen overflowed by 16px and
   the player had to scroll to reach the fourth answer key. Reported on an
   iPhone 16 Plus; measured at 430x932 as a document 948px tall.
   A layout that budgets the viewport cannot afford a margin it did not ask
   for. */
body { margin: 0; }

.gtc {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.gtc-screen { display: none; flex: 1; flex-direction: column; }
.gtc-screen.is-active { display: flex; }

/* ---------------------------------------------------------------- the board
   A departure board is darker than the wall it hangs on, so the HUD is darker
   than the page rather than lighter. Fixed to the top because it carries the
   thing a player checks mid-round — how many lives are left — and hunting for
   it costs more attention than the strip costs space.

   Three slots, and the middle one is the point: `1fr auto 1fr` centres the
   second child against the strip, not against whatever happens to be beside
   it, so the lives stay dead centre whether or not Duo's turn label is
   showing. */
.gtc-board {
  position: sticky;
  top: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.75rem;
  padding: 0.55rem clamp(0.7rem, 3vw, 1.1rem);
  background: var(--board);
  border-bottom: 1px solid var(--hairline);
}
.gtc-board > :last-child { justify-self: end; }
.gtc-board > :nth-child(2) { justify-self: center; }

/* The game's strip places its three items by column instead of by order, and
   it has to. `hidden` computes to `display: none`, which takes an element out
   of grid placement entirely — so with Duo's turn label hidden, `:nth-child(2)`
   still selected the lives but the lives had slid into the first column, and
   "centred" centred them inside the left third. They sat at x=95 on a 430px
   screen. Naming the columns makes every slot hold its ground whether or not
   its neighbour is showing, which matters twice here: Daily hides the lives
   too. */
#screen-game .gtc-board > .gtc-turn { grid-column: 1; justify-self: start; }
#screen-game .gtc-board > .gtc-lives { grid-column: 2; justify-self: center; }
#screen-game .gtc-board > .gtc-progress { grid-column: 3; justify-self: end; }

/* The lives, centred and at three times the area they had.
   They were 9px squares in the left corner beside the word "Lives", sharing
   the strip with a streak counter — the one thing a player checks mid-round,
   put where the eye goes last and sized like a caption. Now they are the
   middle of the board and nothing else is amber up there. */
.gtc-lives { display: flex; align-items: center; gap: 0.5rem; }
.gtc-lives[hidden] { display: none; }
/* The label sits quiet beside the pips: it names them without competing with
   them, which is the whole reason the pips could grow in the first place. */
.gtc-lives .gtc-label { color: var(--chalk-4); }
.gtc-pips { display: flex; gap: 7px; }
.gtc-pip {
  width: 16px; height: 16px;
  background: var(--hairline-lit);
  border-radius: 2px;
  transition: background 160ms ease, transform 160ms ease;
}
.gtc-pip.is-on {
  background: var(--amber);
  /* Bigger squares can carry a glow that 9px ones could not; it is what keeps
     the lit pips reading as lit rather than merely as a different colour. */
  box-shadow: 0 0 0 1px rgba(242,169,59,0.25), 0 0 10px -2px var(--amber);
}
/* A life lost should be felt, not merely displayed: the pip goes out and the
   row flinches. One frame of movement, no bounce. */
.gtc-pip.is-spent {
  background: var(--rust);
  box-shadow: none;
  transform: scaleY(0.35);
}

/* The left slot: which mode you are in, and in Duo whose turn it is.
   Quiet on purpose. It is there to be checked, not read — the lives are the
   thing the eye should land on, and a second amber item on a three-item strip
   would take that away. The Duo rule below overrides the colour, because a
   player's name in a pass-and-play round is the state that matters most. */
.gtc-turn {
  font-family: var(--code-face);
  font-size: var(--board-xs);
  letter-spacing: 0.12em;
  color: var(--chalk-4);
  font-variant-numeric: tabular-nums;
}
.gtc-turn[hidden] { display: none; }

.gtc-progress {
  font-family: var(--code-face);
  font-size: var(--board-xs);
  color: var(--chalk-3);
  font-variant-numeric: tabular-nums;
}

.gtc-back {
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--chalk-4);
  padding: 0.2rem 0;
}
.gtc-back:hover { color: var(--chalk-2); }

/* ------------------------------------------------------------------ the photo
   A fixed-height band with `contain`, not a cropped `cover`.

   The first version was a 3:2 box with object-fit:cover, which looked right
   until a tall photograph arrived: Kraków's St Florian's Gate is 960×1544, and
   cropping a tower to a horizontal strip removes the tower. Measuring the pool
   settled it — 353 of 584 images are narrower than 3:2 and 140 are portrait or
   square, with a median ratio of 1.38. Cropping was not an edge case, it was
   the majority.
   
   `contain` on a dark ground also happens to be the metaphor the whole design
   is built on: a slide on a lightbox, whole, with the board around it. The
   height is fixed so the answer keys never move between questions — layout
   shift under a button is how a player mis-taps. */
.gtc-plate {
  position: relative;
  background: #05090c;
  /* Through a variable because two rules need this number and they must never
     disagree: the review bar takes its height out of the plate, and a second
     literal copy of `min(58dvh, 31rem)` is a copy that gets updated once. */
  /* THE THIRD TERM IS THE ONE THAT MATTERS. 44dvh and 20rem cap how
     big the photograph may get; `100dvh - 23rem` is what actually has
     to be left over — the top bar, the clock, the wildcards, the
     question and four answer keys. Without it the plate took its
     fraction of the viewport whether or not the answers had room, and
     on a 780px-tall window the last key fell off the bottom.

     It differs by branch because the keys do: stacked one per row below
     40rem they need 33rem underneath, side by side above it they need 27.
     Both figures were measured in the browser with the review bar present,
     which is when the column is at its tallest. */
  --plate-h: min(44dvh, 20rem, calc(100dvh - 33rem));
  /* A CAP, NOT A HEIGHT, and the difference is the whole bug.
     `height: 58dvh` took 452px of a 780px window whether or not the answers
     below had room, so the screen overflowed and the last key fell off the
     bottom — at that one viewport height, silently, since 900px tall happened
     to fit. The photograph is the element that can give: it is cropped with
     object-fit either way, and a landmark is still a landmark 60px shorter.
     The answers cannot give; a key you have to scroll to is a key you cannot
     press. So the plate takes what is left, up to the cap. */
  height: var(--plate-h);
  /* WITHOUT THIS THE HEIGHT ABOVE IS A SUGGESTION.
     The plate is a flex item, and a flex item's default `min-height: auto`
     forbids shrinking below its content's intrinsic size. The photograph is
     1280x853, so at 320px wide its natural height is 215px — and every
     narrower viewport silently ignored the height it had been given and used
     215 instead. That is why the small-phone cap appeared to do nothing: it
     was computing 96px correctly and losing to a minimum nobody had written. */
  min-height: 0;
  border-bottom: 1px solid var(--hairline);
  overflow: hidden;
}
/* Portrait sources are 24% of the pool and `contain` makes them narrow, so the
   band gets taller where there is room rather than leaving a tower the size of
   a stamp on a 27-inch monitor. */
@media (min-width: 40rem) {
  /* 27rem is measured, not estimated: the top bar and the play column
     come to 425px at the desktop sizes, and the play column is at its
     tallest while the review bar is reserving space under the keys.
     25rem was the first guess and left 20px hanging off the bottom. */
  .gtc-plate { --plate-h: min(58dvh, 31rem, calc(100dvh - 27rem)); }
}
/* And smaller where there is no room. A short viewport is a small phone with
   the browser's own toolbars showing — 375x560 on an iPhone SE — and there
   44% of it still left the fourth key 11px below the fold. The photo gives up
   those pixels because the alternative is an answer the player cannot reach. */
@media (max-height: 600px) {
  /* SETS THE VARIABLE, NOT THE HEIGHT. It set `height` directly and therefore
     beat every cap computed above it — the small-phone rule below was
     resolving to 96px, correctly, and losing to this silently. That cost an
     hour: I was reading --plate-h, finding the right expression, and watching
     the element render 38dvh anyway.
     One property, one mechanism. A second way of saying the same thing is a
     second thing to keep in step, and this one had already drifted. */
  .gtc-plate { --plate-h: min(38dvh, 20rem, calc(100dvh - 29.5rem)); }
}
.gtc-plate img {
  width: 100%; height: 100%;
  object-fit: contain;
  display: block;
}
.gtc-plate-tag {
  position: absolute;
  left: 0.7rem; bottom: 0.7rem;
  font-family: var(--code-face);
  font-size: var(--board-xs);
  letter-spacing: 0.12em;
  color: var(--chalk);
  background: rgba(10,16,20,0.72);
  border: 1px solid rgba(230,237,240,0.22);
  padding: 0.22rem 0.5rem;
  backdrop-filter: blur(2px);
}

/* ------------------------------------------------------------------ the keys */
.gtc-play {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;   /* the keys belong near the photo, not stranded
                                at the top of 250px of empty ground */
  gap: var(--pad);
  padding: var(--pad);
  max-width: 40rem;
  width: 100%;
  margin: 0 auto;
}

.gtc-ask {
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--chalk-3);
  text-align: center;
}

.gtc-keys {
  display: grid;
  gap: 0.6rem;
  grid-template-columns: 1fr;
}
/* Two columns from 23rem, not 30rem. At 30rem every phone made — 390px, 393px,
   412px, 430px — fell under the breakpoint and got four keys stacked in one
   column: 237px of the viewport where a 2x2 grid needs 114px. That single
   choice was most of why the game did not fit on a phone.
   23rem (368px) leaves ~150px of text per key, and the longest playable city
   name is sixteen characters ("Ho Chi Minh City", "Saint Petersburg") which
   measures ~130px at this weight. Checked against the data rather than
   guessed; if a longer name is ever added it wraps, it does not overflow. */
@media (min-width: 23rem) { .gtc-keys { grid-template-columns: 1fr 1fr; } }

.gtc-key {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  min-height: 3.4rem;
  padding: 0.6rem 0.85rem;
  text-align: center;
  background: var(--panel);
  border: 1px solid var(--hairline-lit);
  border-radius: var(--radius);
  box-shadow: var(--shadow-key);
  transition: background 120ms ease, border-color 120ms ease;
}
.gtc-key:hover:not(:disabled) {
  background: var(--panel-lit);
  border-color: var(--hairline-lit);
}
.gtc-key:disabled { cursor: default; }

.gtc-key-city { font-size: var(--key); font-weight: 700; letter-spacing: -0.01em; }

/* The city code is the one motif of the design, and it must not appear before
   the answer: "ROM · IT" beside the word Rome hands over the country, which is
   most of the question. It is a reward for answering, not a label. */
.gtc-key-code {
  font-family: var(--code-face);
  font-size: var(--board-xs);
  letter-spacing: 0.12em;
  color: var(--chalk-4);
  opacity: 0;
  transition: opacity 200ms ease 80ms;
}
.gtc-keys.is-resolved .gtc-key-code { opacity: 1; }

.gtc-key.is-right {
  border-color: var(--jade);
  background: var(--jade-bg);
}
.gtc-key.is-right .gtc-key-city { color: var(--jade-lit); }
.gtc-key.is-wrong {
  border-color: var(--rust);
  background: var(--rust-bg);
}
.gtc-key.is-wrong .gtc-key-city { color: var(--rust-lit); }
.gtc-key.is-dimmed { opacity: 0.42; }

/* ------------------------------------------------------------------ the modal
   This is the only place in the game set in a serif, and deliberately: the HUD
   is operated and the modal is read. Same reason the type scale changes. */
.gtc-modal-veil {
  position: fixed; inset: 0;
  background: rgba(4,8,11,0.82);
  display: grid;
  place-items: end center;
  z-index: 40;
}
.gtc-modal-veil[hidden] { display: none; }

.gtc-modal {
  width: 100%;
  max-width: 34rem;
  max-height: 88dvh;
  overflow-y: auto;
  background: var(--ground);
  border: 1px solid var(--hairline);
  border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: var(--shadow-modal);
  padding: var(--pad);
  animation: gtc-rise 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@keyframes gtc-rise { from { transform: translateY(14px); opacity: 0; } }
@media (min-width: 40rem) {
  .gtc-modal-veil { place-items: center; }
  .gtc-modal { border-bottom: 1px solid var(--hairline); border-radius: var(--radius); }
}

.gtc-modal-verdict {
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
}
.gtc-modal-verdict.is-right { color: var(--jade-lit); }
.gtc-modal-verdict.is-wrong { color: var(--rust-lit); }

.gtc-modal h2 {
  font-family: var(--prose-face);
  font-weight: 400;
  font-size: var(--title);
  line-height: 1.12;
  letter-spacing: -0.015em;
  margin: 0.3rem 0 0.15rem;
  text-wrap: balance;
}
.gtc-modal-where {
  font-family: var(--prose-face);
  font-style: italic;
  color: var(--amber);
  font-size: var(--prose);
  margin: 0 0 1rem;
}

/* Facts as a definition list, not a paragraph: a date and an architect are
   fields, and a reader scanning for "when" should not have to read a sentence
   to find it. */
.gtc-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.3rem 1rem;
  margin: 0 0 1rem;
  padding: 0.8rem 0;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}
.gtc-facts dt {
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--chalk-3);
  padding-top: 0.18rem;
}
.gtc-facts dd { margin: 0; font-size: var(--board-md); color: var(--chalk); }

.gtc-modal p.gtc-prose {
  font-family: var(--prose-face);
  font-size: var(--prose);
  line-height: 1.6;
  color: var(--chalk-2);
  margin: 0 0 1rem;
}

/* Everything below the basics is folded away. The art quiz handover is explicit
   that the modal is where a run dies: a wall of text after every answer and the
   player stops reading, then stops playing. */
.gtc-fold {
  border-top: 1px solid var(--hairline);
}
.gtc-fold summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.7rem 0;
  cursor: pointer;
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--chalk-3);
  list-style: none;
}
.gtc-fold summary::-webkit-details-marker { display: none; }
.gtc-fold summary::after { content: "+"; font-family: var(--code-face); color: var(--chalk-4); }
.gtc-fold[open] summary::after { content: "−"; }
.gtc-fold summary:hover { color: var(--chalk); }
.gtc-fold > *:not(summary) { padding-bottom: 0.9rem; }
.gtc-fold ul { margin: 0; padding-left: 1.1rem; }
.gtc-fold li {
  font-family: var(--prose-face);
  font-size: var(--board-md);
  color: var(--chalk-2);
  margin-bottom: 0.5rem;
}

.gtc-credit {
  font-family: var(--code-face);
  font-size: 0.58rem;
  color: var(--chalk-4);
  margin: 1rem 0 0;
}
.gtc-credit a { color: inherit; }

/* Sticky inside the modal, because the modal scrolls. On a 375×812 phone the
   card is 715px tall and "Next landmark" sat below the fold: the one action the
   player needs was reachable only by scrolling a dialog they had just been
   handed. Pinned to the bottom, it is always where the thumb already is. */
/* The modal's footer: the flag row and the Next button pinned together.
   Next alone was sticky, and adding the flag row above it put the row in the
   scrolling body underneath a floating button — half-covered and clipped at
   the card's edge. Two things that must always be reachable have to be pinned
   as one block, not one pinned and one hoping. */
.gtc-modal-foot {
  position: sticky;
  bottom: 0;
  z-index: 2;
  background: var(--ground);
  box-shadow: 0 -0.9rem 0.9rem -0.6rem var(--ground);
}
.gtc-modal-foot .gtc-next { margin-top: 0; }

.gtc-next {
  width: 100%;
  margin-top: 1.1rem;
  padding: 0.85rem;
  background: var(--amber);
  color: #21160a;
  border-radius: var(--radius);
  font-size: var(--board-sm);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
}
.gtc-next:hover { background: #ffbc55; }

/* ================================================================= timer
   Twenty seconds a question, with a bar. Two rules learned from the art
   quiz's own bug reports, and both matter more than the styling:

   1. The clock does not start until the photograph is on screen. On a poor
      connection it otherwise counts down against a blank plate.
   2. Running out of time says so. Silently marking it wrong looked identical
      to answering correctly and being rejected — which is exactly how a
      player reported it. */
.gtc-timer {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  align-items: center;
}
.gtc-timer-row {
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  font-family: var(--code-face);
  font-variant-numeric: tabular-nums;
}
.gtc-timer-value { font-size: 1.5rem; color: var(--chalk); letter-spacing: -0.02em; }
.gtc-timer-unit {
  font-size: var(--board-xs);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--chalk-3);
}
.gtc-timer-bar {
  width: 100%;
  max-width: 22rem;
  height: 3px;
  background: var(--hairline);
  overflow: hidden;
}
.gtc-timer-fill {
  height: 100%;
  width: 100%;
  background: var(--amber);
  transform-origin: left;
  transition: transform 1s linear, background 300ms ease;
}
/* The last five seconds turn rust and the number pulses. Colour alone would
   fail a colour-blind player, so the size moves too. */
.gtc-timer.is-urgent .gtc-timer-fill { background: var(--rust); }
.gtc-timer.is-urgent .gtc-timer-value {
  color: var(--rust-lit);
  animation: gtc-tick 1s steps(2) infinite;
}
@keyframes gtc-tick { 50% { transform: scale(1.12); } }

/* ============================================================= wildcards
   Four, one use each per game. They sit under the timer because that is the
   order a player needs them in: see the clock, then decide to spend. */
.gtc-wilds {
  display: flex;
  justify-content: center;
  gap: 0.45rem;
  flex-wrap: wrap;
}
.gtc-wild {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  min-width: 4.1rem;
  padding: 0.45rem 0.5rem;
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  transition: background 120ms ease, border-color 120ms ease, opacity 200ms ease;
}
.gtc-wild:hover:not(:disabled) { background: var(--panel-lit); border-color: var(--hairline-lit); }
.gtc-wild-icon { font-size: 1rem; line-height: 1; color: var(--amber); }
.gtc-wild-label {
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--chalk-3);
}
/* Spent, not hidden. A vanished button leaves the row jumping and the player
   wondering what was there; a dimmed one says "you used that". */
.gtc-wild.is-spent { opacity: 0.3; }
.gtc-wild.is-spent .gtc-wild-icon { color: var(--chalk-4); }
.gtc-wild:disabled { cursor: default; }

.gtc-key.is-cut {
  opacity: 0.22;
  text-decoration: line-through;
  text-decoration-color: var(--rust);
}

/* ================================================================= hint card
   Small, and dismissed by tapping anywhere. A hint is an aside, so it does not
   get the full modal's furniture. */
.gtc-hint-veil {
  position: fixed; inset: 0;
  background: rgba(4,8,11,0.7);
  display: grid; place-items: center;
  z-index: 50;
  padding: var(--pad);
}
.gtc-hint-veil[hidden] { display: none; }
.gtc-hint-card {
  max-width: 26rem;
  background: var(--panel);
  border: 1px solid var(--amber);
  border-radius: var(--radius);
  padding: 1.2rem;
  text-align: center;
  animation: gtc-rise 200ms ease;
}
.gtc-hint-eyebrow {
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--amber);
}
.gtc-hint-text {
  font-family: var(--prose-face);
  font-size: var(--prose);
  line-height: 1.5;
  color: var(--chalk);
  margin: 0.6rem 0 0.9rem;
}
.gtc-hint-tap { font-size: var(--board-xs); color: var(--chalk-4); letter-spacing: 0.08em; }

/* ================================================================= the front
   Same anatomy as guessthepainter's home: a top bar with the wordmark and
   nav, a hero of eyebrow / title / lede / calls to action, a collage of
   photographs, a footer band. Only the palette and the faces change.

   One departure, and it is deliberate. The art quiz lists its three modes as
   equal sub-links under one START button. Here the Daily gets its own card,
   because the SERP says so: the sites ranking for "guess the city" on no
   authority at all are the daily ones, and what they have is people pasting a
   result into a chat. A mode that earns the traffic should not be a footnote
   under the mode that does not. */
.gtc-front { display: flex; flex-direction: column; min-height: 100dvh; }

.gtc-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem clamp(1rem, 4vw, 2.5rem);
  border-bottom: 1px solid var(--hairline);
}
.gtc-brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--chalk);
  text-decoration: none;
}
.gtc-brand svg { width: 26px; height: 26px; flex: none; }
.gtc-brand-word {
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}
.gtc-topnav { display: flex; align-items: center; gap: clamp(0.7rem, 2vw, 1.5rem); }
.gtc-topnav a, .gtc-topnav button {
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--chalk-3);
  text-decoration: none;
}
.gtc-topnav a:hover, .gtc-topnav button:hover { color: var(--chalk); }
@media (max-width: 40rem) { .gtc-topnav { display: none; } }

.gtc-hero {
  flex: 1;
  display: grid;
  gap: clamp(1.5rem, 5vw, 4rem);
  align-items: center;
  grid-template-columns: 1fr;
  padding: clamp(1.5rem, 5vw, 4rem) clamp(1rem, 4vw, 2.5rem);
  max-width: 78rem;
  width: 100%;
  margin: 0 auto;
}
@media (min-width: 56rem) { .gtc-hero { grid-template-columns: 1.05fr 1fr; } }

.gtc-eyebrow {
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--amber);
  margin: 0 0 0.9rem;
}
.gtc-hero h1 {
  font-family: var(--prose-face);
  font-weight: 400;
  font-size: clamp(2.1rem, 6.5vw, 3.6rem);
  line-height: 1.03;
  letter-spacing: -0.025em;
  margin: 0 0 1rem;
  text-wrap: balance;
}
.gtc-hero h1 em { font-style: italic; color: var(--amber); }
.gtc-lede {
  font-family: var(--prose-face);
  font-size: 1.1rem;
  line-height: 1.55;
  color: var(--chalk-2);
  margin: 0 0 1.8rem;
  max-width: 32rem;
}

.gtc-start {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.9rem 1.6rem;
  background: var(--amber);
  color: #21160a;
  border-radius: var(--radius);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.gtc-start:hover { background: #ffbc55; }

/* The Daily, given its own card rather than a sub-link. */
.gtc-daily {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  width: 100%;
  max-width: 26rem;
  margin: 1.1rem 0 1.2rem;
  padding: 0.8rem 1rem;
  background: var(--panel);
  border: 1px solid var(--amber);
  border-radius: var(--radius);
  text-align: left;
}
.gtc-daily:hover { background: var(--panel-lit); }
.gtc-daily-main { display: flex; flex-direction: column; gap: 0.15rem; }
.gtc-daily-title { font-size: 0.95rem; font-weight: 700; color: var(--chalk); }
.gtc-daily-sub { font-size: var(--board-xs); color: var(--chalk-3); letter-spacing: 0.05em; }
.gtc-daily-date {
  font-family: var(--code-face);
  font-size: var(--board-xs);
  color: var(--amber);
  letter-spacing: 0.08em;
  text-align: right;
  white-space: nowrap;
}

.gtc-modes { display: flex; flex-wrap: wrap; gap: 0.4rem 1rem; }
.gtc-modes button {
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--chalk-3);
}
.gtc-modes button:hover { color: var(--amber); }

/* The collage. Six photographs at slight angles, because the game is about
   looking at photographs and the front page should say so before any words do.
   Hidden below the breakpoint: on a phone it would push the CTA off screen,
   and the CTA is the point. */
.gtc-collage { display: none; }
@media (min-width: 56rem) {
  .gtc-collage {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.6rem;
  }
  .gtc-collage figure {
    margin: 0;
    aspect-ratio: 3 / 4;
    overflow: hidden;
    border: 1px solid var(--hairline);
    border-radius: 2px;
    background: #05090c;
  }
  .gtc-collage img { width: 100%; height: 100%; object-fit: cover; display: block;
                     filter: saturate(0.9); }
  .gtc-collage figure:nth-child(2) { transform: translateY(-1.2rem); }
  .gtc-collage figure:nth-child(5) { transform: translateY(-1.2rem); }
}

.gtc-footband {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem 1.5rem;
  padding: 1rem clamp(1rem, 4vw, 2.5rem);
  border-top: 1px solid var(--hairline);
  font-size: var(--board-xs);
  letter-spacing: 0.06em;
  color: var(--chalk-4);
}
.gtc-footband a { color: var(--chalk-3); text-decoration: none; }
.gtc-footband a:hover { color: var(--chalk); }

/* The prose below the game.
   It used to be clipped to a single pixel — the .sr-only pattern — which is
   the right tool for an icon's label and the wrong one for two hundred words
   of keyword copy no sighted visitor ever sees. That is hidden text under
   Google's spam policies, trivially detectable, and the likeliest outcome was
   never a penalty but simply being discounted: months of believing the front
   page carried SEO copy that counted for nothing.

   It is real text now. It costs the player nothing because it sits BELOW the
   fold — the hero fills the viewport and Start playing is at the top — so you
   reach this only by choosing to scroll past the game. Quiet, not hidden:
   smaller, softer, narrower measure. The FAQ is in <details>, collapsed, which
   is indexable and is also simply how a reader wants a list of questions.

   The links matter as much as the words. The front page previously pointed at
   four internal pages out of 258. */
.gtc-seo {
  max-width: 62ch;
  margin: 0 auto;
  padding: 3.5rem 1.25rem 4.5rem;
  color: var(--chalk-3);
  font-size: 0.92rem;
  line-height: 1.7;
  border-top: 1px solid rgba(255,255,255,0.08);
}
.gtc-seo h2 {
  font-family: var(--board-face);
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--chalk-2);
  margin: 2.4rem 0 0.6rem;
}
.gtc-seo h2:first-child { margin-top: 0; }
.gtc-seo p { margin: 0 0 0.9rem; }
.gtc-seo a { color: var(--chalk-2); text-decoration: underline; text-underline-offset: 2px; }
.gtc-seo a:hover { color: var(--chalk); }

/* A grid rather than a comma-separated run: twenty-four city names in a
   sentence is a wall, and each of these is a link somebody might actually
   want to press. */
.gtc-seo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: 0.35rem 0.9rem;
  margin: 0 0 1.2rem;
}
.gtc-seo-grid a { text-decoration: none; font-size: 0.88rem; }
.gtc-seo-grid a:hover { text-decoration: underline; }

.gtc-seo details {
  border-top: 1px solid rgba(255,255,255,0.07);
  padding: 0.55rem 0;
}
.gtc-seo summary {
  cursor: pointer;
  color: var(--chalk-2);
  font-weight: 500;
  list-style: none;
}
.gtc-seo summary::-webkit-details-marker { display: none; }
.gtc-seo summary::before { content: "+ "; opacity: 0.6; }
.gtc-seo details[open] summary::before { content: "\2212 "; }
.gtc-seo details p { margin: 0.55rem 0 0.3rem; }

/* ============================================================ duo mode
   Whose turn it is has to be unmissable, not tasteful. A player who answers on
   someone else's turn has lost a life that was not theirs, and no amount of
   apologising fixes that — so the board takes the player's colour outright
   rather than a hint of it.

   Warm for player one, cold for player two: on a dark ground temperature reads
   apart instantly, and it survives colour blindness in a way two hues of
   similar warmth would not. */
.gtc-screen.is-duo .gtc-board {
  background: var(--turn-solid);
  border-bottom: 3px solid var(--turn-solid);
  box-shadow: 0 0 24px -6px var(--turn-solid);
}
/* The board is now a bright bar, so its text has to flip to dark to stay
   readable — chalk-on-amber is the classic unreadable pairing. */
.gtc-screen.is-duo .gtc-board,
.gtc-screen.is-duo .gtc-board .gtc-label,
.gtc-screen.is-duo .gtc-board .gtc-progress { color: #10171d; }
.gtc-screen.is-duo .gtc-pip { background: rgba(16,23,29,0.28); }
.gtc-screen.is-duo .gtc-pip.is-on { background: #10171d; }
.gtc-screen.is-duo .gtc-pip.is-spent { background: rgba(16,23,29,0.5); }

.gtc-screen.is-duo .gtc-turn {
  font-family: var(--board-face);
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: #10171d !important;
}
/* The whole lower half carries the colour, not a hint of it. A 9% tint was
   technically present and practically invisible, and the point of the colour is
   that nobody answers on the wrong turn — so it goes where the player is
   looking, which is the keys, not the strip at the top. */
.gtc-screen.is-duo .gtc-play {
  background: var(--turn-zone);
  border-top: 1px solid var(--turn-solid);
  box-shadow: inset 0 24px 40px -30px var(--turn-solid);
}
.gtc-screen.is-duo .gtc-keys {
  border-left: 3px solid var(--turn-solid);
  padding-left: 0.7rem;
}
/* The keys pick up the turn colour on their edge, so the thing you are about to
   press is labelled with whose press it is. */
.gtc-screen.is-duo .gtc-key { border-color: color-mix(in srgb, var(--turn-solid) 45%, var(--hairline-lit)); }
.gtc-screen.is-duo .gtc-key:hover:not(:disabled) { border-color: var(--turn-solid); }
.gtc-screen.is-duo .gtc-ask { color: var(--turn-solid); }

/* ============================================================ the arrivals
   The result screen was a line of text and a button, and it read as an error
   message. A run is the thing the player just spent five minutes on, so it
   gets the largest type on the site and the number gets to be the subject.

   The headline scales with the result. Not decoration: 90% and 30% are
   different events, and a screen that renders them identically tells the
   player their effort did not register. */
.gtc-arrivals {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.1rem;
  padding: var(--pad);
  max-width: 40rem;
  width: 100%;
  margin: 0 auto;
}

.gtc-verdict {
  font-family: var(--prose-face);
  font-weight: 400;
  line-height: 0.92;
  letter-spacing: -0.035em;
  margin: 0;
  text-wrap: balance;
}
.gtc-verdict .gtc-score {
  display: block;
  font-size: clamp(4rem, 22vw, 9rem);
  font-variant-numeric: tabular-nums;
  color: var(--chalk);
}
.gtc-verdict .gtc-of {
  font-size: clamp(1rem, 4vw, 1.5rem);
  color: var(--chalk-3);
  letter-spacing: 0;
}
/* Three bands. A strong run turns the number amber and grows it; a weak one
   stays quiet rather than shouting a bad score back at you. */
.gtc-arrivals[data-band="high"] .gtc-score {
  color: var(--amber);
  font-size: clamp(5rem, 27vw, 11rem);
}
.gtc-arrivals[data-band="low"] .gtc-score { font-size: clamp(3rem, 16vw, 6rem); }

.gtc-tagline {
  font-family: var(--prose-face);
  font-style: italic;
  font-size: clamp(1.1rem, 3.6vw, 1.6rem);
  color: var(--amber);
  margin: 0;
}
.gtc-arrivals[data-band="low"] .gtc-tagline { color: var(--chalk-2); font-style: normal; }

/* Three cards, because three numbers is the story of a run: how many, out of
   how many, and the longest stretch without a mistake. */
.gtc-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }
.gtc-stat {
  padding: 0.7rem 0.5rem;
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  text-align: center;
}
.gtc-stat-value {
  font-family: var(--code-face);
  font-size: 1.5rem;
  color: var(--chalk);
  font-variant-numeric: tabular-nums;
  display: block;
}
.gtc-stat.is-lead { border-color: var(--amber); }
.gtc-stat.is-lead .gtc-stat-value { color: var(--amber); }
.gtc-stat-label {
  font-size: 0.55rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--chalk-3);
}

/* ------------------------------------------------------------- the claim
   The figure a run earned, immediately above the name field it is arguing
   for. Set in the monospace rather than the serif because it is a reading off
   a board, not a sentence about the run — the verdict above it is the
   sentence, and the two must not compete for the same voice.

   `is-strong` is the top of the ladder: inside the all-time ten, or the week's
   top five. Those get the amber and the rule above them. Everything below
   stays in chalk, because dressing "#7 today" like a trophy is how a player
   learns to stop believing the screen. */
.gtc-claim {
  display: grid;
  gap: 0.15rem;
  padding: 0.7rem 0.85rem;
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-left: 2px solid var(--hairline-lit);
  border-radius: var(--radius);
}
.gtc-claim[hidden] { display: none; }
.gtc-claim-figure {
  font-family: var(--code-face);
  font-size: var(--board-sm);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--chalk);
  margin: 0;
  font-variant-numeric: tabular-nums;
}
.gtc-claim-call {
  font-size: var(--board-xs);
  letter-spacing: 0.04em;
  color: var(--chalk-3);
  margin: 0;
}
.gtc-claim.is-strong {
  border-left-color: var(--amber);
  background: var(--amber-glow);
}
.gtc-claim.is-strong .gtc-claim-figure { color: var(--amber); }
.gtc-claim.is-strong .gtc-claim-call { color: var(--chalk-2); }

/* Nothing to claim, so the score takes the room the claim would have had.
   The screen is not missing a component; it is answering a different
   question, and it should look like it meant to. */
.gtc-arrivals.is-noplace .gtc-score { font-size: clamp(4.5rem, 25vw, 10rem); }
.gtc-arrivals.is-noplace[data-band="low"] .gtc-score { font-size: clamp(3.4rem, 18vw, 7rem); }

.gtc-save { display: flex; gap: 0.5rem; }
.gtc-save input {
  flex: 1;
  min-width: 0;
  padding: 0.75rem 0.85rem;
  background: var(--panel);
  border: 1px solid var(--hairline-lit);
  border-radius: var(--radius);
  color: var(--chalk);
  font-family: var(--board-face);
  font-size: 0.9rem;
}
.gtc-save input::placeholder { color: var(--chalk-4); }
/* width:auto, because .gtc-next carries width:100% for its use inside the
   modal, and inherited here it squeezed the name field down to sixteen
   pixels. */
.gtc-save button { flex: none; width: auto; padding: 0.75rem 1.1rem; }
.gtc-save input { min-width: 7rem; }

/* One primary per screen. Saving the score is the new thing being offered, so
   it keeps the amber; playing again is the obvious next step and does not need
   to shout to be found. Two amber buttons side by side just cancel out. */
.gtc-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
.gtc-actions .gtc-ghost { flex: 1; min-width: 12rem; }
.gtc-ghost {
  padding: 0.85rem 1.1rem;
  background: var(--panel);
  border: 1px solid var(--hairline-lit);
  border-radius: var(--radius);
  color: var(--chalk);
  font-size: var(--board-sm);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
}
.gtc-ghost:hover { background: var(--panel-lit); }

/* ============================================================ leaderboard
   Local for now: these are this device's runs, and the screen says so rather
   than implying a world ranking that does not exist. The storage sits behind
   one pair of functions so a server-backed board can replace it without the
   screen changing. */
.gtc-board-list { display: flex; flex-direction: column; }
.gtc-board-row {
  display: grid;
  grid-template-columns: 2rem 1fr auto auto;
  gap: 0.9rem;
  align-items: baseline;
  padding: 0.6rem 0.2rem;
  border-bottom: 1px solid var(--hairline);
}
.gtc-board-rank {
  font-family: var(--code-face);
  font-size: var(--board-xs);
  color: var(--chalk-4);
  font-variant-numeric: tabular-nums;
}
.gtc-board-name { font-size: 0.95rem; color: var(--chalk-2); }
.gtc-board-when { font-family: var(--code-face); font-size: 0.56rem; color: var(--chalk-4); }
/* One number now, not "7/10", so it can carry the weight it was sharing — and
   it needs a floor and a right edge. "7" and "23" are different widths, and a
   column that is only ever as wide as its own row is not a column: the eye
   cannot run down it. Three digits of room and tabular figures give every
   score the same right edge. */
.gtc-board-score {
  font-family: var(--code-face);
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--chalk);
  font-variant-numeric: tabular-nums;
  min-width: 2.2rem;
  text-align: right;
}
.gtc-board-row.is-new { background: var(--amber-glow); }
.gtc-board-row.is-new .gtc-board-name,
.gtc-board-row.is-new .gtc-board-score { color: var(--amber); }
/* A run of this player's own, wherever it sits. Marked so the row below the
   ellipsis reads as "you, at 23rd" rather than as one more stranger. */
.gtc-board-row.is-mine .gtc-board-name {
  color: var(--chalk);
  font-weight: 700;
}
.gtc-board-row.is-mine .gtc-board-rank { color: var(--chalk-2); }
/* The break between the ten and your own row. Three dots, because whatever
   number sits between them is a number we did not fetch and cannot claim. */
.gtc-board-gap {
  font-family: var(--code-face);
  font-size: var(--board-xs);
  color: var(--chalk-4);
  letter-spacing: 0.3em;
  text-align: center;
  margin: 0;
  padding: 0.45rem 0;
}
.gtc-board-empty {
  font-family: var(--prose-face);
  color: var(--chalk-3);
  padding: 1.5rem 0;
}

/* ============================================================ mobile menu
   The nav was simply hidden below 40rem, which on a phone left no route to
   Landmarks or Credits at all — the whole site unreachable from its own front
   page. A hidden nav needs a way back in, not just a breakpoint. */
.gtc-burger {
  display: none;
  font-size: 1.3rem;
  line-height: 1;
  color: var(--chalk-2);
  padding: 0.2rem 0.4rem;
}
@media (max-width: 40rem) { .gtc-burger { display: block; } }

.gtc-sheet {
  position: fixed; inset: 0;
  z-index: 60;
  background: rgba(4,8,11,0.86);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.gtc-sheet[hidden] { display: none; }
.gtc-sheet-inner {
  background: var(--ground);
  border-top: 1px solid var(--hairline);
  padding: 1rem 1.2rem 1.6rem;
  animation: gtc-rise 200ms ease;
}
.gtc-sheet a, .gtc-sheet button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--hairline);
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--chalk);
  text-decoration: none;
}
.gtc-sheet a:last-child, .gtc-sheet button:last-child { border-bottom: 0; }

/* ============================================================ how to play
   Reachable from the front page and from the board. Four rows, because the
   game has four things worth explaining and a wall of prose in a modal is a
   wall nobody reads. */
.gtc-howto { display: flex; flex-direction: column; gap: 0.9rem; }
.gtc-howto-row { display: grid; grid-template-columns: 2.2rem 1fr; gap: 0.9rem; align-items: start; }
.gtc-howto-mark {
  font-family: var(--code-face);
  font-size: 1.1rem;
  color: var(--amber);
  text-align: center;
}
.gtc-howto-row h3 {
  font-family: var(--prose-face);
  font-weight: 400;
  font-size: 1.05rem;
  margin: 0 0 0.15rem;
  color: var(--chalk);
}
.gtc-howto-row p {
  font-family: var(--prose-face);
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--chalk-2);
  margin: 0;
}

/* ============================================================ duo setup
   Names before the first question. The art quiz asks for them too, and the
   reason shows up on the result screen: "Player 2 wins" is a worse sentence
   than "Marta wins", and the whole point of a pass-and-play mode is that the
   two players are in the same room. */
.gtc-setup { display: flex; flex-direction: column; gap: 0.7rem; }
.gtc-setup-field { display: flex; flex-direction: column; gap: 0.3rem; }
.gtc-setup-field label {
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
}
.gtc-setup-field:nth-child(1) label { color: var(--p1); }
.gtc-setup-field:nth-child(2) label { color: var(--p2); }
.gtc-setup-field input {
  padding: 0.75rem 0.85rem;
  background: var(--panel);
  border: 1px solid var(--hairline-lit);
  border-radius: var(--radius);
  color: var(--chalk);
  font-family: var(--board-face);
  font-size: 0.95rem;
}

/* ============================================================ mode picker
   Start playing opens this rather than dropping straight into Classic. Four
   modes that differ in kind — timed, daily, untimed, two-player — and choosing
   between them is a decision, not a setting. */
/* --------------------------------------------------------- the pick backdrop
   Photographs behind the mode selector, blurred into weather.

   Two rules hold it together. The blur lives on the wrapper, not on each
   image, so the browser composites one layer instead of six — six separately
   blurred 1100px photographs is a visible stutter on a phone as the screen
   opens. And the veil above them is a hard requirement, not a taste: the
   buttons are the only thing on this screen, and a photograph is a texture
   with contrast of its own. Without the veil, "Three lives, twenty seconds a
   landmark" lands on a bright sky and disappears.

   The images are scaled up past the edges of the screen. A blur samples
   nothing beyond the element, so an unscaled image fades to transparent at
   its own border and draws a pale seam along every gap in the grid. */
#screen-pick { position: relative; isolation: isolate; }
.gtc-backdrop {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.gtc-backdrop-grid {
  position: absolute;
  inset: -8%;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(3, 1fr);
  filter: blur(20px) saturate(0.9);
  transform: scale(1.08);
}
@media (min-width: 40rem) {
  .gtc-backdrop-grid { grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(2, 1fr); }
}
.gtc-backdrop-grid img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 62% of the ground colour across the middle, deepening to 84% at both edges
   where the board strip and the footer meet it.

   The even middle is the point. The first attempt ran a gradient from 88% to
   58% and back, tuned by eye against these six photographs — which is a
   contrast budget that depends on which tile happens to sit under the
   heading. Six specific images is not a rule. A flat veil means every piece
   of text on this screen has the same guaranteed floor behind it, and the
   backdrop can be swapped for six others without re-checking anything.

   62% was chosen by looking: above it the photographs stop reading as cities,
   below it the screen stops reading as part of a dark game. */
.gtc-backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--ground) 84%, transparent) 0%,
      color-mix(in srgb, var(--ground) 62%, transparent) 18%,
      color-mix(in srgb, var(--ground) 62%, transparent) 82%,
      color-mix(in srgb, var(--ground) 84%, transparent) 100%);
}
/* The board strip is sticky and the backdrop is absolute, so without this the
   photographs would sit over the top of it. */
#screen-pick > .gtc-board,
#screen-pick > .gtc-arrivals { position: relative; z-index: 1; }

/* The screen the backdrop is for. Keys stay legible against it because every
   button already carries its own panel colour and a border. */
.gtc-pick { display: grid; gap: 0.5rem; }
.gtc-pick-btn {
  display: grid;
  /* max-content, not a fixed 2.4rem column: the mark strips are 2, 3 and 5
     bars wide and a fixed column either clips the five or leaves a hole
     beside the two. */
  grid-template-columns: max-content 1fr auto;
  gap: 0.75rem;
  align-items: center;
  /* Scales with the viewport's HEIGHT, not its width. This screen has to fit
     in one viewport on a phone in landscape — 380px tall — and five rows of
     fixed padding do not. */
  padding: clamp(0.6rem, 1.9vh, 0.9rem) clamp(0.7rem, 2.6vw, 1rem);
  background: var(--panel);
  border: 1px solid var(--hairline-lit);
  border-radius: var(--radius);
  text-align: left;
  transition: background 160ms, border-color 160ms, transform 160ms;
  /* A floor for the tap target, and it is a floor rather than a height because
     the rows should still grow with their content on a roomy screen.
     Measured, not guessed: on a phone held sideways the compaction rules below
     had squeezed these to 37px while 140px of the panel sat empty — the
     shrinking was doing work nothing had asked for. */
  min-height: 44px;
}
.gtc-pick-btn:hover,
.gtc-pick-btn:focus-visible {
  background: var(--panel-lit);
  border-color: var(--amber);
  transform: translateY(-1px);
}

/* The mark strip. Each bar is one of the things the sentence beside it
   counts — see the note in index.html. Hollow means the sentence names an
   absence, which is why Learn's are outlines. */
.gtc-pick-marks {
  display: flex;
  gap: 3px;
  align-items: center;
  align-self: start;
  margin-top: 0.42em;          /* optical alignment to the name's cap height */
}
.gtc-pick-marks i {
  display: block;
  width: 6px;
  height: 13px;
  border-radius: 1px;
  background: var(--amber);
  flex: 0 0 auto;
}
.gtc-pick-marks.is-hollow i {
  background: none;
  box-shadow: inset 0 0 0 1px var(--amber);
}
.is-lead .gtc-pick-marks i { width: 7px; height: 16px; }

.gtc-pick-body { min-width: 0; }
.gtc-pick-name { font-size: 1rem; font-weight: 700; display: block; line-height: 1.2; }
.is-lead .gtc-pick-name { font-size: clamp(1.05rem, 3.2vw, 1.18rem); }
.gtc-pick-desc {
  display: block;
  margin-top: 1px;
  font-size: var(--board-xs);
  line-height: 1.4;
  color: var(--chalk-3);
  letter-spacing: 0.04em;
}
.gtc-pick-tag {
  font-family: var(--code-face);
  font-size: var(--board-xs);
  color: var(--amber);
  white-space: nowrap;
}

/* "or something else" — a rule with a word in it. The two modes above are
   what most people want; without a break, five equal rows make the reader do
   the sorting the design should have done for them. */
.gtc-pick-sep {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0.15rem 0.1rem;
  font-family: var(--code-face);
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--chalk-4);
}
.gtc-pick-sep::before,
.gtc-pick-sep::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--hairline);
}

/* The three secondary modes share a row where there is width for it. Below
   34rem they stack, because two columns of a 160px card turn the description
   into a column of single words. */
.gtc-pick-more { display: grid; gap: 0.5rem; }
@media (min-width: 34rem) { .gtc-pick-more { grid-template-columns: 1fr 1fr; } }
@media (min-width: 52rem) { .gtc-pick-more { grid-template-columns: repeat(3, 1fr); } }
/* In the compact grid the tag would collide with a wrapped description, and
   it is the least load-bearing thing in the row — Easy's "54" is already the
   second half of its own sentence. */
@media (min-width: 34rem) {
  .gtc-pick-more .gtc-pick-btn { grid-template-columns: max-content 1fr; }
  .gtc-pick-more .gtc-pick-tag { display: none; }
}

/* Short viewports: a phone in landscape, or a small laptop with the browser
   chrome taking half the screen. Everything shrinks together rather than the
   screen growing a scrollbar, because a mode you have to scroll to find is a
   mode most people never try. */
@media (max-height: 640px) {
  .gtc-pick { gap: 0.4rem; }
  .gtc-pick-more { gap: 0.4rem; }
  .gtc-pick-btn { padding: 0.5rem 0.75rem; }
  .gtc-pick-marks i { height: 11px; }
  .is-lead .gtc-pick-marks i { height: 13px; }
  .is-lead .gtc-pick-name { font-size: 1.02rem; }
  .gtc-pick-desc { font-size: 0.68rem; }
  .gtc-pick-sep { margin: 0; }
}
@media (max-height: 520px) {
  .gtc-pick-desc { display: none; }
  .gtc-pick-sep { display: none; }
}

/* ============================================================ learn grid
   Four photographs of one city at once, instead of one photograph of one
   landmark. Four pieces of evidence beat one, which is what makes this the
   mode you can learn in: a single Gothic façade could be anywhere in Europe,
   but four buildings together carry a city's whole architectural accent. */
.gtc-quad {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px;
  background: var(--hairline);
  height: min(46dvh, 22rem);
}
@media (min-width: 40rem) { .gtc-quad { height: min(56dvh, 28rem); } }
.gtc-quad figure { margin: 0; overflow: hidden; background: #05090c; position: relative; }
.gtc-quad img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gtc-quad figcaption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 0.3rem 0.5rem;
  background: linear-gradient(transparent, rgba(5,9,12,0.88));
  font-family: var(--code-face);
  font-size: 0.56rem;
  letter-spacing: 0.08em;
  color: var(--chalk-2);
  opacity: 0;
  transition: opacity 200ms ease;
}
/* The names appear only after answering — before that they would be four
   labels spelling out the answer. */
.gtc-quad.is-resolved figcaption { opacity: 1; }

/* A finished daily still looks like a card worth reading — it carries today's
   score — but it stops advertising itself as an action. */
.gtc-daily.is-done { border-color: var(--hairline-lit); }
.gtc-daily.is-done .gtc-daily-title { color: var(--chalk-2); }
.gtc-daily.is-done .gtc-daily-date { color: var(--chalk-4); }

/* ======================================================= touch targets
   Keyed on `pointer: coarse`, not on width. A narrow window with a mouse does
   not need bigger targets; a finger does, at any width.
   
   Measured before writing this: the mode row was 13px tall, "Back" 18px, the
   footer links 11px. Apple asks for 44 and Android for 48, and the reason is
   not politeness — a 13px target on a moving bus is a mis-tap, and a mis-tap
   here means answering the wrong city or leaving the game. */
@media (pointer: coarse) {
  /* The report buttons came out 22px on a phone. They are meant to be small,
     but small is a visual weight, not a hit area — and a mis-tap here files a
     complaint about a photograph the player had no problem with, which is worse
     than no report at all. */
  .gtc-flag button {
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .gtc-modes { gap: 0.2rem 0.6rem; }
  .gtc-modes button {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: 0 0.55rem;
  }
  .gtc-back {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: 0 0.5rem;
    margin: 0 -0.5rem;      /* keep the visual position, grow only the target */
  }
  .gtc-burger {
    min-width: 44px;
    min-height: 44px;
    display: grid;
    place-items: center;
    margin-right: -0.4rem;
  }
  .gtc-footband a {
    display: inline-block;
    padding: 0.95rem 0;    /* 11px of text needs 16 either side to clear 44 */
  }
  .gtc-brand { min-height: 44px; }
  /* The wildcards are already 4 across a 375px screen; without a floor they
     shrink under the finger as soon as a label wraps. */
  .gtc-wild { min-height: 46px; min-width: 3.9rem; }
  .gtc-key { min-height: 52px; }
}

/* ============================================================ board chips
   Filters, in the shape guessthepainter uses: a row of pills where the active
   one is filled. */
.gtc-chips { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.gtc-chip {
  padding: 0.4rem 0.8rem;
  background: var(--panel);
  border: 1px solid var(--hairline-lit);
  border-radius: 999px;
  font-size: var(--board-xs);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--chalk-3);
}
.gtc-chip:hover { color: var(--chalk); }
.gtc-chip.is-on {
  background: var(--amber);
  border-color: var(--amber);
  color: #21160a;
}
@media (pointer: coarse) { .gtc-chip { min-height: 40px; } }

/* The outer choice, set apart from the inner one.
   Two chip rows in the same style read as one row that wrapped, and then a
   player cannot tell that Solo/Easy and Week/All time are different questions.
   The mode row is heavier and sits above a rule; the range row stays light
   underneath it. */
.gtc-chips-mode {
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--hairline);
  margin-bottom: 0.15rem;
}
.gtc-chips-mode .gtc-chip {
  font-size: var(--board-sm);
  padding: 0.5rem 1.1rem;
}
.gtc-chips-mode .gtc-chip.is-on { font-weight: 700; }

/* The top three carry the accent; the rest stay quiet. A column of identical
   numbers is a column nobody reads. */
.gtc-board-rank.is-top { color: var(--amber); font-weight: 700; }

/* The share button leads on a daily result, because sharing is what a daily is
   for — the SERP evidence for building one at all was that the sites ranking on
   no authority are the ones people paste into chats. Play again stays quiet. */
.gtc-actions #over-share { flex: 1; min-width: 12rem; }
.gtc-share-note {
  width: 100%;
  margin: 0.3rem 0 0;
  font-family: var(--code-face);
  font-size: 0.58rem;
  letter-spacing: 0.06em;
  color: var(--chalk-3);
  white-space: pre-line;
}

/* Daily and Solo carry a heavier edge: they are the two modes most people
   want, and a row of four identical cards makes the reader do the sorting the
   design should have done for them. */
.gtc-pick-btn.is-lead { border-width: 2px; }
.gtc-pick-btn[data-mode="daily"] { border-color: var(--amber); }
.gtc-pick-btn[data-mode="classic"].is-lead { border-color: var(--hairline-lit); }
.gtc-pick-btn[data-mode="classic"].is-lead:hover { border-color: var(--amber); }

/* A finished daily is dimmed here exactly as it is on the front page. It stays
   clickable — it shows the result you already have — so it must not look
   disabled either; spent, not forbidden. */
.gtc-pick-btn.is-done {
  opacity: 0.55;
  border-color: var(--hairline-lit);
}
/* A spent daily is dimmed, and its marks dim with it — an amber strip on a
   grey row is the one thing that would still look live. */
.gtc-pick-btn.is-done .gtc-pick-marks i { background: var(--chalk-4); }
.gtc-pick-btn.is-done .gtc-pick-marks.is-hollow i {
  background: none; box-shadow: inset 0 0 0 1px var(--chalk-4);
}
.gtc-pick-btn.is-done .gtc-pick-tag { color: var(--chalk-4); }

/* ---- Reporting a bad photograph -----------------------------------------
   Bottom of the modal, quiet, below the credit. The player came to read about
   the landmark; a report control competing with that would get clicked out of
   idle curiosity and the reports would stop meaning anything.

   Marked state is a filled amber outline rather than a colour swap, so the row
   still reads as controls and not as a verdict on the photograph. */
.gtc-flag {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin: 0.2rem 0 1rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--hairline);
}

.gtc-flag-q {
  font-size: var(--board-xs);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--chalk-4);
  margin-right: auto;
}

.gtc-flag button {
  font-size: var(--board-xs);
  letter-spacing: 0.04em;
  color: var(--chalk-3);
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 0.3rem 0.55rem;
  /* Without this two of the three labels wrapped and the row came out with
     buttons of 43, 43 and 32 pixels — a ragged row reads as broken rather than
     as quiet. On a narrow screen the media query below gives them a line of
     their own instead of letting them wrap. */
  white-space: nowrap;
  transition: color .12s, border-color .12s, background .12s;
}

.gtc-flag button:hover { color: var(--chalk-2); border-color: var(--hairline-lit); }

.gtc-flag button.is-on {
  color: var(--amber);
  border-color: var(--amber);
  background: var(--amber-glow);
}

/* On a phone the label would eat the row and push a button onto its own line,
   so it steps aside and lets the three controls sit together. */
@media (max-width: 30rem) {
  .gtc-flag-q { flex-basis: 100%; margin-bottom: 0.15rem; }
  .gtc-flag button { flex: 1; text-align: center; }
}

/* ======================================================== the review bar
   What replaced the modal between questions in Solo, Easy and Daily. See the
   note in index.html for why.

   Absolute rather than fixed: it belongs to the game screen, not to the
   window, and a fixed bar would sit over the result screen and the mode
   picker too. `has-review` on the screen reserves its height so the keys are
   never underneath it — reserving unconditionally would leave a strip of dead
   space through the first question of every run, before there is anything to
   review. */
/* ONE number, used twice and never written twice. The bar needs its height
   reserved above the keys so the last answer is not sitting behind it, and
   taken off the photograph so the screen does not grow past the viewport to
   pay for it. Two literals would drift, and the symptom would be a key half
   hidden on one phone only. */
#screen-game { position: relative; --bar-h: 4.4rem; }
#screen-game.has-review .gtc-play { padding-bottom: var(--bar-h); }

.gtc-review {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 20;
  /* Three columns so the middle one is centred against the BAR, not against
     whatever is left over beside the chevron. The two 1fr rails are equal and
     empty on the left, which is what keeps the text optically centred instead
     of nudged left by the chevron's width. minmax(0,1fr) rather than 1fr, or
     a long landmark name refuses to shrink and pushes the chevron off. */
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  padding: 0.8rem clamp(0.8rem, 3vw, 1.4rem);
  /* Slightly lifted off the ground rather than a different colour: the screen
     is nearly black, and the bar has to read as part of it while still being
     obviously a separate surface you can press. The hairline does most of that
     work; the fill is barely two steps up. */
  background: var(--panel-raised);
  border: 0;
  border-top: 1px solid var(--chalk-3);
  /* The shadow is the separation the colours cannot give on a near-black
     screen. Upward only, and short, so it reads as a lifted edge rather than
     as a glow. */
  box-shadow: 0 -8px 20px -10px rgba(0, 0, 0, 0.85);
  color: var(--chalk);
  text-align: left;
  cursor: pointer;
  font: inherit;
  transition: background 160ms;
}
.gtc-review:hover,
.gtc-review:focus-visible { background: var(--panel-lit); outline: none; }

.gtc-review-left {
  grid-column: 2;
  display: flex; align-items: center; gap: 0.6rem; min-width: 0;
}
.gtc-review-chevron-cell { grid-column: 3; justify-self: end; }
.gtc-review-thumb {
  width: 34px; height: 42px;
  flex: 0 0 34px;
  border-radius: 1px;
  overflow: hidden;
  background: rgba(255,255,255,0.06);
}
.gtc-review-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.gtc-review-text { display: flex; align-items: baseline; gap: 0.5rem; min-width: 0; }
.gtc-review-label {
  font-family: var(--code-face);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  flex-shrink: 0;
}
/* The verdict is already on the keys in green and red. Here it is a word with
   a tint, not a block of colour: a full-width red bar after every wrong answer
   is the game shouting at somebody who is still playing. */
.gtc-review.is-right .gtc-review-label { color: var(--jade-lit); }
.gtc-review.is-wrong .gtc-review-label { color: var(--rust-lit); }

/* The one line that must never wrap. A landmark name is long, a phone is
   narrow, and a bar that grows to two lines pushes the keys up mid-run. */
.gtc-review-title {
  font-size: 1rem;
  /* 6.7:1 against the raised panel, up from 9.3:1. The title is the payload;
     the label beside it is already carrying a tint, so this is the one that
     should be plainly bright. */
  color: var(--chalk);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.gtc-review-chevron {
  grid-column: 3;
  justify-self: end;
  font-size: 1.5rem;
  color: var(--chalk-2);
  line-height: 1;
}
.gtc-review:hover .gtc-review-chevron { color: var(--amber); }

@media (max-height: 640px) {
  #screen-game { --bar-h: 3.7rem; }
  .gtc-review { padding: 0.55rem clamp(0.6rem, 3vw, 1rem); }
  .gtc-review-thumb { width: 28px; height: 34px; flex-basis: 28px; }
  .gtc-review-title { font-size: 0.92rem; }
}

/* ============================== the game screen, on a phone held sideways
   844x390 is 844 pixels wide and the screen was stacking everything in one
   column 550 pixels tall, so a third of the game sat below the fold and the
   answers had to be scrolled to. This predates the review bar — 135px of
   overflow before it existed, which nobody had measured — and the bar made it
   25px worse, which is what sent me looking.

   The fix is not to shrink five things until they fit. It is to stop wasting
   half the screen: short and wide puts the photograph beside the answers
   instead of above them, which is the shape the device is actually offering.

   Both conditions matter. `max-height` alone would do this to a narrow phone
   in portrait; `min-width` alone would do it to a desktop window. It is the
   combination that means "landscape phone or a very short laptop window". */
@media (max-height: 560px) and (min-width: 44rem) {
  #screen-game {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr) auto;
    /* `1fr` has to divide something. Without a ceiling the grid grew to fit its
       rows instead of the rows fitting the grid, so the moment the review bar
       filled its row the whole screen got 69px taller and hung off the bottom.
       The row is only flexible relative to a container that is not. */
    max-height: 100dvh;
    align-items: center;
    column-gap: clamp(0.6rem, 2vw, 1.4rem);
  }
  #screen-game > .gtc-board { grid-column: 1 / -1; grid-row: 1; }
  #screen-game > .gtc-plate {
    grid-column: 1; grid-row: 2;
    /* In the two-column layout the row is the constraint, not a
       fraction of the viewport, so the cap comes off. */
    height: 100%; max-height: none; min-height: 0;
  }
  #screen-game > .gtc-quad  { grid-column: 1; grid-row: 2; }
  #screen-game > .gtc-play  {
    grid-column: 2; grid-row: 2;
    max-width: none;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.4rem clamp(0.6rem, 2vw, 1rem);
  }
  #screen-game > .gtc-review { grid-column: 1 / -1; grid-row: 3; position: static; }
  /* Reserving space for a bar that now has a row of its own would push the
     grid taller than the viewport again. */
  #screen-game.has-review .gtc-play { padding-bottom: 0.4rem; }

  .gtc-plate img { height: 100%; width: 100%; object-fit: cover; }
  .gtc-ask { margin: 0.1rem 0; }
  /* The clock is the one thing that must stay readable at a glance while the
     eye is on the photograph, so it shrinks least. */
  .gtc-timer-value { font-size: 1.5rem; }
  .gtc-wild { padding: 0.3rem 0.5rem; }
  .gtc-keys { gap: 0.4rem; }
}

/* Small phone, portrait — 320x568 and anything near it.
   The keys go two-column at 23rem, so below that they stack four deep and the
   screen ran 100px past the fold. That was true before the review bar existed
   and nobody had measured it; the bar made it 14px BETTER, because it takes
   its room out of the photograph.

   Two columns here would be the obvious fix and is the wrong one: at 320px
   each key would be about 150px wide and "Saint Petersburg" does not fit in
   150px. So the photograph gives up the height instead. It is the element with
   the most to spare — a landmark is still recognisable at 12rem, and a city
   name that wraps mid-word is not still readable. */
@media (max-height: 620px) and (max-width: 26rem) {
  /* 29.5rem here rather than 33: this block has already compacted the
     clock, the wildcards and the gaps, so less has to fit below. */
  .gtc-plate { --plate-h: min(28dvh, 10.2rem, calc(100dvh - 29.5rem)); }
  .gtc-play { gap: 0.55rem; padding-top: 0.6rem; }
  .gtc-ask { margin: 0.15rem 0; }
  .gtc-timer-value { font-size: 1.6rem; }
  .gtc-wild { padding: 0.35rem 0.4rem; }
}
