/* analyzer-only styles, layered on site.css */

/*
 * 700px used to be the floor, on the reasoning that panning the whole page beat
 * a table scrolling inside a stationary layout. That traded away phones, which
 * is the wrong trade for a tool people reach for while looking at a puzzle, so
 * 700px is now an inflection point rather than a wall: below it the table sheds
 * columns and the clamped fields are given more lines (see the foot of this
 * file). The remaining floor is set by the rules panel, where a right-aligned
 * count and a left-aligned name eventually meet.
 */
body { min-width: 320px; }

:root {
  /* Four pastels at close to equal lightness, so a square split into bands
     reads as several rules rather than one muddy new color. */
  /* Chosen by simulating protanopia, deuteranopia and tritanopia and keeping
     the set whose closest pair stays furthest apart under all three: worst-case
     ΔE 14.9, against 1.9 for the blue/violet pair this replaces. All four are
     light enough for black letters and clearly distinct from the white grid. */
  --hl-lowscore: #efc29e;
  --hl-rare:     #d3c7e7;
  --hl-proper:   #c7eae0;
  --hl-abbrev:   #fcf9d5;

  /* The selected answer is hatched rather than outlined, so it reads on top of
     any fill without spending another colour. */
  --hatch: repeating-linear-gradient(45deg,
             rgba(64, 64, 64, 0.42) 0 1.4px, transparent 1.4px 5px);

  --select:      #6d4ade;
}

/* --------------------------------------------------------------- dropzone */

.dropzone {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 14px 16px;
  /* The same measure the text pages use, so the two read as one site. */
  max-width: 76ch;
  margin-inline: auto;
  margin-bottom: 14px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-sunk);
}

/* `display: flex` above would otherwise beat the UA's [hidden] rule. */
.dropzone[hidden] { display: none; }

.dropzone.is-over {
  border-color: var(--select);
  background: var(--lav-soft);
}

.dropzone__text { color: var(--muted); font-size: 12.5px; }

