/* ==========================================================================
   four-in-a-row.css — four in a row's arena
   (src/assets/js/games/four-in-a-row/view.mjs), inside the table games.css
   draws: the board as a grid of hairline cells, each column a button under
   its number, the discs in it (games.css .g-disc: filled for one side, a ring
   for the other) and a line saying whose are whose. Every class here is .fr-*.
   ========================================================================== */

.fr {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(14 * var(--s, 1px));
}
/* The board: its columns side by side — seven on the classic board, six to nine as the table picked
   (view.mjs writes the board's size on it: data-cols, data-rows). One measure sets the rest:
   --cell, a cell's side, which is also a column's width and so a finger's target. The discs
   (games.css .g-disc) take their size from --disc. What is raised inside the board (a marked cell,
   the focused column) is raised within it and over nothing else on the page. */
.fr-board {
  --cell: calc(56 * var(--s, 1px));
  --disc: calc(var(--cell) * 0.7);
  display: flex;
  isolation: isolate;
  font-family: var(--font-mono);
  color: var(--ink);
  -webkit-user-select: none;
  user-select: none;
}
/* A column: its number and its cells, the whole height one target. Neighbours overlap by their
   hairline, so the grid's inner lines are drawn once. */
.fr-col {
  -webkit-appearance: none;
  appearance: none;
  display: flex;
  flex-direction: column;
  flex: none;
  inline-size: var(--cell);
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  overflow: visible; /* a disc starts its fall a little above the number: some browsers clip a button */
  background: none;
  font: inherit;
  color: inherit;
  cursor: default;
  -webkit-tap-highlight-color: transparent;
}
.fr-col + .fr-col { margin-inline-start: -1px; }
.fr--live .fr-col:not(:disabled) { cursor: pointer; }
/* The keyboard's cursor: the ring base.css draws, set on the column's own edge (outside it, it
   would run beside the hairlines as a second line) and raised over the columns either side. */
.fr-col:focus-visible {
  position: relative;
  z-index: 2;
  outline-offset: calc(-2 * var(--s, 1px));
}
/* The same ring once more, over the column's own cells: a marked cell is raised (below), and
   where it stands in this column it would cut the ring in two. */
.fr-col:focus-visible::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  outline: inherit;
  outline-offset: inherit;
  pointer-events: none;
}

/* The numbers name the columns and are the keys that drop into them. They say whose turn it is at
   the board itself: green and a little heavier while the turn is yours (as the table's "your turn"
   is), muted while it is not. Over a column that is full the number fades, and once the game is
   over the keys are gone (their row stays, so the board does not move). */
.fr-n {
  display: flex;
  align-items: center;
  justify-content: center;
  block-size: calc(30 * var(--s, 1px));
  font-size: calc(13 * var(--s, 1px));
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--ink-muted);
  transition:
    color 150ms ease,
    opacity 150ms ease;
}
.fr--live .fr-n {
  color: var(--green);
  font-weight: 500;
}
.fr-col:disabled .fr-n {
  color: var(--ink-muted);
  font-weight: 400;
  opacity: 0.45;
}
.fr--over .fr-n { visibility: hidden; }
/* A press a full column could not take: its number in red, for a moment (view.mjs takes it away). */
.fr-col:disabled .fr-n.fr-n--no {
  color: var(--red);
  opacity: 1;
}

/* A cell: a hairline square, like one of 24's tiles, with room for one disc in its middle. */
.fr-cell {
  display: grid;
  place-items: center;
  block-size: var(--cell);
  border: 1px solid var(--hairline);
  transition:
    border-color 150ms ease,
    background-color 150ms ease;
}
.fr-cell + .fr-cell { margin-block-start: -1px; }
.fr-cell .g-disc { transition: color 150ms ease; }

/* The disc just dropped, until the next one: its cell framed in green and filled a touch, as 24
   marks the tile that is picked. Raised, so the frame is drawn over its neighbours' hairlines. The
   frame comes as the disc lands, not before it (view.mjs keeps .fr--falling on the board while a
   disc is in the air). */
.fr-cell--last,
.fr-cell--win {
  position: relative;
  z-index: 1;
}
.fr:not(.fr--falling) .fr-cell--last,
.fr:not(.fr--falling) .fr-cell--win {
  border-color: var(--green);
  background: color-mix(in srgb, var(--green) 10%, var(--bg));
}
/* The four that won turn green, in their frames, and every other disc steps back: the game is
   over, and the line is what is left to look at. */
.fr:not(.fr--falling) .fr-cell--win .g-disc { color: var(--green); }
.fr--over:not(.fr--falling) .fr-cell:not(.fr-cell--win) .g-disc { color: var(--ink-muted); }

/* Where a disc would land: this player's own, faint and pink, in the lowest empty cell of one
   column — the one under the pointer (only where there is a hover), or the one the keyboard's
   cursor is on once the keys were the last to point (view.mjs sets .fr--keys). Only on this
   player's turn, and not while a disc is still falling. Under the pointer the column's number
   goes pink with it; under the keys the column has the focus ring. */
