/* Neon Arena — typing race view («⌨️ Гонки на клавиатуре»): two race lanes with a finish
   flag and live WPM/ACC, the shared text rendered per char (typed = dimmed
   green, wrong char = red, caret = pulsing gold), a spring-animated 3-2-1-GO
   overlay, a big race countdown clock (replaces the chess clocks), and a
   result panel with both sides' stats. Loaded after game.css/checkers.css;
   reuses .fighter/.board-frame/.board-countdown/.board-waiting/
   .rematch-splash primitives from the chess game view. */

/* The match is one screenful. `.view-game` (game.css) is the frame — a
   `minmax(0,1fr) 340px` grid whose height is the SCENE's, written by
   `fitMatchColumn()` into `--match-h`, with the opponent bar pinned to the top
   of the board column, the board taking what is left and the player's own bar
   and the action row at the bottom. This file used to override that with a
   `display:flex` root and an inner `.tr-main` at `align-items:start`, which
   is how the column came out 734px tall inside a 660px scene at 1280×800 —
   the player's own clock clipped by the fold and the buttons below it. */

.view-tr { overflow: visible; }

/* === stage === */
/* `container-type: inline-size` so the countdown can be sized from the BOARD
   COLUMN rather than from the window: `clamp(44px, 12vw, 92px)` made «ПОЕХАЛИ!»
   about 700px wide inside a 468px column. */
.tr-stage {
  position: relative;
  container-type: inline-size;
  container-name: trstage;
  padding: 12px;
  display: flex;
  flex-direction: column;
  /* `.board-frame` centres its children; the lanes and the text card are
     full-width rows and came out 230px wide inside a 468px column. */
  align-items: stretch;
  /* start, not center: `overflow: hidden` on a centred column clips BOTH
     ends, and the top lane lost its name and its percentage. */
  justify-content: flex-start;
  gap: 12px;
  min-height: 0;
  overflow: hidden;
}