.status { margin: -4px auto 12px; max-width: 76ch; font-size: 12.5px; color: var(--muted); }
.status--error { color: #b42318; }

.puzzle-meta {
  margin: 12px 0 0;
  font-size: 12.5px;
  color: var(--ink-soft);
}

.puzzle-meta strong { color: var(--ink); }

/* The page's prose leading is deliberately open, but these are data displays
   rather than paragraphs and only get taller for it. */
.rules,
.statlist,
.selected,
.answers,
.multi__menu,
.scope { line-height: 1.5; }

.rule { line-height: 1.35; }

/* ------------------------------------------------------------ grid layout */

.split {
  display: grid;
  /* Fixed, not fluid: 750 + 14 + 384 = 1148, the card's content width. The
     split was found by experiment -- the square grid block's height has to
     equal the four right-hand blocks stacked, and the right column has to stay
     wide enough that the busiest answer's venue chips still fit the card.
     Every panel is placed by name, in every band. There is no wrapper element
     around the right-hand blocks: one used to hold them and had to be undone
     with `display: contents` wherever they paired off differently, which is
     both fragile and invisible in the markup. Areas cost four lines a band and
     say exactly where everything goes. */
  grid-template-columns: 750px 384px;
  grid-template-rows: auto auto auto 1fr auto;
  grid-template-areas:
    "grid  title"
    "grid  stats"
    "grid  rules"
    "grid  selected"
    "table .";
  gap: 14px;
  align-items: stretch;
  margin-bottom: 14px;
}

/* min-width:0 so the table's scroller can shrink; a grid item defaults to
   min-width:auto and would otherwise stretch to its content. */
.split > * { min-width: 0; margin-bottom: 0; }

/* Square, and sized by its own width, so a 15x15 and a 21x21 sit in the same
   box. JS sets the height; `start` keeps it square rather than stretching it to
   whatever the blocks beside it come to. */
/* Which shape the block takes, read by fitGrid. `square` wherever a column of
   blocks sits beside the grid, so the two agree on a height; `fit` wherever the
   grid has the width to itself and a short puzzle can give the page its slack
   back. Declared here rather than as a breakpoint in the script, so the two
   cannot drift apart. */
.panel--grid     { grid-area: grid; align-self: start; --grid-box: square; }
.panel--table    { grid-area: table; }
.panel--title    { grid-area: title; }
.panel--stats    { grid-area: stats; }
.panel--rules    { grid-area: rules; }
/* `start`, never the default stretch: the card sizes to its own content in
   every band, so a short clue does not leave a field of white below it inside
   the box. Wherever its row is taller -- the `1fr` at desktop, or a taller
   block paired beside it -- the leftover is card background, not card. */
.panel--selected { grid-area: selected; align-self: start; }

/* The grid fills the square, so a square puzzle sits snugly in it. */
.panel--grid > .panel__body {
  display: flex;
  height: 100%;
}

/* Two columns still, but reproportioned. Going straight from the 750/384 split
   to a single column made the grid as wide as the page -- over 1100px at 1240,
   a screenful of grid to scroll past before anything else appeared. Here the
   grid is capped well under that and the table, no longer boxed into the grid's
   column, spans the whole width. The band is narrow on purpose: see the columns
   below for why it cannot reach further down. */
@media (max-width: 1239px) and (min-width: 1010px) {
  .split {
    /* Measured, the same way the desktop split was. The grid spans rows 2-3
       only -- stats sits beside the title, not beside the grid -- so what it
       has to clear is the rules block plus the card:

           grid + 34  >=  215 rules + 14 gap + (card + 34)
           grid       >=  229 + card(side)

       and the card's height is bounded by its own clamps rather than by the
       column, so this is a fixed figure and not a sampled one:

           head        47   min-height 36 + 10 padding + 1 border
           chips       88   .clamp--chips, four rows
           score       22   one line at 12.5px/1.75
           your clue   44   .clamp--2, two lines
           latest clue 44   .clamp--2, two lines
           gaps        28   four at 7
           padding     34   panel padding and border
                      307

       so the rules block at 223 plus a 14px gap plus that card wants a grid of
       at least 509px. An earlier version read 465px off a sampled card of
       236px, which is what a typical card comes to, not what the clamps allow --
       a full one dropped past the grid's foot.

       The floor is 520px with the column at its natural 384px: a 918px content
       area, a 1002px window, and the 1010px below is that with headroom. Above
       1018px of content the grid parks at 620px and the column takes the rest;
       between the two the column holds 384px and the grid gives way. */
    grid-template-columns: minmax(520px, 620px) minmax(384px, 1fr);
    grid-template-rows: auto auto 1fr auto;
    grid-template-areas:
      "title stats"
      "grid  rules"
      "grid  selected"
      "table table";
  }
}

/* Centred, and capped rather than filling the column. Uncapped the grid would
   jump from 620px to the full content width the instant the layout stopped
   being two columns -- growing as the page got narrower, and putting a
   screenful of grid above everything else, which is what this whole range
   exists to avoid. At 520px the grid only ever steps down: 750, 620, 520, then
   with the page. Below about 610px the column is narrower than the cap and it
   stops applying. The cap is 520px because that is what the band above hands
   over at its own floor, so the grid crosses 1010px without changing size.

   Centred with `width: 100%` plus auto margins, never `justify-self: center`.
   Both `justify-self: center` and bare auto margins size a grid item to its
   content, and this item's content is a grid whose width JS has already written
   in pixels: the panel takes that width, `fitGrid` reads it back as the space
   available, and the two agree on a size that never shrinks again -- the grid
   hanging off both edges of a narrowing page. The explicit width breaks that
   loop by measuring the panel against the column. */
@media (max-width: 1009px) {
  /* `width: 100%` is load-bearing, not decoration. Auto margins take priority
     over `stretch`, so on their own they would size the panel to its content --
     and its content is a grid whose width JS has already written in pixels. An
     explicit width keeps the panel measured against the column instead. */
  .panel--grid { width: 100%; max-width: 520px; margin-inline: auto; }

  /* Nothing sits beside the grid from here down -- it spans every column -- so
     a puzzle wider than it is tall may keep its own height. */
  .panel--grid { --grid-box: fit; }
}

/* One shape for the whole middle of the range: the two compact blocks share a
   row above the grid, and the grid and the card each take the full width.

   Stats and the highlight rules need far less width than the card does -- it
   carries a chip per venue -- so they are the pair worth keeping, and the card
   is better off spanning. An earlier version paired the card with the rules
   from 800px up and only fell back to this below, but that put a reshuffle in
   the middle of the range for no gain: this shape reads the same at 1100px as
   at 750px, so there is nothing to reshuffle.

   The floor is the rules row: a checkbox, a swatch, "STWL scores", an operator,
   a dropdown and a right-aligned count come to 262px, so 296px of column with
   the panel's padding and border. Two of those plus the gap need a 606px
   content area, which is a 680px window -- and 700px is where the card drops
   its venue chips for a single total anyway, so the two changes share a
   boundary rather than landing a few pixels apart. */
/* Wide enough for the title to sit in half the width: stacking it above the
   stats puts both beside the rules block instead of spending a full row on a
   two-line title. That is about 75px of height back -- the pair comes to 227px
   against the rules' 215px, where a title row plus a stats/rules row came to
   302px -- and the grid and the card start that much further up the page.

   It stops at 800px rather than carrying on to 700 because the title is the one
   block here whose content is arbitrary: a long puzzle title in half a 700px
   window truncates hard, and it is the first thing the card is read against. */
@media (max-width: 1009px) and (min-width: 800px) {
  .split {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: repeat(5, auto);
    grid-template-areas:
      "title    rules"
      "stats    rules"
      "grid     grid"
      "selected selected"
      "table    table";
  }
}

@media (max-width: 799px) and (min-width: 700px) {
  .split {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: repeat(5, auto);
    grid-template-areas:
      "title    title"
      "stats    rules"
      "grid     grid"
      "selected selected"
      "table    table";
  }
}

/* One column, in reading order. */
@media (max-width: 699px) {
  .split {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(6, auto);
    /* The card sits directly under the grid, as it does in every other band;
       the stats and the highlight rules go above it rather than between the
       two, which left the card reading as unrelated to the grid it describes. */
    grid-template-areas: "title" "stats" "rules" "grid" "selected" "table";
  }
}

/* The side blocks stack against the square's height. The selected-answer card
   sizes to its own content -- an entry with a short clue should not sit in a
   field of white -- and is the only one allowed to shrink, so a long one stops
   at the foot of the grid and scrolls rather than pushing past it. */
/* Only where the square constrains the height. The card sizes to its own
   content -- an entry with a short clue should not sit in a field of white --
   so `align-self: start` rather than filling its row, and `max-height: 100%`
   caps it at the row so a long one scrolls inside instead of pushing past the
   grid's foot. The row is the `1fr`: the grid block spans all four rows at a
   fixed height, the three auto rows take their content, and this one absorbs
   the rest. That used to need a JS-computed max-height on a wrapper.

   Scoped to this band on purpose. As an unscoped rule it sat after the media
   queries and so beat them everywhere, letting the body shrink below its own
   content at widths where nothing was constraining it -- the card's lower rows
   spilled out of the bottom of the box. */
@media (min-width: 1240px) {
  .panel--selected {
    max-height: 100%;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  .panel--selected > .panel__body { flex: 0 1 auto; min-height: 0; }
}


/* -------------------------------------------------------------- the grid */

.grid-wrap {
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.grid:focus-visible {
  outline: 2px solid var(--select);
  outline-offset: 3px;
}

.grid {
  container-type: inline-size;
  display: grid;
  gap: 0;
  border: 2px solid var(--ink);
  background: var(--ink);
}

.cell {
  position: relative;
  aspect-ratio: 1;
  background: #fff;
  outline: 1px solid var(--ink);
  outline-offset: -0.5px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  user-select: none;
  overflow: hidden;
}

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

.cell__letter {
  position: relative;
  z-index: 1;
  font-size: calc(100cqw / var(--cols) * 0.5 * var(--shrink, 1));
  line-height: 1;
  font-weight: 500;
  letter-spacing: -0.03em;
  padding-top: calc(100cqw / var(--cols) * 0.14);
  white-space: nowrap;
}

.cell__number {
  position: absolute;
  z-index: 1;
  top: 3%;
  left: 6%;
  font-size: calc(100cqw / var(--cols) * 0.26);
  line-height: 1.1;
  color: var(--ink-soft);
}

.cell__circle {
  position: absolute;
  z-index: 1;
  inset: 6%;
  border: 1px solid var(--ink-soft);
  border-radius: 50%;
  pointer-events: none;
}

/* Sits above whatever bands the square has, below its letter. */
.cell.is-marked::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: var(--hatch);
  pointer-events: none;
}

/* ----------------------------------------------------------- highlighting */

.rules { display: flex; flex-direction: column; gap: 0; }

.rule {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 2px 6px;
  /* The two rules carrying a dropdown are taller than the two without, which
     left the list unevenly spaced; this makes every row the taller one. */
  min-height: 30px;
  border-radius: var(--radius-s);
}

.rule:hover { background: var(--surface-sunk); }

.rule input[type="checkbox"] {
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--btn);
  cursor: pointer;
  flex: none;
}

.rule__swatch {
  width: 15px;
  height: 15px;
  border-radius: 4px;
  border: 1px solid rgba(0, 0, 0, 0.16);
  flex: none;
}

.rule__label { font-size: 12.5px; cursor: pointer; }

/* Comparison operators come off the UI font, not Poppins, so `<` and `≤` match
   each other. Poppins draws `<` small and light and has no `≤` at all, which
   left the two rules disagreeing. Nudged up slightly: at 12.5px the operators
   read smaller than the words around them. */
.rule__op {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  font-size: 13.5px;
}

.rule__count { color: var(--muted); font-size: 12px; margin-left: auto; flex: none; }

.rule select {
  width: auto;
  padding: 2px 22px 2px 7px;
  font-size: 12px;
  background-position: right 8px center, right 4px center;
}

/* -------------------------------------------------- year and venue pickers */

/* The pickers decide what "counts" means, so they sit indented directly
   under that rule rather than in an options panel of their own. */
.scope {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 2px 0 10px 30px;
  font-size: 12.5px;
  color: var(--muted);
}

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

/* A fixed label column lines the two dropdowns up under each other. */
.scope__word { flex: none; width: 5ch; }

/* Sized to their own text, like the dropdowns on the rules above. */
.scope .multi { flex: none; }

.scope .multi__toggle {
  width: auto;
  /* Wide enough for the longest label each can show, so neither is clipped. */
  min-width: 11ch;
  padding: 2px 22px 2px 7px;
  font-size: 12px;
}

#venue-multi .multi__toggle { min-width: 20ch; }

.scope .multi__toggle::after { right: 8px; }


/* venue multi-select */

.multi { position: relative; }

.multi__toggle {
  width: 100%;
  text-align: left;
  font: inherit;
  font-size: 13px;
  background: var(--field);
  border: 1px solid transparent;
  border-radius: var(--radius-s);
  padding: 9px 30px 9px 11px;
  cursor: pointer;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.multi__toggle:hover { background: var(--field-hover); }

.multi__toggle::after {
  content: "";
  position: absolute;
  right: 12px;
  top: 50%;
  border: 4px solid transparent;
  border-top-color: var(--ink-soft);
  margin-top: -1px;
}

.multi__menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  /* Capped against the viewport as well: this is absolutely positioned from a
     control that is itself indented, so a flat 300px hangs off a phone. */
  min-width: min(300px, calc(100vw - 48px));
  max-height: 320px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-s);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
  padding: 8px;
}

