/* Rainbow Clash */

:root {
  --bg: #080b14;
  --bg-2: #0e1424;
  --surface: #141d31;
  --surface-2: #1c2740;
  --line: #26324c;
  --text: #e8eefb;
  --muted: #93a1bb;
  --light: #f2f6ff;
  --dark: #0a1020;
  --accent: #6ee7ff;
  /* How a match ended, named once so a result card and a profile tally can
     never drift apart on what a win, a draw and a loss look like. */
  --win: #3ddc84;
  --draw-c: #ffd93d;
  --loss: #ff8484;
  /* The eight the board is dealt from. They are the same eight the engine
     holds, and tune.js writes them here as it reads tune.json, so the two
     decorative rings below follow a colour the maker changes. --c9 is the
     first one again, because a ring has to close. */
  --c1: #ff4b4b;
  --c2: #ff9a2e;
  --c3: #ffd93d;
  --c4: #3ddc84;
  --c5: #22d3ee;
  --c6: #3b82f6;
  --c7: #a855f7;
  --c8: #ff4fd8;
  --c9: #ff4b4b;
  --radius: 14px;
  --pad: clamp(8px, 2.2vw, 16px);
  color-scheme: dark;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: ui-rounded, "SF Pro Rounded", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", sans-serif;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

body {
  background:
    radial-gradient(120% 90% at 50% -20%, #1a2a4d 0%, transparent 60%),
    radial-gradient(90% 70% at 110% 110%, #3a1a45 0%, transparent 65%),
    var(--bg);
}

#app {
  display: grid;
  grid-template-areas: "bar" "stage" "dock";
  grid-template-rows: auto minmax(0, 1fr) auto;
  height: 100dvh;
  max-height: 100dvh;
  padding: calc(var(--pad) + env(safe-area-inset-top)) var(--pad) calc(var(--pad) + env(safe-area-inset-bottom));
  gap: var(--pad);
}

/* While the tutorial's lesson is up it is a row of its own directly above the
   dock, so that it is the first thing read and the palette it talks about is
   the next thing down. Only the row is added: a row kept for a hidden coach
   would leave its share of the gap standing empty above the buttons. */
#app.coaching {
  grid-template-areas: "bar" "stage" "coach" "dock";
  grid-template-rows: auto minmax(0, 1fr) auto auto;
}

/* ------------------------------------------------------------- top bar -- */

#bar {
  grid-area: bar;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 10px;
  min-width: 0;
}

/* Each player's score sits at their own end of the share bar, so the number
   and the length of bar beside it are always the same person. */
.share-row {
  flex: 1 1 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

/* A seat looking at the board mirrored reads this row mirrored too. Only the
   order of the two ends swaps; the bar in the middle keeps its own left to
   right reading, which paintShare fills to match. */
.share-row.flipped { flex-direction: row-reverse; }

/* How much of the board each player holds, tinted with the colour their land
   currently is, so it doubles as a "who is what colour" reminder. */
.share-wrap {
  position: relative;
  flex: 1 1 auto;
  min-width: 24px;
  display: flex;
  align-items: center;
}

.share {
  flex: 1 1 auto;
  width: 100%;
  display: flex;
  height: 7px;
  border-radius: 999px;
  overflow: hidden;
  background: #1a2438;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
}

/* The halfway mark, standing on the middle of the bar. Half the board is the
   number that decides a match, and without something standing at it the two
   lengths have to be compared against each other every time.
   Its point meets the bar rather than hovering over it: a mark with a gap
   under it has to be lined up by eye down that gap, and the whole reason this
   is here is to be the thing you read the two lengths against. It takes no
   place in the row, so the bar keeps its height. */
.share-mark {
  position: absolute;
  left: 50%;
  bottom: calc(100% - 3px);
  margin-left: -7px;
  width: 0;
  height: 0;
  border-left: 7px solid transparent;
  border-right: 7px solid transparent;
  border-top: 9px solid rgba(236,243,255,.95);
  pointer-events: none;
}

.share-seg {
  display: block;
  height: 100%;
  transition: width .45s cubic-bezier(.3,.9,.3,1), background .3s;
}

.share-seg + .share-seg { box-shadow: inset 2px 0 0 rgba(8,11,20,.85); }

/* How long is left on the turn. It runs the full width of the row, in the
   colour of whoever is holding the turn, and empties from the far side back
   toward that player, so the end it drains to is the end that owns it. */
.clock-row {
  flex: 1 1 100%;
  height: 8px;
  border-radius: 999px;
  background: #1a2438;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
  overflow: hidden;
  min-width: 0;
}

.clock-fill {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
  transform-origin: left center;
  /* No transition: this is driven every frame, and a transition on top of it
     would lag the bar behind the clock it is showing. */
  will-change: transform;
}

/* The tutorial match has no turn clock, so the row is not drawn there at all.
   An empty bar sitting under the scores would say a turn is running out when
   nothing is, and there is nothing to read on it. */
.clock-row[hidden] { display: none; }

/* The clock of a turn nobody at this device can play, or of a match that has
   ended, is there to be read and not to be acted on. */
.clock-row.quiet .clock-fill { opacity: .34; }
.clock-row.over { opacity: .3; }

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  flex: 0 1 auto;
}

/* The mark. It was a colour wheel: the eight colours of the board arranged in
   spectrum order around a circle, with a cyan glow behind it. The eight were
   the right eight, and the arrangement was the thing that was wrong. A wheel
   of every hue is the picture of a colour picker, and this game has never
   looked like one, and the glow behind it was a ninth colour the board does
   not have. What the game looks like is a grid of flat tiles with two of them
   grown into lands, so that is what the mark is: the same three-by-three
   fragment the favicon and the cover carry, drawn by workshop/make-art.py
   from the palette in engine.js and from nowhere else. */
.brand-dot {
  width: 22px; height: 22px;
  border-radius: 24%;
  flex: none;
  background-image: url("icon.svg");
  background-size: 100% 100%;
  background-repeat: no-repeat;
}

