/* ------------------------------------------------------------------ */
/*  A Small Puzzle                                                     */
/* ------------------------------------------------------------------ */

:root {
  /* Newsprint. A light scheme, close to the paper a mini is printed on.
     Every colour the page draws lives here — the theme lab in admin mode
     writes these same names, so anything you settle on there pastes back
     into this block. */
  --ink:        #f7f7f4;   /* the page */
  --glow:       #ffffff;   /* wash behind everything */
  --ink-soft:   #ffffff;   /* raised panels */
  --ink-line:   #dcdcd6;   /* panel edges, grid rules */
  --text:       #16171c;
  --text-dim:   #63646d;
  --faint:      #8a8b93;   /* dimmest legible text */
  --fainter:    #b4b5bb;   /* separators */
  --hair:       #cfcfc9;   /* hairlines under empty banner slots */

  --paper:      #ffffff;   /* an empty square */
  --paper-dim:  #ecece7;
  --block:      #6f7178;   /* black squares — grey, not black; on a light
                              page a true black reads as a hole punched
                              through it */
  --cell-ink:   #16171c;   /* the letters */
  --cell-num:   #6c6d75;   /* the little clue numbers */

  /* Three cell states that have to read apart at a glance. The active entry
     separates by hue, the cursor by saturation, and the solved wash gets its
     own tone so it can't be mistaken for the cursor sitting still. */
  --cell-entry:  #a7d8f5;
  --cell-cursor: #f5d547;
  --cursor-ring: #c9a91a;
  --cell-solved: #cdeccd;
  --solved-ring: #8cc08c;

  --amber:      #1a6fd4;   /* accent. Named for the dark scheme it came from */
  --amber-soft: #14477f;   /* the same accent where it carries large text */
  --rose:       #c0392b;
  --key-bg:     #dcdce2;   /* keyboard caps */

  /* Spectral and Space Grotesk, from Google Fonts. The <link> lives in the
     head of index.html — without it these fall through to the local faces
     listed after them. This is the one thing in the puzzle that needs the
     network; everything else is served from the same origin. */
  --serif: Spectral, "Iowan Old Style", Palatino, Georgia, serif;
  --sans:  "Space Grotesk", ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;

  --cell: clamp(48px, 15.5vw, 74px);
  --gap: 2px;
}

/* Newsprint, after dark. The same page at night rather than a different
   design: neutral greys instead of neutral off-whites, the same blue accent
   lifted until it carries on a dark ground, and the three cell states
   holding the same hue relationships — blue entry, yellow cursor, green
   solved — at the saturations that survive white letters sitting on them.
   The squares go dark and the letters go light, the way a mini reads in a
   dark app; a white grid on a black page would be a lamp in the face.

   Which of the two is in force is written on <html> as data-theme by the
   little script in the head of index.html, before the first paint. */
:root[data-theme="dark"] {
  --ink:        #14151a;
  --glow:       #1d1f27;
  --ink-soft:   #1b1d24;
  --ink-line:   #454854;   /* the rules between squares. Lighter than either
                              kind of square, so the grid is drawn by its
                              lines here rather than by its fill */
  --text:       #eceded;
  --text-dim:   #a0a2ac;
  --faint:      #74767f;
  --fainter:    #55575f;
  --hair:       #43454e;

  --paper:      #2e313a;
  --paper-dim:  #24262d;
  --block:      #08090c;   /* and here a near-black square is right: on a
                              dark page it reads as a gap, not a hole */
  --cell-ink:   #f2f3f5;
  --cell-num:   #9698a2;

  /* Entry and solved stay dark and take white letters — a grid that lights
     up all the way is a lamp in the face at 1am. The cursor is the one
     bright thing on the board, and it takes dark letters instead. */
  --cell-entry:  #2c5a86;
  --cell-cursor: #e0bb45;
  --cursor-ring: #a8871f;
  --cell-solved: #2b5233;
  --solved-ring: #4e8a5c;

  --amber:      #6cb0f5;
  --amber-soft: #a8d3fb;
  --rose:       #e0736e;
  --key-bg:     #313440;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  min-height: 100%;
  background: var(--ink);
  color: var(--text);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}