.multi__menu[hidden] { display: none; }

.multi__presets {
  display: flex;
  flex-wrap: nowrap;
  gap: 6px;
  padding: 0 2px 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 6px;
}

.multi__presets button {
  white-space: nowrap;
  font: inherit;
  font-size: 11.5px;
  padding: 4px 9px;
  border-radius: 5px;
  border: 1px solid var(--border);
  background: var(--surface);
  cursor: pointer;
  color: var(--ink-soft);
}

.multi__presets button:hover { background: var(--field); }

.multi__opt {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 6px;
  border-radius: 5px;
  font-size: 12.5px;
  cursor: pointer;
}

.multi__opt:hover { background: var(--surface-sunk); }

.multi__opt--pick {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  font-size: 12.5px;
  border: 0;
  background: none;
  color: var(--ink);
}

.multi__opt--pick.is-picked { background: var(--field); font-weight: 500; }

.multi__opt input { accent-color: var(--btn); margin: 0; flex: none; }

.multi__opt code { color: var(--muted); font-size: 11.5px; }

.multi__opt .mini-tag {
  margin-left: auto;
  font-size: 10.5px;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0 4px;
}

/* ----------------------------------------------------------------- table */

.table-scroll { overflow-x: auto; min-width: 0; }

table.answers {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
  /* A floor for the answer column, but never one that exceeds the space we were
     actually given: a bare `72ch` overflows whenever the container is narrower
     than that, which scrolls the table sideways *and* pins the answer column at
     a width it cannot shrink below. `min()` makes the floor yield first. */
  min-width: min(72ch, 100%);
  /* Fixed, so the columns do not jump about as filters change what is in them.
     Widths come from measuring 780 rows: the four narrow columns are set past
     their widest observed content, and the two that wrap split the rest. */
  table-layout: fixed;
}

