/* The board.

   What this replaces, and why each one mattered:

     * the board was `height: min(58vh, 620px)` with a `min-height` — a viewport
       measurement for an object with a fixed shape. In a short landscape window
       it came out square and the points looked stretched; in a narrow column it
       came out tall and thin. It now has an aspect ratio and takes its size from
       whatever box it is given.

     * the point triangles were CSS borders of `clamp(150px, 23vh, 250px)`, a
       height unrelated to the quadrant containing them, so they overshot or fell
       short of the middle depending on the window.

     * the checkers were `clamp(28px, 3.8vw, 46px)` — sized from the *viewport
       width*, so a small board on a wide screen got checkers too big for their
       points, and five of them overflowed the stack.

   Everything here is measured against the board itself with container units, so
   the whole thing scales as one piece and is correct at any size.

   Theming is a set of custom properties. A theme changes colour and material,
   never geometry, so no theme can break the layout. */

/* The default theme, on anything that draws a board. A specific theme below
   overrides whichever of these it cares to. */
.backgammon-board,
.preview-board {
  --frame: 2.6cqw;
  --bar-width: 6.4cqw;
  --tray-width: 4.2cqw;
  --point-height: 42cqh;
  --checker: min(6.4cqw, 8.2cqh);
  --checker-overlap: calc(var(--checker) * -0.22);

  --felt: radial-gradient(120% 90% at 50% 0%, #1d5a44, #10382a 70%, #0b2a20);
  --frame-colour: #1a3a2e;
  --frame-edge: rgba(0, 0, 0, .55);
  --point-a: #0d6b4e;
  --point-b: #e8d9b5;
  --point-edge: rgba(0, 0, 0, .25);
  --bar: linear-gradient(90deg, #08201a, #14493a 45%, #08201a);
  --tray: rgba(3, 14, 10, .72);
  --tray-edge: rgba(255, 255, 255, .07);
  --light-checker: radial-gradient(circle at 34% 26%, #fffdf6, #ecdcb9 52%, #b9a276);
  --light-rim: rgba(255, 255, 255, .5);
  --dark-checker: radial-gradient(circle at 34% 26%, #3d5a54, #14302a 55%, #061713);
  --dark-rim: rgba(255, 255, 255, .16);
  --accent: #f0c55d;
}

/* The board is not alone in the stage: the dice and the Roll button sit under
   it, and the action bar under those, and the stage clips what does not fit.
   Sizing the board against the whole stage buried both of them — on a 740x360
   phone the Roll button ended up 46px below the clip and there is no scroll to
   reach it.

   So the board is measured against a box that holds only the board and takes
   whatever height the fixed furniture leaves. Its height comes from flex rather
   than from its contents, which is what makes `container-type: size` safe. */
.board-fit { --board-aspect: 1.42; }

.board-fit {
  /* Size containment means the board inside contributes nothing to this box's
     height, so a flex basis of 0 or auto both resolve to nothing: on a 320x640
     phone the furniture filled the stage and the board was left 34px, which
     rendered it 48x34. The height has to come from somewhere that is not the
     contents, and the width already is that somewhere. */
  flex: 0 0 auto;
  width: 100%;
  height: auto;
  aspect-ratio: var(--fit-aspect, var(--board-aspect, 1.42));
  max-height: 100%;
  min-height: 0;

  display: flex;
  align-items: center;
  justify-content: center;
  container-type: size;
  container-name: stage;
}

.backgammon-board {
  /* Real boards are wider than they are tall, and this is the shape.

     It is written as explicit dimensions rather than `aspect-ratio` because
     pwa.css gives this element `flex: 1 1 auto` inside a column flexbox, and a
     flex item whose main size comes from flex layout ignores `aspect-ratio`
     entirely. On a 740x360 phone in landscape that produced a 714x158 board —
     4.5:1, stubby triangles, 10px checkers. Taking the size out of flex's hands
     is what makes the shape hold.

     The pair of min()s is the largest box of --board-aspect that fits the
     stage, whichever dimension binds: width binds in portrait, height in
     landscape. */
  --board-aspect: 1.42;

  /* Everything inside measures itself against this box. */
  container-type: size;
  container-name: board;

  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  overflow: hidden;

  padding: var(--frame);
  border: 0;
  border-radius: clamp(10px, 2.4cqw, 22px);
  background: var(--felt);
  box-shadow:
    inset 0 0 0 var(--frame) var(--frame-colour),
    inset 0 0 0 calc(var(--frame) + 1px) var(--frame-edge),
    inset 0 0 6cqw rgba(0, 0, 0, .34),
    0 18px 45px rgba(0, 0, 0, .3);

  /* A checker has to fit its point's width *and* leave room for five of them
     plus a count badge in the quadrant's height — see --checker above, where
     the smaller of the two wins. */
}

/* ------------------------------------------------------------------ points */
.backgammon-board .quadrant {
  display: flex;
  position: relative;
  align-items: flex-start;
  padding-inline: calc(var(--bar-width) / 2 + var(--tray-width));
}
/* The two halves face the bar, so the padding is on the inner edge only. */
.backgammon-board .q1,
.backgammon-board .q3 { padding-left: var(--tray-width); padding-right: calc(var(--bar-width) / 2); }
.backgammon-board .q2,
.backgammon-board .q4 { padding-right: var(--tray-width); padding-left: calc(var(--bar-width) / 2); }
.backgammon-board .q3,
.backgammon-board .q4 { align-items: flex-end; }

.backgammon-board .point {
  flex: 1 1 0;
  min-width: 0;
  height: var(--point-height);
  position: relative;
  display: flex;
  justify-content: center;
}

/* styles.css draws these triangles with borders — `border-top: clamp(150px,
   23vh, 250px) solid`. Those declarations are still in the cascade and would
   paint a second, differently-sized triangle underneath this one, so they are
   explicitly cleared rather than left to overlap. */
.backgammon-board .point::before,
.backgammon-board .point::after {
  border: 0;
  width: auto;
  height: auto;
}

/* A triangle that always reaches exactly as far as its point is tall. Borders
   could not do this: their size is a length, not a share of the parent. */
.backgammon-board .point::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--point-a);
  box-shadow: inset 0 0 0 1px var(--point-edge);
}
.backgammon-board .q1 .point::before,
.backgammon-board .q2 .point::before { clip-path: polygon(0 0, 100% 0, 50% 100%); }
.backgammon-board .q3 .point::before,
.backgammon-board .q4 .point::before { clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.backgammon-board .point.alt::before { background: var(--point-b); }

/* ---------------------------------------------------------------- checkers */
.backgammon-board .checker-stack {
  position: relative;
  z-index: 3;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 0.6cqh;
}
.backgammon-board .q3 .checker-stack,
.backgammon-board .q4 .checker-stack {
  flex-direction: column-reverse;
  padding-top: 0;
  padding-bottom: 0.6cqh;
}

.backgammon-board .checker,
.bar-stack .checker {
  width: var(--checker);
  height: var(--checker);
  flex: 0 0 auto;
  padding: 0;
  border-radius: 50%;
  border: 0;
  cursor: pointer;
  background: var(--light-checker);
  box-shadow:
    inset 0 0 0 max(1px, .28cqw) var(--light-rim),
    inset 0 -0.5cqw 1cqw rgba(0, 0, 0, .22),
    0 .4cqw .8cqw rgba(0, 0, 0, .35);
  transition: transform .14s ease, box-shadow .14s ease;
}
.backgammon-board .checker + .checker,
.bar-stack .checker + .checker { margin-top: var(--checker-overlap); }
.backgammon-board .q3 .checker + .checker,
.backgammon-board .q4 .checker + .checker { margin-top: 0; margin-bottom: var(--checker-overlap); }

.backgammon-board .checker.dark,
.bar-stack .checker.dark {
  background: var(--dark-checker);
  box-shadow:
    inset 0 0 0 max(1px, .28cqw) var(--dark-rim),
    inset 0 -0.5cqw 1cqw rgba(0, 0, 0, .3),
    0 .4cqw .8cqw rgba(0, 0, 0, .4);
}

.backgammon-board .checker.selected {
  transform: translateY(calc(var(--checker) * -0.16)) scale(1.04);
  box-shadow:
    0 0 0 max(2px, .5cqw) var(--accent),
    0 .8cqw 1.4cqw rgba(0, 0, 0, .5);
}

.backgammon-board .stack-count {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 4;
  font-style: normal;
  font-size: max(9px, 3cqh);
  font-weight: 800;
  line-height: 1;
  padding: .6cqh 1.4cqw;
  border-radius: 10cqw;
  background: rgba(0, 0, 0, .62);
  color: #fff;
  pointer-events: none;
}

/* ------------------------------------------------------------ legal targets */
/* The ring is on the point, not the checker: the whole column is the target,
   and on a phone the checker itself is only about 28px across. */
.backgammon-board .point.legal-target::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: calc(var(--checker) * 0.92);
  height: calc(var(--checker) * 0.92);
  border-radius: 50%;
  border: max(2px, .55cqw) dashed var(--accent);
  opacity: .85;
  z-index: 2;
  animation: boardPulse 1.4s ease-in-out infinite;
}
.backgammon-board .point.source::before { filter: brightness(1.25); }
@keyframes boardPulse {
  0%, 100% { opacity: .85; transform: translate(-50%, -50%) scale(1); }
  50% { opacity: .45; transform: translate(-50%, -50%) scale(1.12); }
}

/* --------------------------------------------------------------- the bar */
.backgammon-board .center-bar {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: var(--bar-width);
  transform: translateX(-50%);
  background: var(--bar);
  box-shadow:
    inset 0 0 2cqw rgba(0, 0, 0, .55),
    inset .25cqw 0 0 var(--frame-colour),
    inset -0.25cqw 0 0 var(--frame-colour);
  z-index: 4;
  display: grid;
  grid-template-rows: 1fr auto 1fr;
  align-items: center;
  justify-items: center;
}
.backgammon-board .bar-stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 1cqh 0;
}
.backgammon-board .bar-stack.top { align-self: start; }
.backgammon-board .bar-stack.bottom { align-self: end; flex-direction: column-reverse; }
.backgammon-board .bar-count {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  font-size: max(8px, 2.6cqh);
  color: rgba(255, 255, 255, .5);
}
.backgammon-board .bar-count.top { top: 3cqh; }
.backgammon-board .bar-count.bottom { bottom: 3cqh; }

.backgammon-board .cube {
  position: relative;
  width: max(22px, 6cqh);
  height: max(22px, 6cqh);
  border-radius: 1.4cqw;
  background: linear-gradient(140deg, #fbf3e2, #cbbb9d);
  color: #14181b;
  display: grid;
  place-items: center;
  font-weight: 900;
  font-size: max(10px, 3cqh);
  box-shadow: 0 .6cqw 1.2cqw rgba(0, 0, 0, .45);
  z-index: 5;
}

/* ------------------------------------------------------------- bear-off */
.backgammon-board .bearoff {
  position: absolute;
  top: var(--frame);
  bottom: var(--frame);
  width: var(--tray-width);
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: .5cqh;
  padding: .6cqh .4cqw;
  border-radius: 1.4cqw;
  background: var(--tray);
  box-shadow: inset 0 0 0 1px var(--tray-edge);
}
.backgammon-board .bearoff.left { left: calc(var(--frame) + .4cqw); }
.backgammon-board .bearoff.right { right: calc(var(--frame) + .4cqw); }
.backgammon-board .bearoff span {
  flex: 1;
  border-radius: .8cqw;
  background: rgba(255, 255, 255, .05);
}
/* renderOff marks a borne-off slot `mine` or `theirs`, matching the same
   convention the checkers use: yours is the light set, theirs the dark one. */
.backgammon-board .bearoff span.filled.mine { background: var(--light-checker); }
.backgammon-board .bearoff span.filled.theirs { background: var(--dark-checker); }
.backgammon-board .bearoff.legal-target {
  box-shadow: inset 0 0 0 max(2px, .5cqw) var(--accent);
  animation: boardPulse 1.4s ease-in-out infinite;
}

/* ============================================================== themes =====
   A theme sets colour and material only. Geometry lives above, so no theme can
   change the shape of the board or the size of a checker. */

[data-board="walnut"] {
  --felt: radial-gradient(120% 90% at 50% 0%, #7c4f2e, #5d3a21 70%, #482c19);
  --frame-colour: #6b4426;
  --frame-edge: rgba(0, 0, 0, .6);
  --point-a: #35211a;
  --point-b: #c59a63;
  --bar: linear-gradient(90deg, #2a1810, #5d3722 45%, #2a1810);
  --tray: rgba(24, 13, 8, .72);
  --light-checker: radial-gradient(circle at 34% 26%, #fdf3df, #dbc8a8 52%, #97815f);
  --dark-checker: radial-gradient(circle at 34% 26%, #4a5763, #16212a 55%, #050c11);
  --accent: #f0c55d;
}

[data-board="midnight"] {
  --felt: radial-gradient(120% 90% at 50% 0%, #1b2b38, #111c26 70%, #0a141c);
  --frame-colour: #1e2f3c;
  --frame-edge: rgba(0, 0, 0, .6);
  --point-a: #1f3b4d;
  --point-b: #35566b;
  --point-edge: rgba(255, 255, 255, .05);
  --bar: linear-gradient(90deg, #0b141b, #1d3040 45%, #0b141b);
  --tray: rgba(5, 11, 15, .75);
  --light-checker: radial-gradient(circle at 34% 26%, #f2f7fa, #cfdce4 52%, #8fa2ae);
  --dark-checker: radial-gradient(circle at 34% 26%, #2f4150, #101a22 55%, #050a0e);
  --accent: #58d6c2;
}

[data-board="ivory"] {
  --felt: radial-gradient(120% 90% at 50% 0%, #f4efe4, #e6dcc9 70%, #d8ccb4);
  --frame-colour: #cbb894;
  --frame-edge: rgba(120, 96, 60, .5);
  --point-a: #b9a57c;
  --point-b: #fffaf0;
  --point-edge: rgba(80, 64, 40, .18);
  --bar: linear-gradient(90deg, #d9cbac, #efe5d0 45%, #d9cbac);
  --tray: rgba(150, 128, 92, .42);
  --tray-edge: rgba(90, 72, 44, .18);
  --light-checker: radial-gradient(circle at 34% 26%, #ffffff, #f0e7d6 52%, #c3b393);
  --light-rim: rgba(120, 100, 66, .35);
  --dark-checker: radial-gradient(circle at 34% 26%, #5a6470, #262e38 55%, #121820);
  --dark-rim: rgba(255, 255, 255, .22);
  --accent: #c0872b;
}

[data-board="carbon"] {
  --felt:
    repeating-linear-gradient(45deg, rgba(255,255,255,.018) 0 2px, transparent 2px 4px),
    radial-gradient(120% 90% at 50% 0%, #22262b, #15181c 70%, #0d0f12);
  --frame-colour: #1c2024;
  --frame-edge: rgba(0, 0, 0, .7);
  --point-a: #24292f;
  --point-b: #32383f;
  --point-edge: rgba(174, 134, 255, .16);
  --bar: linear-gradient(90deg, #0c0e11, #262c34 45%, #0c0e11);
  --tray: rgba(0, 0, 0, .62);
  --tray-edge: rgba(174, 134, 255, .18);
  --light-checker: radial-gradient(circle at 34% 26%, #f6f4ff, #d9d2ef 52%, #9d94bd);
  --light-rim: rgba(174, 134, 255, .5);
  --dark-checker: radial-gradient(circle at 34% 26%, #2f3440, #171a20 55%, #0a0c10);
  --dark-rim: rgba(174, 134, 255, .34);
  --accent: #ae86ff;
}

[data-board="aurora"] {
  --felt:
    radial-gradient(90% 70% at 20% 0%, rgba(88, 214, 194, .22), transparent 60%),
    radial-gradient(90% 70% at 85% 10%, rgba(174, 134, 255, .2), transparent 60%),
    linear-gradient(180deg, #101c2a, #0a131d);
  --frame-colour: #16283a;
  --frame-edge: rgba(0, 0, 0, .6);
  --point-a: #16384a;
  --point-b: #2f6f7e;
  --point-edge: rgba(88, 214, 194, .2);
  --bar: linear-gradient(90deg, #070e16, #17334a 45%, #070e16);
  --tray: rgba(4, 9, 16, .72);
  --tray-edge: rgba(88, 214, 194, .18);
  --light-checker: radial-gradient(circle at 34% 26%, #eafffb, #bfeee4 52%, #6fb0a5);
  --light-rim: rgba(234, 255, 251, .55);
  --dark-checker: radial-gradient(circle at 34% 26%, #46407a, #1d1a3a 55%, #0c0a1c);
  --dark-rim: rgba(174, 134, 255, .4);
  --accent: #58d6c2;
}

/* ================================================================ touch =====
   On a phone the checker is about 28px across, which is small for a thumb. The
   target is the whole point column — roughly 28x120 — and the ring marks where
   the checker will land rather than where to press. */
@media (pointer: coarse) {
  .backgammon-board .point { touch-action: manipulation; }
  .backgammon-board .checker { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
  /* A tapped point needs a stronger mark than a hovered one. */
  .backgammon-board .point.legal-target::after { border-width: max(3px, .7cqw); opacity: 1; }
}

@media (hover: hover) {
  .backgammon-board .point:hover::before { filter: brightness(1.12); }
  .backgammon-board .checker:hover { transform: translateY(calc(var(--checker) * -0.08)); }
}

@media (prefers-reduced-motion: reduce) {
  .backgammon-board .point.legal-target::after,
  .backgammon-board .bearoff.legal-target { animation: none; }
}

/* ----------------------------------------------------------- the preview */
/* The little board on the Play screen. Same theme variables, no interaction. */
.preview-board {
  aspect-ratio: 1.42 / 1;
  container-type: size;
  container-name: board;
  position: relative;
  overflow: hidden;
  border-radius: clamp(8px, 2cqw, 16px);
  background: var(--felt, #17332a);
  box-shadow: inset 0 0 0 2.4cqw var(--frame-colour, #1a3a2e), inset 0 0 6cqw rgba(0, 0, 0, .35);
  display: flex;
  align-items: stretch;
  padding: 3.4cqw;
  gap: 1.4cqw;
}
.preview-board .pv-half { flex: 1; display: flex; }
.preview-board .pv-point {
  flex: 1;
  position: relative;
}
.preview-board .pv-point::before,
.preview-board .pv-point::after {
  content: "";
  position: absolute;
  left: 4%;
  right: 4%;
  height: 42%;
  background: var(--point-a, #0d6b4e);
}
.preview-board .pv-point::before { top: 0; clip-path: polygon(0 0, 100% 0, 50% 100%); }
.preview-board .pv-point::after { bottom: 0; clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.preview-board .pv-point:nth-child(odd)::before,
.preview-board .pv-point:nth-child(even)::after { background: var(--point-b, #e8d9b5); }
.preview-board .pv-bar {
  flex: 0 0 5cqw;
  background: var(--bar, #12342a);
  border-radius: 1cqw;
}
.preview-board .pv-chip {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 78%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--light-checker, #ecdcb9);
  box-shadow: 0 .4cqw .8cqw rgba(0, 0, 0, .35);
}
.preview-board .pv-chip.dark { background: var(--dark-checker, #14302a); }

/* ---------------------------------------------------------- the picker */
.board-picker {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin: 16px 0 4px;
  text-align: start;
}
.board-option {
  display: grid;
  gap: 4px;
  padding: 10px;
  border-radius: 14px;
  border: 1px solid var(--line, #1e3442);
  background: rgba(255, 255, 255, .02);
  color: var(--text, #eef4f7);
  font: inherit;
  cursor: pointer;
  transition: border-color .15s ease, transform .15s ease;
}
.board-option:hover { border-color: var(--line2, #294454); transform: translateY(-2px); }
.board-option.on { border-color: var(--gold, #e7bb57); background: rgba(231, 187, 87, .08); }
.board-option .preview-board { width: 100%; margin-bottom: 6px; }
.board-option b { font-size: 12.5px; }
.board-option small { font-size: 10.5px; color: var(--muted, #8da3b1); line-height: 1.5; }


/* ------------------------------------------------------- winning the size --
   styles.css and pwa.css both size this element and both load after board.css,
   so a plain `.backgammon-board` here loses on source order: pwa.css's
   `flex: 1 1 auto` was still winning, and flex then shrank the board's height
   from the 270px it asked for to 177px. `body.in-match .backgammon-board` sets
   the height too, at (0,2,1). Doubling the class inside the stage gives (0,3,0),
   which clears both without reaching for !important. */
.board-fit > .backgammon-board.backgammon-board {
  flex: 0 0 auto;
  align-self: center;
  width: min(100cqw, calc(100cqh * var(--board-aspect)));
  height: min(100cqh, calc(100cqw / var(--board-aspect)));
  aspect-ratio: auto;
  min-height: 0;
  max-height: none;
  margin-inline: auto;
}

/* ================================================ a phone held sideways ====
   360px of height is the whole budget, and at 1.42 the board can only be 398px
   wide inside it — 55% of a 740px screen, with 25px columns to aim a thumb at.

   Two things are done about it. The match header gives back the height it was
   spending on a stacked score block, and the board is allowed to run wider so
   it uses the width that is actually there. 1.7 is as far as that goes: it puts
   the columns at 31px and holds the points at 3.3:1, still the proportions of a
   board. Past about 2:1 the columns keep growing but the checkers cannot follow
   — their size is set by the five-high stack, not by the width — and the board
   starts to read as stretched. */
@media (orientation: landscape) and (max-height: 480px) {
  .backgammon-board { --board-aspect: 1.7; }

  .match-shell { gap: 4px; }

  /* Stacked, the furniture took 183px of a 360px screen and left the board
     177px — while 440px of width sat empty beside it. Turned on its side, the
     dice and the actions take that spare width and give the height back: the
     board goes from 301x177 to roughly 480x283, and the columns from 19px to
     31px. Nothing is hidden and nothing moves out of reach. */
  /* pwa.css turns this into a flex column at `body.in-match .board-stage`,
     which is (0,2,1) and loads later. (0,3,0) clears it. */
  .match-main > .board-stage.board-stage {
    padding: 4px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(168px, 216px);
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "toolbar toolbar"
      "board   dice"
      "board   actions";
    gap: 6px;
    align-items: stretch;
  }
  .board-stage > .board-toolbar { grid-area: toolbar; }
  /* Here the grid row is the height, so the wrapper stops deriving its own. */
  .board-stage > .board-fit {
    grid-area: board;
    --board-aspect: 1.7;
    aspect-ratio: auto;
    height: auto;
    align-self: stretch;
    min-height: 0;
    min-width: 0;
  }
  .board-stage > .dice-area { grid-area: dice; }
  .board-stage > .match-actions { grid-area: actions; }

  /* A column 168-216px wide reads top to bottom, not left to right. */
  .board-stage > .dice-area {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: center;
    gap: 8px;
    text-align: center;
  }
  .dice-area .dice-cluster { justify-content: center; }
  .dice-area .roll-btn { width: 100%; }
  .dice-area #pipCounts { font-size: 10px; }

  .board-stage > .match-actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px;
  }
  .match-actions button { font-size: 11px; padding: 6px 4px; }

  /* The score, the two players and the clocks on one line instead of three.

     styles.css sizes the middle column at .72fr, which is 80px on a 740px
     screen, and on one row this content wants about 198px. It overflowed onto
     the player plates either way; in Persian the collision is plain to see, the
     badge sitting on top of the player's own name. The middle column takes what
     it needs and the plates give way. */
  .match-top {
    padding: 2px 8px;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  }
  .match-center { flex-direction: row; align-items: center; gap: 10px; min-width: 0; }
  .player-plate { min-width: 0; }
  .player-plate b,
  .player-plate span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .match-center .match-score { font-size: 19px; line-height: 1.1; }
  .player-plate { gap: 6px; }

  /* Context that is welcome on a tall screen and is costing height on this one.
     Nothing here is the state of the game. */
  .match-center .match-meta,
  .match-center .match-note,
  .match-center .free-badge,
  .match-top .plate-sub,
  .match-top .eyebrow { display: none; }
}

/* ------------------------------------------------ without size containers --
   The board falls back to the shape it declares and the stage's own height. */
@supports not (container-type: size) {
  .board-fit > .backgammon-board.backgammon-board {
    width: 100%;
    height: auto;
    aspect-ratio: 1.42 / 1;
    max-height: 100%;
  }
}

/* ------------------------------------------------------- Persian landscape --
   pwa.css holds `.board-stage` at `direction: ltr` on purpose: the board is
   geometry and its quadrants must not mirror. That also stops this grid from
   mirroring, which would leave the board on the left of a right-to-left screen.
   The areas are swapped by hand instead, so the board sits where the eye starts
   and the board's own insides stay exactly as they are. */
@media (orientation: landscape) and (max-height: 480px) {
  [dir="rtl"] .match-main > .board-stage.board-stage {
    grid-template-columns: minmax(168px, 216px) minmax(0, 1fr);
    grid-template-areas:
      "toolbar toolbar"
      "dice    board"
      "actions board";
  }
}


/* ==================================================== a phone held upright ==
   A backgammon board is a landscape object and a phone in the hand is not, so
   upright the board could only ever be 336x237 on a 390px screen — a quarter of
   the height doing nothing, and 22.6px point columns to aim a thumb at.

   The board is turned on its side instead, which is what every backgammon app
   on a phone does. Nothing about the board itself changes: the same grid, the
   same quadrants, the same points, the same move logic. Only the frame it is
   drawn in is portrait, and the board is rotated inside it. Points become rows
   running across the screen, which is the shape a thumb is good at — the narrow
   dimension of a tap target goes from 22.6px to about 37px.

   `rotate()` transforms hit testing along with the pixels, so clicks land where
   they look like they land and board.js does not know this happened. */
@media (orientation: portrait) and (max-width: 700px) {
  .board-fit {
    /* The footprint is the board standing up: as tall as the board is wide. */
    --fit-aspect: 1 / 1.42;
    position: relative;
    overflow: hidden;
  }

  .board-fit > .backgammon-board.backgammon-board {
    /* The same "largest box that fits" as everywhere else, with the two
       container axes swapped, because after the quarter turn the board's width
       runs down the footprint's height. */
    width: min(100cqh, calc(100cqw * var(--board-aspect)));
    height: min(100cqw, calc(100cqh / var(--board-aspect)));
    /* pwa.css caps this at `max-width: 100%`, which is the right cap for a board
       lying flat and the wrong one for a board standing up: turned, its width
       runs down the wrapper's height, and the cap squared it off at 336x336. */
    max-width: none;

    /* Before it turns, the board is wider than the frame it stands in, and a
       flex item that overflows its main axis is placed by rules that then feed
       into `rotate()`'s own centre — the board came out 71px above where it
       belonged. Pinning it to the middle of the frame and turning it about that
       point leaves nothing to interpret. */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) rotate(var(--board-spin, 90deg));
  }

  /* Everything on the board is a circle, a triangle or a rail and turns with it
     quite happily. These three are text and have to stay the right way up. */
  .backgammon-board .stack-count {
    transform: translate(-50%, -50%) rotate(calc(var(--board-spin, 90deg) * -1));
  }
  .backgammon-board .bar-count {
    transform: translateX(-50%) rotate(calc(var(--board-spin, 90deg) * -1));
  }
  .backgammon-board .cube {
    transform: rotate(calc(var(--board-spin, 90deg) * -1));
  }
}