body {
  background:
    radial-gradient(1100px 620px at 50% -12%, var(--glow) 0%, transparent 62%),
    var(--ink);
  overscroll-behavior: none;
}

/* The input that summons the mobile keyboard. It has to stay focusable
   and very nearly visible — iOS won't raise the keyboard for a field that
   is display:none, opacity:0, or behind a negative z-index. */
#keytrap {
  position: fixed;
  top: 0; left: 0;
  width: 1px; height: 1px;
  opacity: .01;
  border: 0; padding: 0;
  background: transparent;
  color: transparent;
  caret-color: transparent;
  font-size: 16px;          /* stops iOS zooming on focus */
  pointer-events: none;
}

/* ─────────────  the light/dark switch  ─────────────

   Fixed to the top-right corner, so it is on every screen and in the way of
   none of them — the admin link owns the opposite corner. It shows where it
   would take you rather than where you are: a moon on the light page, a sun
   on the dark one. Both glyphs are in the markup and CSS picks between them,
   so the right one is on screen at first paint without waiting for app.js. */

.scheme-toggle {
  position: fixed;
  top: calc(8px + env(safe-area-inset-top));
  right: 8px;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  appearance: none;
  border: 1px solid var(--ink-line);
  border-radius: 50%;
  background: var(--ink-soft);
  color: var(--text-dim);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color .18s ease, border-color .18s ease, background .18s ease;
}
.scheme-toggle:hover, .scheme-toggle:focus-visible {
  color: var(--amber);
  border-color: var(--amber);
  outline: none;
}
.scheme-toggle .glyph { transform: translateY(-.02em); }

:root[data-theme="dark"] .scheme-toggle .to-dark,
:root:not([data-theme="dark"]) .scheme-toggle .to-light { display: none; }

#app {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

/* ─────────────  screens  ───────────── */

.screen {
  display: none;
  flex: 1;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 28px 20px calc(28px + env(safe-area-inset-bottom));
  gap: 18px;
}
.screen.is-active {
  display: flex;
  animation: fade-up .5s cubic-bezier(.2,.7,.3,1) both;
}

@keyframes fade-up {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ─────────────  cover / interstitial  ───────────── */

.cover {
  max-width: 30rem;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

.eyebrow {
  margin: 0;
  font-size: .72rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--amber);
}

/* The cover photograph — same paper-and-shadow treatment as the reveal
   snapshots, sized off the viewport so the title and Begin button still
   clear the fold on a short phone. */
.cover-photo {
  margin: 0;
  padding: 9px 9px 11px;
  background: var(--paper);
  border-radius: 2px;
  box-shadow: 0 18px 38px -18px #000;
  transform: rotate(-1.4deg);
  max-width: min(100%, 16rem);
}
.cover-photo img {
  display: block;
  width: 100%;
  max-height: min(44dvh, 380px);
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 38%;
  background: var(--paper-dim);
}

.cover-title {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(2.4rem, 11vw, 3.6rem);
  line-height: 1.05;
  letter-spacing: -.01em;
}

.cover-note {
  margin: 0;
  color: var(--text-dim);
  font-size: .95rem;
  line-height: 1.65;
}

.cover-fine {
  margin: 6px 0 0;
  font-size: .72rem;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.cover-fine a {
  color: var(--faint);
  text-decoration: none;
  border-bottom: 1px solid var(--hair);
  padding-bottom: 1px;
}
.cover-fine a:hover { color: var(--text-dim); }

.btn {
  margin-top: 8px;
  appearance: none;
  border: 1px solid var(--amber);
  background: transparent;
  color: var(--amber);
  font-family: var(--sans);
  font-size: .78rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  padding: 13px 34px;
  border-radius: 2px;
  cursor: pointer;
  transition: background .22s ease, color .22s ease;
}
.btn:hover, .btn:focus-visible {
  background: var(--amber);
  color: var(--ink);
  outline: none;
}

@keyframes write-in {
  from { opacity: 0; letter-spacing: .34em; filter: blur(6px); }
  to   { opacity: 1; letter-spacing: .06em; filter: none; }
}

/* ─────────────  puzzle header  ───────────── */

.puz-head {
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.puz-count {
  margin: 0;
  font-size: .68rem;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--faint);
}
.puz-count .of { color: var(--fainter); }

.puz-clock {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: .08em;
  color: var(--text-dim);
}
.puz-clock::before {
  content: '·';
  margin: 0 .6em;
  color: var(--fainter);
}

.puz-title {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.5rem, 6.5vw, 2rem);
  letter-spacing: .01em;
}

.puz-card {
  margin: 0;
  min-height: 1.1em;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1rem, 4vw, 1.18rem);
  line-height: 1.35;
  color: var(--amber);
  opacity: .9;
}