.answers th {
  text-align: left;
  padding: 0;
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
  position: sticky;
  top: 0;
  background: var(--surface);
}

.sort {
  width: 100%;
  font: inherit;
  font-weight: 500;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 8px 10px;
  text-align: inherit;
  cursor: pointer;
}

.col-num .sort { text-align: right; }
.sort:hover { color: var(--ink); }
.sort.is-sorted { color: var(--ink); }

/* An arrow only on the column actually in use. */
.sort.is-sorted::after { content: " \2191"; }
.sort.is-sorted[data-dir="desc"]::after { content: " \2193"; }

.answers td {
  padding: 5px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  /* Transparent, so the row's own rule colours show through. */
  background: transparent;
}

.answers tbody tr { cursor: pointer; }

/* An overlay rather than a colour, so hovering does not hide the row's bands. */
.answers tbody tr:hover td { box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.04); }

/* The selection is hatched here exactly as it is in the grid. Cell backgrounds
   paint above the row's, and the hatch's gaps are transparent, so the rule
   colours still read through it. */
.answers tbody tr.is-marked td { background-image: var(--hatch); }

/* Fixed narrow columns sized past their widest measured content; the answer
   column takes whatever is left, which keeps it clear of its 24ch minimum. */
/* Widths live on the cells rather than a <colgroup>. A colgroup maps columns to
   cells by position, so hiding a cell with display:none shifted every later
   cell one slot left -- the answer inherited the 5ch key width and the last
   <col> was left with no cell, showing as dead space the table then scrolled to
   reach. Classing the cells removes the mapping and the problem with it. */
