/* The @font-face rules are in fonts.css. */

/* Sized for an 11" iPad in landscape (1194 × 834), fluid either side of it. */

:root {
  color-scheme: dark;
  font-family: "Univers Next Pro", Inter, ui-sans-serif, system-ui, sans-serif;
  font-weight: 700;
  background: #050b14;
  color: #e8f1ff;
  --accent: #5ef0a0; /* the Result and Leaderboard green */
  --control-size: 6.5vmin; /* the menu button, and the player card's height */
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  background: #050b14;
  touch-action: manipulation; /* no double-tap zoom on the web; the app stops it on a phone */
}

/* A game, not a page: no text to select, and no press-and-hold callout
   (copy, look up) on iOS. */
body {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* ---- Screens: one visible at a time ---- */

.screen[hidden] { display: none; }

.screen { position: relative; }

/* Fills the viewport behind whichever screen is showing. */
.swirl {
  --swirl-grid-cell: 7px; /* whole pixels, so the lines stay even */
  --swirl-grid-shade: rgba(0, 0, 0, 0.25);
  position: fixed;
  inset: 0;
}

.swirl[hidden] { display: none; }

.swirl-canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* LED-panel grid from the mock-up: each cell darkens softly towards its edges.
   Static, so it's painted once and just composited over the moving canvas. */
.swirl::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(90deg, var(--swirl-grid-shade), transparent 30%, transparent 70%, var(--swirl-grid-shade)),
    linear-gradient(0deg, var(--swirl-grid-shade), transparent 30%, transparent 70%, var(--swirl-grid-shade));
  background-size: var(--swirl-grid-cell) var(--swirl-grid-cell);
  will-change: transform; /* keep it on its own layer so the canvas never repaints it */
}

.screen-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2vmin;
  height: 100%;
}

/* Game: the board dead centre, filling nearly the whole height. */
.screen-game {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}

#board,
.board-pulse {
  --board-size: min(94vh, 94vw); /* the board drawn inside the box, which is taller in portrait */
  display: block;
  height: 94vh;
  max-width: 94vw;
  aspect-ratio: 1;
}

/* Laid exactly over the board: same size, centred the same way. */
.board-pulse {
  position: absolute;
  inset: 0;
  margin: auto;
}

.board-pulse[hidden] { display: none; }

/* Wraps the board and the glow layer, which is laid over it. */
.board-zoom { position: relative; }

/* Phones: the whole board is too small to aim at, so it zooms in and
   slides up or down to bring the section due next into the middle of the
   screen, staying centred side to side. It moves on after each hit.
   board-svg.js (setCurrent) sets --focus-y: how far above or below the
   board's centre the middle of that section is (from the bull out to its
   number), as a share of the board's size. With nothing due (the run is
   over), or while the screen first shows the whole board (app.js,
   .is-overview), it's zoomed out. It moves this wrapper, so the board's own bump
   and fades still play. The move is in board sizes, not %: in portrait
   the box is taller than the board drawn in it. */
@media (max-height: 500px), (max-width: 500px) {
  .board-zoom {
    --board-zoom: 1.8;
    --board-size: min(94vh, 94vw); /* as #board */
    transition: transform 0.8s cubic-bezier(0.65, 0, 0.35, 1);
  }

  .board-zoom.has-focus:not(.is-overview) {
    transform:
      translateY(calc(var(--focus-y) * var(--board-zoom) * -1 * var(--board-size)))
      scale(var(--board-zoom));
  }
}

@media (prefers-reduced-motion: reduce) {
  .board-zoom { transition: none; }
}

/* Top left, mirroring the menu: avatar, name over targets hit, then the clock. */
.player-card {
  position: absolute;
  top: 25px;
  left: 25px;
  display: flex;
  align-items: center;
  gap: 1.8vmin;
  height: var(--control-size); /* level with the menu button, top right */
  padding: 0 3vmin 0 0.8vmin;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  background: rgba(14, 14, 20, 0.85);
  color: #fff;
}

.player-card p { margin: 0; }

.player-avatar {
  display: grid;
  place-items: center;
  flex: none;
  width: calc(var(--control-size) - 1.6vmin - 2px); /* inside the padding and border */
  height: calc(var(--control-size) - 1.6vmin - 2px);
  border-radius: 50%;
  /* Univers capitals sit 0.11em above centre; padding the top drops the
     letter back to the middle of the circle. */
  padding-top: 0.22em;
  background: #8ec5ea;
  color: #0b1a2a;
  font-size: 2vmin;
}

.player-name {
  max-width: 18vmin; /* long names are cut short so the card stays clear of the board */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* Univers capitals sit 0.11em above centre; drop them level. */
  position: relative;
  top: 0.11em;
  font-size: 2.2vmin;
  line-height: 1.2; /* room for descenders, which the ellipsis box would clip */
}

.player-time {
  font-family: "Archetype Display", Inter, ui-sans-serif, system-ui, sans-serif;
  font-weight: normal;
  font-size: 2.8vmin;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  /* Archetype's figures sit 0.145em above centre; drop them level. */
  position: relative;
  top: 0.145em;
}

/* Clocks (app.js, renderClock): every Archetype figure is 0.828em wide, but
   the 1 is drawn left of centre in its slot and the 4 and 7 right of it, so
   they seem to jump as the clock runs. Each figure gets a fixed slot and
   those three are nudged back to the middle. */
.clock-digit,
.clock-sep {
  display: inline-block;
  width: 0.828em;
}

.clock-sep[data-char=":"] { width: 0.27em; }
.clock-sep[data-char="."] { width: 0.265em; }