/* ─────────────  grid  ───────────── */

.grid-wrap {
  padding: 10px;
  border-radius: 4px;
  background: var(--ink-soft);
  box-shadow: 0 20px 50px -28px #000, inset 0 0 0 1px var(--ink-line);
}
.grid-wrap.narrow { padding: 8px; }

.grid {
  display: grid;
  grid-template-columns: repeat(5, var(--cell));
  grid-auto-rows: var(--cell);
  gap: var(--gap);
  background: var(--ink-line);
  padding: var(--gap);
  touch-action: manipulation;
}
.grid-final { grid-template-columns: repeat(3, var(--cell)); }

.cell {
  position: relative;
  background: var(--paper);
  color: var(--cell-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--sans);
  font-weight: 600;
  font-size: calc(var(--cell) * .52);
  line-height: 1;
  cursor: pointer;
  user-select: none;
  transition: background .12s ease;
}

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

.cell.in-entry { background: var(--cell-entry); }
.cell.is-cursor {
  background: var(--cell-cursor);
  box-shadow: inset 0 0 0 2px var(--cursor-ring);
}

/* The dark scheme's cursor is a bright square in a dark grid, so the letter
   standing on it flips to the colour of the page. Safe to scope to the
   cursor: app.js drops the class the moment the mini is solved, so this
   never lands on the solved wash. */
:root[data-theme="dark"] .cell.is-cursor { color: var(--ink); }

.cell .num {
  position: absolute;
  top: 2px; left: 4px;
  font-size: calc(var(--cell) * .21);
  font-weight: 600;
  color: var(--cell-num);
  line-height: 1;
}

.cell .ltr {
  transform: translateY(.04em);
  animation: pop-in .16s ease-out;
}

@keyframes pop-in {
  from { opacity: .2; transform: translateY(.04em) scale(.7); }
  to   { opacity: 1;  transform: translateY(.04em) scale(1); }
}

/* wrong letters shake and refuse to lock in */
.cell.is-wrong { animation: shake .34s cubic-bezier(.36,.07,.19,.97) both; }

@keyframes shake {
  10%, 90% { transform: translateX(-1.5px); }
  20%, 80% { transform: translateX(3px); }
  30%, 50%, 70% { transform: translateX(-5px); }
  40%, 60% { transform: translateX(5px); }
}

.grid.is-solved .cell:not(.is-block) {
  background: var(--cell-solved);
  box-shadow: inset 0 0 0 1px var(--solved-ring);
  transition: background .45s ease, box-shadow .45s ease;
}

/* ─────────────  clue bar  ───────────── */

.dock {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
}