.brand-name {
  font-size: clamp(14px, 3.6vw, 19px);
  font-weight: 800;
  letter-spacing: .2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.score {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 10px 5px 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  transition: border-color .18s, background .18s, transform .18s;
}

.score.active {
  border-color: var(--accent);
  background: var(--surface-2);
  transform: translateY(-1px);
}

.score-who { display: flex; align-items: center; gap: 6px; min-width: 0; }

.score-name {
  font-size: clamp(10px, 2.6vw, 12px);
  color: var(--muted);
  white-space: nowrap;
}

.score.active .score-name { color: var(--text); }

.score-num {
  font-size: clamp(13px, 3.4vw, 16px);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  min-width: 1.4em;
  text-align: right;
}

.badge {
  display: grid;
  place-items: center;
  width: 20px; height: 20px;
  border-radius: 50%;
  font-size: 11px;
  font-weight: 800;
  flex: none;
}

.badge-light { background: var(--light); color: #0b1020; box-shadow: 0 0 0 2px rgba(255,255,255,.18); }
.badge-dark  { background: var(--dark); color: #eaf1ff; box-shadow: 0 0 0 2px rgba(180,200,235,.5) inset, 0 0 0 1px #9fb3d4; }

.icon-btn {
  flex: none;
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font-size: 15px;
  font-weight: 800;
  cursor: pointer;
  padding: 0;
}
.icon-btn:hover { background: var(--surface-2); }

/* -------------------------------------------------------------- stage -- */

#stage {
  grid-area: stage;
  display: grid;
  place-items: center;
  min-height: 0;
  min-width: 0;
  position: relative;
}

/* The wrap and the canvas are the stage, not the size of the canvas's own
   markup. A canvas with no width and height attributes is 300 by 150, and a
   wrap that sizes itself to its content is that same small box: on a phone the
   page then opens with a stamp in the middle of an empty screen until the
   script gets round to measuring. The script still sets exact pixel sizes on
   every resize; this is what the first paint is, before it runs. */
#boardWrap {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
}

#board {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: var(--radius);
  touch-action: manipulation;
  cursor: pointer;
}

/* ---------------------------------------------------------------- intro -- */

/* The coin flip that opens a match. It sits over the board rather than over the
   whole page, so the scores and the clock stay readable while it plays, and it
   is dismissed by a tap, so nobody has to sit through it. */
.intro {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: 8px;
  border-radius: var(--radius);
  background: radial-gradient(75% 65% at 50% 50%, rgba(9,13,24,.78), rgba(6,9,17,.95));
  cursor: pointer;
  animation: fade .18s ease;
}

.intro[hidden] { display: none; }

.intro-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(8px, 2.4vh, 16px);
  text-align: center;
}

.intro-lead {
  margin: 0;
  font-size: clamp(10px, 2.6vw, 12px);
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--muted);
}

.intro-coins { display: flex; align-items: center; gap: clamp(12px, 5vw, 30px); }

.intro-line {
  margin: 0;
  min-height: 1.3em;
  font-size: clamp(13px, 3.8vw, 18px);
  font-weight: 800;
}

/* Each coin wears the colour that player's land is wearing on the board, so
   the flip names the two sides by the thing the eye is already reading. */
.coin {
  width: clamp(46px, 16vw, 76px);
  height: clamp(46px, 16vw, 76px);
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--coin, #7a8699);
  box-shadow: 0 0 0 3px rgba(255,255,255,.2), 0 10px 24px rgba(0,0,0,.5);
  opacity: .5;
  transition: opacity .3s ease, box-shadow .3s ease, transform .3s ease;
}

.coin .badge {
  width: 42%;
  height: 42%;
  font-size: clamp(11px, 3.4vw, 16px);
}

.coin.spin { animation: coinspin .95s cubic-bezier(.35,.05,.25,1) both; }

@keyframes coinspin {
  from { transform: rotateY(0deg) scale(.86); }
  to   { transform: rotateY(1800deg) scale(1); }
}

.coin.win {
  opacity: 1;
  transform: translateY(-5px) scale(1.08);
  box-shadow: 0 0 0 3px #fff, 0 0 30px 7px var(--coin, #7a8699), 0 10px 24px rgba(0,0,0,.5);
}

.coin.lose { opacity: .24; transform: scale(.9); }

/* --------------------------------------------------------------- dock -- */

#dock {
  grid-area: dock;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.turn-line {
  margin: 0;
  font-size: clamp(12px, 3.4vw, 15px);
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 7px;
  /* One line, always: a status that wrapped to two lines would take height off
     the board and make it jump as the game is played. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* A block with its overflow hidden has no minimum height of its own, so in a
     column that is short of room the flex box squeezes it to nothing and the
     line that says what just happened disappears. It keeps its height instead
     and the dock scrolls, which is a thing a person can see and use. */
  flex: 0 0 auto;
}

/* The sentence is a block of its own inside the line so that the ellipsis has
   something to be applied to. See the note in setStatus. */
.turn-line .turn-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.turn-line .swatch-inline {
  width: 13px; height: 13px;
  border-radius: 4px;
  flex: none;
  box-shadow: 0 0 0 1px rgba(255,255,255,.25);
}

/* Four to a row, whatever the screen. There are eight colours and they used to
   wrap as a flex row, so on a phone six fitted on the first line and the last
   two grew to fill the second: two dim slabs the width of the dock sitting
   under a palette, which reads as something gone wrong rather than as the two
   colours still in the board. Equal tracks make the eight a rectangle on every
   screen, and the phone gets four to a row of the same size the wide layout
   already had. */
.palette {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 7px;
}

/* The tile is the colour, with nothing written on it. */
.swatch {
  position: relative;
  width: 100%;
  min-width: 0;
  min-height: clamp(40px, 6.6vh, 72px);
  border-radius: 12px;
  border: 1px solid rgba(255,255,255,.16);
  background: var(--sw);
  cursor: pointer;
  padding: 0;
  transition: transform .12s ease, box-shadow .12s ease;
  overflow: hidden;
  -webkit-tap-highlight-color: transparent;
}

.swatch:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0,0,0,.4); }
.swatch:active { transform: translateY(0) scale(.97); }

/* Bright means "you can take this now". Dimmed means it is a colour you could
   take, just not on this turn. Faded out means it does not touch your land at
   all, so tapping it could never do anything. */
.swatch[disabled] {
  opacity: .55;
  cursor: default;
  transform: none;
  box-shadow: none;
  filter: saturate(.55);
}

.swatch[disabled][data-legal="0"] {
  opacity: .2;
  filter: saturate(.25);
}

.swatch.taken { box-shadow: 0 0 0 2px var(--accent); }

.hint {
  margin: 0;
  font-size: clamp(10px, 2.7vw, 12px);
  color: var(--muted);
  line-height: 1.35;
}

/* The coach, in the tutorial. It takes the hint's place in the telling: two
   explanations of the same game on one screen is one too many, and the lesson
   is the one that is being read.

   It is tinted with the accent so it reads as somebody talking rather than as
   more of the furniture, and it is deliberately NOT hidden by the short screen
   rule that hides the hint: the hint is a reminder that can be fetched back
   with the question mark beside the board, and the lesson cannot. */
.coach {
  grid-area: coach;
  margin: 0;
  padding: 8px 10px 9px;
  border-radius: 12px;
  border: 1px solid rgba(110, 231, 255, .3);
  border-left-width: 3px;
  background: rgba(110, 231, 255, .07);
}