.answers .c-key    { width: 5ch; }
.answers .c-length { width: 9ch; }
.answers .c-counts { width: 9ch; }
.answers .c-score  { width: 8ch; }
.answers .c-labels { width: 11ch; }

.col-key    { white-space: nowrap; color: var(--muted); }
/* Takes whatever the sized columns leave, never below ~17ch; the widest
   answer measured was 21.5ch. */
.col-answer { font-weight: 500; }
.col-num    { text-align: right; white-space: nowrap; }

.chip {
  display: inline-block;
  padding: 1px 5px;
  margin: 0 3px 3px 0;
  border-radius: 4px;
  background: var(--field);
  font-size: 11px;
  color: var(--ink-soft);
  white-space: nowrap;
}

.chip--dot { border-left: 3px solid transparent; }

.clue-src { color: var(--muted); font-size: 11px; white-space: nowrap; margin-left: 2px; }

.none { color: var(--muted); }

/* ------------------------------------------ puzzle stats, score breakdown */

/* Two lines, always: a long title or byline is truncated rather than allowed
   to change the block's height. */
.puzzle-title {
  margin: 0;
  max-width: none;
  font-size: 12.5px;
  line-height: 1.45;
}

.puzzle-title strong,
.puzzle-title span {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* min-height keeps both line boxes even when a puzzle carries no title or no
   byline, so the block cannot collapse and unbalance the two columns. */
.puzzle-title strong { font-size: 15px; line-height: 1.4; min-height: 21px; }
.puzzle-title span { color: var(--muted); min-height: 18px; }

.statlist {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 4px 12px;
  font-size: 12.5px;
}

.statlist dt { color: var(--muted); white-space: nowrap; }

.statlist dd {
  margin: 0;
  grid-column: 3;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.statlist .statlist__pct {
  grid-column: 2;
  color: var(--muted);
  text-align: right;
}

/* ------------------------------------------------------ clamped elements */

/* Fixed line counts, so no field can change the height of the block it sits in.
   Where the content is actually cut, `is-truncated` makes it clickable. */
.clamp { overflow: hidden; }

.clamp--1 { white-space: nowrap; text-overflow: ellipsis; }

.clamp--2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* The chips are a wrapping flex row, which -webkit-line-clamp cannot measure,
   so this one is capped by height instead. */
.clamp--chips { max-height: 88px; }   /* four rows of chips */

.clamp.is-truncated { cursor: pointer; }
.clamp.is-truncated:hover { text-decoration: underline dotted var(--border-strong); }

.peek {
  position: absolute;
  z-index: 40;
  max-width: min(360px, calc(100vw - 24px));
  padding: 8px 10px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-s);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}

/* ------------------------------------------------------- selected answer */

/*
 * Fixed height, so picking a different answer cannot resize the grid. The
 * content varies by a line or two with the clue's length, how many venues it
 * has run in, and whether it carries a label chip. These are the measured
 * worst case at each sidebar width plus headroom; the overflow is a safety
 * valve for an unusually long clue, not an expectation.
 */
/* Sized by the column now, not fixed: the grid is square regardless, so the
   card's height cannot feed back into it. */
#selected { overflow-y: auto; }

@media (max-width: 1239px) { #selected { overflow-y: visible; } }

.selected { display: grid; gap: 7px; font-size: 12.5px; }

.selected__head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
  /* Pinned, so the rule and the rows below it do not shift by a couple of
     pixels as you move between answers that do and do not carry a label. */
  min-height: 36px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}

/* The chip's bottom margin is for wrapping lists; in the head it just adds height. */
.selected__head .chip { margin-bottom: 0; }

.selected__key { color: var(--muted); font-size: 12.5px; }

.selected__answer {
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.selected__figures {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px 26px;
}

.selected__stat { display: flex; align-items: baseline; }
.selected__stat span { color: var(--muted); margin-right: 6px; white-space: nowrap; }
.selected__figures b,
.selected__stat b { font-variant-numeric: tabular-nums; }

.selected__row {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.selected__rowlabel {
  flex: none;
  color: var(--muted);
}

.selected__row--note { color: var(--muted); }

.selected__venues { display: flex; flex-wrap: wrap; gap: 0; }

/* One venue chip per publication is the whole point of the card at a width that
   can show them. Below that they take five or six rows and crowd out the score
   and the clue, so a single total stands in for them. Both rows are rendered
   and one is hidden, which keeps it a layout decision rather than something the
   renderer has to know about the viewport. */
.selected__row--total { display: none; }

@media (max-width: 699px) {
  .selected__row--venues { display: none; }
  .selected__row--total { display: flex; }
}



/* ------------------------------------------------- narrow screens (phones)

   Below the old 700px floor the layout keeps going rather than stopping.

   The column widths switch from `ch` to percentages here, and that is the whole
   trick. `table-layout: fixed` honours a specified width even when the table
   has less room than the widths add up to, so `ch` widths overflow -- and since
   they are absolute while the breakpoints are in px, whether they overflow
   depends on how wide the font happens to draw a `0`. Percentages of the table
   can never sum past the space available, so the table always fits and every
   column shrinks smoothly as the page narrows, with no measuring to get wrong.

   Columns still drop, least useful first: `#` is a key the grid already shows,
   `length` is derivable from the answer beside it, and `score` and `label` are
   what a solver came for. Both of those stay in the selected-answer card at
   every width.

   Each drop hands its share to the answer column, so the answer column widens
   at a breakpoint and then resumes shrinking. That step is inherent to dropping
   a column -- the freed width has to go somewhere -- but it is bounded by the
   share being released, and the percentages below keep those shares modest.

   Hiding a column means hiding its class on the th and the td together. Do not
   reintroduce a <colgroup>: columns map to cells by position, so a hidden cell
   pulls every later cell one column to the left and strands the last <col> as
   blank space.
*/

@media (max-width: 699px) {
  /* No absolute floor: the table now fits whatever it is given, so the answer
     column shrinks with the page instead of the page scrolling under it. */
  .answers { min-width: 0; }

  /* `#` -- the grid already labels every entry. */
  .answers .c-key { display: none; }

  /* Chosen so the sized columns take about what their `ch` widths took just
     above 700px -- otherwise the answer column would leap on crossing the
     breakpoint -- and so each one stays near its content at the narrow end of
     the band: the label column bottoms out around 62px against a chip that
     needs about 48px. */
  .answers .c-length { width: 11%; }
  .answers .c-counts { width: 11%; }
  .answers .c-score  { width: 10%; }
  .answers .c-labels { width: 13%; }

  /* More room before the ellipsis. */
  .puzzle-title strong,
  .puzzle-title span {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }

  .clamp--2 { -webkit-line-clamp: 4; }
  .clamp--chips { max-height: 154px; }   /* seven rows of chips */
}

@media (max-width: 560px) {
  /* `length` -- the answer is in the next column; counting it is not hard. */
  .answers .c-length { display: none; }

  .answers .c-counts { width: 13%; }
  .answers .c-score  { width: 12%; }
  .answers .c-labels { width: 15%; }
}

@media (max-width: 480px) {
  /* The rules are a single flex row with the match count pushed right by
     `margin-left: auto`. Once the row cannot hold name, operator, dropdown and
     count at once, let it wrap instead of letting the count ride up against
     the dropdown. */
  .rule { flex-wrap: wrap; row-gap: 2px; }
  .scope { margin-left: 14px; }
  .scope__row { flex-wrap: wrap; }
}

@media (max-width: 430px) {
  /* `label` -- the chip costs the most width of the three, and the
     selected-answer card still names it. */
  .answers .c-labels { display: none; }

  .answers .c-counts { width: 17%; }
  .answers .c-score  { width: 16%; }
}

@media (max-width: 400px) {
  /* Answer and count only. Both survivors are what the highlight rules key on,
     so the row fills still explain themselves without the numbers behind them. */
  .answers .c-score { display: none; }

  .answers .c-counts { width: 24%; }
}