.cluebar {
  display: flex;
  align-items: center;
  gap: 12px;
  width: min(100%, 30rem);
  min-height: 3.2rem;
  padding: 12px 16px;
  border-radius: 3px;
  background: var(--ink-soft);
  box-shadow: inset 0 0 0 1px var(--ink-line);
}
.cluebar.solo { justify-content: center; }

.clue-body {
  flex: 1;
  display: flex;
  align-items: baseline;
  gap: 12px;
  min-width: 0;
}

/* Hidden on desktop, where the clue-nav row below does this job. */
.clue-arrow {
  display: none;
  flex: none;
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--sans);
  font-size: 1.4rem;
  line-height: 1;
  width: 40px;
  height: 44px;
  cursor: pointer;
}
.clue-arrow:active { color: var(--text); }

.clue-label {
  flex: none;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  color: var(--amber);
}

.clue-text {
  font-family: var(--serif);
  font-size: 1.02rem;
  line-height: 1.4;
}

/* ─────────────  clue nav  ───────────── */

.clue-nav {
  display: flex;
  gap: 8px;
  align-items: stretch;
}

.nudge {
  appearance: none;
  border: 1px solid var(--ink-line);
  background: var(--ink-soft);
  color: var(--text-dim);
  font-family: var(--sans);
  font-size: .95rem;
  min-width: 44px;
  padding: 8px 12px;
  border-radius: 3px;
  cursor: pointer;
  transition: color .18s ease, border-color .18s ease;
}
.nudge.wide {
  min-width: 108px;
  font-size: .7rem;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.nudge:hover, .nudge:focus-visible {
  color: var(--text);
  border-color: var(--key-bg);
  outline: none;
}

/* ─────────────  keyboard  ─────────────

   Only on touch devices. The native keyboard is 40% of a phone screen, an
   unpredictable 40%, and it lands squarely on top of the clue — so on a
   phone we bring our own and never summon theirs. */

.kbd { display: none; }

.kbd-row {
  display: flex;
  justify-content: center;
  gap: var(--key-gap);
}

.key {
  flex: 1 1 0;
  min-width: 0;
  max-width: 46px;
  height: var(--key-h);
  appearance: none;
  border: 0;
  border-radius: 5px;
  background: var(--key-bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 1.05rem;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  touch-action: manipulation;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.key.is-down { background: var(--amber); color: var(--ink); }
.key.wide { flex: 1.6 1 0; max-width: 68px; font-size: 1.2rem; }

/* ─────────────  touch layout  ─────────────

   The clue and the keyboard sit on the floor of the viewport; the grid and
   banner get the room that's left. Cells shrink a little to pay for it. */

@media (hover: none) and (pointer: coarse) {
  :root {
    --cell: clamp(38px, 12.4vw, 62px);
    --key-h: 46px;
    --key-gap: 5px;
  }

  .kbd {
    display: flex;
    flex-direction: column;
    gap: var(--key-gap);
    width: 100%;
    padding: 6px 4px;
  }

  .clue-arrow { display: block; }

  /* The direction toggle is redundant here — tapping the active square
     already flips it, the same way the NYT mini does. */
  #screen-puzzle .clue-nav { display: none; }

  .dock {
    position: fixed;
    left: 0; right: 0;
    /* Stand on top of the admin bar while it's open; flat on the floor
       otherwise. --admin-h is published by app.js. */
    bottom: var(--admin-h, 0px);
    z-index: 5;
    gap: 6px;
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--ink);
    box-shadow: 0 -18px 30px -22px #000;
  }

  .cluebar {
    width: 100%;
    border-radius: 0;
    padding: 10px 4px;
    min-height: 3rem;
    box-shadow: none;
    background: transparent;
    border-bottom: 1px solid var(--ink-line);
  }
  .clue-text { font-size: .98rem; }

  /* Room for the dock, so the banner never hides underneath it. */
  #screen-puzzle {
    justify-content: flex-start;
    gap: 12px;
    padding-top: 12px;
    padding-bottom: calc(12px + var(--dock-h, 250px) + var(--admin-h, 0px));
  }

  /* The final screen keeps the dock too — three squares still need typing. */
  #screen-question { padding-bottom: calc(12px + var(--dock-h, 250px) + var(--admin-h, 0px)); }

  .grid-wrap { padding: 8px; }
}

/* Short phones — an SE is 667px tall and the dock alone wants 200 of them.
   Everything gives up a little so the whole puzzle stays on one screen
   without scrolling. */
@media (hover: none) and (pointer: coarse) and (max-height: 720px) {
  :root {
    --cell: clamp(34px, 11.2vw, 56px);
    --key-h: 40px;
  }

  .puz-title { font-size: clamp(1.3rem, 5.6vw, 1.7rem); }
  .puz-card  { font-size: .98rem; }
  .key       { font-size: .98rem; }

  #screen-puzzle { gap: 10px; }
  .cluebar { min-height: 2.7rem; padding: 8px 4px; }
  .clue-text { font-size: .92rem; }
}

/* ─────────────  banner  ───────────── */

.banner {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 14px;
  margin-top: 4px;
  min-height: 30px;
}

/* One mark per mini. Empty until earned, and saying nothing either way —
   the letters and the lengths that used to live here were the leak. */
.seal {
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--hair);
  border-radius: 2px;
  background: transparent;
  transition: background .55s ease, border-color .55s ease;
}