.coach[hidden] { display: none; }

.coach-h {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0 0 3px;
  font-size: clamp(11px, 3vw, 13px);
  font-weight: 800;
  color: var(--accent);
  line-height: 1.25;
}

/* A block of its own, because the ellipsis cannot reach a bare text node in a
   flex row. */
.coach-h b {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.coach-h i {
  margin-left: auto;
  flex: none;
  font-style: normal;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .5px;
  color: var(--muted);
}

.coach-b {
  margin: 0;
  font-size: clamp(10px, 2.7vw, 12px);
  color: var(--text);
  line-height: 1.4;
}

.dock-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

.dock-row .btn { flex: 1 1 90px; }

.btn {
  font: inherit;
  font-size: clamp(11px, 3vw, 13px);
  font-weight: 600;
  padding: 9px 8px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  min-width: 0;
  width: 100%;
}

.btn { width: auto; white-space: nowrap; flex: 0 0 auto; background: var(--surface-2); }
.btn:hover, select:hover { border-color: #3a4c72; }
.btn.primary { background: linear-gradient(180deg, #3d7bff, #2d5fd8); border-color: #4a86ff; color: #fff; }

/* ------------------------------------------------- landscape / wide -- */

/* Side by side, which a wide window wants and a short one needs: stacked, a
   landscape phone 320 tall leaves the board about forty pixels and there is no
   game left in it. Width alone does not say this, so height is asked as well. */
@media (orientation: landscape) and (min-width: 620px),
       (orientation: landscape) and (max-height: 460px) {
  #app {
    grid-template-areas: "bar bar" "stage dock";
    grid-template-columns: minmax(0, 1fr) clamp(210px, 26vw, 330px);
    grid-template-rows: auto minmax(0, 1fr);
  }
  /* The lesson takes the head of that column, above the line and the palette;
     the board keeps the full height of the window beside them. */
  #app.coaching {
    grid-template-areas: "bar bar" "stage coach" "stage dock";
    grid-template-rows: auto auto minmax(0, 1fr);
  }
  #dock { overflow-y: auto; }
  /* The dock is a column beside the board here, so its height is whatever the
     window leaves, and a short one has to fit the palette, the line and the
     buttons without scrolling them off. */
  .swatch { min-height: clamp(34px, 5.6vh, 44px); }
}

/* A window too short to hold the explanation besides the game. The palette, the
   turn line and the buttons all have to be reachable, and the board has to keep
   as much of the height as it can, so the paragraph steps aside and the question
   mark beside the board brings the same words back in full. Portrait keeps the
   paragraph longer than landscape does because its dock sits under the board and
   takes the board's height with it when it grows. */
@media (orientation: landscape) and (max-height: 430px),
       (orientation: portrait) and (max-height: 520px) {
  .hint { display: none; }
  .swatch { min-height: 34px; }
  /* The coach cannot step aside the way the hint does, because it is the
     lesson rather than a reminder of one, so it gives up its padding and a
     point of type and keeps every word. */
  .coach { padding: 6px 8px 7px; }
  .coach-h { margin-bottom: 2px; }
  .coach-b { font-size: 10px; line-height: 1.3; }
  /* The four controls beside the board on one row instead of two.
     Measured: a landscape dock is between 210 and 219 pixels wide here, and
     the two labelled buttons at their full size want 90 each, so Menu and New
     match take the first row and the two round buttons wrap under them. That
     is 75 pixels of a column that has about 200, spent on a second row, and it
     is what pushed the question mark off the bottom of a 320 tall window.
     A point of type and a little padding off the labels buys all four a place
     on one row, and the round buttons keep the size they had.

     The 90 pixel basis goes with it. A basis is not a width: it is what the
     line is measured against when it decides where to break, so two buttons
     that are forty and eighty pixels of text were being counted as ninety each
     and the pair of them, with the round buttons, came to more than the column
     has. At their own width the four come to about 186 of the 210 and the row
     grows them into what is left. */
  .dock-row { gap: 3px; }
  .dock-row .btn { flex: 1 1 auto; font-size: 11px; padding: 7px 5px; }
}

/* A landscape window short enough that the lesson and the buttons cannot share
   the column beside the board. Measured: at 667x375 the dock has 269 pixels
   and the palette, the line and the row already want 253 of them, so a lesson
   put in there with them takes the buttons off the bottom of the window and
   the only way back to the menu is a scroll nobody would think to make.

   So at this height the lesson steps out of the column and takes a row of the
   whole window above the game. It is wider there, which costs it a line or
   two, and the board gives up those pixels instead of the controls doing so.
   The dock is left with exactly what it had before the tutorial existed.

   It is asked for by a class the page sets rather than by `:has`, so that a
   browser without `:has` lays the page out as it did and not as something
   nobody designed. */
@media (orientation: landscape) and (max-height: 430px) {
  #app.coaching {
    grid-template-areas: "bar bar" "coach coach" "stage dock";
    grid-template-rows: auto auto minmax(0, 1fr);
  }
}

/* Keep the title readable on a narrow phone by dropping the seat names. */
@media (max-width: 470px) {
  .score-name { display: none; }
  .score { padding: 5px 9px 5px 5px; gap: 5px; }

  /* The head of the profile page carries three things side by side: the level
     badge, the level with its bar, and the score. At 320 wide the middle of
     those is about a hundred and twenty pixels, so the line under the level
     was cut off with an ellipsis and the climb to the next level was wrapped
     over two lines. Neither is a thing to lose: the level and the climb go on
     their own lines and the summary is allowed to run on to a second. */
  .prof-head .prof-top { flex-direction: column; align-items: flex-start; gap: 1px; }
  .prof-head .prof-sub { white-space: normal; overflow: visible; text-overflow: clip; }
}

@media (min-width: 1100px) and (orientation: landscape) {
  #app { grid-template-columns: minmax(0, 1fr) clamp(260px, 22vw, 360px); }
}

/* -------------------------------------------------------------- sheets -- */

.sheet {
  position: fixed;
  inset: 0;
  background: rgba(4, 7, 14, .72);
  backdrop-filter: blur(7px);
  display: grid;
  place-items: center;
  padding: var(--pad);
  /* Above the menu, and not below it. The menu is opened over a match and a
     sheet is opened over the menu: How to play is reached from a button in the
     menu, and a sheet drawn under the menu it was opened from is a button that
     appears to do nothing. The result sheet closes the menu on its way in
     anyway, so nothing here depends on the menu being in front. */
  z-index: 55;
  animation: fade .16s ease;
}

.sheet[hidden] { display: none; }

@keyframes fade { from { opacity: 0; } }

.sheet-card {
  position: relative;
  width: min(520px, 100%);
  max-height: min(86dvh, 700px);
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: clamp(16px, 4vw, 26px);
  box-shadow: 0 24px 70px rgba(0,0,0,.6);
  animation: rise .2s cubic-bezier(.2,.9,.3,1);
}

@keyframes rise { from { transform: translateY(14px) scale(.98); opacity: 0; } }

.sheet-close {
  position: absolute;
  top: 10px; right: 10px;
  width: 32px; height: 32px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}

.sheet h2 {
  margin: 0 0 10px;
  font-size: clamp(18px, 5vw, 24px);
  letter-spacing: .2px;
}

.sheet h3 {
  margin: 18px 0 6px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--muted);
}