/* === race lanes === */
.tr-lanes { flex: 0 0 auto; display: flex; flex-direction: column; gap: 10px; }
.tr-lane {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--stroke);
  background: var(--panel-soft);
  transition: border-color var(--dur-fast), box-shadow var(--dur-med);
}
.tr-lane.is-self { border-color: rgba(241, 193, 82, 0.35); }
.tr-lane-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.tr-lane-name {
  font-weight: 800;
  font-size: 13.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.tr-lane.is-self .tr-lane-name { color: var(--gold); }
.tr-lane-pct {
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  font-size: 13px;
  color: var(--text-dim);
  flex: 0 0 auto;
}
.tr-lane-track {
  position: relative;
  height: 14px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--stroke);
}
.tr-lane-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  min-width: 0;
  border-radius: var(--r-pill);
  background: var(--cyan-grad);
  box-shadow: 0 0 12px rgba(124, 201, 255, 0.45);
  transition: width 0.3s var(--ease-out);
}
.tr-lane.is-self .tr-lane-fill {
  background: var(--gold-grad);
  box-shadow: 0 0 12px rgba(241, 193, 82, 0.5);
}
/* bright cap on the fill edge = the racer's nose */
.tr-lane-fill::after {
  content: "";
  position: absolute;
  right: -1px;
  top: 50%;
  transform: translateY(-50%);
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 10px 2px rgba(255, 255, 255, 0.55);
}
.tr-lane-fill[style^="width: 0"]::after,
.tr-lane-fill[style="width: 0.00%"]::after { opacity: 0; }
.tr-lane-flag {
  position: absolute;
  right: 7px;
  top: 50%;
  transform: translateY(-56%);
  font-size: 13px;
  line-height: 1;
  opacity: 0.9;
}
.tr-lane.is-finished .tr-lane-flag { animation: trFlagPop 0.6s var(--spring) both; }
@keyframes trFlagPop {
  0% { transform: translateY(-56%) scale(0.4) rotate(-18deg); }
  60% { transform: translateY(-56%) scale(1.5) rotate(8deg); }
  100% { transform: translateY(-56%) scale(1) rotate(0); }
}
.tr-lane-stats {
  font-size: 12px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* red pulse when the opponent (or the player) pulls ahead */
.tr-lane.is-overtake { animation: trOvertake 1.2s ease-out; }
@keyframes trOvertake {
  0% { box-shadow: 0 0 0 rgba(255, 93, 108, 0); }
  22% { box-shadow: 0 0 26px rgba(255, 93, 108, 0.55); border-color: rgba(255, 93, 108, 0.75); }
  100% { box-shadow: 0 0 0 rgba(255, 93, 108, 0); }
}

/* === typing surface === */
.tr-text-card {
  position: relative;
  /* The one row that gives: the lanes and the stats are fixed, the paragraph
     takes what is left and scrolls inside itself rather than pushing the lanes
     off the top of the stage. The mock's own card is 22px 26px at radius 16. */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  border-radius: var(--r-md);
  border: 1px solid var(--glass-brd);
  background: var(--panel);
  padding: 18px 18px 16px;
  cursor: text;
  -webkit-tap-highlight-color: transparent;
}
.tr-text {
  white-space: pre-wrap;
  word-break: break-word;
  font-family: var(--font-body);
  font-size: 1.06rem;
  line-height: 1.8;
  letter-spacing: 0.015em;
  color: var(--text-dim);
  max-height: 230px;
  overflow-y: auto;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
/* While the soft keyboard is up, 230px of text can sit exactly behind the keys
   — and the caret is the one thing the racer must see. `--kb-h`/`kb-open` come
   from js/core/viewport.js; the 400px is the measured chrome above and around
   the card (hud, lanes, paddings — tune on device, the SHAPE is the fix), and
   the 90px floor keeps ~3 lines at 1.8 line-height. At rest the 230px above is
   the single source of truth. */
html.kb-open .tr-text {
  max-height: clamp(90px, calc(100dvh - var(--kb-h, 0px) - 400px), 230px);
}
.tr-ch { position: relative; border-radius: 4px; transition: background 120ms ease, color 120ms ease; }
.tr-ch.ok { color: rgba(53, 199, 131, 0.62); }
.tr-ch.cur {
  color: var(--text);
  background: rgba(241, 193, 82, 0.2);
  box-shadow: -2px 0 0 var(--gold), 0 2px 0 var(--gold);
  animation: trCaret 1.05s ease-in-out infinite;
}
/* after .cur on purpose: the error marker doubles as the caret position.
   Struck through, because a red block alone reads as "here" and the player
   needs "delete this"; the ← hangs to the right in absolute position so the
   arrow never reflows the paragraph the player is reading. */
.tr-ch.err {
  background: rgba(255, 93, 108, 0.85);
  color: #fff;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(255, 255, 255, 0.9);
  box-shadow: -2px 0 0 rgba(255, 93, 108, 0.9), 0 0 10px rgba(255, 93, 108, 0.6);
}
.tr-ch.err::after {
  content: "←";
  position: absolute;
  left: 100%;
  top: 0;
  bottom: 0;
  display: inline-flex;
  align-items: center;
  margin-left: 1px;
  padding: 0 1px;
  border-radius: 3px;
  /* An opaque chip, not a translucent glyph: it lands on top of the next
     character, and half-covering that character is worse than covering it.
     While the caret is frozen the next character cannot be typed anyway, and
     the arrow disappears the instant Backspace lands. */
  background: rgba(5, 7, 11, 0.94);
  color: var(--danger);
  font-size: 0.9em;
  line-height: 1.15;
  font-weight: 800;
  text-decoration: none;
  pointer-events: none;
}
@keyframes trCaret {
  0%, 100% { background: rgba(241, 193, 82, 0.26); box-shadow: -2px 0 0 var(--gold), 0 2px 0 var(--gold); }
  50% { background: rgba(241, 193, 82, 0.06); box-shadow: -2px 0 0 rgba(241, 193, 82, 0.3), 0 2px 0 rgba(241, 193, 82, 0.3); }
}

/* visually hidden but focusable typing sink; 16px+ font blocks iOS auto-zoom */
.tr-ghost-input {
  position: absolute;
  bottom: 8px;
  left: 8px;
  width: 24px;
  height: 24px;
  font-size: 16px;
  opacity: 0.01;
  border: none;
  background: transparent;
  color: transparent;
  caret-color: transparent;
  padding: 0;
  pointer-events: none;
}
.tr-focus-hint {
  position: absolute;
  left: 50%;
  bottom: -13px;
  z-index: 2;
  transform: translateX(-50%);
  padding: 6px 14px;
  border-radius: var(--r-pill);
  background: rgba(4, 7, 11, 0.82);
  border: 1px solid rgba(241, 193, 82, 0.4);
  color: var(--gold);
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
  pointer-events: none;
  animation: trHintBob 1.6s ease-in-out infinite;
}
@keyframes trHintBob {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50% { transform: translateX(-50%) translateY(-3px); }
}

/* === «упёрся в опечатку» ===
   Three levels, driven from views/typing_race.js by wasted keypresses. It sits
   BELOW the text on purpose: nothing the player is reading may move, and there
   is nothing tappable underneath to shove out from under a thumb. */
.tr-blk {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: var(--r-md);
  border: 1px solid rgba(241, 193, 82, 0.4);
  background: rgba(30, 24, 8, 0.72);
  animation: trBlkIn 0.22s var(--ease-out) both;
}
.tr-blk.hidden { display: none; }
@keyframes trBlkIn {
  0% { opacity: 0; transform: translateY(-4px); }
  100% { opacity: 1; transform: none; }
}
.tr-blk-key {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: var(--r-sm);
  border: 1px solid rgba(241, 193, 82, 0.5);
  background: rgba(241, 193, 82, 0.1);
  color: var(--gold);
  font-size: 15px;
  line-height: 1;
}
.tr-blk-body { min-width: 0; }
.tr-blk-head {
  font-size: 13px;
  font-weight: 800;
  line-height: 1.3;
  color: var(--gold);
}
.tr-blk-meta {
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.tr-blk-meta:empty { display: none; }

/* level 2 — the player is still typing into the block, so say the thing they
   are actually thinking. The shake fires on a 1.9s INTERVAL, not continuously:
   one cycle is 12% movement and 88% still. */
.tr-blk[data-level="2"],
.tr-blk[data-level="3"] {
  border-color: rgba(255, 93, 108, 0.6);
  background: rgba(32, 12, 16, 0.78);
  animation: trBlkIn 0.22s var(--ease-out) both, trBlkNudge 1.9s ease-in-out 0.22s infinite;
}
.tr-blk[data-level="2"] .tr-blk-head,
.tr-blk[data-level="3"] .tr-blk-head { color: var(--danger); }
.tr-blk[data-level="2"] .tr-blk-key,
.tr-blk[data-level="3"] .tr-blk-key {
  border-color: rgba(255, 93, 108, 0.65);
  background: rgba(255, 93, 108, 0.14);
  color: var(--danger);
  animation: trBlkKey 1.4s ease-in-out infinite;
}
@keyframes trBlkNudge {
  0%, 12%, 100% { transform: translateX(0); }
  3% { transform: translateX(-5px); }
  6% { transform: translateX(5px); }
  9% { transform: translateX(-3px); }
}
@keyframes trBlkKey {
  0%, 100% { box-shadow: 0 0 0 rgba(255, 93, 108, 0); }
  50% { box-shadow: 0 0 14px rgba(255, 93, 108, 0.6); }
}

/* level 3 — the race visibly stops: the text drains of colour and the card
   takes a red halo, so the screen itself stops looking alive. */
.tr-blk[data-level="3"] {
  box-shadow: 0 0 22px rgba(255, 93, 108, 0.35);
}
.tr-text-card.is-blocked {
  border-color: rgba(255, 93, 108, 0.55);
  box-shadow: 0 0 0 1px rgba(255, 93, 108, 0.2), 0 0 28px rgba(255, 93, 108, 0.3);
}
/* saturate alone is invisible on a paragraph that has not been typed into yet
   — the only saturated ink is the green prefix — so the brightness step is
   what actually reads as "the race has stopped". */
.tr-text-card.is-blocked .tr-text {
  filter: saturate(0.2) brightness(0.72);
  transition: filter var(--dur-med) ease;
}
/* the mistake keeps its colour — it is the one thing still worth looking at */
.tr-text-card.is-blocked .tr-ch.err { filter: saturate(2.4); }

/* === countdown overlay (3-2-1-GO) === */
.tr-cd {
  position: absolute;
  inset: 0;
  z-index: 9;
  display: flex;
  /* column, not row: the digit and the keyboard hint are two lines of one
     message, and side by side the hint landed outside the board column. */
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  pointer-events: none;
  background: radial-gradient(ellipse at center, rgba(4, 7, 11, 0.55), rgba(4, 7, 11, 0) 68%);
}
.tr-cd.hidden { display: none; }
.tr-cd-digit {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(56px, 26cqi, 132px);
  line-height: 1;
  color: var(--gold);
  text-shadow: 0 0 30px rgba(241, 193, 82, 0.75), 0 0 70px rgba(241, 193, 82, 0.4);
}
.tr-cd-digit.is-go {
  color: var(--ok);
  font-size: clamp(30px, 11cqi, 62px);
  letter-spacing: 0.06em;
  text-shadow: 0 0 30px rgba(53, 199, 131, 0.8), 0 0 70px rgba(53, 199, 131, 0.45);
}
.tr-cd-digit.pop { animation: trCdPop 0.55s var(--spring) both; }
@keyframes trCdPop {
  0% { transform: scale(0.35); opacity: 0; filter: brightness(2.4); }
  60% { transform: scale(1.18); opacity: 1; }
  100% { transform: scale(1); filter: brightness(1); }
}

/* === race clock (replaces the chess clocks) === */
.tr-clock-row { display: flex; justify-content: center; margin-top: -2px; }
.tr-race-clock {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(22px, 7cqi, 34px);
  font-variant-numeric: tabular-nums;
  letter-spacing: 1px;
  padding: 6px 22px;
  border-radius: var(--r-md);
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.2);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.2);
  border: 1px solid var(--glass-brd);
  box-shadow: var(--shadow-pop);
  transition: color var(--dur-fast), border-color var(--dur-fast);
}
.tr-race-clock.panic { color: var(--gold); border-color: rgba(241, 193, 82, 0.45); }
.tr-race-clock.critical {
  color: var(--danger);
  border-color: rgba(255, 93, 108, 0.55);
  animation: glowPulseDanger 1s ease-in-out infinite;
}

/* === result panel === */
.tr-result {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(4, 7, 11, 0.72);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-radius: var(--r-sm);
}
.tr-result.hidden { display: none; }
.tr-res-frame {
  width: min(460px, 96%);
  max-height: 100%;
  overflow-y: auto;
  padding: clamp(14px, 4cqi, 26px);
  border-radius: var(--r-xl);
  border: 1px solid rgba(241, 193, 82, 0.45);
  background: var(--panel-strong);
  box-shadow: var(--shadow-card), var(--shadow-glow-gold);
  text-align: center;
  animation: trResIn 0.5s var(--spring) both;
}
@keyframes trResIn {
  0% { transform: scale(0.8) translateY(14px); opacity: 0; }
  100% { transform: none; opacity: 1; }
}
.tr-res-kicker {
  font-size: 11px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 800;
}
.tr-res-title {
  margin-top: 8px;
  font-family: var(--font-display);
  font-size: clamp(20px, 5.4cqi, 34px);
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.tr-res-title[data-tone="gold"] { color: var(--gold); text-shadow: 0 0 22px rgba(241, 193, 82, 0.65); }
.tr-res-title[data-tone="danger"] { color: var(--danger); text-shadow: 0 0 22px rgba(255, 93, 108, 0.6); }
.tr-res-line { margin-top: 8px; font-size: 13.5px; color: var(--text-dim); }
.tr-res-grid {
  margin-top: 18px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.tr-res-col {
  padding: 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--stroke);
  background: var(--panel-soft);
  min-width: 0;
}
.tr-res-col.is-winner { border-color: rgba(241, 193, 82, 0.5); box-shadow: var(--shadow-glow-gold); }
.tr-res-name {
  font-size: 12.5px;
  font-weight: 800;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tr-res-wpm {
  margin-top: 6px;
  font-family: var(--font-display);
  font-size: clamp(24px, 7cqi, 40px);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
}
.tr-res-col.is-winner .tr-res-wpm { color: var(--gold); text-shadow: 0 0 18px rgba(241, 193, 82, 0.5); }
.tr-res-unit {
  margin-top: 2px;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 800;
}
.tr-res-sub { margin-top: 8px; font-size: 12px; color: var(--text-dim); }
.tr-res-frame .btn { margin-top: 16px; }

/* === fighter-card mini stats (in place of chess clocks) === */
.tr-fighter-stats {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

/* === responsive ===
   Was `@media (max-width: 520/390)` — window questions; the empty `@container`
   stub above was the abandoned half of this conversion. An authed player at an
   800-1279px window races inside a 486-527px scene (rail + context column come
   off the window first — shell.css «WINDOW CLASSES»), where the desktop text
   size and 230px cap never adapted. The numbers stay; the box changes — below
   an 800px window the two units agree, so phones measure byte-identical.
   durak.css and nardy.css carry the same conversion. */
@container scene (max-width: 520px) {
  .tr-stage { padding: 10px; gap: 12px; }
  .tr-text-card { padding: 14px 12px 12px; }
  .tr-text { font-size: 1rem; max-height: 190px; }
}
@container scene (max-width: 390px) {
  .tr-text { font-size: 0.98rem; line-height: 1.75; }
  .tr-lane { padding: 8px 10px; }
  .tr-lane-stats { font-size: 11px; }
  .tr-blk { padding: 8px 10px; gap: 8px; }
  .tr-blk-head { font-size: 12.5px; }
  .tr-blk-key { width: 28px; height: 28px; font-size: 14px; }
  .tr-res-grid { gap: 8px; }
  .tr-res-col { padding: 10px 8px; }
  .tr-race-clock { padding: 5px 16px; }
}

/* === reduced motion === */
@media (prefers-reduced-motion: reduce) {
  .tr-lane-fill { transition: none; }
  .tr-lane.is-finished .tr-lane-flag,
  .tr-lane.is-overtake,
  .tr-ch.cur,
  .tr-focus-hint,
  .tr-cd-digit.pop,
  .tr-res-frame,
  .tr-race-clock.critical { animation: none; }
  /* The escalation still escalates without motion: the colours, the strike
     through the character, the ← and the counter all survive. */
  .tr-blk,
  .tr-blk[data-level="2"],
  .tr-blk[data-level="3"],
  .tr-blk[data-level="2"] .tr-blk-key,
  .tr-blk[data-level="3"] .tr-blk-key { animation: none; }
  .tr-text-card.is-blocked .tr-text { transition: none; }
}

/* Countdown layout hint: half the corpus is English, and the three seconds
   before GO are the only moment where switching the keyboard is still free. */
.tr-cd-lang {
  margin-top: 10px;
  max-width: 88%;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.2px;
  text-align: center;
  color: var(--gold);
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.55);
}