.seal.is-filled {
  background: var(--amber-soft);
  border-color: var(--amber-soft);
}

/* Only the one she just earned pops; see renderBanner in app.js. */
.seal.is-just-filled { animation: seal-in .55s cubic-bezier(.2,.8,.3,1); }

@keyframes seal-in {
  from { transform: scale(.55); }
  60%  { transform: scale(1.18); }
  to   { transform: scale(1); }
}

/* ─────────────  the question  ───────────── */

.question { gap: 22px; }

.q-banner {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: .12em;
  min-height: 1.3em;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.7rem, 8.5vw, 2.9rem);
  line-height: 1.15;
  color: var(--amber-soft);
  letter-spacing: .01em;
}

/* ── the envelopes ──

   Closed, each is a small square sitting in a wider box: the box is what
   gives the row its spacing, so nothing has to shuffle sideways when a word
   arrives. Opening sets the box to the measured width of the word (app.js)
   and the word unfurls out of the clip. */

.q-seal {
  position: relative;
  flex: none;
  width: 2.3em;
  height: 1.2em;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
  overflow: hidden;
  -webkit-tap-highlight-color: transparent;
  /* The word inside a sealed envelope is only hidden by opacity. Without
     this, a long press could drag a selection across it and light up the
     one thing on the page that isn't ready to be read. */
  -webkit-user-select: none;
  user-select: none;
  transition: width .55s cubic-bezier(.2,.8,.3,1);
}
.q-seal.is-open { cursor: default; }
.q-seal:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

.q-face {
  position: absolute;
  left: 50%; top: 50%;
  width: .66em; height: .66em;
  margin: -.33em 0 0 -.33em;
  border-radius: .05em;
  background: var(--amber-soft);
  opacity: .32;
  transition: opacity .3s ease, transform .5s cubic-bezier(.2,.8,.3,1);
}

/* The one she can open is the bright one. It breathes as well, but the
   brightness is what carries when motion is turned down. */
.q-seal.is-next .q-face {
  opacity: 1;
  animation: seal-breathe 1.9s ease-in-out infinite;
}

.q-seal.is-open .q-face {
  opacity: 0;
  transform: scale(2.4);
  animation: none;
}

@keyframes seal-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.16); }
}

.q-seal .q-word {
  position: absolute;
  left: 0; top: 50%;
  transform: translateY(-50%);
  white-space: pre;
  opacity: 0;
  filter: blur(6px);
  transition: opacity .5s ease .1s, filter .5s ease .1s;
}
.q-seal.is-open .q-word { opacity: 1; filter: none; }