/* The board switcher on the result sheet, and the line under the list saying
   when the board being shown starts again.

   The switcher is the .segs control the menu already uses for difficulty and
   for the board size, so it is the same control in the same place on the page
   rather than a second kind of segmented button. Its top margin is the one
   thing that has to be set here: it follows the heading rather than a
   paragraph, and the heading has no bottom margin to give it. */
.board-slot .segs { margin: 10px 0 10px; }
.lb-when { margin-top: 8px; }

/* A board is a list of people, and a row of it is a control when there is a
   name on it to look up: the tap opens what that player's scores say, which is
   the one thing a stranger's name cannot tell you.

   Four columns: the place, the name, the level that score stands at, and the
   score. The name is the one that gives, so a long handle is shortened rather
   than pushing the two numbers off the side of a 320 wide phone. */
.lb-list {
  display: flex;
  flex-direction: column;
  margin-bottom: 12px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--bg-2);
  overflow: hidden;
}

.lb-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 14px;
  border: 0;
  border-top: 1px solid var(--line);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
}

.lb-row:first-child { border-top: 0; }
button.lb-row { cursor: pointer; }
button.lb-row:hover { background: rgba(255, 255, 255, .03); }
button.lb-row:active { background: rgba(255, 255, 255, .07); }
/* A guest row is a row and not a control: there is no name to look up. */
.lb-row.flat { cursor: default; }
.lb-row.mine { background: rgba(110, 231, 255, .07); }