/* The game clock's box is fixed to exactly 00:00.00 (six figures, a colon
   and a point), so nothing inside it can ever change the card's width. */
.player-time {
  width: calc(6 * 0.828em + 0.27em + 0.265em);
  overflow: hidden;
}

.clock-digit[data-char="1"] { transform: translateX(0.121em); }
.clock-digit[data-char="4"] { transform: translateX(-0.096em); }
.clock-digit[data-char="7"] { transform: translateX(-0.099em); }

/* Game: Quit bottom left and Reset bottom right, menu items on their own
   (index.html). Quit's first tap turns it red and asks again (app.js,
   setQuitArmed); Reset asks in a dialog (app.js, Reset). */
.game-button {
  position: absolute;
  bottom: 25px;
}

.quit-button { left: 25px; }
.reset-button { right: 25px; }

/* The run is over once the fifth section is hit; nothing left to quit or reset. */
.is-finished .game-button {
  visibility: hidden;
}

/* Raised like the pill buttons: a solid face on a darker edge, pressing
   down onto it. Quit armed is the same key in red. (.menu-item.game-button:
   these win over the menu item's own look, which the parked menu still uses.) */
.menu-item.game-button {
  --game-button-edge: max(3px, 0.5vmin);
  --game-button-edge-colour: #000;
  border: 1px solid #a8a8ad;
  background: linear-gradient(180deg, #2c2c30 0%, #151517 55%, #0a0a0b 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    inset 0 -2px 3px rgba(0, 0, 0, 0.35),
    0 var(--game-button-edge) 0 var(--game-button-edge-colour),
    0 calc(var(--game-button-edge) + 0.6vmin) 1.8vmin rgba(0, 0, 0, 0.55);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
  transition: translate 0.08s ease-out, box-shadow 0.08s ease-out;
}

.menu-item.game-button:active {
  translate: 0 var(--game-button-edge);
  background: linear-gradient(180deg, #232326 0%, #101012 55%, #070708 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.2),
    inset 0 -1px 2px rgba(0, 0, 0, 0.35),
    0 0 0 var(--game-button-edge-colour),
    0 0.3vmin 0.8vmin rgba(0, 0, 0, 0.55);
}

.menu-item.game-button.menu-item-leave {
  --game-button-edge-colour: #2a0508;
  border-color: #f06e6e;
  background: linear-gradient(180deg, #6a2128 0%, #3d1015 55%, #26080b 100%);
  color: #ffc2c2;
}

.menu-item.game-button.menu-item-leave:active {
  background: linear-gradient(180deg, #5a1b21 0%, #330c11 55%, #1f0609 100%);
}

/* Phones: big enough to tap, inside the home-indicator and notch areas. */
@media (max-height: 500px), (max-width: 500px) {
  .menu-item.game-button {
    bottom: max(16px, env(safe-area-inset-bottom));
    gap: 8px;
    padding: 13px 20px 13px 16px;
    font-size: 15px;
  }

  .quit-button { left: max(16px, env(safe-area-inset-left)); }
  .reset-button { right: max(16px, env(safe-area-inset-right)); }

  .menu-item.game-button .menu-icon {
    width: 16px;
    height: 16px;
  }
}

.player-divider {
  align-self: stretch;
  width: 1px;
  margin: 1.4vmin 0.4vmin;
  background: rgba(255, 255, 255, 0.18);
}

/* Phones: vmin leaves the card about 26px tall with an 11px clock, and
   there's too little room beside the board to grow it as one row. So it
   stacks: avatar and name, then a big clock under them. That fits in the
   empty corner of the board's square, clear of the round board. */
@media (max-height: 500px), (max-width: 500px) {
  .player-card {
    top: max(16px, env(safe-area-inset-top));
    left: max(16px, env(safe-area-inset-left));
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 8px;
    height: auto;
    padding: 10px 14px 12px 10px;
    border-radius: 16px;
  }

  .player-avatar {
    width: 26px;
    height: 26px;
    font-size: 12px;
  }

  .player-name {
    max-width: 104px;
    font-size: 14px;
  }

  .player-divider { display: none; }

  .player-time {
    grid-column: 1 / -1;
    padding-left: 2px;
    font-size: 21px;
  }
}

/* Launch: the Target Timer logo (images/targetTimer-logo.webp, 1739 × 980).
   The lettering fills only the middle third of the image's height, with
   transparent glow around it, so the negative margins trim the box to the
   lettering: the logo stays centred on it and the button hangs just below. */
.title-hero {
  --logo-width: min(104vw, 143vh); /* wider than the screen is fine: the sides are transparent glow */
  --logo-height: calc(var(--logo-width) * 980 / 1739);
  margin: calc(var(--logo-height) * -0.343) 0 calc(var(--logo-height) * -0.322);
  /* Grows out of the centre and fades in whenever Launch appears (unhiding restarts it). */
  animation: hero-in 1.4s cubic-bezier(0.16, 1, 0.3, 1) 1.3s both;
}

.title-hero img {
  display: block;
  width: var(--logo-width);
  height: var(--logo-height);
}

@keyframes hero-in {
  from { opacity: 0; transform: scale(0.2); }
  to { opacity: 1; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .title-hero { animation: none; }
}

/* The title is dead centre; anything else in .hero hangs below it
   without moving it. */
.hero {
  position: relative;
  --hero-actions-gap: 7vmin; /* Launch: from the lettering down to Start */
}

/* Launch: the title and buttons sit a touch above centre. */
[data-screen="launch"] .hero { top: -5vh; }

/* Rules: Start sits closer under the card than Launch's buttons do. */
[data-screen="rules"] .hero { --hero-actions-gap: 4vmin; }

.hero > .pill-button,
.hero-actions {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  width: max-content;
  margin: 4vmin auto 0;
}

/* Buttons under the title or card, side by side and all as wide and as
   tall as the biggest: Launch's Start and Leaderboard, Rules' Back / Next / Start. */
.hero-actions {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 2.5vmin;
  margin-top: var(--hero-actions-gap);
}

/* Rounded call-to-action over the swirl: a solid, slightly raised key with a
   light outline. It sits on a darker edge and presses down onto it. */
.pill-button {
  /* Archetype's capitals sit high in the line box; shift them down so they
     look centred, without changing the button's height. */
  --pill-text-drop: 0.16em;
  --pill-edge: max(3px, 0.5vmin); /* depth of the edge below the face */
  --pill-edge-colour: #000;
  padding: calc(1.8vmin + var(--pill-text-drop)) 5.5vmin calc(1.8vmin - var(--pill-text-drop));
  border: 1px solid #a8a8ad;
  border-radius: 999px;
  background: linear-gradient(180deg, #2c2c30 0%, #151517 55%, #0a0a0b 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    inset 0 -2px 3px rgba(0, 0, 0, 0.35),
    0 var(--pill-edge) 0 var(--pill-edge-colour),
    0 calc(var(--pill-edge) + 0.6vmin) 1.8vmin rgba(0, 0, 0, 0.55);
  color: #fff;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
  font-family: "Archetype Display", Inter, ui-sans-serif, system-ui, sans-serif;
  font-weight: normal;
  font-size: 2.7vmin;
  letter-spacing: 0.04em;
  line-height: 1;
  text-transform: uppercase;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* translate, not transform: the entrance and exit animations own transform. */
  transition: translate 0.08s ease-out, box-shadow 0.08s ease-out;
}

.pill-button:active {
  translate: 0 var(--pill-edge);
  background: linear-gradient(180deg, #232326 0%, #101012 55%, #070708 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.2),
    inset 0 -1px 2px rgba(0, 0, 0, 0.35),
    0 0 0 var(--pill-edge-colour),
    0 0.3vmin 0.8vmin rgba(0, 0, 0, 0.55);
}

/* Launch: rises in once the title has landed. Rules: once the copy has wiped in. */
[data-screen="launch"] .pill-button {
  animation: pill-in 0.8s cubic-bezier(0.16, 1, 0.3, 1) 2.2s both;
}

[data-screen="rules"] .pill-button {
  animation: pill-in 0.8s cubic-bezier(0.16, 1, 0.3, 1) 1.9s both;
}

@keyframes pill-in {
  from { opacity: 0; transform: translateY(2vmin); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  [data-screen="launch"] .pill-button,
  [data-screen="rules"] .pill-button { animation: none; }
}

/* Phones (an iPad is never under 744px either way): vmin leaves Launch's and
   Rules' buttons about 25px tall, so they get fixed sizes big enough to tap. */
@media (max-height: 500px), (max-width: 500px) {
  [data-screen="launch"] .pill-button,
  [data-screen="rules"] .pill-button {
    padding: calc(15px + var(--pill-text-drop)) 30px calc(15px - var(--pill-text-drop));
    font-size: 17px;
  }

  [data-screen="launch"] .hero-actions,
  [data-screen="rules"] .hero-actions { gap: 14px; }
}

/* ---- Menu: top right, over every screen ---- */

.menu {
  position: fixed;
  z-index: 10;
  top: 25px;
  right: 25px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1.6vmin;
}

.menu-icon {
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.menu-toggle {
  display: grid;
  place-items: center;
  width: var(--control-size);
  height: var(--control-size);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(110, 140, 160, 0.45);
  color: #fff;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.menu-toggle:active { background: rgba(110, 140, 160, 0.6); }

.menu-toggle .menu-icon {
  width: 3vmin;
  height: 3vmin;
  transition: transform 0.25s ease;
}

/* Down to open, up to close. */
.menu-toggle[aria-expanded="true"] .menu-icon { transform: rotate(180deg); }

.menu-items {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1.6vmin;
  margin: 0;
  padding: 0;
  list-style: none;
}

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

.menu-item {
  display: flex;
  align-items: center;
  gap: 1.4vmin;
  padding: 1.8vmin 3.4vmin 1.8vmin 2.8vmin;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  background: rgba(14, 14, 20, 0.85);
  color: #fff;
  font: inherit;
  font-size: 2.3vmin;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.menu-item:active { background: rgba(34, 34, 44, 0.92); }

.menu-item .menu-icon {
  width: 2.7vmin;
  height: 2.7vmin;
}

/* Univers keeps room below the baseline for descenders these labels don't
   have, so the letters sit 0.11em above centre; drop them back level with
   the icon. */
.menu-item span {
  position: relative;
  top: 0.11em;
}

.menu-item-leave {
  border-color: rgba(240, 110, 110, 0.45);
  background: rgba(40, 12, 16, 0.85);
  color: #f28b8b;
}

.menu-item-leave:active { background: rgba(60, 18, 22, 0.92); }

/* The items drop in one after another as the menu opens. */
.menu-items li {
  animation: menu-drop 0.35s cubic-bezier(0.16, 1, 0.3, 1) calc(var(--i, 0) * 0.05s) both;
}

@keyframes menu-drop {
  from { opacity: 0; transform: translateY(-1.5vmin); }
}

@media (prefers-reduced-motion: reduce) {
  .menu-toggle .menu-icon { transition: none; }
  .menu-items li { animation: none; }
}

/* Leaving a screen (Launch → Rules → Game → Result). app.js adds .is-leaving: the
   content goes and the button drops out. The screen itself runs leave-hold for
   as long as that takes, and the next screen takes over when it ends
   (animationend on "leave-hold"). */
.screen.is-leaving { animation: leave-hold 0.6s both; }
[data-screen="rules"].is-leaving { animation-duration: 0.9s; }

/* Changes nothing: it only times the exit. */
@keyframes leave-hold {
  to { opacity: 1; }
}

[data-screen="launch"].is-leaving .title-hero {
  animation: hero-out 0.55s cubic-bezier(0.7, 0, 0.84, 0) both;
}

/* Rules: the card is masked shut into its centre; its copy fades just ahead of it. */
[data-screen="rules"].is-leaving .rules-card {
  animation: card-close 0.75s cubic-bezier(0.6, 0, 0.2, 1) 0.15s both;
}

[data-screen="rules"].is-leaving .rules-copy {
  animation: fade-out 0.4s ease-in both;
}

.screen.is-leaving .pill-button {
  pointer-events: none;
  animation: pill-out 0.3s ease-in both;
}

/* Game: the board shrinks away (glow layer with it), the stats fade. */
[data-screen="game"].is-leaving #board,
[data-screen="game"].is-leaving .board-pulse {
  animation: hero-out 0.55s cubic-bezier(0.7, 0, 0.84, 0) both;
}

[data-screen="game"].is-leaving .player-card,
[data-screen="game"].is-leaving .game-button {
  pointer-events: none;
  animation: fade-out 0.4s ease-in both;
}

/* --card-bleed: how far past the card the open mask reaches, so a card
   with a shadow (Rules) keeps it. */
@keyframes card-close {
  from {
    clip-path: inset(calc(-1 * var(--card-bleed, 0px))
      round calc(var(--card-radius) + var(--card-bleed, 0px)));
  }
  to { clip-path: inset(50% 50% round var(--card-radius)); }
}

@keyframes fade-out {
  to { opacity: 0; }
}

@keyframes hero-out {
  from { opacity: 1; transform: scale(1); }
  to { opacity: 0; transform: scale(0.2); }
}

@keyframes pill-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(2vmin); }
}

/* The card is unmasked from the centre outwards; its contents settle in after. */
[data-screen="rules"] .rules-card {
  animation: card-reveal 0.9s both;
}

@keyframes card-reveal {
  0%, 15% {
    clip-path: inset(50% 50% round var(--card-radius));
    animation-timing-function: cubic-bezier(0.6, 0, 0.2, 1);
  }
  100% {
    clip-path: inset(calc(-1 * var(--card-bleed, 0px))
      round calc(var(--card-radius) + var(--card-bleed, 0px)));
  }
}

/* Then the copy is wiped in as one block, top to bottom: a mask that's opaque
   above a soft gradient edge and clear below it slides down over the text. */
[data-screen="rules"] .rules-copy {
  -webkit-mask-image: linear-gradient(to bottom, #000 40%, transparent 60%);
  mask-image: linear-gradient(to bottom, #000 40%, transparent 60%);
  -webkit-mask-size: 100% 250%;
  mask-size: 100% 250%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  animation: copy-wipe 1.6s cubic-bezier(0.33, 0, 0.2, 1) 0.6s both;
}

/* 100%: the clear end of the gradient covers the block; 0%: the opaque end does. */
@keyframes copy-wipe {
  from { -webkit-mask-position: 0 100%; mask-position: 0 100%; }
  to { -webkit-mask-position: 0 0; mask-position: 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  [data-screen="rules"] .rules-card,
  [data-screen="rules"] .rules-copy { animation: none; }
  [data-screen="rules"] .rules-copy { -webkit-mask-image: none; mask-image: none; }
}

/* Game: the board, player card and Quit button fade in. */
[data-screen="game"] #board,
[data-screen="game"] .player-card,
[data-screen="game"] .game-button {
  animation: fade-in 0.9s ease-out 0.45s both;
}

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

@media (prefers-reduced-motion: reduce) {
  [data-screen="game"] #board,
  [data-screen="game"] .player-card,
  [data-screen="game"] .game-button { animation: none; }
}

/* Result: opened like the Rules card — unmasked from the centre, then the
   copy wiped in top to bottom. */
[data-screen="result"] .result-card {
  animation: card-reveal 0.9s both;
}

[data-screen="result"] .result-copy {
  -webkit-mask-image: linear-gradient(to bottom, #000 40%, transparent 60%);
  mask-image: linear-gradient(to bottom, #000 40%, transparent 60%);
  -webkit-mask-size: 100% 250%;
  mask-size: 100% 250%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  animation: copy-wipe 1.6s cubic-bezier(0.33, 0, 0.2, 1) 0.6s both;
}

@media (prefers-reduced-motion: reduce) {
  [data-screen="result"] .result-card,
  [data-screen="result"] .result-copy { animation: none; }
  [data-screen="result"] .result-copy { -webkit-mask-image: none; mask-image: none; }
}

/* Rules: a solid, raised panel in the middle of the screen,
   with the copy centred and broken where the mock-up breaks it. */
.rules-card {
  --card-radius: 2.4vmin;
  --card-edge: max(4px, 0.6vmin); /* depth of the edge below the face, as on the buttons */
  --card-bleed: 6vmin; /* room in the reveal mask for the shadow */
  width: 65vw;
  padding: 5vmin 4vmin;
  border: 1px solid #48484d;
  border-radius: var(--card-radius);
  /* Solid, like the buttons: a navy face lit from above, sitting on a
     darker edge with a soft shadow under it. */
  background: linear-gradient(180deg, #242427 0%, #141416 45%, #0a0a0b 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    inset 0 -3px 6px rgba(0, 0, 0, 0.35),
    0 var(--card-edge) 0 #000,
    0 calc(var(--card-edge) + 1vmin) 3.5vmin rgba(0, 0, 0, 0.6);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.45);
  /* The mock-up is set in a regular weight; only Univers Bold is bundled,
     so the system sans stands in until a regular cut is added. */
  font-family: system-ui, -apple-system, "Helvetica Neue", sans-serif;
  font-weight: 400;
  font-size: 2.7vmin;
  line-height: 1.3;
  text-align: center;
  color: #fff;
}

.rules-copy {
  display: flex;
  flex-direction: column;
  gap: 1.3em;
}

.rules-copy p { margin: 0; }

/* Tablet: the groups don't show; the paragraphs run on as one card, and
   there are no pages to turn. */
.rules-group { display: contents; }
.rules-dots,
#rules-back,
#rules-next { display: none; }

/* Phones: one group at a time, as pages (app.js, Rules pages). The card
   fills the screen above the buttons, and the text grows to suit it. The
   groups share one grid cell so the card never changes size between pages.
   The text wraps to the card, so the tablet line breaks are dropped. */
@media (max-height: 500px), (max-width: 500px) {
  /* The card and the buttons as a column filling the screen, inside the
     notch and home-indicator areas. */
  [data-screen="rules"] .hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    width: 100%;
    height: 100%;
    padding:
      calc(max(16px, env(safe-area-inset-top)) + 25px)
      max(16px, env(safe-area-inset-right))
      calc(max(16px, env(safe-area-inset-bottom)) + 25px)
      max(16px, env(safe-area-inset-left));
  }

  [data-screen="rules"] .hero-actions {
    position: static;
    margin: 0;
  }

  .rules-card {
    display: flex;
    flex: 1;
    flex-direction: column;
    width: 100%;
    max-width: 530px;
    --card-radius: 18px;
    --card-bleed: 32px;
    padding: 24px 28px 18px;
    font-size: clamp(17px, min(5.6vh, 6vw), 24px);
    line-height: 1.4;
  }

  .rules-copy {
    display: grid;
    flex: 1;
  }

  .rules-copy br { display: none; }

  .rules-group {
    grid-area: 1 / 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.9em;
    visibility: hidden;
  }

  .rules-group.is-current { visibility: visible; }

  /* Turning a page: the new one slides in from the side it's coming from. */
  .has-paged .rules-group.is-current {
    animation: rules-page-in 0.35s cubic-bezier(0.16, 1, 0.3, 1) both;
  }

  .rules-dots {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 16px;
  }

  .rules-dot {
    width: 8px;
    height: 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.3);
    transition: width 0.25s ease, background-color 0.25s ease;
  }

  .rules-dot.is-current {
    width: 22px;
    background: var(--accent);
  }

  /* Back on every page (on the first it goes home); Next until the last,
     where Start takes over. */
  #rules-back,
  #rules-next { display: block; }
  .is-last-page #rules-next,
  [data-screen="rules"]:not(.is-last-page) #continue { display: none; }

  /* Buttons that appear on a page turn skip the entrance (they'd wait for
     the copy wipe again); the exit still plays. */
  [data-screen="rules"].has-paged:not(.is-leaving) .pill-button { animation: none; }

  /* Back and Next rise in as the card opens, not after the copy wipe. */
  [data-screen="rules"] .pill-button { animation-delay: 0.15s; }
}

@keyframes rules-page-in {
  from { opacity: 0; translate: var(--rules-page-from, 24px) 0; }
  to { opacity: 1; translate: 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  .has-paged .rules-group.is-current { animation: none; }
}

.stat-label {
  margin: 0;
  font-size: 2.2vmin;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.6;
}

/* Result: the player's time on a dark glass card, as in the mock-up. */
.result-card {
  --card-radius: 3vmin;
  width: min(70vw, 82vmin);
  padding: 7vmin 5vmin 6vmin;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--card-radius);
  background: rgba(14, 14, 20, 0.82);
  text-align: center;
  color: #fff;
}

.result-copy {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.result-copy > * { margin: 0; }

.result-label {
  font-size: 2.4vmin;
  letter-spacing: 0.3em;
  margin-right: -0.3em; /* the tracking after the last letter, so it stays centred */
  text-transform: uppercase;
  color: var(--accent);
}

.result-label-muted {
  margin-top: 5vmin;
  color: rgba(255, 255, 255, 0.55);
}

.result-name {
  font-family: "Archetype Display", Inter, ui-sans-serif, system-ui, sans-serif;
  font-weight: normal; /* one cut only; don't let the browser fake a bold */
  margin-top: 1.5vmin;
  font-size: 6.5vmin;
  line-height: 1;
  text-transform: uppercase;
  text-shadow: 0 0 3vmin rgba(255, 255, 255, 0.25);
  overflow-wrap: anywhere;
}

.result-rule {
  width: 12vmin;
  height: 0.5vmin;
  margin: 4vmin 0;
  border-radius: 999px;
  background: var(--accent);
  box-shadow: 0 0 2vmin var(--accent);
}

.result-time {
  font-family: "Archetype Display", Inter, ui-sans-serif, system-ui, sans-serif;
  font-weight: normal;
  margin-top: 1.5vmin;
  font-size: 7.5vmin;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 3vmin rgba(94, 240, 160, 0.45);
}

.result-darts {
  margin-top: 1vmin;
  font-size: 5.5vmin;
  line-height: 1;
  color: rgba(255, 255, 255, 0.85);
}

/* ---- Leaderboard: your result as a bar on top, the standings below ---- */

.screen-leaderboard {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3.5vmin;
  height: 100%;
  padding: 3.5vmin 4vw 3.5vmin;
}

.summary-card {
  --card-radius: 3vmin;
  display: flex;
  align-items: center;
  gap: 4.5vmin;
  padding: 3.2vmin 6vmin;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--card-radius);
  background: rgba(14, 14, 20, 0.82);
  color: #fff;
}

.summary-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.2vmin;
}

.summary-player { align-items: flex-start; }

.summary-cell > * { margin: 0; }

.summary-label {
  font-size: 1.8vmin;
  letter-spacing: 0.3em;
  margin-right: -0.3em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}

.summary-label-accent { color: var(--accent); }

.summary-name,
.summary-time {
  font-family: "Archetype Display", Inter, ui-sans-serif, system-ui, sans-serif;
  font-weight: normal;
  line-height: 1;
}

.summary-name {
  font-size: 4vmin;
  text-transform: uppercase;
}

.summary-time {
  font-size: 6vmin;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 2vmin rgba(94, 240, 160, 0.35);
}

.summary-darts {
  font-size: 4vmin;
  line-height: 1;
}

.summary-divider {
  align-self: stretch;
  width: 1px;
  margin: 1vmin 0;
  background: rgba(255, 255, 255, 0.18);
}

.standings {
  display: flex;
  justify-content: center;
  gap: 3vw;
  width: 100%;
  flex: 0 1 auto;
  min-height: 0;
}

/* Two panels, each taking half; the cap only bites if one is ever alone. */
.standings-panel {
  display: flex;
  flex-direction: column;
  flex: 1;
  max-width: 110vmin;
  padding: 3.5vmin 3.5vmin 2vmin;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 3vmin;
  background: rgba(14, 14, 20, 0.78);
  color: #fff;
  overflow: hidden;
}

.standings-title {
  margin: 0 0 2vmin;
  font-size: 2.8vmin;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The short green bar under each title. */
.standings-title::after {
  content: "";
  display: block;
  width: 5.5vmin;
  height: 0.45vmin;
  margin-top: 1.3vmin;
  border-radius: 999px;
  background: var(--accent);
}

/* The panels are only as tall as their five rows, and the screen centres
   them. The rows still shrink to fit if a long name makes the bar above taller. */
.standings-rows {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.standings-row {
  display: flex;
  align-items: center;
  gap: 2vmin;
  flex: 0 1 7.6vmin;
  min-height: 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.standings-row:last-child { border-bottom: 0; }

.row-rank {
  width: 2vmin;
  font-size: 2vmin;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.5);
}

.row-avatar {
  display: grid;
  place-items: center;
  flex: none;
  width: 4.6vmin;
  height: 4.6vmin;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  font-size: 1.7vmin;
}

.row-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 2.6vmin;
}

.row-score {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.4vmin;
}

.row-darts {
  font-size: 1.6vmin;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.55);
}

.row-time {
  font-size: 2.8vmin;
  font-variant-numeric: tabular-nums;
}

.standings-row:first-child .row-time { color: var(--accent); }

/* Live Players: where the player stands, and their own row picked out. */
.standings-note {
  margin: -0.5vmin 0 1vmin;
  font-size: 2vmin;
  font-weight: 400;
  color: var(--accent);
}

.standings-note:empty { display: none; }

/* Live Players, when the event's leaderboard is switched off (app.js, init). */
.standings-panel[hidden] { display: none; }

.standings-row.is-you .row-name { color: var(--accent); }

.standings-row.is-you .row-avatar {
  background: var(--accent);
  color: #04140c;
}

/* Below the top rows, so set apart from them. */
.standings-row.is-detached { margin-top: 1.5vmin; }

.row-you {
  font-size: 1.6vmin;
  letter-spacing: 0.3em;
  margin-right: -0.3em;
  text-transform: uppercase;
  color: var(--accent);
}

.standings-empty {
  padding: 1.5vmin 0;
  font-size: 2.2vmin;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.55);
}

.standings-actions {
  display: flex;
  gap: 2.5vmin;
}

.pill-button-primary {
  --pill-edge-colour: #137a43;
  border-color: #2fbf72;
  background: linear-gradient(180deg, #a4fbcb 0%, var(--accent) 50%, #3fd585 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    inset 0 -2px 3px rgba(0, 60, 30, 0.25),
    0 var(--pill-edge) 0 var(--pill-edge-colour),
    0 calc(var(--pill-edge) + 0.6vmin) 1.8vmin rgba(0, 0, 0, 0.55);
  color: #04140c;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.35);
}

.pill-button-primary:active {
  background: linear-gradient(180deg, #8ff1b8 0%, #4cd98c 50%, #36c277 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    inset 0 -1px 2px rgba(0, 60, 30, 0.25),
    0 0 0 var(--pill-edge-colour),
    0 0.3vmin 0.8vmin rgba(0, 0, 0, 0.55);
}

/* The standings come in once the bar has settled: panels rise, their rows
   follow one by one, then the buttons. */
[data-screen="leaderboard"] .standings-panel {
  animation: rise-in 0.7s cubic-bezier(0.16, 1, 0.3, 1) 0.55s both;
}

[data-screen="leaderboard"] .standings-panel + .standings-panel { animation-delay: 0.65s; }

[data-screen="leaderboard"] .standings-row {
  animation: rise-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) calc(0.85s + var(--i, 0) * 0.08s) both;
}

[data-screen="leaderboard"] .standings-actions {
  animation: rise-in 0.7s cubic-bezier(0.16, 1, 0.3, 1) 1.4s both;
}

/* Leaving (Play again): the whole screen fades; app.js waits for it. */
.screen-leaderboard.is-leaving {
  pointer-events: none;
  animation: fade-out 0.45s ease-in both;
}

@keyframes rise-in {
  from { opacity: 0; transform: translateY(3vmin); }
}

@media (prefers-reduced-motion: reduce) {
  [data-screen="leaderboard"] .standings-panel,
  [data-screen="leaderboard"] .standings-row,
  [data-screen="leaderboard"] .standings-actions { animation: none; }
}

/* Phones: the two boards side by side, as on a tablet, each a solid raised
   card like the Rules one and sized in px. On a short screen the rows give
   way to fit; past that, each list scrolls under its title. */
@media (max-height: 500px), (max-width: 500px) {
  .screen-leaderboard {
    gap: 14px;
    padding:
      max(16px, env(safe-area-inset-top))
      max(16px, env(safe-area-inset-right))
      max(16px, env(safe-area-inset-bottom))
      max(16px, env(safe-area-inset-left));
  }

  .standings {
    gap: 12px;
    width: min(100%, 900px);
  }

  .standings-panel {
    min-width: 0;
    max-width: 560px; /* only bites when Pros is alone */
    padding: 14px 16px 6px;
    border: 1px solid #48484d;
    border-radius: 18px;
    background: linear-gradient(180deg, #242427 0%, #141416 45%, #0a0a0b 100%);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.22),
      inset 0 -3px 6px rgba(0, 0, 0, 0.35),
      0 4px 0 #000,
      0 14px 28px rgba(0, 0, 0, 0.6);
  }

  .standings-title {
    margin-bottom: 8px;
    font-size: 14px;
  }

  .standings-title::after {
    width: 28px;
    height: 3px;
    margin-top: 7px;
  }

  .standings-rows {
    overflow-x: hidden; /* up and down only */
    overflow-y: auto;
    overscroll-behavior: contain;
    touch-action: pan-y;
    scrollbar-width: none;
  }

  .standings-rows::-webkit-scrollbar { display: none; }

  .standings-row {
    gap: 10px;
    flex: 0 1 46px;
    min-height: 28px;
  }

  .standings-row.is-detached { margin-top: 6px; }

  .row-rank {
    flex: none;
    width: 12px;
    font-size: 12px;
  }

  .row-avatar {
    width: 26px;
    height: 26px;
    font-size: 11px;
  }

  .row-name { font-size: 14px; }

  /* Darts beside the time, so a row is one line high. */
  .row-score {
    flex: none;
    flex-direction: row;
    align-items: baseline;
    gap: 10px;
  }

  .row-darts { font-size: 11px; }
  .row-time { font-size: 15px; }
  .row-you { font-size: 10px; }

  .standings-note,
  .standings-empty { font-size: 13px; }

  .screen-leaderboard .pill-button {
    padding: calc(15px + var(--pill-text-drop)) 30px calc(15px - var(--pill-text-drop));
    font-size: 17px;
  }

  /* Leaderboard screen: the result bar above the cards, sized down and
     solid like them. */
  .summary-card {
    gap: 20px;
    padding: 10px 26px;
    border: 1px solid #48484d;
    border-radius: 16px;
    background: linear-gradient(180deg, #242427 0%, #141416 45%, #0a0a0b 100%);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.22),
      inset 0 -3px 6px rgba(0, 0, 0, 0.35),
      0 4px 0 #000,
      0 10px 22px rgba(0, 0, 0, 0.6);
  }

  .summary-cell { gap: 5px; }
  .summary-label { font-size: 10px; }
  .summary-name { font-size: 17px; }
  .summary-time { font-size: 24px; }
  .summary-darts { font-size: 18px; }
  .summary-divider { margin: 4px 0; }
}

/* Phones held upright: half the width each is narrow, so the initials go
   and the time and darts drop under the name, leaving it the full width. */
@media (max-width: 500px) {
  .standings { gap: 8px; }
  .standings-panel { padding: 12px 10px 4px; }

  .standings-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-content: center;
    gap: 3px 8px;
    flex: none;
    min-height: 50px;
  }

  .row-rank { grid-row: span 2; }
  .row-avatar { display: none; }
  .row-name { font-size: 13px; }

  /* Time on the left, darts (pros only) on the right. */
  .row-score {
    grid-column: 2 / -1;
    justify-content: space-between;
  }

  .row-darts { order: 1; }

  .row-time { font-size: 14px; }

  /* The result bar: closed up so the clock stays on one line. */
  .summary-card {
    gap: 14px;
    padding: 10px 18px;
  }

  .summary-time {
    font-size: 21px;
    white-space: nowrap;
  }

  /* A step smaller, so Play again and Share fit side by side. */
  .screen-leaderboard .pill-button {
    padding: calc(14px + var(--pill-text-drop)) 20px calc(14px - var(--pill-text-drop));
    font-size: 15px;
    white-space: nowrap;
  }
}

/* ---- Reset dialog: the game screen's Reset button (app.js, Reset) ----
   A raised card like the Rules one, over the dimmed game. */
.confirm-overlay {
  position: fixed;
  z-index: 15; /* over the screens, under the test notice */
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4vmin;
  background: rgba(2, 4, 10, 0.72);
  animation: fade-in 0.25s ease-out both;
}

.confirm-overlay[hidden] { display: none; }

.confirm-card {
  width: min(100%, 62vmin);
  padding: 5vmin 5vmin 4.5vmin;
  border: 1px solid #48484d;
  border-radius: 2.4vmin;
  background: linear-gradient(180deg, #242427 0%, #141416 45%, #0a0a0b 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    inset 0 -3px 6px rgba(0, 0, 0, 0.35),
    0 max(4px, 0.6vmin) 0 #000,
    0 calc(max(4px, 0.6vmin) + 1vmin) 3.5vmin rgba(0, 0, 0, 0.6);
  color: #fff;
  text-align: center;
  animation: rise-in 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.confirm-title {
  margin: 0 0 4vmin;
  font-size: 3.2vmin;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Cancel and Reset side by side, as wide as each other. */
.confirm-actions {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 2.5vmin;
}

@media (max-height: 500px), (max-width: 500px) {
  .confirm-overlay {
    padding:
      max(16px, env(safe-area-inset-top))
      max(16px, env(safe-area-inset-right))
      max(16px, env(safe-area-inset-bottom))
      max(16px, env(safe-area-inset-left));
  }

  .confirm-card {
    width: min(100%, 420px);
    padding: 24px 24px 22px;
    border-radius: 18px;
  }

  .confirm-title {
    margin-bottom: 20px;
    font-size: 18px;
  }

  .confirm-actions { gap: 14px; }

  .confirm-actions .pill-button {
    padding: calc(15px + var(--pill-text-drop)) 20px calc(15px - var(--pill-text-drop));
    font-size: 17px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .confirm-overlay,
  .confirm-card { animation: none; }
}

/* ---- Morph: Result card → Leaderboard bar (View Transitions, app.js morphTo) ----
   Each named part is captured on both screens and glides from one to the
   other; the card is captured without them, so it is just the box and can
   stretch from tall to wide. Parts only on the Result card (the green rule)
   fade where they stand. */
.vt-card { view-transition-name: result-card; }
.vt-eyebrow { view-transition-name: result-eyebrow; }
.vt-name { view-transition-name: result-name; }
.vt-rule { view-transition-name: result-rule; }
.vt-time-label { view-transition-name: result-time-label; }
.vt-time { view-transition-name: result-time; }
.vt-darts-label { view-transition-name: result-darts-label; }
.vt-darts { view-transition-name: result-darts; }

::view-transition-group(*) {
  animation-duration: 0.85s;
  animation-timing-function: cubic-bezier(0.6, 0, 0.2, 1);
}

::view-transition-old(result-card),
::view-transition-new(result-card) {
  height: 100%;
}

/* Test builds only: bottom right, over every screen. */
.test-notice {
  position: fixed;
  z-index: 20;
  right: 25px;
  bottom: 25px;
  margin: 0;
  padding: 0.9vmin 1.8vmin;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  background: rgba(14, 14, 20, 0.85);
  color: #fff;
  font-size: 1.8vmin;
  letter-spacing: 0.08em;
  font-family: inherit;
  font-weight: inherit;
  text-transform: uppercase;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.test-notice:active { background: rgba(60, 60, 76, 0.9); }

/* ---- Leaderboard debug panel (debug.js): test builds only ---- */

.debug-panel {
  --debug-ok: #5ef0a0;
  --debug-wait: #ffc857;
  --debug-bad: #ff6b5e;
  position: fixed;
  z-index: 19; /* under the notice, which closes it */
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: 3vmin 3vmin 9vmin;
  background: rgba(6, 8, 14, 0.96);
  color: #e8f1ff;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.75vmin;
  font-weight: 400;
  line-height: 1.45;
}

.debug-panel[hidden] { display: none; }

.debug-head {
  display: flex;
  align-items: center;
  gap: 1.5vmin;
  margin-bottom: 2vmin;
  /* The app keeps the top-right corner for its own handle: taps there never arrive. */
  padding-right: 90px;
}

.debug-head h2 {
  flex: 1;
  margin: 0;
  font-size: 2.4vmin;
  font-weight: 700;
}

.debug-button {
  padding: 1vmin 2.2vmin;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.debug-body {
  display: flex;
  gap: 3vmin;
  flex: 1;
  min-height: 0;
}

.debug-column {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
  min-height: 0;
}

.debug-column h3 {
  margin: 0 0 1vmin;
  font-size: 1.6vmin;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}

.debug-steps,
.debug-log {
  margin: 0 0 2vmin;
  padding: 0;
  list-style: none;
}

.debug-step {
  display: flex;
  gap: 1.5vmin;
  padding: 0.7vmin 0 0.7vmin 2.6vmin;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  position: relative;
}

/* The light: green done, amber in hand, red wrong, grey not yet. */
.debug-step::before {
  content: "";
  position: absolute;
  left: 0;
  top: 1.25vmin;
  width: 1.3vmin;
  height: 1.3vmin;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.25);
}

.debug-step.is-ok::before { background: var(--debug-ok); }
.debug-step.is-wait::before { background: var(--debug-wait); }
.debug-step.is-bad::before { background: var(--debug-bad); }

.debug-step-label {
  flex: 0 0 22vmin;
  font-weight: 700;
}

.debug-step-detail {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
  color: rgba(255, 255, 255, 0.8);
}

.debug-step.is-bad .debug-step-detail { color: var(--debug-bad); }

.debug-reply,
.debug-log {
  flex: 1;
  min-height: 0;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0;
  padding: 1.2vmin;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 1.2vmin;
  background: rgba(0, 0, 0, 0.35);
  font: inherit;
  font-size: 1.55vmin;
}

.debug-reply { white-space: pre-wrap; overflow-wrap: anywhere; }

.debug-line {
  padding: 0.35vmin 0;
  overflow-wrap: anywhere;
  color: rgba(255, 255, 255, 0.75);
}

.debug-line.is-out { color: #8fc7ff; }
.debug-line.is-in { color: var(--debug-ok); }
.debug-line.is-bad { color: var(--debug-bad); }