.fr-ghost.g-disc {
  visibility: hidden;
  color: var(--pink);
  opacity: 0.5;
}
@media (hover: hover) {
  .fr--live:not(.fr--keys) .fr-col:hover:not(:disabled) .fr-n { color: var(--pink-text); }
  .fr--live:not(.fr--keys):not(.fr--falling) .fr-col:hover:not(:disabled) .fr-ghost { visibility: visible; }
}
.fr--live.fr--keys:not(.fr--falling) .fr-col:focus-visible .fr-ghost { visibility: visible; }

/* Whose discs are whose: "you are" and the disc itself, then the other player's. */
.fr-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: calc(2 * var(--s, 1px)) 1.2ch;
}
.fr-who {
  display: inline-flex;
  align-items: center;
  gap: 1ch;
  min-inline-size: 0;
  white-space: nowrap;
}
/* A dot between the two, which is no part of what a screen reader says (the first line is for a
   browser that does not know the second). */
.fr-who + .fr-who::before {
  content: "\00b7";
  content: "\00b7" / "";
}
/* A name gives way before the line breaks (as in the table's top line): twenty characters, the
   longest a name can be typed, fit beside the rest on any but the narrowest phone, so this cuts
   only a name in a wider script. */
.fr-who-name {
  max-inline-size: 20ch;
  overflow: hidden;
  text-overflow: ellipsis;
}
.fr-legend .g-disc {
  --disc: calc(13 * var(--s, 1px));
  flex: none;
}
/* A ring this small keeps its hole: a thinner line than the board's. */
.fr-legend .g-disc--ring { border-width: calc(2 * var(--s, 1px)); }

/* ---- A reader's own colours (Windows' high contrast) --------------------------- */
/* There the browser repaints every background, and a filled disc, which is nothing but its
   background, would be gone from the board and the legend. It keeps its fill, in the reader's own
   text colour; and the marks, which their colours no longer carry, are drawn in the system's
   highlight as a second line inside the cell. */
@media (forced-colors: active) {
  .fr .g-disc--solid {
    forced-color-adjust: none;
    background: CanvasText;
  }
  .fr:not(.fr--falling) .fr-cell--last,
  .fr:not(.fr--falling) .fr-cell--win {
    border-color: Highlight;
    outline: calc(2 * var(--s, 1px)) solid Highlight;
    outline-offset: calc(-3 * var(--s, 1px));
  }
}

/* ---- Short windows --------------------------------------------------------- */
/* A board seven rows tall stands 55px higher than the classic, and a laptop's window that holds
   the classic's whole table, down to the buttons under it, would cut this one's off. In a window
   under 665px tall its cells are 48px: seven rows of 48 stand as high as the classic's six of 56.
   (Wider than a phone only: a phone's cells are set by its width, below.) */
@media (min-width: 600.02px) and (max-height: 664.98px) {
  .fr-board[data-rows="7"] { --cell: calc(48 * var(--s, 1px)); }
}

/* ---- Phones ---------------------------------------------------------------- */
/* Seven columns of 48px are 330px, inside the 335px column of a 375px phone. Narrower than that
   they give way: 44px (302px in the 320px column of a 360px phone), then 40px (274px in the 280px
   column of a 320px one). Six columns keep the same cells.
   Eight and nine columns cannot have them: n columns of c are n × c − (n − 1) wide (neighbours
   share a hairline), and the page's column is the window less 40px. Each takes the widest whole
   cell that fits the narrowest phone of a step — eight: 42px (329px of the 335), 40px (313 of 320),
   35px (273 of 280); nine: 38px (334 of 335), 36px (316 of 320), 32px (280 of 280, to the pixel).
   On the larger phones, from 412px, nine have room for the eight's 42px (370 of 372) — and no
   more than that for either: seven rows of 42 already stand 5px over the classic board.
   A column stays one target from its number to the floor, so what narrows is only its width. */
@media (max-width: 600px) {
  .fr-board { --cell: calc(48 * var(--s, 1px)); }
  .fr-board[data-cols="8"],
  .fr-board[data-cols="9"] { --cell: calc(42 * var(--s, 1px)); }
}
@media (max-width: 411.98px) {
  .fr-board[data-cols="9"] { --cell: calc(38 * var(--s, 1px)); }
}
@media (max-width: 374.98px) {
  .fr-board { --cell: calc(44 * var(--s, 1px)); }
  .fr-board[data-cols="8"] { --cell: calc(40 * var(--s, 1px)); }
  .fr-board[data-cols="9"] { --cell: calc(36 * var(--s, 1px)); }
}
@media (max-width: 359.98px) {
  .fr-board { --cell: calc(40 * var(--s, 1px)); }
  .fr-board[data-cols="8"] { --cell: calc(35 * var(--s, 1px)); }
  .fr-board[data-cols="9"] { --cell: calc(32 * var(--s, 1px)); }
  .fr-who-name { max-inline-size: 12ch; }
}