.lb-rank {
  min-width: 14px;
  color: var(--muted);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.lb-who {
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lb-lv {
  flex: none;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .4px;
  color: var(--muted);
  white-space: nowrap;
}

.lb-val { font-weight: 900; font-variant-numeric: tabular-nums; }
/* A board the player is not on, or one that could not be read. Said in the same
   column as a score so the four boards line up down the card. */
.lb-val.dim { font-size: 12px; font-weight: 600; color: var(--muted); }
.lb-row.mine .lb-who, .lb-row.mine .lb-val { color: var(--accent); }

.lb-back { margin-bottom: 14px; }

.sheet p, .sheet li {
  margin: 0 0 8px;
  font-size: clamp(13px, 3.6vw, 15px);
  line-height: 1.5;
  color: #cdd8ee;
}

.sheet ul { margin: 0; padding-left: 18px; }
/* Bold text in a sheet reads light. The seat badges are bold too but carry
   their own ink, and letting this reach them painted the "1" white on white. */
.sheet b:not(.badge) { color: var(--text); }

/* A finished match, told apart at a glance. Three outcomes, three tints, and
   one of three marks: a tick, a pair of level bars, a cross. The card keeps
   its own surface colour and only takes a wash of the tint at the top, so the
   text on it stays as readable as it is on any other sheet. */
.sheet-card.res-win {
  border-color: rgba(61, 220, 132, .46);
  background-image: linear-gradient(180deg, rgba(61, 220, 132, .20), rgba(61, 220, 132, 0) 190px);
  box-shadow: 0 24px 70px rgba(0, 0, 0, .6), 0 0 56px -14px rgba(61, 220, 132, .75);
}
.sheet-card.res-draw {
  border-color: rgba(255, 217, 61, .42);
  background-image: linear-gradient(180deg, rgba(255, 217, 61, .17), rgba(255, 217, 61, 0) 190px);
  box-shadow: 0 24px 70px rgba(0, 0, 0, .6), 0 0 56px -14px rgba(255, 217, 61, .6);
}
.sheet-card.res-loss {
  border-color: rgba(255, 132, 132, .42);
  background-image: linear-gradient(180deg, rgba(255, 132, 132, .16), rgba(255, 132, 132, 0) 190px);
  box-shadow: 0 24px 70px rgba(0, 0, 0, .6), 0 0 56px -14px rgba(255, 132, 132, .65);
}

.res-band { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }

.res-badge {
  width: 42px; height: 42px;
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  border: 2px solid currentColor;
  background: rgba(255, 255, 255, .07);
}
.res-badge svg { width: 24px; height: 24px; display: block; }

.res-word {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 2.4px;
  text-transform: uppercase;
}

.res-win .res-badge, .res-win .res-word { color: var(--win); }
.res-draw .res-badge, .res-draw .res-word { color: var(--draw-c); }
.res-loss .res-badge, .res-loss .res-word { color: var(--loss); }

/* A win throws a little colour behind the mark, drawn from the same eight the
   board is made of, so the celebration belongs to this game and to no other. */
.res-win .res-badge {
  background:
    conic-gradient(from 210deg, var(--c1), var(--c2), var(--c3), var(--c4), var(--c5), var(--c6), var(--c7), var(--c8), var(--c9));
  color: #071018;
  border-color: #fff;
  box-shadow: 0 0 0 4px rgba(255, 255, 255, .10);
}

.result-head {
  font-size: clamp(22px, 7vw, 34px);
  font-weight: 900;
  margin: 0 0 4px;
  letter-spacing: -.4px;
}
/* The score the match moved takes an outcome's colour too, so the one line
   somebody reads first on the way out of a match is not the one line still
   wearing the page's general accent.

   It is the STRIP'S OWN outcome and not the card's, because pass and play has
   two people at one device and only one record. Player 2 wins there and the
   card says so in green; the score beside it is the device owner's, who held
   seat 1 and lost, and a green "+3 score ... Lost" is one line saying two
   things. The strip is coloured by what it counts.

   Written against the strip's own class rather than its child, so it outranks
   the plain accent rule further down the sheet. Two classes on one element does
   that at any order in the file; naming the class alone does not. */
.sc-strip.sc-w .st b { color: var(--win); }
.sc-strip.sc-d .st b { color: var(--draw-c); }
.sc-strip.sc-l .st b { color: var(--loss); }

.sc-strip.sc-w .sb i { background: linear-gradient(90deg, #1fb96a, var(--win)); }
.sc-strip.sc-d .sb i { background: linear-gradient(90deg, #d99b0c, var(--draw-c)); }
.sc-strip.sc-l .sb i { background: linear-gradient(90deg, #c9504f, var(--loss)); }

.res-win .result-head { color: #b6f7d0; }
.res-draw .result-head { color: #ffeaa8; }
.res-loss .result-head { color: #ffc4c4; }

.result-sub { color: var(--muted); margin: 0 0 16px; }

.result-grid {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px 14px;
  padding: 14px 16px;
  border-radius: 14px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  margin-bottom: 18px;
}

.result-grid .rk { display: flex; align-items: center; gap: 8px; font-weight: 700; }
.result-grid .rv { text-align: right; font-weight: 800; font-variant-numeric: tabular-nums; }
/* The caller's own row. The name and the number are two cells of the grid and
   neither contains the other, so the rule has to be the class on each of them:
   a descendant selector here matched nothing at all, and the row that was
   supposed to stand out looked like every other one on the board. */
.result-grid .win { color: var(--accent); }

.sheet-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.sheet-actions .btn { padding: 11px 18px; font-size: clamp(13px, 3.6vw, 15px); }

.kv { display: flex; gap: 8px; align-items: center; margin: 10px 0; flex-wrap: wrap; }

.code-box {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 10px 12px;
  margin: 10px 0;
}

.code-box code {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 14px;
  letter-spacing: 1px;
  color: var(--accent);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
}

.note { font-size: 12.5px; color: var(--muted); line-height: 1.45; }
.warn { color: #ffc46b; }

@keyframes spin { to { transform: rotate(360deg); } }

.spinner {
  display: inline-block;
  width: 14px; height: 14px;
  border: 2px solid rgba(255,255,255,.25);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .8s linear infinite;
  vertical-align: -2px;
}

/* --------------------------------------------------------------- level -- */

/* A player's level, wherever that player's name is. Hidden until the profile
   has been read, so a chip never shows a level the page has not been told. */
.lvl {
  display: none;
  flex: none;
  padding: 2px 6px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .2px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: #dceaff;
  background: linear-gradient(90deg, rgba(110,231,255,.24), rgba(168,85,247,.3));
  box-shadow: inset 0 0 0 1px rgba(110,231,255,.35);
}

.lvl.on { display: inline-block; }

/* ---------------------------------------------------------------- menu -- */

/* The way in. It covers the page rather than sitting over the board, because
   it is where a match is chosen and there is nothing behind it worth reading
   until it has been. It scrolls: the whole menu is taller than a short phone
   in landscape, and everything on it is a choice somebody has to be able to
   reach. */
.menu {
  position: fixed;
  inset: 0;
  z-index: 50;
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 50% -12%, #1d2f57 0%, transparent 62%),
    radial-gradient(95% 62% at 108% 112%, #3d1a4c 0%, transparent 66%),
    var(--bg);
  animation: fade .16s ease;
}

.menu[hidden] { display: none; }

.menu-scroll {
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: calc(env(safe-area-inset-top, 0px) + 20px) var(--pad) calc(env(safe-area-inset-bottom, 0px) + 24px);
}

.menu-inner {
  width: min(560px, 100%);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
}

.menu-head { text-align: center; margin: 4px 0 clamp(16px, 3.6vh, 26px); }

/* The glow that used to sit behind this is gone with the wheel it was there to
   light. It was #6ee7ff, which is not one of the eight, and a mark that needs
   a colour the game does not own to be visible is a mark that is not working. */
.brand-dot-lg {
  display: block;
  width: 48px;
  height: 48px;
  margin: 0 auto 12px;
}

.menu-title {
  margin: 0;
  font-size: clamp(25px, 7.6vw, 35px);
  font-weight: 900;
  letter-spacing: -.6px;
}

.menu-title-sm { font-size: clamp(19px, 5.6vw, 25px); margin-bottom: 16px; }

/* The line under a heading. On the home screen it is the last thing in the
   header block, which has its own space beneath it; on the two screens that
   begin with a heading and a line, it is the last thing before the first
   question, and a question asked directly under a sentence reads as part of
   it. So it carries the space itself, and the header block takes it back. */
.menu-tag {
  margin: 7px 0 clamp(12px, 2.8vh, 18px);
  font-size: clamp(12px, 3.4vw, 14px);
  color: var(--muted);
}
.menu-head .menu-tag { margin-bottom: 0; }

/* The menu is three screens and shows one. Each is a column, like the menu
   itself, so the back link and the title sit where they sat before. */
.mview { display: flex; flex-direction: column; }
.mview[hidden] { display: none; }

/* The menu's background: a match playing itself, in a band between the title
   and the cards. It is the whole of what is behind the menu, and it is the
   only moving thing on it, which is why it is a band and not a wash. Its
   height is asked for in viewport units as well as pixels so that a short
   landscape window shrinks it rather than pushing the cards off the screen. */
/* The band is the shape of the recording, and its size is whatever is left
   after the window has been given its share. Both halves matter. A band that
   filled the width and took its height from a clamp would be stretched to
   whatever the window happened to be: on a laptop that is four and a half to
   one against a recording that is one and a half to one, and the crop that
   fills it leaves three rows of a nine row board on screen. A strip of tiles
   is not a match, and the caption underneath it says a match is what this is.
   So the height leads and the width follows from it, capped by the column it
   sits in, which keeps every row of the board in the picture at every size.
   The cap is generous at the top end, because a tall window can afford one. */
.hero {
  --band: clamp(118px, 30vh, 300px);
  position: relative;
  container-type: inline-size;
  width: min(100%, calc(var(--band) * 606 / 360));
  aspect-ratio: 606 / 360;
  margin: 0 auto clamp(15px, 3.4vh, 22px);
  border-radius: 20px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: #0b1120;
  box-shadow: 0 16px 38px rgba(0, 0, 0, .42);
}

.hero-vid { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Under the caption, so the words are read on a floor rather than on whatever
   colour the board happened to be painting at that moment. */
.hero-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top,
    rgba(6, 9, 18, .88) 0%, rgba(6, 9, 18, .22) 42%, rgba(6, 9, 18, 0) 74%);
}

/* On its own pill rather than straight onto the board. It is the one line that
   says what the picture is, and the picture underneath it changes colour twenty
   times a second: a caption that is legible on one move and lost on the next is
   worse than no caption. */
.hero-cap {
  position: absolute;
  left: 12px; bottom: 12px;
  max-width: calc(100% - 24px);
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(6, 9, 18, .58);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  /* Sized off the band and not off the window, because the band is what it has
     to fit inside and the band is not the width of the window: a short window
     leaves it a third of the page. At a fixed size the line wrapped onto two
     rows there and covered the board it was describing. */
  font-size: clamp(8.5px, 3.4cqw, 11px);
  font-weight: 700;
  letter-spacing: .5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-transform: uppercase;
  color: #c3cfee;
}

/* The search, which is a screen with nothing to configure on it. */
.find-box {
  margin: 4px 0 clamp(18px, 4vh, 26px);
  padding: 26px 18px 22px;
  border-radius: 20px;
  border: 1px solid var(--line);
  background: var(--surface);
  text-align: center;
}

.find-spin { margin-bottom: 15px; }
.find-line { margin: 0; font-size: clamp(15px, 4.5vw, 17px); font-weight: 800; }

.find-clock {
  margin: 10px 0 0;
  font-size: clamp(30px, 11vw, 42px);
  font-weight: 900;
  letter-spacing: -1px;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}

.find-clock[hidden] { display: none; }
.find-spin[hidden] { display: none; }
.find-box .note { margin: 12px 0 0; text-align: center; }

/* The name of a room of your own. Monospaced and spaced out because it is a
   string somebody reads aloud or types into another machine, and a keyboard
   that will not join the letters together needs to see where they end. */
.find-code {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  margin: 12px 0 0;
  padding: 9px 12px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--bg-2);
}

.find-code[hidden] { display: none; }

.find-code-cap {
  flex: none;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .7px;
  text-transform: uppercase;
  color: var(--muted);
}

.find-code code {
  min-width: 0;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: clamp(13px, 4vw, 16px);
  letter-spacing: .6px;
  color: var(--accent);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  user-select: all;
}
.find-acts { display: flex; flex-direction: column; gap: 10px; }
.find-acts .btn { padding: 13px 18px; font-size: clamp(13px, 3.6vw, 15px); }
.find-acts .btn[hidden] { display: none; }
.find-pair { display: flex; gap: 10px; }
.find-pair .btn { flex: 1 1 0; }

/* Naming the room, under the search. A rule above it, because these are not
   more things to do with the search that is running: they are the other way of
   meeting somebody, and the two are alternatives rather than a sequence. */
.find-ways {
  margin-top: clamp(16px, 3.4vh, 22px);
  padding-top: clamp(14px, 3vh, 18px);
  border-top: 1px solid var(--line);
}

.find-ways[hidden] { display: none; }
.find-ways .sect { text-align: center; }

.join-row { display: flex; gap: 10px; margin-top: 8px; }

.join-in {
  flex: 1 1 auto;
  min-width: 0;
  padding: 12px 13px;
  border-radius: 13px;
  border: 1px solid var(--line);
  background: var(--bg-2);
  color: var(--text);
  font: inherit;
  font-size: clamp(13px, 3.6vw, 15px);
  font-weight: 700;
  letter-spacing: .4px;
}

.join-in::placeholder { color: var(--muted); font-weight: 600; letter-spacing: 0; }
.join-in:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.join-row .btn { padding: 12px 16px; font-size: clamp(13px, 3.6vw, 15px); }

.sect {
  margin: 0 0 9px;
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--muted);
}

.menu-cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 clamp(16px, 3vw, 26px); }
.col-a { min-width: 0; }
.col-b { min-width: 0; }
#diffSect, .col-b { margin-bottom: clamp(15px, 3.6vh, 22px); }

/* the profile, which is also the way into the whole profile */
.prof {
  display: flex;
  align-items: center;
  gap: 13px;
  width: 100%;
  margin-bottom: clamp(16px, 3.6vh, 24px);
  padding: 13px 14px;
  border-radius: 17px;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color .16s, transform .12s;
}

.prof:hover { border-color: #3a4c72; }
.prof:active { transform: scale(.99); }

/* The level, on a tile of the board. This was the other colour wheel: a ring
   of the eight in spectrum order with the level sitting in its hole, which is
   the same wheel the header used to wear. It is a board tile now, and the
   number sits on a dark disc over it so it can still be read. It is drawn at
   fifty-four pixels, so the fragment underneath is a shape and a colour rather
   than a board anybody counts: what it has to say is "this game" at a glance,
   and the number says the rest. */
.lv-tile {
  position: relative;
  flex: none;
  width: 54px;
  height: 54px;
  border-radius: 24%;
  display: grid;
  place-items: center;
  background-image: url("icon.svg");
  background-size: 100% 100%;
  background-repeat: no-repeat;
}

/* The tile is `display: grid`, which beats the browser's own `[hidden]` rule,
   and it is hidden while there is no level to put in it. See paintWho. */
.lv-tile[hidden] { display: none; }

.lv-tile::before {
  content: "";
  position: absolute;
  inset: 12px;
  border-radius: 50%;
  background: rgba(8, 11, 20, .94);
}

.lv-tile b { position: relative; font-size: 21px; font-weight: 900; }

.prof-mid { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; }

.prof-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.prof-top b { font-size: clamp(14px, 4vw, 16px); font-weight: 800; }
.prof-top span { font-size: clamp(11px, 3vw, 12.5px); color: var(--muted); font-variant-numeric: tabular-nums; }

.prof-bar {
  display: block;
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: #1a2438;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
}

.prof-bar i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #6ee7ff, #a855f7);
  transition: width .45s cubic-bezier(.3,.9,.3,1);
}

.prof-sub {
  font-size: clamp(10.5px, 2.9vw, 12px);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.prof-go { flex: none; font-size: 22px; font-weight: 700; color: var(--muted); }

/* the three ways to play */
/* The three ways in. Each one is the whole of its row, because tapping it is
   not a choice to be recorded and confirmed later, it is the thing that opens
   the next screen. Three columns of small tiles read as a setting, which is
   what they used to be and is not what they are now. */
.modes { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; margin-bottom: clamp(15px, 3.6vh, 22px); }

.mode {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 13px;
  padding: 10px 14px 10px 10px;
  border-radius: 18px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color .16s, background .16s, transform .12s;
}

.mode:hover { border-color: #3a4c72; background: var(--surface-2); }
.mode:active { transform: scale(.985); }

.mode-mid { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.mode-mid b { font-size: clamp(14px, 4.1vw, 16px); font-weight: 800; line-height: 1.15; }
.mode-mid span { font-size: clamp(11px, 3.1vw, 12.5px); color: var(--muted); line-height: 1.3; }
.mode-go { flex: none; font-size: 22px; font-weight: 700; line-height: 1; color: var(--muted); }
.mode:hover .mode-go { color: var(--accent); }

/* What a first run is offered. It is the only thing on this screen that is
   there for some people and not others, so it carries the accent and sits in a
   box of its own: it must be readable at a glance as an offer rather than
   mistaken for a fourth way to play. It is laid out as a column and not as a
   row because the button inside it is a real control with a real width, and a
   control squeezed beside two lines of text at 320px is a control nobody can
   hit. */
.firstoff {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin: -4px 0 clamp(15px, 3.6vh, 22px);
  padding: 13px 14px 14px;
  border-radius: 18px;
  border: 1px solid #33518f;
  background: linear-gradient(180deg, rgba(61, 123, 255, .14), rgba(61, 123, 255, .04));
}
/* A class that gives an element a display takes the hidden attribute away from
   it: the attribute is a user agent rule, and any author rule beats it. So the
   offer says it again for itself, the way every other block in this file that
   is turned on and off does. Without this line `hidden = true` does nothing at
   all here, and the offer stands on the menu for somebody who has played
   hundreds of matches, which is the offer answering a question they stopped
   asking long ago. */
.firstoff[hidden] { display: none; }
.firstoff b { font-size: clamp(13.5px, 3.9vw, 15px); font-weight: 800; line-height: 1.15; }
.firstoff span { font-size: clamp(11px, 3.1vw, 12.5px); color: var(--muted); line-height: 1.35; }
.firstoff .play {
  margin-top: 7px;
  padding: 12px 16px;
  border-radius: 14px;
  font-size: clamp(13px, 3.8vw, 15px);
  box-shadow: 0 8px 20px rgba(45, 95, 216, .28);
}

/* Each opponent is a shape rather than a word: a chip, two people, a ring. */
.mode-ico {
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  background: var(--mk, #26324c);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08);
}

.ico-cpu { --mk: #16324a; }
.ico-hot { --mk: #3a2450; }
.ico-on  { --mk: #123a2c; }

.mode-ico::before { content: ""; display: block; }

.ico-cpu::before {
  width: 15px; height: 15px;
  border-radius: 5px;
  background: #6ee7ff;
  box-shadow: 0 0 0 3px rgba(110,231,255,.2);
}

.ico-hot::before {
  width: 12px; height: 12px;
  border-radius: 50%;
  background: #ffd93d;
  transform: translateX(-3px);
  box-shadow: 6px 0 0 0 #ff4fd8;
}

.ico-on::before {
  width: 17px; height: 17px;
  border-radius: 50%;
  border: 3px solid #3ddc84;
}

/* how hard the computer plays */
.segs {
  display: flex;
  gap: 4px;
  padding: 4px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--surface);
}

.segs button {
  flex: 1 1 0;
  min-width: 0;
  padding: 10px 6px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: clamp(11.5px, 3.2vw, 13.5px);
  font-weight: 700;
  cursor: pointer;
  transition: background .16s, color .16s;
}

.segs button.on { background: var(--surface-2); color: var(--text); box-shadow: inset 0 0 0 1px var(--accent); }

/* the board sizes */
.sizes { display: grid; grid-template-columns: repeat(auto-fit, minmax(78px, 1fr)); gap: 7px; }

.chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 4px;
  border-radius: 13px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  cursor: pointer;
  transition: border-color .16s, background .16s;
}

.chip b { font-size: clamp(11px, 3vw, 12.5px); font-weight: 800; }
.chip span { font-size: clamp(9.5px, 2.7vw, 11px); color: var(--muted); font-variant-numeric: tabular-nums; }
.chip.on { border-color: var(--accent); background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--accent); }
.chip.on span { color: var(--text); }

/* a board of your own */
.custom { display: flex; gap: 8px; margin-top: 9px; animation: fade .16s ease; }
.custom[hidden] { display: none; }

.num {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 4px 4px 4px 11px;
  border-radius: 13px;
  border: 1px solid var(--line);
  background: var(--surface);
}

.num span {
  flex: none;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .7px;
  text-transform: uppercase;
  color: var(--muted);
}

.num input {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  padding: 9px 6px;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--bg-2);
  color: var(--text);
  font: inherit;
  font-size: 15px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.play {
  width: 100%;
  margin-top: 4px;
  padding: 16px 18px;
  border-radius: 17px;
  border: 1px solid #4a86ff;
  background: linear-gradient(180deg, #3d7bff, #2d5fd8);
  color: #fff;
  font: inherit;
  font-size: clamp(15px, 4.4vw, 18px);
  font-weight: 800;
  letter-spacing: .3px;
  cursor: pointer;
  box-shadow: 0 12px 28px rgba(45, 95, 216, .34);
  transition: transform .12s, box-shadow .12s;
}

.play:active { transform: translateY(1px) scale(.995); }

/* The second thing the menu offers, under the thing it is for. Quiet enough
   that the eye still lands on Play first: it is a different weight of outline
   and no fill, rather than a second blue slab competing with the first. */
.play.ghost {
  margin-top: 8px;
  padding: 12px 18px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font-size: clamp(13px, 3.8vw, 15px);
  font-weight: 700;
  box-shadow: none;
}

.play.ghost:hover { border-color: #3a4c72; background: var(--surface-2); }
.play.ghost:active { transform: translateY(1px); }

/* Closing the menu. It is the same round cross the sheets are closed with, and
   it sits in the corner the header leaves empty rather than in the stack of
   buttons at the bottom: the menu opens on a match people are part way through
   as often as it opens on nothing, and there it is a way back rather than
   another thing to run.

   Sticky, so it stays where the hand already is when the menu is scrolled,
   which on a short phone it is. The negative margin takes back the height it
   would otherwise add above the title. */
.menu-x {
  position: sticky;
  top: 6px;
  align-self: flex-end;
  z-index: 3;
  width: 40px;
  height: 40px;
  margin-bottom: -46px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  font: inherit;
  font-size: 19px;
  line-height: 1;
  display: grid;
  place-items: center;
  cursor: pointer;
}

.menu-x[hidden] { display: none; }

.back {
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 13px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.back:hover { color: var(--text); }

.menu-note {
  margin: 13px 0 0;
  font-size: 11.5px;
  line-height: 1.5;
  text-align: center;
  color: var(--muted);
}

/* ------------------------------------------------------------ profile -- */

.prof-head {
  display: flex;
  align-items: center;
  gap: 15px;
  padding: 16px;
  border-radius: 17px;
  border: 1px solid var(--line);
  background: var(--bg-2);
  margin-bottom: 16px;
}

.prof-head .prof-ring { width: 64px; height: 64px; }
.prof-head .prof-ring b { font-size: 25px; }
.prof-head .prof-mid { gap: 7px; }

/* The score, at the end of the head. The level is how far somebody has come
   and the score is the number a match moves, so the two lead the page together.
   It is the last thing in the row and it is narrow, because the level bar
   beside it is the part that has to have room at 320 wide. */
.prof-score {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  padding-left: 13px;
  border-left: 1px solid var(--line);
}

.prof-score b {
  font-size: clamp(22px, 7vw, 29px);
  font-weight: 900;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}

.prof-score span {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .9px;
  text-transform: uppercase;
  color: var(--muted);
}

.prof-score i {
  font-style: normal;
  font-size: 11px;
  font-weight: 700;
  color: var(--win);
  font-variant-numeric: tabular-nums;
}

.prof-score i:empty { display: none; }
.prof-score.neg i { color: var(--loss); }

/* The win rate, above the three counts it is worked out from. Its own block
   rather than a fourth tile beside them: Won, Drawn and Lost are three things
   that happened, and this is a share of them, so it is worth a bar and the sum
   that produced it. Four tiles in one row would also have squeezed the label
   below what a 320 wide phone can hold. */
.wr {
  padding: 12px 15px 14px;
  border-radius: 15px;
  border: 1px solid var(--line);
  background: var(--bg-2);
  margin-bottom: 10px;
}

.wr-h { display: flex; align-items: baseline; gap: 9px; margin-bottom: 9px; }

.wr-k {
  flex: none;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .9px;
  text-transform: uppercase;
  color: var(--muted);
}

/* A block of its own so the ellipsis has something to reach, and flexible so it
   is the part that gives way when the row is tight. */
.wr-sub {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: clamp(10.5px, 2.9vw, 12px);
  font-weight: 600;
  color: var(--muted);
}

.wr-n {
  margin-left: auto;
  flex: none;
  font-size: clamp(18px, 5.4vw, 22px);
  font-weight: 900;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--win);
}

.wr-bar { height: 7px; border-radius: 4px; background: var(--bg); overflow: hidden; }

.wr-bar i { display: block; height: 100%; border-radius: 4px; background: linear-gradient(90deg, #1fb96a, var(--win)); }

.prof-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 18px; }

.stat {
  padding: 12px 6px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--bg-2);
  text-align: center;
}

.stat b { display: block; font-size: clamp(19px, 6vw, 24px); font-weight: 900; font-variant-numeric: tabular-nums; }
.stat span { font-size: 10px; font-weight: 700; letter-spacing: .9px; text-transform: uppercase; color: var(--muted); }
.stat.w b { color: var(--win); }
.stat.d b { color: var(--draw-c); }
.stat.l b { color: var(--loss); }

.wdl {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 7px 14px;
  padding: 13px 15px;
  border-radius: 15px;
  border: 1px solid var(--line);
  background: var(--bg-2);
  margin-bottom: 18px;
}

.wdl .k { font-size: 13.5px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; }
.wdl .v { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--muted); white-space: nowrap; }
.wdl .v i { font-style: normal; }
.wdl .v i.w { color: var(--win); }
.wdl .v i.d { color: var(--draw-c); }
.wdl .v i.l { color: var(--loss); }
/* The group's own win rate, in the page's own colour rather than in one of the
   three outcome colours: it is not a fourth count, it is what the three beside
   it come to. */
.wdl .v i.r { color: var(--text); }
.wdl .v i.r::before { content: '\00b7'; margin: 0 6px 0 2px; color: var(--muted); }

.wdl .k .none { font-weight: 600; color: var(--muted); }

/* what a finished match moved the score by, on the result */
.sc-strip {
  padding: 13px 15px;
  border-radius: 15px;
  border: 1px solid var(--line);
  background: var(--bg-2);
  margin-bottom: 18px;
}

.sc-strip .st { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 9px; }
.sc-strip .st b { font-size: clamp(15px, 4.4vw, 18px); font-weight: 900; color: var(--accent); }
.sc-strip .st span { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }

.sc-strip .sb {
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: #1a2438;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
}

.sc-strip .sb i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #6ee7ff, #a855f7);
  transition: width .5s cubic-bezier(.3,.9,.3,1);
}

/* ----------------------------------------------------------- level up -- */

.levelup {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: var(--pad);
  background: radial-gradient(70% 60% at 50% 42%, rgba(13,22,44,.88), rgba(5,8,16,.96));
  backdrop-filter: blur(6px);
  animation: fade .18s ease;
}

.levelup[hidden] { display: none; }

.lv-card {
  position: relative;
  overflow: hidden;
  width: min(340px, 100%);
  padding: 30px 22px 22px;
  border-radius: 24px;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #1b2740, #121a2c);
  box-shadow: 0 26px 70px rgba(0,0,0,.6);
  text-align: center;
  animation: rise .24s cubic-bezier(.2,.9,.3,1);
}

/* The eight colours of the game, turning slowly behind the number. */
.lv-rays {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 230%;
  height: 230%;
  margin: -115% 0 0 -115%;
  border-radius: 50%;
  background: conic-gradient(var(--c1), var(--c2), var(--c3), var(--c4), var(--c5), var(--c6), var(--c7), var(--c8), var(--c9));
  opacity: .17;
  filter: blur(17px);
  animation: spin 17s linear infinite;
  pointer-events: none;
}

.lv-lead, .lv-num, .lv-line, .lv-sub, .lv-actions { position: relative; }

.lv-lead {
  margin: 0;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 2.6px;
  text-transform: uppercase;
  color: var(--muted);
}

.lv-num {
  margin: 8px 0 2px;
  font-size: clamp(56px, 19vw, 78px);
  font-weight: 900;
  line-height: 1;
  background: linear-gradient(180deg, #ffffff, #93d4ff);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.lv-line { margin: 6px 0 0; font-size: clamp(14px, 4.2vw, 17px); font-weight: 800; }
.lv-sub { margin: 7px 0 20px; font-size: 12.5px; color: var(--muted); line-height: 1.45; }
.lv-actions { margin: 0; }

/* ----------------------------------------------------- menu, wide and short -- */

/* Side by side on anything with the width for it: the menu is a page of
   choices, and two columns of them is one screenful instead of two on a
   laptop and on a phone held sideways. */
@media (min-width: 720px) and (min-height: 420px) {
  .menu-inner { width: min(880px, 100%); }
  .menu-cols { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

/* A window with very little height. Nothing is dropped: every choice here is
   one somebody has to be able to make, so the menu scrolls and the spacing
   between them is what gives way. */
@media (max-height: 430px) {
  .menu-head { margin-bottom: 14px; }
  .brand-dot-lg { width: 34px; height: 34px; margin-bottom: 8px; }
  .menu-title { font-size: 22px; }
  .menu-tag { display: none; }
  .prof { margin-bottom: 14px; padding: 10px 12px; }
  #diffSect, .col-b { margin-bottom: 12px; }
  .modes { margin-bottom: 12px; }
  .mode { padding: 9px 5px 8px; gap: 6px; }
  .mode-ico { width: 28px; height: 28px; border-radius: 9px; }
  .play { padding: 12px 16px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