.q-mark {
  margin-left: -.12em;      /* cancel the row gap so it hugs the last word */
  opacity: 0;
  transition: opacity .5s ease .35s;
}
#screen-question.is-asked .q-mark { opacity: 1; }

.q-hint {
  margin: 0;
  font-size: .72rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--faint);
  transition: opacity .5s ease;
}
.q-hint.is-gone { opacity: 0; }

/* Tap or click, depending on what she's holding. This pair has to live
   here rather than up in the touch block — that block comes earlier in the
   file, and at equal specificity the last rule wins. */
.q-hint .tap { display: none; }
@media (hover: none) and (pointer: coarse) {
  .q-hint .tap   { display: inline; }
  .q-hint .click { display: none; }
}

/* The squares and the keyboard stay away until she has opened all four —
   and stay untappable while they're invisible. */
#screen-question .grid-wrap,
#screen-question .cluebar,
#screen-question .dock {
  opacity: 0;
  pointer-events: none;
}
#screen-question.is-asked .grid-wrap,
#screen-question.is-asked .cluebar,
#screen-question.is-asked .dock {
  pointer-events: auto;
  animation: fade-up .6s cubic-bezier(.2,.7,.3,1) both;
  animation-delay: .85s;
}

.yes-word {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(4rem, 24vw, 8rem);
  line-height: 1;
  color: var(--amber-soft);
  animation: write-in 1s cubic-bezier(.2,.8,.3,1) both;
}


/* ─────────────  times  ─────────────
   The clock never shows while she is solving — it turns up afterwards,
   on the interstitial, as a souvenir rather than a pressure. */

/* Her time is the interstitial now — the word she'd earned used to sit
   above it in 5rem serif, which gave the game away four minis early. */
.tween-time {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: clamp(2.4rem, 13vw, 3.6rem);
  letter-spacing: .06em;
  color: var(--amber);
  animation: write-in .8s cubic-bezier(.2,.8,.3,1) both;
}

.times {
  width: min(100%, 22rem);
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .85rem;
  color: var(--text-dim);
}
.times li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 0;
  border-bottom: 1px solid var(--ink-soft);
}
.times li:last-child {
  border-bottom: 0;
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px solid var(--hair);
  color: var(--amber-soft);
}
.times .label { text-align: left; }

.share-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.share-note {
  margin: 0;
  min-height: 1.1em;
  font-size: .72rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* ─────────────  photographs  ─────────────
   They fall in one after another, each landing at a slight angle, the way
   a handful of prints would if you dropped them on a table. */

.photos {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  /* Narrow enough that four prints land two-by-two rather than three
     across with an orphan underneath. */
  width: min(100%, 30rem);
  margin-top: 6px;
}

.photo {
  /* 42vw keeps two per row with the gap on a 360px phone. */
  width: clamp(140px, 42vw, 208px);
  padding: 10px 10px 32px;
  background: var(--paper);
  border-radius: 2px;
  box-shadow: 0 14px 30px -14px #000;
  transform: rotate(var(--tilt)) translateY(-14px);
  opacity: 0;
  animation: drop-in .62s cubic-bezier(.2,.8,.3,1) forwards;
  animation-delay: var(--delay);
}
.photo img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  background: var(--paper-dim);
}

@keyframes drop-in {
  from { opacity: 0; transform: rotate(0deg) translateY(-26px) scale(.94); }
  to   { opacity: 1; transform: rotate(var(--tilt)) translateY(0) scale(1); }
}

@media (max-width: 380px) {
  .banner { gap: 11px; }
  .seal { width: 16px; height: 16px; }
  .screen { padding-left: 14px; padding-right: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    /* Kill the staggers too — the words of the question, the photographs
       falling in. Without this the animations collapse but their delays
       don't, and the question screen sits empty for the best part of two
       seconds before anything shows up. */
    animation-delay: 0s !important;
  }
}
