.not-found-page {
  box-sizing: border-box;
  display: grid;
  min-height: 100vh;
  margin: 0;
  padding: 32px 20px;
  place-items: center;
  background: radial-gradient(ellipse at 50% 35%, #24211c 0, #141414 50%, #101010 100%);
  color: #f2f2f2;
  font-family: Arial, sans-serif;
  text-align: center;
}
body:has(> .not-found-page) { margin: 0; background: #101010; }
.not-found-card { width: 460px; max-width: 100%; }
.not-found-brand { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; }
/* the logo as on the site (components/BrandLogo.tsx): the mark and the name, each sized here */
.not-found-mark { display: block; height: 50px; width: auto; }
.not-found-word { display: block; height: 36px; width: auto; }
.not-found-code {
  margin-top: 40px;
  color: #292722;
  font-size: clamp(100px, 22vw, 172px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -8px;
  text-shadow: 0 1px 0 #4c4030;
}
.not-found-accent { width: 44px; height: 3px; margin: 24px auto; border-radius: 3px; background: #ff9e45; }
.not-found-card h1 { margin: 0 0 14px; font-size: 32px; font-weight: 700; letter-spacing: -1px; }
.not-found-card p { margin: 0; color: #a5a29e; font-size: 15px; line-height: 1.7; }
.not-found-home {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 22px;
  margin-top: 32px;
  padding: 13px 22px;
  border: 1px solid #78502a;
  border-radius: 8px;
  background: #292016;
  color: #ffb36b;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.not-found-home:hover { background: #382a1b; border-color: #ff9e45; }
.not-found-home:focus-visible, .not-found-brand:focus-visible { outline: 2px solid #ff9e45; outline-offset: 5px; }
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
@layer properties {
  @supports (((-webkit-hyphens: none)) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color: rgb(from red r g b)))) {
    *, :before, :after, ::backdrop {
      --tw-rotate-x: initial;
      --tw-rotate-y: initial;
      --tw-rotate-z: initial;
      --tw-skew-x: initial;
      --tw-skew-y: initial;
      --tw-border-style: solid;
      --tw-shadow: 0 0 #0000;
      --tw-shadow-color: initial;
      --tw-shadow-alpha: 100%;
      --tw-inset-shadow: 0 0 #0000;
      --tw-inset-shadow-color: initial;
      --tw-inset-shadow-alpha: 100%;
      --tw-ring-color: initial;
      --tw-ring-shadow: 0 0 #0000;
      --tw-inset-ring-color: initial;
      --tw-inset-ring-shadow: 0 0 #0000;
      --tw-ring-inset: initial;
      --tw-ring-offset-width: 0px;
      --tw-ring-offset-color: #fff;
      --tw-ring-offset-shadow: 0 0 #0000;
      --tw-outline-style: solid;
      --tw-blur: initial;
      --tw-brightness: initial;
      --tw-contrast: initial;
      --tw-grayscale: initial;
      --tw-hue-rotate: initial;
      --tw-invert: initial;
      --tw-opacity: initial;
      --tw-saturate: initial;
      --tw-sepia: initial;
      --tw-drop-shadow: initial;
      --tw-drop-shadow-color: initial;
      --tw-drop-shadow-alpha: 100%;
      --tw-drop-shadow-size: initial;
    }
  }
}

@layer theme {
  :root, :host {
    --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
      "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
      "Courier New", monospace;
    --default-transition-duration: .15s;
    --default-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
    --default-font-family: var(--font-sans);
    --default-mono-font-family: var(--font-mono);
  }
}

@layer base {
  *, :after, :before, ::backdrop {
    box-sizing: border-box;
    border: 0 solid;
    margin: 0;
    padding: 0;
  }

  ::file-selector-button {
    box-sizing: border-box;
    border: 0 solid;
    margin: 0;
    padding: 0;
  }

  html, :host {
    -webkit-text-size-adjust: 100%;
    tab-size: 4;
    line-height: 1.5;
    font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
    font-feature-settings: var(--default-font-feature-settings, normal);
    font-variation-settings: var(--default-font-variation-settings, normal);
    -webkit-tap-highlight-color: transparent;
  }

  hr {
    height: 0;
    color: inherit;
    border-top-width: 1px;
  }

  abbr:where([title]) {
    -webkit-text-decoration: underline dotted;
    text-decoration: underline dotted;
  }

  h1, h2, h3, h4, h5, h6 {
    font-size: inherit;
    font-weight: inherit;
  }

  a {
    color: inherit;
    -webkit-text-decoration: inherit;
    -webkit-text-decoration: inherit;
    -webkit-text-decoration: inherit;
    text-decoration: inherit;
  }

  b, strong {
    font-weight: bolder;
  }

  code, kbd, samp, pre {
    font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
    font-feature-settings: var(--default-mono-font-feature-settings, normal);
    font-variation-settings: var(--default-mono-font-variation-settings, normal);
    font-size: 1em;
  }

  small {
    font-size: 80%;
  }

  sub, sup {
    vertical-align: baseline;
    font-size: 75%;
    line-height: 0;
    position: relative;
  }

  sub {
    bottom: -.25em;
  }

  sup {
    top: -.5em;
  }

  table {
    text-indent: 0;
    border-color: inherit;
    border-collapse: collapse;
  }

  :-moz-focusring {
    outline: auto;
  }

  progress {
    vertical-align: baseline;
  }

  summary {
    display: list-item;
  }

  ol, ul, menu {
    list-style: none;
  }

  img, svg, video, canvas, audio, iframe, embed, object {
    vertical-align: middle;
    display: block;
  }

  img, video {
    max-width: 100%;
    height: auto;
  }

  button, input, select, optgroup, textarea {
    font: inherit;
    font-feature-settings: inherit;
    font-variation-settings: inherit;
    letter-spacing: inherit;
    color: inherit;
    opacity: 1;
    background-color: #0000;
    border-radius: 0;
  }

  ::file-selector-button {
    font: inherit;
    font-feature-settings: inherit;
    font-variation-settings: inherit;
    letter-spacing: inherit;
    color: inherit;
    opacity: 1;
    background-color: #0000;
    border-radius: 0;
  }

  :where(select:is([multiple], [size])) optgroup {
    font-weight: bolder;
  }

  :where(select:is([multiple], [size])) optgroup option {
    padding-inline-start: 20px;
  }

  ::file-selector-button {
    margin-inline-end: 4px;
  }

  ::placeholder {
    opacity: 1;
  }

  @supports (not ((-webkit-appearance: -apple-pay-button))) or (contain-intrinsic-size: 1px) {
    ::placeholder {
      color: currentColor;
    }

    @supports (color: color-mix(in lab, red, red)) {
      ::placeholder {
        color: color-mix(in oklab, currentcolor 50%, transparent);
      }
    }
  }

  textarea {
    resize: vertical;
  }

  ::-webkit-search-decoration {
    -webkit-appearance: none;
  }

  ::-webkit-date-and-time-value {
    min-height: 1lh;
    text-align: inherit;
  }

  ::-webkit-datetime-edit {
    display: inline-flex;
  }

  ::-webkit-datetime-edit-fields-wrapper {
    padding: 0;
  }

  ::-webkit-datetime-edit {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-year-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-month-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-day-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-hour-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-minute-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-second-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-millisecond-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-meridiem-field {
    padding-block: 0;
  }

  ::-webkit-calendar-picker-indicator {
    line-height: 1;
  }

  :-moz-ui-invalid {
    box-shadow: none;
  }

  button, input:where([type="button"], [type="reset"], [type="submit"]) {
    appearance: button;
  }

  ::file-selector-button {
    appearance: button;
  }

  ::-webkit-inner-spin-button {
    height: auto;
  }

  ::-webkit-outer-spin-button {
    height: auto;
  }

  [hidden]:where(:not([hidden="until-found"])) {
    display: none !important;
  }
}

@layer components;

@layer utilities {
  .invisible {
    visibility: hidden;
  }

  .visible {
    visibility: visible;
  }

  .absolute {
    position: absolute;
  }

  .fixed {
    position: fixed;
  }

  .relative {
    position: relative;
  }

  .static {
    position: static;
  }

  .sticky {
    position: sticky;
  }

  .block {
    display: block;
  }

  .contents {
    display: contents;
  }

  .grid {
    display: grid;
  }

  .hidden {
    display: none;
  }

  .inline {
    display: inline;
  }

  .table {
    display: table;
  }

  .shrink {
    flex-shrink: 1;
  }

  .grow {
    flex-grow: 1;
  }

  .transform {
    transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
  }

  .resize {
    resize: both;
  }

  .rounded {
    border-radius: .25rem;
  }

  .border {
    border-style: var(--tw-border-style);
    border-width: 1px;
  }

  .shadow {
    --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, #0000001a), 0 1px 2px -1px var(--tw-shadow-color, #0000001a);
    box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
  }

  .ring {
    --tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
    box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
  }

  .outline {
    outline-style: var(--tw-outline-style);
    outline-width: 1px;
  }

  .filter {
    filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
  }

  .transition {
    transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
    transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
    transition-duration: var(--tw-duration, var(--default-transition-duration));
  }

  .outline-none {
    --tw-outline-style: none;
    outline-style: none;
  }
}

:root {
  color-scheme: dark;
  --radius: .5rem;
  --background: #242424;
  --foreground: #ffffffdb;
  --card: #292929;
  --card-foreground: #ffffffdb;
  --popover: #2f2f2f;
  --popover-foreground: #ffffffdb;
  --primary: #ff9e45;
  --primary-foreground: #191919;
  --secondary: #333;
  --secondary-foreground: #ffffffc7;
  --muted: #303030;
  --muted-foreground: #ffffff8f;
  --accent: #3a3a3a;
  --accent-foreground: #ffffffe6;
  --destructive: #ff5d5d;
  --border: #ffffff14;
  --input: #ffffff1f;
  --ring: #ff9e45;
}

* {
  box-sizing: border-box;
}

html, body, #root {
  min-height: 100%;
}

body {
  background: var(--background);
  min-width: 1120px;
  color: var(--foreground);
  margin: 0;
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif;
  font-size: 14px;
}

button, input {
  font: inherit;
}

button {
  color: inherit;
}

.no-scrollbar {
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.no-scrollbar::-webkit-scrollbar {
  width: 0;
  height: 0;
  display: none;
}

.cell-fill i {
  min-width: 0;
  height: 100%;
  display: block;
}

.matrix-loader-panel {
  animation: 1.4s ease-in-out infinite matrix-loader-lift;
}

@keyframes matrix-loader-lift {
  0%, 100% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(-2px);
  }
}

@media (max-width: 1280px) {
  body {
    min-width: 980px;
  }
}

@property --tw-rotate-x {
  syntax: "*";
  inherits: false
}

@property --tw-rotate-y {
  syntax: "*";
  inherits: false
}

@property --tw-rotate-z {
  syntax: "*";
  inherits: false
}

@property --tw-skew-x {
  syntax: "*";
  inherits: false
}

@property --tw-skew-y {
  syntax: "*";
  inherits: false
}

@property --tw-border-style {
  syntax: "*";
  inherits: false;
  initial-value: solid;
}

@property --tw-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}

@property --tw-shadow-color {
  syntax: "*";
  inherits: false
}

@property --tw-shadow-alpha {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}

@property --tw-inset-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}

@property --tw-inset-shadow-color {
  syntax: "*";
  inherits: false
}

@property --tw-inset-shadow-alpha {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}

@property --tw-ring-color {
  syntax: "*";
  inherits: false
}

@property --tw-ring-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}

@property --tw-inset-ring-color {
  syntax: "*";
  inherits: false
}

@property --tw-inset-ring-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}

@property --tw-ring-inset {
  syntax: "*";
  inherits: false
}

@property --tw-ring-offset-width {
  syntax: "<length>";
  inherits: false;
  initial-value: 0;
}

@property --tw-ring-offset-color {
  syntax: "*";
  inherits: false;
  initial-value: #fff;
}

@property --tw-ring-offset-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}

@property --tw-outline-style {
  syntax: "*";
  inherits: false;
  initial-value: solid;
}

@property --tw-blur {
  syntax: "*";
  inherits: false
}

@property --tw-brightness {
  syntax: "*";
  inherits: false
}

@property --tw-contrast {
  syntax: "*";
  inherits: false
}

@property --tw-grayscale {
  syntax: "*";
  inherits: false
}

@property --tw-hue-rotate {
  syntax: "*";
  inherits: false
}

@property --tw-invert {
  syntax: "*";
  inherits: false
}

@property --tw-opacity {
  syntax: "*";
  inherits: false
}

@property --tw-saturate {
  syntax: "*";
  inherits: false
}

@property --tw-sepia {
  syntax: "*";
  inherits: false
}

@property --tw-drop-shadow {
  syntax: "*";
  inherits: false
}

@property --tw-drop-shadow-color {
  syntax: "*";
  inherits: false
}

@property --tw-drop-shadow-alpha {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}

@property --tw-drop-shadow-size {
  syntax: "*";
  inherits: false
}
/* ============================================================================
   Theme palette — the only values that stay variables.

   Sizes, spacing and font sizes are written as plain px INSIDE each rule (see
   docs/frontend_rules.md): a number you can read and edit where you see it
   beats chasing an alias through this file. Colours are different — the same
   grey is reused in fifty places and has to change everywhere at once.
   ============================================================================ */

:root {
  /* surfaces */
  --surface-page: #242424;
  --surface-panel: #292929;
  --surface-rail: #333333;
  --surface-sunken: #1f1f1f;
  --surface-raised: #3a3a3a;
  --surface-hover: #353535;
  --surface-active: #3d3d3d;
  /* the light that sweeps a loading outline (the config card, owner 2026-10-15) */
  --skeleton-sheen: rgba(255, 255, 255, 0.16);

  /* text */
  --text-strong: rgba(255, 255, 255, 0.9);
  --text-normal: rgba(255, 255, 255, 0.86);
  --text-soft: rgba(255, 255, 255, 0.72);
  --text-dim: rgba(255, 255, 255, 0.62);
  --text-muted: rgba(255, 255, 255, 0.56);
  --text-on-accent: #242424;

  /* lines */
  --line: rgba(255, 255, 255, 0.08);
  --line-strong: #4a4a4a;

  /* Single source of action colours for the matrix, Hands and Actions. */
  --action-fold: #3f7fbd;
  --action-fold-hover: #4a8ecd;
  --action-passive: #58b967;
  --action-passive-hover: #63c973;
  --action-aggressive: #f7343f;
  --action-raise: #eb303a;
  --action-aggressive-hover: #ff4450;
  --action-allin: #861b21;
  --action-allin-hover: #9a2129;

  /* grades (trainer feedback; shared with engine.ts GRADE_COLORS).
     There is no separate colour for a blunder: it is the same red as a wrong
     move (owner request 2026-08-17), so the burgundy --grade-worst is gone and
     nothing is left pointing at it. */
  --grade-good: #58b967;
  --grade-warn: #e6a935;
  --grade-bad: #f7343f;

  /* accent */
  --accent-brand: #ff9e45;
  /* light blue: the «blue» news cover (the neural rows of the Solutions library were blue until owner 2026-10-14 «убери голубой цвет») */
  --neural-text: #8fc7ff;
  /* AI Custom Solve in the rail (owner 2026-10-14: «иконку получше, типа фиолетовенькую») */
  --ai-accent: #b69cff;
  --ai-accent-strong: #7c5cf0;
  --accent-brand-hover: #ffad5f;
  /* A deeper orange, owner value 2026-08-17. Only the trainer's Next hand
     button wears it, and it hovers UP to --accent-brand — the two are one pair,
     which is why this lives beside it rather than in the action colours. */
  --accent-brand-deep: #fc8e29;
  /* Ink for text sitting ON the orange, and the answer is white (owner report
     2026-08-17, twice: once for the study modal's confirm button and once for
     Next hand). The near-black --text-on-accent belongs on the GREEN buttons;
     on orange it reads as a black label stuck to the button, and a dark warm
     brown was no better — at label size it still just looks black.
     White costs contrast (2.2:1 against #ff9e45) and is used anyway: these are
     short, heavy, wide-tracked words on a big target, and the owner has now
     rejected the dark alternative twice. */
  --text-on-brand: #ffffff;
}

/* Action fills share these classes; inline styles only set dynamic dimensions. */
.action-fill.is-fold { background: var(--action-fold); }
.action-fill.is-call { background: var(--action-passive); }
.action-fill.is-bet { background: var(--action-aggressive); }
.action-fill.is-raise { background: var(--action-raise); }
.action-fill.is-allin { background: var(--action-allin); }
/* Bet / raise size shades (actionShade in lib/poker.ts): step N mixes N*10%
   of the all-in colour into the plain bet colour; 8 (80%) is the darkest. */
.action-fill.is-bet.is-shade-1 { background: color-mix(in srgb, var(--action-allin) 10%, var(--action-aggressive)); }
.action-fill.is-bet.is-shade-2 { background: color-mix(in srgb, var(--action-allin) 20%, var(--action-aggressive)); }
.action-fill.is-bet.is-shade-3 { background: color-mix(in srgb, var(--action-allin) 30%, var(--action-aggressive)); }
.action-fill.is-bet.is-shade-4 { background: color-mix(in srgb, var(--action-allin) 40%, var(--action-aggressive)); }
.action-fill.is-bet.is-shade-5 { background: color-mix(in srgb, var(--action-allin) 50%, var(--action-aggressive)); }
.action-fill.is-bet.is-shade-6 { background: color-mix(in srgb, var(--action-allin) 60%, var(--action-aggressive)); }
.action-fill.is-bet.is-shade-7 { background: color-mix(in srgb, var(--action-allin) 70%, var(--action-aggressive)); }
.action-fill.is-bet.is-shade-8 { background: color-mix(in srgb, var(--action-allin) 80%, var(--action-aggressive)); }
.action-fill.is-raise.is-shade-1 { background: color-mix(in srgb, var(--action-allin) 10%, var(--action-raise)); }
.action-fill.is-raise.is-shade-2 { background: color-mix(in srgb, var(--action-allin) 20%, var(--action-raise)); }
.action-fill.is-raise.is-shade-3 { background: color-mix(in srgb, var(--action-allin) 30%, var(--action-raise)); }
.action-fill.is-raise.is-shade-4 { background: color-mix(in srgb, var(--action-allin) 40%, var(--action-raise)); }
.action-fill.is-raise.is-shade-5 { background: color-mix(in srgb, var(--action-allin) 50%, var(--action-raise)); }
.action-fill.is-raise.is-shade-6 { background: color-mix(in srgb, var(--action-allin) 60%, var(--action-raise)); }
.action-fill.is-raise.is-shade-7 { background: color-mix(in srgb, var(--action-allin) 70%, var(--action-raise)); }
.action-fill.is-raise.is-shade-8 { background: color-mix(in srgb, var(--action-allin) 80%, var(--action-raise)); }
/* The matrix's heat views (owner 2026-10-16, lib/heatmap.ts): EV, Equity, EQR and Compare EV paint each combo of a class on one scale,
   level 0 red .. 10 green, through orange and yellow (the four stops below). */
:root {
  --heat-red: #e8453c;
  --heat-orange: #f3923a;
  --heat-yellow: #c8c24b;
  --heat-green: #5bc464;
  /* the Blockers cells (DetailsPanels blockerColor): yellow at 0 mixing to green (the card raises an action) or red (lowers it) */
  --blocker-positive: #72c55e;
  --blocker-negative: #f34e43;
  --blocker-neutral: #efb348;
}
.heat-fill.is-heat-0 { background: var(--heat-red); }
.heat-fill.is-heat-1 { background: color-mix(in srgb, var(--heat-orange) 50%, var(--heat-red)); }
.heat-fill.is-heat-2 { background: var(--heat-orange); }
.heat-fill.is-heat-3 { background: color-mix(in srgb, var(--heat-yellow) 33%, var(--heat-orange)); }
.heat-fill.is-heat-4 { background: color-mix(in srgb, var(--heat-yellow) 67%, var(--heat-orange)); }
.heat-fill.is-heat-5 { background: var(--heat-yellow); }
.heat-fill.is-heat-6 { background: color-mix(in srgb, var(--heat-green) 20%, var(--heat-yellow)); }
.heat-fill.is-heat-7 { background: color-mix(in srgb, var(--heat-green) 40%, var(--heat-yellow)); }
.heat-fill.is-heat-8 { background: color-mix(in srgb, var(--heat-green) 60%, var(--heat-yellow)); }
.heat-fill.is-heat-9 { background: color-mix(in srgb, var(--heat-green) 80%, var(--heat-yellow)); }
.heat-fill.is-heat-10 { background: var(--heat-green); }
/* The admin page's charts (owner 2026-10-20, pages/admin/charts.tsx): four series colours in this fixed order, checked as a set on the
   panel's dark surface (#292929: lightness band, colour-blind separation, contrast) - an amber, a violet, an aqua, a blue - and the hairline
   of their grids. */
:root {
  --chart-1: #d9782a;
  --chart-2: #9085e9;
  --chart-3: #199e70;
  --chart-4: #3987e5;
  --chart-grid: #383838;
}
/* ============================================================================
   The site's first screen (owner 2026-10-20: «красивую загрузку с анимацией
   нашего логотипа, чтобы если у пользователя нет ассетов, то чтобы ему сайт не
   открывался пока нет картинок»).

   #boot is drawn by index.html itself, beside #root, so it is the first thing
   painted and runs on unbroken until src/app/boot.ts opens the site (session,
   page file and its pictures here, or 4 s): it then fades away from the page
   already drawn under it (.is-leaving) and leaves the document. The built
   index.html carries these rules inline (vite.config.ts firstPaint), so this
   file stands on its own: only the colours of tokens.css come with it.

   Aurora (owner 2026-10-21: «Замени на сайте анимацию на 5-ю версию, посмотрю
   как выглядит», loader 5 of /loaders): a warm light of three soft patches
   drifts behind, the logo comes into focus and floats, a light passes through
   it (cut to its shapes by a mask of the two pictures), three dots wait under
   it. Leaving: the light widens, the logo lifts and blurs, all of it fades.
   Only transform, opacity and filter move (frontend_rules 5b.3); every
   movement is one segment from start to end (5b.2).

   .page-loading is the same screen for a page file still on its way
   (components/PageLoading.tsx), coming a beat late.
   ============================================================================ */

.boot {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: #171615;
  color: var(--text-normal);
  transition: opacity 520ms cubic-bezier(0.4, 0, 0.2, 1);   /* = BOOT_LEAVE_MS in app/boot.ts */
}
.boot.is-leaving { opacity: 0; pointer-events: none; }
.boot img { max-width: none; }

/* the warm light: three soft patches drifting slowly, each its own way */
.boot-sky {
  position: absolute;
  inset: 0;
  animation: boot-show 1400ms ease-out both;
  transition: transform 520ms cubic-bezier(0.4, 0, 0.2, 1);
}
.boot.is-leaving .boot-sky { transform: scale(1.3); }
.boot-blob {
  position: absolute;
  left: 50%;
  top: 50%;
  border-radius: 50%;
  mix-blend-mode: screen;
}
.boot-blob.is-one {
  width: 560px;
  height: 560px;
  margin: -280px 0 0 -280px;
  background: radial-gradient(circle, rgba(255, 138, 48, 0.42) 0%, rgba(255, 138, 48, 0) 62%);
  animation: boot-aurora-one 9000ms ease-in-out infinite alternate both;
}
.boot-blob.is-two {
  width: 480px;
  height: 480px;
  margin: -240px 0 0 -240px;
  background: radial-gradient(circle, rgba(255, 70, 110, 0.26) 0%, rgba(255, 70, 110, 0) 62%);
  animation: boot-aurora-two 11000ms ease-in-out infinite alternate both;
}
.boot-blob.is-three {
  width: 440px;
  height: 440px;
  margin: -220px 0 0 -220px;
  background: radial-gradient(circle, rgba(255, 210, 120, 0.24) 0%, rgba(255, 210, 120, 0) 62%);
  animation: boot-aurora-three 13000ms ease-in-out infinite alternate both;
}
@keyframes boot-aurora-one {
  from { transform: translate(-190px, -70px) scale(1); }
  to { transform: translate(70px, 50px) scale(1.18); }
}
@keyframes boot-aurora-two {
  from { transform: translate(190px, 60px) scale(1.1); }
  to { transform: translate(-70px, -60px) scale(0.92); }
}
@keyframes boot-aurora-three {
  from { transform: translate(30px, 140px) scale(0.9); }
  to { transform: translate(-150px, -30px) scale(1.12); }
}
@keyframes boot-show {
  from { opacity: 0; }
  to { opacity: 1; }
}
.boot-veil {
  pointer-events: none;
  position: absolute;
  inset: 0;
  background: radial-gradient(75% 75% at 50% 50%, rgba(23, 22, 21, 0) 35%, rgba(23, 22, 21, 0.85) 100%);
}

.boot-stage {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 36px;
  transition: transform 520ms cubic-bezier(0.4, 0, 0.2, 1), filter 520ms cubic-bezier(0.4, 0, 0.2, 1);
}
.boot.is-leaving .boot-stage { transform: translateY(-10px); filter: blur(4px); }

/* the logo comes into focus, then floats; the mark (296 x 128) and the lettering (1790 x 309) side by side, as BrandLogo draws them */
.boot-focus { animation: boot-focus 1200ms cubic-bezier(0.16, 1, 0.3, 1) 150ms both; }
@keyframes boot-focus {
  from { opacity: 0; transform: scale(1.14); filter: blur(12px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}
.boot-logo {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  animation: boot-float 3200ms ease-in-out 1300ms infinite alternate both;
}
@keyframes boot-float {
  from { transform: translateY(0); }
  to { transform: translateY(-5px); }
}
.boot-mark { display: block; height: 60px; }
.boot-word { display: block; height: 42px; }

/* a warm light through the logo: a band moving under a mask of the two pictures, so it lights only the mark and the letters */
.boot-shine {
  pointer-events: none;
  position: absolute;
  inset: 0;
  overflow: hidden;
  -webkit-mask-image: url("/assets/maxgto-mark-COQvd4oj.webp"), url("/assets/maxgto-word-B4gfxSmT.svg");
  mask-image: url("/assets/maxgto-mark-COQvd4oj.webp"), url("/assets/maxgto-word-B4gfxSmT.svg");
  -webkit-mask-position: left center, right center;
  mask-position: left center, right center;
  -webkit-mask-size: auto 60px, auto 42px;
  mask-size: auto 60px, auto 42px;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.boot-shine::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 34%;
  background: linear-gradient(105deg, rgba(255, 236, 210, 0) 10%, rgba(255, 236, 210, 0.55) 50%, rgba(255, 236, 210, 0) 90%);
  transform: translateX(-110%);
  animation: boot-shine 4200ms 1400ms infinite;
}
/* across in one segment, then still (outside the logo) until the next pass */
@keyframes boot-shine {
  0% { transform: translateX(-110%); animation-timing-function: cubic-bezier(0.45, 0, 0.2, 1); }
  40%, 100% { transform: translateX(310%); }
}

/* three dots waiting under the logo, each a beat after the one before */
.boot-dots { display: flex; gap: 10px; animation: boot-show 600ms ease-out 1000ms both; }
.boot-dots i {
  display: block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #ffc58a;
  animation: boot-dot 700ms ease-in-out infinite alternate both;
}
.boot-dots i:nth-child(2) { animation-delay: 230ms; }
.boot-dots i:nth-child(3) { animation-delay: 460ms; }
@keyframes boot-dot {
  from { opacity: 0.25; transform: scale(0.7); }
  to { opacity: 1; transform: scale(1.1); }
}

/* the scripts never came: after 12 s the loader says so, with Reload (the page's own address) */
.boot-late {
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 48px;
  margin: 0;
  text-align: center;
  font-size: 13px;
  color: var(--text-muted);
  opacity: 0;
  visibility: hidden;
  animation: boot-late 400ms ease-out 12s both;
}
.boot-late a { margin-left: 6px; color: var(--accent-brand); font-weight: 600; text-decoration: none; }
.boot-late a:hover { text-decoration: underline; }
@keyframes boot-late {
  to { opacity: 1; visibility: visible; }
}

@media (max-width: 520px) {
  .boot-logo { gap: 12px; }
  .boot-mark { height: 40px; }
  .boot-word { height: 28px; }
  .boot-shine {
    -webkit-mask-size: auto 40px, auto 28px;
    mask-size: auto 40px, auto 28px;
  }
  .boot-blob.is-one { width: 380px; height: 380px; margin: -190px 0 0 -190px; }
  .boot-blob.is-two { width: 320px; height: 320px; margin: -160px 0 0 -160px; }
  .boot-blob.is-three { width: 300px; height: 300px; margin: -150px 0 0 -150px; }
}

/* the loader of a page file still on its way (components/PageLoading.tsx): the same screen in the page's place, a beat late */
body:has(.page-loading) { min-width: 0; }
.page-loading { animation: boot-fade-in 300ms ease-out 180ms both; }
@keyframes boot-fade-in {
  from { opacity: 0; }
}
/* ============================================================================
   Playing cards. Size is set by ONE pair of variables per usage, and the rank
   and the suit watermark scale with it — so a card never has to be resized in
   three places.

   To resize a card family, set --card-width / --card-height on its class (see
   .seat-card and .board-card in practice.css) — rank and suit follow.
   ============================================================================ */

.playing-card {
  --card-width: 60px;
  --card-height: 78px;
  --card-rank-font: calc(var(--card-height) * var(--rank-size, 0.6));
  /* 0.55 of the height, and the number is a fit, not a taste (owner report
     2026-08-17). A suit glyph is about 0.89em WIDE, so at the old 1.05 it drew
     56px of ink across a 34px card — wider than every single family we have,
     which is why it read as a shapeless dark smear instead of a suit. The
     narrowest card is the study strip at W/H = 0.567, so 0.55 x height is the
     largest glyph that still fits inside it whole, with a margin. Raise this
     and the widest suits get clipped again. */
  --card-suit-font: calc(var(--card-height) * var(--suit-size, 1.2));

  /* Per-suit tuning knobs. Neutral here; the four blocks further down are what
     you actually edit. See "TUNING THE SUITS" below. */
  --suit-scale: 1;
  --suit-x: 0;
  --suit-y: 0;

  position: relative;
  display: block;
  /* A card is never squeezed: in a flex row (the board, a seat's hand, the
     strip) a shrinkable item gets squashed the moment the row runs out of
     width, and a card that is narrower than it is tall stops looking like a
     card at all. */
  flex-shrink: 0;
  width: var(--card-width);
  height: var(--card-height);
  overflow: hidden;
  border: var(--card-border-width, 1px) solid;
  border-radius: var(--card-radius, 6px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 3px 0 rgba(0, 0, 0, 0.38);
}

.playing-card.suit-s {
  --suit-glyph: var(--suit-s-glyph, "\2660");
  --suit-mask: var(--suit-s-mask, url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20100%20100%22%3E%3Cpath%20d%3D%22M50%208C50%208%2088%2034%2088%2057C88%2070%2079%2079%2068%2079C61%2079%2055%2075%2052%2069C53%2081%2057%2089%2064%2095L36%2095C43%2089%2047%2081%2048%2069C45%2075%2039%2079%2032%2079C21%2079%2012%2070%2012%2057C12%2034%2050%208%2050%208Z%22%20fill%3D%22black%22%2F%3E%3C%2Fsvg%3E"));
  --suit-color: var(--suit-s-color, #555555);
  border-color: var(--card-border-color, var(--suit-s-border, #7a7a7a));
  background: var(--suit-s-face, linear-gradient(145deg, #737373 0%, #555555 48%, #3f3f3f 100%));
}

.playing-card.suit-h {
  --suit-glyph: var(--suit-h-glyph, "\2665");
  --suit-mask: var(--suit-h-mask, url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20100%20100%22%3E%3Cpath%20d%3D%22M50%2092C18%2068%206%2050%206%2033C6%2018%2017%208%2030%208C39%208%2046%2013%2050%2021C54%2013%2061%208%2070%208C83%208%2094%2018%2094%2033C94%2050%2082%2068%2050%2092Z%22%20fill%3D%22black%22%2F%3E%3C%2Fsvg%3E"));
  --suit-color: var(--suit-h-color, #e60800);
  border-color: var(--card-border-color, var(--suit-h-border, #eb342e));
  background: var(--suit-h-face, linear-gradient(145deg, #ed4842 0%, #e60800 48%, #a10600 100%));
}

.playing-card.suit-d {
  --suit-glyph: var(--suit-d-glyph, "\2666");
  --suit-mask: var(--suit-d-mask, url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20100%20100%22%3E%3Cpath%20d%3D%22M50%204L94%2050L50%2096L6%2050Z%22%20fill%3D%22black%22%2F%3E%3C%2Fsvg%3E"));
  --suit-color: var(--suit-d-color, #2f45d7);
  border-color: var(--card-border-color, var(--suit-d-border, #4d66ff));
  background: var(--suit-d-face, linear-gradient(145deg, #5368ff 0%, #2f45d7 48%, #1e2e9b 100%));
}

.playing-card.suit-c {
  --suit-glyph: var(--suit-c-glyph, "\2663");
  --suit-mask: var(--suit-c-mask, url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20100%20100%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2229%22%20r%3D%2220%22%20fill%3D%22black%22%2F%3E%3Ccircle%20cx%3D%2227%22%20cy%3D%2259%22%20r%3D%2220%22%20fill%3D%22black%22%2F%3E%3Ccircle%20cx%3D%2273%22%20cy%3D%2259%22%20r%3D%2220%22%20fill%3D%22black%22%2F%3E%3Cpath%20d%3D%22M44%2060h12c0%2018%203%2027%209%2033H35c6-6%209-15%209-33z%22%20fill%3D%22black%22%2F%3E%3C%2Fsvg%3E"));
  --suit-color: var(--suit-c-color, #0a922c);
  border-color: var(--card-border-color, var(--suit-c-border, #10b83a));
  background: var(--suit-c-face, linear-gradient(145deg, #16be45 0%, #0a922c 48%, #06651f 100%));
}

/* ============================================================================
   TUNING THE SUITS — edit only the four blocks below.

   Every suit is drawn at a different weight by the font: a club reads bulky, a
   diamond narrow, a heart and a spade somewhere between. So each one gets its
   own size and its own nudge instead of sharing a single number (owner request
   2026-08-17).

     --suit-scale   size, as a multiplier of the family's --card-suit-font.
                    1 = untouched, 1.1 = a tenth bigger, 0.9 = a tenth smaller.
     --suit-x       nudge sideways. POSITIVE moves RIGHT, negative LEFT.
     --suit-y       nudge vertically. POSITIVE moves UP, negative DOWN.

   Both nudges are fractions of the CARD HEIGHT, not pixels, so a tune made on
   one card holds on all six sizes: 0.05 is "a twentieth of the card", which is
   3px on the strip card and 3.9px on a picked one. 0 is dead centre
   horizontally and the resting height vertically.

   The overall size of every suit at once is --card-suit-font at the top of this
   file; these four only say how the suits differ from each other.

   The numbers here were tuned by eye in the appearance panel and pasted back
   (owner, 2026-08-17). Anything the panel writes at :root overrides them.
   ============================================================================ */
.playing-card.suit-s {          /* ♠ spade */
  --suit-scale: var(--suit-s-scale, 1);
  --suit-x: var(--suit-s-x, 0.27);
  --suit-y: var(--suit-s-y, -0.255);
}

.playing-card.suit-h {          /* ♥ heart */
  --suit-scale: var(--suit-h-scale, 1.02);
  --suit-x: var(--suit-h-x, 0.235);
  --suit-y: var(--suit-h-y, -0.295);
}

.playing-card.suit-d {          /* ♦ diamond — narrow, so it reads smaller */
  --suit-scale: var(--suit-d-scale, 1.04);
  --suit-x: var(--suit-d-x, 0.18);
  --suit-y: var(--suit-d-y, -0.3);
}

.playing-card.suit-c {          /* ♣ club — bulky, so it reads bigger */
  --suit-scale: var(--suit-c-scale, 1.05);
  --suit-x: var(--suit-c-x, 0.195);
  --suit-y: var(--suit-c-y, -0.3);
}

/* The suit as a watermark, drawn WHOLE. Its shape is the only thing naming the
   suit on these cards, so nothing about it may be cropped: it sits inside the
   lower half of the card with the rank riding over it.

   The old version was clipped twice over — off the bottom, and in the study
   variant off the right edge as well — but the real culprit was the size: the
   glyph was wider than the card, so there was no placement that could have
   saved it (owner report 2026-08-17). */
.playing-card-suit {
  pointer-events: none;
  position: absolute;
  bottom: calc(var(--card-height) * (0.04 + var(--suit-y)));
  left: 50%;
  transform: translateX(-50%) translateX(calc(var(--card-height) * var(--suit-x)));
  font-size: calc(var(--card-suit-font) * var(--suit-scale));
  line-height: 1;
  color: var(--card-suit-ink, #000);
  opacity: var(--suit-opacity, 0.28);
  mix-blend-mode: var(--card-suit-blend, multiply);
}

/* The suit is DRAWN by default (owner choice 2026-08-17): the four shapes above
   are painted as a mask with the ink as the background, so they tint and scale
   by the same font-size a character would have. The margin puts the shape's
   base where a glyph's baseline sat, so switching sets does not move it. */
.playing-card-suit::before {
  content: "";
  display: block;
  width: 1em;
  height: 0.78em;
  margin-bottom: 0.21em;
  background: currentColor;
  -webkit-mask: var(--suit-mask) center / contain no-repeat;
  mask: var(--suit-mask) center / contain no-repeat;
}

/* A FONT set instead of a drawn one — the appearance panel puts `suits-text`
   on the document root and writes the four characters. */
:root.suits-text .playing-card-suit::before {
  content: var(--suit-glyph, "\2660");
  display: inline;
  width: auto;
  height: auto;
  margin-bottom: 0;
  background: none;
  -webkit-mask: none;
  mask: none;
}

/* Study variant: the same watermark, a touch stronger. It no longer MOVES the
   glyph — leaning it into the corner cost more than the look was worth. */
.playing-card.is-corner .playing-card-suit {
  opacity: calc(var(--suit-opacity, 0.28) * 1.25);
}

/* ── size families ────────────────────────────────────────────────────── */
.playing-card--strip {          /* flop cards inside a node strip card */
  --card-width: 34px;
  --card-height: 56px;
}

.playing-card--chance {         /* the turn/river card a chance node shows */
  --card-width: 48px;
  --card-height: 64px;
}

.playing-card--picker {         /* board picker grid: same size as the strip */
  --card-width: 34px;
  /* A real number, NOT 100%. The rank and the watermark are sized with
     calc(var(--card-height) * k), and a percentage in a font-size is read
     against the inherited FONT SIZE, not against the box — so this family had
     to carry hand-written font sizes, and those did not track anything. The
     result was a 74px card showing a 42px rank next to a TALLER 78px picked
     card showing a 35px one (owner report 2026-08-17). With a px height the
     family derives like every other one.

     Keep in step with the height of .deck-card in study-modal.css. */
  --card-height: 60px;
}

.playing-card--picked {         /* the chosen card above the picker grid */
  /* Smaller than it was, still clearly bigger than the 34x60 of the deck below
     — the board being built has to outrank the list it is picked from (owner
     request 2026-08-17). */
  --card-width: 48px;
  --card-height: 66px;
}

.playing-card-rank {
  position: absolute;
  z-index: 10;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--card-rank-family, inherit);
  font-size: var(--card-rank-font);
  font-weight: var(--card-rank-weight, 600);
  line-height: 1;
  color: var(--card-rank-color, #fff);
  text-shadow: var(--card-rank-shadow, 0 2px 2px rgba(0, 0, 0, 0.6));
}

/* ── blank theme ──────────────────────────────────────────────────────────
   The other way round: a plain face, and the SUIT's colour carries the rank
   and the watermark instead of the background. Switched on by the appearance
   panel, which puts `cards-blank` on the document root. */
:root.cards-blank .playing-card,
.playing-card.design-blank {
  border-color: rgba(0, 0, 0, 0.22);
  background: var(--card-blank-face, #f3f5f8);
}

:root.cards-blank .playing-card-rank,
.playing-card.design-blank .playing-card-rank {
  color: var(--suit-color);
  text-shadow: none;
}

:root.cards-blank .playing-card-suit,
.playing-card.design-blank .playing-card-suit {
  color: var(--suit-color);
  opacity: var(--suit-opacity, 0.9);
  mix-blend-mode: normal;
}

/* ── card designs ────────────────────────────────────────────────────────
   Settings › Layout › Card design (owner 2026-10-21: «нарисуй еще очень красивые аналоги хотя бы 5 штук дизайнов карт, которые будут
   удобные для покеристов»). PlayingCard puts `design-<id>` on every card (features/appearance/cardTheme.ts), so the whole site follows
   one choice; Classic is the rules above and Blank the block before this one. Every design but Traditional keeps the four-colour deck -
   spades dark (light on a dark face), hearts red, diamonds blue, clubs green - and every size comes off --card-height, so the 19px
   Blockers card and the table's seat cards read alike. The rank fonts have lining figures: digits of one height, the same line for 3
   as for 8 (owner 2026-10-21: Georgia's old-style 3, 4, 5, 7 and 9 dropped below the others in the picker).

   Studio, Flat and Vintage put the rank in the top-left corner and the suit in the bottom-right one, the way a large-index online deck
   does; Midnight, Outline and Jumbo keep the rank in the middle. */
.playing-card.design-studio .playing-card-rank,
.playing-card.design-flat .playing-card-rank,
.playing-card.design-vintage .playing-card-rank {
  top: calc(var(--card-height) * 0.05);
  left: calc(var(--card-height) * 0.08);
  transform: none;
  font-size: calc(var(--card-height) * 0.5);
  font-weight: 800;
  text-shadow: none;
}

.playing-card.design-studio .playing-card-suit,
.playing-card.design-flat .playing-card-suit,
.playing-card.design-vintage .playing-card-suit {
  bottom: calc(var(--card-height) * 0.02);
  left: auto;
  right: calc(var(--card-height) * 0.07);
  transform: none;
  font-size: calc(var(--card-height) * 0.4);
  opacity: 1;
  mix-blend-mode: normal;
}

/* Blank as a design: the suit a faint watermark behind the rank of the same colour, as on Classic (owner 2026-10-21: at the Blank
   block's 0.9 the suit covered the rank). */
.playing-card.design-blank .playing-card-suit {
  opacity: 0.18;
}

/* Studio: a clean white card with the large corner index of an online four-colour deck. */
.playing-card.design-studio {
  border-color: rgba(15, 23, 42, 0.16);
  background: linear-gradient(180deg, #ffffff 0%, #eef1f5 100%);
  box-shadow:
    inset 0 -1px 0 rgba(15, 23, 42, 0.08),
    0 3px 0 rgba(0, 0, 0, 0.38);
}

.playing-card.design-studio.suit-s { --suit-color: #1e2329; }
.playing-card.design-studio.suit-h { --suit-color: #e0262f; }
.playing-card.design-studio.suit-d { --suit-color: #2563eb; }
.playing-card.design-studio.suit-c { --suit-color: #16a34a; }

.playing-card.design-studio .playing-card-rank,
.playing-card.design-studio .playing-card-suit {
  color: var(--suit-color);
}

/* Flat: one solid colour per suit, white index, no gloss. */
.playing-card.design-flat {
  border-color: transparent;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.38);
}

.playing-card.design-flat.suit-s { background: #3d434c; }
.playing-card.design-flat.suit-h { background: #e0383e; }
.playing-card.design-flat.suit-d { background: #2f6fe4; }
.playing-card.design-flat.suit-c { background: #1f9d55; }

.playing-card.design-flat .playing-card-rank {
  color: #ffffff;
}

.playing-card.design-flat .playing-card-suit {
  color: #ffffff;
  opacity: 0.92;
}

/* Midnight: a dark face, the rank lit in its suit's colour, the suit a faint watermark behind it. */
.playing-card.design-midnight {
  background: linear-gradient(160deg, #2a2e36 0%, #16181d 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 3px 0 rgba(0, 0, 0, 0.45);
}

.playing-card.design-midnight.suit-s { --suit-color: #d7dce4; border-color: rgba(215, 220, 228, 0.45); }
.playing-card.design-midnight.suit-h { --suit-color: #ff5a64; border-color: rgba(255, 90, 100, 0.55); }
.playing-card.design-midnight.suit-d { --suit-color: #5b9bff; border-color: rgba(91, 155, 255, 0.55); }
.playing-card.design-midnight.suit-c { --suit-color: #3ddc84; border-color: rgba(61, 220, 132, 0.5); }

.playing-card.design-midnight .playing-card-rank {
  color: var(--suit-color);
  text-shadow: 0 0 calc(var(--card-height) * 0.14) color-mix(in srgb, var(--suit-color) 55%, transparent);
}

.playing-card.design-midnight .playing-card-suit {
  color: var(--suit-color);
  opacity: 0.2;
  mix-blend-mode: normal;
}

/* Outline: a dark card framed in its suit's colour, the rank in the middle and a small suit under it. */
.playing-card.design-outline {
  border-width: 2px;
  background: #202020;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.38);
}

.playing-card.design-outline.suit-s { --suit-color: #c4c9d1; border-color: #c4c9d1; }
.playing-card.design-outline.suit-h { --suit-color: #ff4d55; border-color: #ff4d55; }
.playing-card.design-outline.suit-d { --suit-color: #4f8dff; border-color: #4f8dff; }
.playing-card.design-outline.suit-c { --suit-color: #34c46e; border-color: #34c46e; }

.playing-card.design-outline .playing-card-rank {
  top: 42%;
  font-weight: 700;
  color: var(--suit-color);
  text-shadow: none;
}

.playing-card.design-outline .playing-card-suit {
  bottom: calc(var(--card-height) * 0.03);
  left: 50%;
  transform: translateX(-50%);
  font-size: calc(var(--card-height) * 0.26);
  color: var(--suit-color);
  opacity: 1;
  mix-blend-mode: normal;
}

/* Vintage: cream paper with a thin inner frame, a serif index in deep inks. */
.playing-card.design-vintage {
  border-color: #c4b28a;
  background: linear-gradient(165deg, #fdf8ec 0%, #efe3c8 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.55),
    0 3px 0 rgba(0, 0, 0, 0.38);
}

.playing-card.design-vintage::after {
  content: "";
  position: absolute;
  inset: calc(var(--card-height) * 0.045);
  border: 1px solid rgba(140, 110, 60, 0.3);
  border-radius: 3px;
  pointer-events: none;
}

.playing-card.design-vintage.suit-s { --suit-color: #1f1b16; }
.playing-card.design-vintage.suit-h { --suit-color: #b4232a; }
.playing-card.design-vintage.suit-d { --suit-color: #1e4fa3; }
.playing-card.design-vintage.suit-c { --suit-color: #1d6e3a; }

.playing-card.design-vintage .playing-card-rank {
  font-family: "Times New Roman", Times, serif;
  font-weight: 700;
  font-variant-numeric: lining-nums;
  color: var(--suit-color);
}

.playing-card.design-vintage .playing-card-suit {
  color: var(--suit-color);
}

/* Jumbo: the Classic faces with the rank as large as the card allows, read at a glance across several tables; a small suit in the
   top-right corner. */
.playing-card.design-jumbo .playing-card-rank {
  top: 54%;
  font-size: calc(var(--card-height) * 0.72);
  font-weight: 800;
}

.playing-card.design-jumbo .playing-card-suit {
  top: calc(var(--card-height) * 0.05);
  bottom: auto;
  left: auto;
  right: calc(var(--card-height) * 0.06);
  transform: none;
  font-size: calc(var(--card-height) * 0.2);
  color: #ffffff;
  opacity: 0.85;
  mix-blend-mode: normal;
}

/* Traditional: the red-and-black deck of a live table - a white card, a serif index with its small suit, a larger suit below. */
.playing-card.design-traditional {
  border-color: rgba(0, 0, 0, 0.2);
  background: linear-gradient(180deg, #ffffff 0%, #f2f2f0 100%);
  box-shadow:
    inset 0 -1px 0 rgba(0, 0, 0, 0.06),
    0 3px 0 rgba(0, 0, 0, 0.38);
}

.playing-card.design-traditional.suit-s,
.playing-card.design-traditional.suit-c { --suit-color: #1a1a1a; }
.playing-card.design-traditional.suit-h,
.playing-card.design-traditional.suit-d { --suit-color: #c8102e; }

.playing-card.design-traditional .playing-card-rank {
  top: calc(var(--card-height) * 0.04);
  left: calc(var(--card-height) * 0.07);
  display: flex;
  flex-direction: column;
  align-items: center;
  transform: none;
  font-family: "Times New Roman", Times, serif;
  font-size: calc(var(--card-height) * 0.42);
  font-weight: 700;
  font-variant-numeric: lining-nums;
  color: var(--suit-color);
  text-shadow: none;
}

.playing-card.design-traditional .playing-card-rank::after {
  content: "";
  width: calc(var(--card-height) * 0.2);
  height: calc(var(--card-height) * 0.16);
  margin-top: calc(var(--card-height) * 0.02);
  background: currentColor;
  -webkit-mask: var(--suit-mask) center / contain no-repeat;
  mask: var(--suit-mask) center / contain no-repeat;
}

.playing-card.design-traditional .playing-card-suit {
  bottom: calc(var(--card-height) * 0.02);
  left: auto;
  right: calc(var(--card-height) * 0.07);
  transform: none;
  font-size: calc(var(--card-height) * 0.34);
  color: var(--suit-color);
  opacity: 1;
  mix-blend-mode: normal;
}

/* Aurora: a vivid two-tone face per suit under a glossy top, the rank in white and a soft white suit behind it. */
.playing-card.design-aurora {
  border-color: rgba(255, 255, 255, 0.22);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    0 3px 0 rgba(0, 0, 0, 0.38);
}

.playing-card.design-aurora.suit-s { background: linear-gradient(150deg, #8d97ab 0%, #4b5466 52%, #232833 100%); }
.playing-card.design-aurora.suit-h { background: linear-gradient(150deg, #ff7a93 0%, #e8193f 52%, #9c0b28 100%); }
.playing-card.design-aurora.suit-d { background: linear-gradient(150deg, #5fd0ff 0%, #2b6cff 52%, #1938b8 100%); }
.playing-card.design-aurora.suit-c { background: linear-gradient(150deg, #6ee69a 0%, #13a454 52%, #08683a 100%); }

.playing-card.design-aurora::after {
  content: "";
  position: absolute;
  inset: 0 0 50% 0;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.24) 0%, rgba(255, 255, 255, 0) 100%);
  pointer-events: none;
}

.playing-card.design-aurora .playing-card-rank {
  font-weight: 800;
  color: #ffffff;
  text-shadow: 0 2px 3px rgba(0, 0, 0, 0.35);
}

.playing-card.design-aurora .playing-card-suit {
  color: #ffffff;
  opacity: 0.2;
  mix-blend-mode: normal;
}

/* Soft: pale pastel faces with deep inks - calm on the eyes through a long session. */
.playing-card.design-soft {
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.32);
}

.playing-card.design-soft.suit-s { --suit-color: #2b3038; border-color: #c5cad3; background: #e3e6eb; }
.playing-card.design-soft.suit-h { --suit-color: #c0303a; border-color: #ecb9bc; background: #f8dadc; }
.playing-card.design-soft.suit-d { --suit-color: #2456b8; border-color: #b7cbf0; background: #d9e5fb; }
.playing-card.design-soft.suit-c { --suit-color: #1d7a43; border-color: #b4dcc2; background: #d7f0df; }

.playing-card.design-soft .playing-card-rank {
  font-weight: 700;
  color: var(--suit-color);
  text-shadow: none;
}

.playing-card.design-soft .playing-card-suit {
  color: var(--suit-color);
  opacity: 0.16;
  mix-blend-mode: normal;
}

/* Stripe: a white card under a band of its suit's colour, the rank in the band and the suit below it. */
.playing-card.design-stripe {
  border-color: rgba(0, 0, 0, 0.16);
  background: linear-gradient(180deg, var(--suit-color) 0%, var(--suit-color) 42%, #ffffff 42%, #ffffff 100%);
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.38);
}

.playing-card.design-stripe.suit-s { --suit-color: #343a44; }
.playing-card.design-stripe.suit-h { --suit-color: #e0303a; }
.playing-card.design-stripe.suit-d { --suit-color: #2a66e0; }
.playing-card.design-stripe.suit-c { --suit-color: #18a058; }

.playing-card.design-stripe .playing-card-rank {
  top: 21%;
  font-size: calc(var(--card-height) * 0.34);
  font-weight: 800;
  color: #ffffff;
  text-shadow: none;
}

.playing-card.design-stripe .playing-card-suit {
  bottom: calc(var(--card-height) * 0.04);
  left: 50%;
  transform: translateX(-50%);
  font-size: calc(var(--card-height) * 0.4);
  color: var(--suit-color);
  opacity: 1;
  mix-blend-mode: normal;
}

/* The BACK of a card. Same box as a face, so every size family works on it
   unchanged. The villain's hand sits on the table from the deal and only turns
   over at showdown (owner request 2026-08-17); before that it is this.

   It wears the look of a board card not picked yet in the Study strip (study-strip.css .node-card-slot; owner 2026-10-21: «сделай в
   тренажере вот эти скрытые карты у гто бота таким же стилем ... только без анимации»): a warm dark back and our mark in the middle -
   still, since the bot's cards simply lie there - without the strip's inner frame (owner 2026-10-21: «в тренажере (только там) вот этот
   бордер убери»). Sizes come off --card-height, so every family keeps it. */
.card-back {
  position: relative;
  display: grid;
  flex-shrink: 0;
  width: var(--card-width);
  height: var(--card-height);
  place-items: center;
  overflow: hidden;
  /* no outline and no warm glow in the middle: the plain dark back with the mark (owner 2026-10-21, tuned in the browser) */
  border-radius: var(--card-radius, 6px);
  background: linear-gradient(160deg, #36312d 0%, #221f1d 100%);
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.38);
}

.card-back-mark {
  position: relative;
  display: block;
  width: calc(var(--card-height) * 0.46);
  max-width: none;
  height: auto;
  opacity: 0.9;
  filter: drop-shadow(0 0 4px rgba(255, 140, 50, 0.35));
}

/* ── small inline chip used in tables and lists ───────────────────────── */
.card-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 34px;
  border-radius: 5px;
  background: #f2f5f8;
  color: #14171b;
  font-weight: 850;
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.25);
  /* Never inherit a parent's text-shadow: a dark shadow under dark glyphs on
     the light chip reads as blur (Hands cards, 2026-08-16). */
  text-shadow: none;
}

.card-chip.heart { color: #c23845; }
.card-chip.diamond { color: #2879d0; }
.card-chip.club { color: #1e8a58; }

/* A row of small chips (the board as text-sized cards). */
.board-chips {
  display: flex;
  align-items: center;
  gap: 6px;
}
/* ============================================================================
   Practice trainer — the table, the seats, the action bar and the sidebar.
   Sizes are plain px right here; colours come from tokens.css.
   ============================================================================ */

/* ── page frame ───────────────────────────────────────────────────────────
   Exactly one screen tall: the sidebar and the felt scroll inside themselves,
   so the action bar can never be pushed below the fold. */
.practice-page {
  display: flex;
  height: 100vh;
  overflow: hidden;
  background: var(--surface-page);
  color: var(--text-normal);
}

/* ONE surface from the strip down to the bottom of the felt. The strip used to
   sit on the page colour with a line under it, which made it a header bolted
   on top of the table; it is part of the table (owner request 2026-08-20).
   Carried here rather than on each child so there is no seam to keep in step.
   A raw colour because this is the felt's surround and has no token: the
   surfaces in tokens.css are the panels that sit ON it. */
.practice-main {
  /* What the strip's edge arrows fade into: the surface below, not the page
     colour they default to. */
  --strip-fade: #1a1a1a;
  --strip-fade-soft: rgba(26, 26, 26, 0.7);
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
  overflow: hidden;
  background: #1a1a1a;
}

.practice-body {
  display: flex;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* ── the verdict mark ─────────────────────────────────────────────────────
   One drawing for every place the trainer shows a verdict: the sidebar, the
   strip, the review panel's move tiles and the verdict on a finished hand (see
   GradeIcon). The component draws the shape and its colour; the size and the
   weight of the stroke are here, so each place can match the line of text it
   sits on without a second set of artwork.

   `stroke-width` is inherited by the paths, so one line sets the weight of the
   whole drawing. */
.grade-icon {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  stroke-width: 2.2;
}

/* ── action strip (the hand so far) ───────────────────────────────────── */
.strip {
  display: flex;
  padding: 8px 16px;
}

/* The arrows hang off THIS, not off the track: they have to stay put while what
   is under them scrolls. */
.strip-viewport {
  position: relative;
  min-width: 0;
  flex: 1;
}

/* No scrollbar — the strip is driven from its edges, see StripScroll. */
.strip-track {
  display: flex;
  gap: 6px;
  overflow-x: auto;
}

.strip-step {
  /* Whose decision this tile holds, as raw r,g,b so one value can draw the ring
     both solid and as the soft glow around it. The other seat by default; the
     seat the user is sitting in overrides it just below. */
  --seat-rgb: 230, 169, 53;
  position: relative;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  min-width: 104px;
  border: 1px solid var(--line);
  border-radius: 6px;
  /* A raw value: the tiles sit on the felt's own surround, and none of the
     rail's surfaces is the tone they were asked for (owner request
     2026-08-21). */
  background: #242424;
  padding: 6px 8px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 3px 0 rgba(0, 0, 0, 0.38);
  /* Rides in from the left as it is appended (owner request 2026-08-19). It
     runs on MOUNT, and React keys every tile by its place and its text, so a
     tile already in the strip is never remounted and never replays this — only
     what is genuinely new moves. A rewind, which cuts the strip and re-keys
     what follows, is the one other time it plays, and there it is right: those
     tiles are new again. `both` holds the last frame, so a tile that finishes
     while the tab is in the background still ends up where it belongs. */
  animation: strip-step-in 260ms cubic-bezier(0.22, 0.8, 0.24, 1) both;
}

/* Only `opacity` and `transform`, so the whole entrance is the compositor's
   work. The tile is already in its final place in the flow — the transform is
   the only thing that moves — so nothing after it in the strip is pushed
   about while it arrives. */
@keyframes strip-step-in {
  from {
    opacity: 0;
    transform: translateX(-16px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* A card being turned over needs room for the card and nothing else: the 104px
   a decision needs for its seat, its stack and a word left flop, turn and river
   sitting in a third of their own tile (owner request 2026-08-19). */
.strip-step.is-chance {
  min-width: 25px;
}

.strip-step.is-hero {
  --seat-rgb: 88, 185, 103;
}

/* The ring that says a tile can be opened, and whose move is in it: green for
   the seat the user is sitting in, amber for the other one (owner request
   2026-08-19). It used to be the GRADE's colour, on the tile's own border. The
   verdict has not gone anywhere — it is the tick or the warning beside the
   action, written in the grade's own colour — but a frame around a decision now
   answers "whose", which is the thing a strip of two players is read for.

   A pseudo-element rather than border-color, so that appearing can be an
   ANIMATION instead of a repaint: the ring fades up while it grows the last 4%
   into place, and both of those are `opacity` and `transform`, which the
   compositor runs by itself. Changing the tile's real border would also have
   nudged every word inside it by a pixel each time the mouse went past. */
.strip-step.is-openable::after {
  content: "";
  pointer-events: none;
  position: absolute;
  inset: 0;
  border: 2px solid rgb(var(--seat-rgb));
  border-radius: 6px;
  opacity: 0;
  box-shadow: 0 0 12px rgba(var(--seat-rgb), 0.3);
  transition:
    opacity 170ms ease,
    transform 170ms cubic-bezier(0.22, 0.8, 0.24, 1);
  transform: scale(0.96);
}

.strip-step.is-openable:hover::after,
.strip-step.is-openable:focus-visible::after,
.strip-step.is-open::after {
  opacity: 1;
  transform: scale(1);
}

/* The head lights up with the ring, so the tile reads as one thing coming on
   rather than as a frame drawn around text that ignores it (owner request
   2026-08-19). */
.strip-step.is-openable:hover .strip-step-seat,
.strip-step.is-openable:hover .strip-step-stack,
.strip-step.is-openable:focus-visible .strip-step-seat,
.strip-step.is-openable:focus-visible .strip-step-stack,
.strip-step.is-open .strip-step-seat,
.strip-step.is-open .strip-step-stack {
  color: rgb(var(--seat-rgb));
}

/* Every decision in the strip opens the node it was made at — see .move-review
   and MoveReview.tsx. Chance rows do not: there is nothing behind a card being
   turned over. */
.strip-step.is-openable {
  cursor: pointer;
  transition: background-color 120ms ease;
}

.strip-step.is-openable:hover {
  background: var(--surface-hover);
}

/* The step being looked at: the same ring hover draws, held on. */
.strip-step.is-open {
  background: var(--surface-hover);
}

/* The step that is waiting for the user: nothing has happened in the hand yet
   and it is on them (owner request 2026-08-17). It breathes rather than blinks
   — the border swells out and settles, and a light runs across the words — so
   it reads as "still waiting" instead of as an alert. Amber is the same colour
   the seat on the clock pulses in, given here as raw r,g,b so one set of
   keyframes can fade it all the way out. */
.strip-step.is-waiting {
  --wait: 230, 169, 53;
  /* Both: the entrance still has to run, and the two lists never touch the same
     property — this one is border-colour and box-shadow, the entrance is
     opacity and transform. */
  animation:
    strip-step-in 260ms cubic-bezier(0.22, 0.8, 0.24, 1) both,
    strip-wait 1.7s ease-in-out infinite;
}

@keyframes strip-wait {
  0%, 100% {
    border-color: var(--line);
    box-shadow: 0 0 0 0 rgba(var(--wait), 0);
  }
  50% {
    border-color: var(--grade-warn);
    box-shadow:
      0 0 0 3px rgba(var(--wait), 0.12),
      0 0 14px rgba(var(--wait), 0.22);
  }
}

/* The words are painted by a gradient that slides across them, which is what
   makes the card feel alive without anything moving. */
/* Not an action: a sentence asking for one. */
.strip-step.is-waiting .strip-step-text {
  text-transform: none;
  background: linear-gradient(
    100deg,
    var(--text-muted) 34%,
    var(--text-normal) 50%,
    var(--text-muted) 66%
  );
  background-size: 260% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: strip-wait-sheen 1.7s linear infinite;
}

@keyframes strip-wait-sheen {
  0% { background-position: 150% 0; }
  100% { background-position: -50% 0; }
}

.strip-step-head {
  display: flex;
  background: var(--surface-raised);
  align-items: center;
  font-size: 13px;
  color: var(--text-muted);
}

.strip-step-seat {
  /* SB and BB are already capitals; this is for the streets, which are stored
     lower case and are set FLOP / TURN / RIVER here (owner request
     2026-08-19). */
  text-transform: uppercase;
  font-weight: 700;
  transition: color 170ms ease;
  color: var(--text-soft);
}

/* A seat is a badge; a street is not (owner request 2026-08-19). The modifier
   is what tells them apart — .strip-step-seat carries the street name on a
   chance row, and a lone "turn" set in a chip would read as a player. */
.strip-step-seat.is-seat {
  border-radius: 4px;
  background: var(--surface-raised);
  padding: 1px 4px;
  color: var(--text-strong);
}

/* What the seat still had in front of it at the moment it acted, not the pot
   (owner request 2026-08-19): the pot is on the felt and in the verdict, while
   how deep a seat was is the thing that makes a past decision readable. */
.strip-step-stack {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  transition: color 170ms ease;
}

/* Fixed at the height of a card, not at the height of its own text: a step
   holding a flop is taller than a step holding "raise 5.6", and letting the row
   size itself made the whole strip — and the page under it — grow the moment a
   street arrived (owner report 2026-08-16). Every step is card-height from the
   start, so nothing moves. Must match --card-height on .strip-step-card. */
/* Small: it shares a 14px line with the word it grades — and heavier than
   elsewhere, because at that size a thinner stroke greys out next to 700-weight
   type beside it (owner request 2026-08-20). */
.strip-step-action .grade-icon {
  width: 14px;
  height: 14px;
  stroke-width: 3;
}

.strip-step-action {
  display: flex;
  height: 32px;
  align-items: center;
  gap: 4px;
  /* The action alone sits in from the tile's own padding (owner request
     2026-08-19, trimmed to 3px on 2026-08-20). NOT the head above it: the seat
     and the stack are already where they should be, and they are a separate
     row, so shifting this one leaves them exactly as they were. */
  padding-left: 3px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-normal);
}

/* A chance row holds a card, not an icon and a word. The tile is as wide as
   the street written over it, which is wider than one card, so a card left to
   start where the text does sat with all the slack on its right (owner report
   2026-08-19). Centred, it is under the middle of the word whether the street
   put down one card or three. */
.strip-step.is-chance .strip-step-action {
  justify-content: center;
  padding-left: 0;
}

.strip-step-text {
  /* Every action is one word and a number — see actionText — so this only ever
     raises the word (owner request 2026-08-19). */
  text-transform: capitalize;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A street's cards, drawn instead of spelled out (owner request 2026-08-16).
   Small enough that a three-card flop fits the step it belongs to. */
.strip-step-card {
  --card-width: 24px;
  --card-height: 28px;
  /* .playing-card reads its corner off --card-radius, defaulting to 6px, which
     is a big round on a card this small (see cards.css). */
  --card-radius: 2px;
  margin-top: 6px;
}

/* ── table ────────────────────────────────────────────────────────────── */
.table-area {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 16px;
}

.table-stack {
  /* Nothing on the felt is text to be read out of the page: a drag across the
     table used to leave the board, the pot, a stack and a seat name all
     highlighted, which is the look of something broken rather than of something
     selected (owner request 2026-08-20). The action bar below is deliberately
     NOT covered — the verdict and the numbers on it are worth copying. */
  -webkit-user-select: none;
  user-select: none;
  display: flex;
  width: 100%;
  max-width: 980px;
  flex-direction: column;
  align-items: center;
}

/* The felt itself. Seats sit OUTSIDE it and overlap the edge by the negative
   margin below, the way a real client draws them. */
.felt {
  position: relative;
  /* A stacking context ONLY so the table below can sit at z-index: -1 and still
     be seen: without one a negative layer escapes to the nearest stacking
     context and is painted behind .practice-body's own background, i.e. into
     nothing. The single thing this re-homes is .felt-preparing-veil (z-index
     40) — a transparent overlay centred on the felt, nowhere near the seats
     that overlap its edge — so nothing changes on screen. */
  isolation: isolate;
  display: flex;
  width: 100%;
  flex-direction: column;
  align-items: center;
  /* TRANSPARENT, not deleted. box-sizing is border-box for everything
     (src/index.css), so taking the 6px border away would hand those 12px back
     to the content box and move every card, pot and chip on the felt by 6px.
     The border stays as geometry and stops being paint (owner request
     2026-08-19). */
  border: 6px solid transparent;
  border-radius: 150px;
  padding: 60px 40px;
  margin: -34px 0;
}

/* The table, laid UNDER everything the felt holds (owner request 2026-08-19).
   Drawn 840px wide; 384px is that width through the picture's OWN ratio
   (1760x804), so the table is never stretched — a poker table is a stadium
   shape and squashing one thickens the top and bottom rail while leaving the
   sides alone, which reads as a mistake immediately.

   A LAYER rather than a background, because a background is clipped to its
   border box and the felt's own box is shorter than the table is tall — as a
   background the table lost its top and bottom to that clip. Out of flow it is
   clipped by nothing, and the felt keeps its exact size, so no card, pot or
   chip moves and the seats that overlap the felt's edge go on sitting where
   they sat — now on the table's rail, the way a real client draws them.

   z-index: -1 puts it under every child of the felt at once, so there is no
   per-element ordering to keep in step; the seats are outside the felt and are
   painted above it anyway. */
.felt::before {
  content: "";
  pointer-events: none;
  position: absolute;
  z-index: -1;
  /* 55%, not 50%: the felt's own middle is not the table's. The hero seat sits
     lower than the villain seat rides high, so a table centred on the box read
     as sitting up out of it (owner request 2026-08-19). */
  top: 55%;
  left: 50%;
  width: 840px;
  height: 384px;
  background: url("/assets/poker-table-J1DhjKE4.webp") no-repeat center / contain;
  transform: translate(-50%, -50%);
}

/* The other looks of the table (owner 2026-10-21: «нарисуй еще 4 разных вида покерного стола, простых, но красивых, комфортных и
   удобных и чтобы вписывались в дизайн»; Settings › Layout › Practice table, features/practice/prefs.ts TABLE_LOOKS). Drawn here at
   the picture's own size and shape - 840 x 384, a stadium with round ends - so nothing on the felt moves: the rail is the border, a
   thin trim runs inside it, and the felt is lit from the middle with a fine cloth grain. A look only names its colours; Classic stays
   the picture above. The Settings tiles draw the same colours small (settings.css .settings-table-preview). */
.felt.is-table-midnight::before,
.felt.is-table-graphite::before,
.felt.is-table-burgundy::before,
.felt.is-table-ocean::before {
  border: 36px solid transparent;
  border-radius: 192px;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.06 0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E") padding-box,
    radial-gradient(ellipse 62% 75% at 50% 45%, var(--table-felt-light) 0%, var(--table-felt) 52%, var(--table-felt-dark) 100%) padding-box,
    linear-gradient(180deg, var(--table-rail-light) 0%, var(--table-rail) 38%, var(--table-rail-dark) 100%) border-box;
  box-shadow:
    inset 0 0 0 3px var(--table-trim),
    inset 0 0 0 5px rgba(0, 0, 0, 0.35),
    inset 0 14px 40px rgba(0, 0, 0, 0.5),
    0 0 0 1px rgba(255, 255, 255, 0.05),
    0 18px 36px rgba(0, 0, 0, 0.45);
}

/* Midnight: navy felt, a black rail, a silver trim. */
.is-table-midnight {
  --table-felt-light: #24497d;
  --table-felt: #173462;
  --table-felt-dark: #0b1a36;
  --table-rail-light: #3b3e45;
  --table-rail: #1c1e22;
  --table-rail-dark: #0a0b0d;
  --table-trim: #aeb8c6;
}

/* Graphite: charcoal felt in the site's own greys, a black rail, the brand's orange trim. */
.is-table-graphite {
  --table-felt-light: #3c4046;
  --table-felt: #2a2d32;
  --table-felt-dark: #17191c;
  --table-rail-light: #35373b;
  --table-rail: #18191b;
  --table-rail-dark: #080809;
  --table-trim: var(--accent-brand);
}

/* Burgundy: wine felt, a brown leather rail, a gold trim. */
.is-table-burgundy {
  --table-felt-light: #7a2233;
  --table-felt: #5a1624;
  --table-felt-dark: #2d0910;
  --table-rail-light: #4a3022;
  --table-rail: #2a1a12;
  --table-rail-dark: #120b07;
  --table-trim: #c9a24a;
}

/* Ocean: teal felt, a walnut rail, a brass trim. */
.is-table-ocean {
  --table-felt-light: #1b7f7c;
  --table-felt: #11605e;
  --table-felt-dark: #063436;
  --table-rail-light: #7a5232;
  --table-rail: #4e321c;
  --table-rail-dark: #24160a;
  --table-trim: #d9b46a;
}

/* ── laying out a spot handed over from the study ─────────────────────────
   The line has to be replayed against the server before the table means
   anything, so the felt says what it is doing instead of showing a half-built
   hand (owner request 2026-08-17). */
/* Centred by the LAYOUT, not by a transform. It was `top/left: 50%` plus a
   translate that lived inside the entrance keyframes — so with the system's
   Reduce Motion on, where that animation is switched off, the panel lost its
   centring and sat down-and-right of the middle (owner report 2026-08-17). A
   grid that fills the felt cannot be undone by anything. */
.felt-preparing-veil {
  pointer-events: none;
  position: absolute;
  z-index: 40;
  inset: 0;
  display: grid;
  place-items: center;
}

.felt-preparing {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  background: rgba(20, 20, 20, 0.92);
  padding: 16px 26px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
  animation: felt-preparing-in 220ms ease-out both;
}

@keyframes felt-preparing-in {
  from {
    opacity: 0;
    transform: translateY(4px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* A ring that keeps opening outwards, with the spinner sitting inside it — the
   same idea as the seat on the clock, so the two read as one language. */
.felt-preparing-mark {
  position: relative;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 2px solid var(--accent-brand);
  border-radius: 999px;
}

.felt-preparing-mark::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: 999px;
  animation: felt-preparing-ring 1.6s ease-out infinite;
}

@keyframes felt-preparing-ring {
  0% { box-shadow: 0 0 0 0 rgba(255, 158, 69, 0.55); }
  100% { box-shadow: 0 0 0 14px rgba(255, 158, 69, 0); }
}

.felt-preparing-spinner {
  /* An SVG rotates about its user-space origin unless told otherwise, which
     sends it round the corner instead of spinning in place. */
  transform-box: fill-box;
  transform-origin: center;
  color: var(--accent-brand);
  animation: felt-preparing-spin 900ms linear infinite;
}

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

.felt-preparing-text {
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.04em;
  color: var(--text-normal);
}

.felt-preparing-sub {
  font-size: 11px;
  color: var(--text-muted);
}


/* The pot, announced at the top of the felt. Reads the SAME number as the pill
   under the pile — see potChips in PracticeTable. */
.pot {
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface-sunken);
  padding: 3px 12px;
  font-size: 12px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  color: var(--text-normal);
}

/* Nothing has been collected yet. `visibility`, never `display`: the line has
   to go on holding its own height, or the whole felt rises the moment the
   first street goes in. */
.pot.is-empty {
  visibility: hidden;
}

/* The slot is one card tall whether or not there is a card in it, so a flop
   arriving does not grow the felt and jump the whole table. Must match
   --card-height on .board-card. */
.board {
  display: flex;
  align-items: center;
  gap: 3px;
  min-height: 58px;
  margin-top: 12px;
}

/* The same size as a player's hole cards (owner request 2026-08-17): one deck
   on the table, not two. Keep the two numbers equal to .seat-card's, and the
   min-height on .board above equal to this height.

   A board card is dealt in from the left (owner-supplied animation
   2026-08-17). Two numbers own the timing: --dur is one card's slide, and the
   90ms below is the beat between cards of the same batch. The component only
   says WHICH card this is (`--i`, its place in the batch), so a lone turn card
   does not sit through the flop's stagger.

   `backwards` is what keeps a waiting card off screen: without it the card
   would be drawn in place first and jump left when its turn came. */
.board-card {
  --card-width: 44px;
  --card-height: 58px;
  --dur: 420ms;
  animation: deal-slide var(--dur) cubic-bezier(0.22, 0.7, 0.2, 1) backwards;
  animation-delay: calc(var(--i, 0) * 90ms);
}

@keyframes deal-slide {
  0% {
    transform: translateX(-300px);
    opacity: 0;
  }
  100% {
    transform: none;
    opacity: 1;
  }
}


/* ── the middle ───────────────────────────────────────────────────────────
   Chips that have been swept in sit UNDER the board with what they are worth
   written under them (owner request 2026-08-16), so a street ending reads as
   "everything went to the middle" and the number is where the eye already is.
   The slot keeps its height whether or not there is anything in it, for the
   same reason the message slot below does: a felt that grows mid-hand jumps
   the whole table. Bottom-aligned, so the amount stays put and only the pile
   grows upward — 68px is the tallest pile plus the pill under it. */
.pot-chips {
  display: flex;
  height: 68px;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  margin-top: 8px;
}

/* Same pill as .pot at the top of the felt, minus the word: this one is read
   off the pile it sits under, so it needs no label (owner request
   2026-08-16). */
/* Comes up under the pile a beat after it lands, so the eye reads the chips
   first and the number second. */
.pot-chips-amount {
  animation: pot-amount-in 300ms ease-out 400ms both;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface-sunken);
  padding: 3px 12px;
  font-size: 12px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  color: var(--text-normal);
}

@keyframes pot-amount-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Width, never height: the four drawings share a chip diameter and differ only
   in how high the pile is, so at one width they stand on a common baseline and
   a bigger pot is a taller stack. Constrained by height they would invert —
   the single chip is the widest of the four.

   Chips are never animated (owner request 2026-08-16): money on a table is
   either there or it is not, and fading it in and out read as a glitch. */
.pot-chips-image {
  /* Same width as a seat's pile: chips are the same size wherever they sit on
     the table, so the middle must not be drawn in a bigger denomination. */
  width: 26px;
  height: auto;
  filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.5));
  /* The middle takes the street's chips. It lands rather than appears: up past
     full size and back down, which is what a pile dropped onto felt looks like
     (owner request 2026-08-19). No direction to it on purpose — the chips come
     from BOTH seats at once, so a slide from either one would be a lie about
     half of them. Keyed by the amount in PracticeTable, so every street that
     goes in gets its own landing. */
  animation: pot-chips-land 360ms cubic-bezier(0.22, 0.8, 0.24, 1) 260ms both;
}

@keyframes pot-chips-land {
  0% {
    opacity: 0;
    transform: scale(0.55);
  }
  62% {
    opacity: 1;
    transform: scale(1.12);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

/* The verdict line lives in a slot of fixed height: without it the felt grew
   by a row the moment a message appeared and the whole table jumped
   (owner report 2026-08-16). */
.table-message-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 24px;
  margin-top: 8px;
}

.table-message {
  border-radius: 6px;
  background: var(--surface-rail);
  padding: 4px 12px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-normal);
}

/* ── seats ────────────────────────────────────────────────────────────── */
.seat {
  position: relative;
  display: flex;
  align-items: center;
}

.seat-avatar {
  position: relative;
  /* 14 rather than 10 so that the turn glow, which has to come out OVER the
     hand (owner request 2026-08-19), can sit at 13 — above .seat-cards at 12 —
     and still be covered by the avatar itself, which is what keeps the light
     from washing the face out. Nothing on screen moves: the cards are absolute
     at `left: 100%` and never touch the avatar, so their order against it was
     never visible in the first place. */
  z-index: 14;
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border: 3px solid var(--accent-brand);
  border-radius: 999px;
  background: var(--surface-panel);
  text-align: center;
}

/* EVERY glow this avatar can wear is painted here, on an empty ring lying
   exactly on its outer edge — never on the avatar itself.

   A box-shadow is painted together with the element it belongs to, so pulsing
   one on .seat-avatar re-rasterised the whole circle — fill, border and both
   lines of text — on every frame of an animation that never stops, and left the
   main thread with that work to do at the exact moment the seat name was
   sliding across it. A pseudo-element has nothing in it, so there is nothing to
   repaint but the ring, and the avatar is left animating `transform` alone,
   which the compositor can run without the main thread at all.

   -3px because an absolutely positioned box measures from the PADDING box:
   `inset: 0` would start the ring 3px inside the avatar's own border, so this
   number has to move whenever the border width does — the ring is meant to lie
   exactly ON the outer edge, not beside it. */
.seat-avatar::after {
  content: "";
  pointer-events: none;
  position: absolute;
  inset: -3px;
  border-radius: 999px;
}

.seat.is-hero .seat-avatar {
  border-color: var(--grade-good);
}

/* Whoever is on the clock GLOWS. Two layers of light, BEHIND the avatar.

   Behind is the whole point (owner report 2026-08-19). This used to hang off
   .seat-avatar, and a child cannot get under its parent's own background — a
   positioned pseudo-element is painted after it, whatever its z-index — so the
   light had to be a ring with a hole in the middle to keep from washing the
   face out. At the top of the breath the hole grew past the avatar's edge and
   opened a dark collar between the gold border and the glow. Hung off .seat
   instead, at a z-index under the avatar's own, the light is simply covered by
   the avatar (an opaque #292929 disc), so it can be solid all the way through
   and there is no hole left to escape.

   9 rather than nothing: .seat does not make a stacking context, so a layer at
   z-index auto is painted in document order — and the top seat comes before the
   felt, which would put the villain's glow under the table (the same trap
   .seat-cards documents below). Any positive number clears the felt; under 10
   keeps it under the avatar.

   TWO layers, one period, different peaks: the core swells at 50% and the wide
   bloom follows at 62%, so the light reads as spreading outward rather than as
   two things pulsing. They share 1.8s, so they never drift apart and never
   beat against each other.

   Neither ever reaches zero — the floor is 0.5, so a seat on the clock is lit
   at every moment of the cycle and the glow breathes instead of blinking out
   (owner request 2026-08-19, raised from 0.15 to 0.25 and then to 0.5 on
   2026-08-20). The bottom of the breath is what the eye reads as "off", so it
   has to stay clearly lit: at half strength the seat never stops being the lit
   one and the pulse is a swell on top of a light that is always on.

   --pulse is the colour as raw r,g,b so one pair of keyframe lists serves both
   seats: amber for the villain, green for the hero. It is set on the SEAT so
   that the layers, which are the seat's own pseudo-elements, inherit it. */
.seat.is-to-act {
  --pulse: 230, 169, 53;
}

.seat.is-hero.is-to-act {
  --pulse: 88, 185, 103;
}

.seat.is-to-act .seat-avatar {
  border-color: var(--grade-warn);
}

.seat.is-hero.is-to-act .seat-avatar {
  border-color: var(--grade-good);
}

/* Both discs are centred on the avatar: it is the seat's first in-flow child
   and 64px wide, so its middle is 32px in — the same anchor .seat-action uses.
   The negative margins are half the box, which centres it on that point and
   leaves `transform` free for the animation alone. */
.seat.is-to-act::before,
.seat.is-to-act::after {
  content: "";
  pointer-events: none;
  position: absolute;
  z-index: 13;
  top: 50%;
  left: 32px;
  width: 100px;
  height: 100px;
  margin: -50px 0 0 -50px;
  border-radius: 999px;
}

/* The core: bright where the avatar hides it, still half strength as it clears
   the rim, so the light comes out from under the disc with no seam. */
.seat.is-to-act::before {
  background: radial-gradient(
    closest-side,
    rgba(var(--pulse), 0.8),
    rgba(var(--pulse), 0.55) 58%,
    rgba(var(--pulse), 0) 90%
  );
  animation: seat-glow 1.8s ease-in-out infinite;
}

/* The bloom: wider, softer, and a beat late. */
.seat.is-to-act::after {
  background: radial-gradient(
    closest-side,
    rgba(var(--pulse), 0.45),
    rgba(var(--pulse), 0.3) 54%,
    rgba(var(--pulse), 0) 100%
  );
  animation: seat-bloom 1.8s ease-in-out infinite;
}

/* Only `opacity` and `transform`, on two empty discs: the compositor runs both
   on its own and the main thread never sees a frame of either. Identical first
   and last keyframes, so the loop has no seam to show. */
@keyframes seat-glow {
  0%, 100% {
    opacity: 0.5;
    transform: scale(0.94);
  }
  50% {
    opacity: 1;
    transform: scale(1.05);
  }
}

@keyframes seat-bloom {
  0%, 100% {
    opacity: 0.45;
    transform: scale(0.9);
  }
  62% {
    opacity: 0.8;
    transform: scale(1.12);
  }
}

/* The two lines inside an avatar, in their own wrapper so the seat name and
   the stack can be nudged towards each other (the translateY below) without
   moving the circle. */
.seat-avatar-text {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.seat-name {
  transform: translateY(2px);
  font-size: 16px;
  font-weight: 900;
  line-height: 1;
  color: var(--text-normal);
}

.seat-stack {
  transform: translateY(-2px);
  font-size: 13px;
  font-weight: 900;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* ── action flash ─────────────────────────────────────────────────────── */
/* What a seat just did is announced ON that seat, as a SWAP rather than a
   disappearance (owner request 2026-08-16): the seat name slides out to the
   left, the action rides in from the right in its place, holds, and then the
   two change back — the action leaves the way it came and the name slides in
   again behind it. The name is never simply switched off.

   Both halves move on the SAME axis in opposite directions, which is what makes
   it read as one thing replacing another rather than as two separate fades.
   Enter, hold and exit are ONE keyframe list per element: the chip is removed
   only after 1100ms, when it is already invisible, so nothing has to be
   unmounted mid-flight. Only the ring colour stays a variable — one keyframe
   list serves all four action kinds. */
.seat.is-flash-fold { --flash-rgb: 63, 127, 189; }
.seat.is-flash-call { --flash-rgb: 88, 185, 103; }
.seat.is-flash-bet,
.seat.is-flash-raise { --flash-rgb: 247, 52, 63; }
.seat.is-flash-allin { --flash-rgb: 134, 27, 33; }

/* The avatar takes the hit: one pop outwards in the colour of the action.
   Two animations on two elements rather than one list on the avatar: the pop is
   a `transform` and nothing else, so it stays on the compositor and carries the
   seat name and the stack with it smoothly, while the coloured ring is a
   box-shadow on the empty pseudo-element where a repaint costs nothing. Mixing
   the two in one keyframe list meant the circle and its text were re-painted 66
   times per announcement for the sake of a glow.
   Declared after .seat.is-to-act so it wins if a seat somehow carries both. */
.seat.is-flashing .seat-avatar {
  animation: seat-avatar-pop 1100ms cubic-bezier(0.22, 0.8, 0.24, 1) both;
}

.seat.is-flashing .seat-avatar::after {
  animation: seat-avatar-flash 1100ms cubic-bezier(0.22, 0.8, 0.24, 1) both;
}

@keyframes seat-avatar-pop {
  0% { transform: scale(1); }
  12% { transform: scale(1.07); }
  34%, 100% { transform: scale(1); }
}

@keyframes seat-avatar-flash {
  0% { box-shadow: 0 0 0 0 rgba(var(--flash-rgb), 0.6); }
  12% {
    box-shadow:
      0 0 0 7px rgba(var(--flash-rgb), 0.3),
      0 0 26px rgba(var(--flash-rgb), 0.55);
  }
  70% {
    box-shadow:
      0 0 0 3px rgba(var(--flash-rgb), 0.18),
      0 0 18px rgba(var(--flash-rgb), 0.3);
  }
  100% { box-shadow: 0 0 0 0 rgba(var(--flash-rgb), 0); }
}

/* The seat name rides OUT to the left and back in from the left. It keeps full
   opacity for the first stretch of the trip so the eye sees it leave; it only
   fades once it is off the avatar, which has no clipping of its own.
   The translateY(2px) is .seat-name's own resting nudge and has to be repeated
   in every frame, or the name would jump a couple of pixels as it goes.

   TWO animations, one for where the name IS and one for whether it can be seen,
   because they do not want the same shape. An easing curve is applied to each
   SEGMENT of a keyframe list, not to the list as a whole, so a frame added
   purely to time the fade also cuts the movement in two and gives the name a
   full stop in the middle of it. That is what made the return jerk (owner
   report 2026-08-17): the old list turned round at 78%, flew 31px to a
   dead stop at -7px on the 91% frame — cubic-bezier(.22,.8,.24,1) ends at zero
   speed — and then tore off again for the last 7px. Two hops, read as a stutter
   right where the eye was following it home.

   Split apart, the trip out is one accelerating segment and the trip back is
   ONE decelerating segment all the way to the resting position, with no
   keyframe in between to stop at. The fade keeps its own frames and cannot
   interrupt either.

   Both properties are ones the compositor can animate by itself, so neither
   depends on how busy the main thread is at the time. */
.seat-name.is-yield {
  animation:
    seat-name-slide 1100ms both,
    seat-name-fade 1100ms linear both;
}

@keyframes seat-name-slide {
  0% {
    transform: translateY(2px) translateX(0);
    animation-timing-function: cubic-bezier(0.5, 0, 0.86, 0.36);
  }
  20% {
    transform: translateY(2px) translateX(-38px);
    animation-timing-function: linear;
  }
  76% {
    transform: translateY(2px) translateX(-38px);
    animation-timing-function: cubic-bezier(0.18, 0.78, 0.28, 1);
  }
  100% { transform: translateY(2px) translateX(0); }
}

@keyframes seat-name-fade {
  0%, 9% { opacity: 1; }
  20%, 76% { opacity: 0; }
  93%, 100% { opacity: 1; }
}

/* The stack line dims under the chip instead of showing through it. */
.seat.is-flashing .seat-stack {
  animation: seat-stack-dim 1100ms cubic-bezier(0.22, 0.8, 0.24, 1) both;
}

@keyframes seat-stack-dim {
  0% { opacity: 1; }
  14%, 70% { opacity: 0.22; }
  100% { opacity: 1; }
}

/* The chip itself. It is wider than the avatar on purpose — "raise 5.6" reads
   as a call-out over the seat, the way a real client shows it, and it is the
   topmost thing a seat can show: 30 clears the cards, the chips and the dealer
   button, all of which are its siblings (see the note in PracticeTable).

   Centred on the AVATAR, not on the seat: the avatar is the seat's first
   in-flow child and 64px wide, so its middle is 32px in, while the seat's own
   middle is dragged right by the hand of cards beside it. */
.seat-action {
  position: absolute;
  top: 50%;
  left: 32px;
  z-index: 30;
  overflow: hidden;
  transform: translate(-50%, -50%);
  border-radius: 999px;
  padding: 6px 13px;
  font-size: 12px;
  font-weight: 900;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #ffffff;
  box-shadow:
    0 6px 18px rgba(0, 0, 0, 0.55),
    inset 0 1px 0 rgba(255, 255, 255, 0.22);
  animation: seat-action 1100ms cubic-bezier(0.22, 0.8, 0.24, 1) both;
}

.seat-action.is-fold { background: var(--action-fold); }
.seat-action.is-passive { background: var(--action-passive); color: var(--text-on-accent); }
.seat-action.is-aggressive { background: var(--action-aggressive); }
.seat-action.is-allin { background: var(--action-allin); }

/* Comes in from the RIGHT as the name leaves to the left, and goes back out
   the same way it arrived. The scale bump on landing is what gives it weight;
   the blur only ever applies while it is off to the side. */
@keyframes seat-action {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) translateX(46px) scale(0.78);
    filter: blur(6px);
  }
  11% {
    opacity: 1;
    filter: blur(0);
  }
  17% {
    transform: translate(-50%, -50%) translateX(0) scale(1.12);
  }
  25% { transform: translate(-50%, -50%) translateX(0) scale(0.97); }
  32% { transform: translate(-50%, -50%) translateX(0) scale(1); }
  74% {
    opacity: 1;
    transform: translate(-50%, -50%) translateX(0) scale(1);
    filter: blur(0);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -50%) translateX(46px) scale(0.82);
    filter: blur(5px);
  }
}

/* One light sweep across the chip right after it lands, left to right, clipped
   by the chip's own overflow.

   It is a narrow band that MOVES rather than an oversized gradient whose
   background-position is animated. The two look the same; the difference is
   that a background-position has to be re-painted every frame, and the chip is
   itself flying across the avatar at the time — a repaint inside it forces the
   whole chip to be re-rastered mid-flight instead of just being moved by the
   compositor, and that is paid for in dropped frames on the animation the eye
   is actually following. A transform costs nothing. */
.seat-action::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 55%;
  background: linear-gradient(
    105deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.5) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  animation: seat-action-sheen 1100ms ease-out both;
}

@keyframes seat-action-sheen {
  0%, 16% { transform: translateX(-110%); }
  56%, 100% { transform: translateX(300%); }
}


/* ── the number the other seat drew ───────────────────────────────────────
   The seat that is not the user's does not choose its move, it DRAWS one from
   the solution's own mix. This is the number that came up, shown for a moment
   over the avatar so the draw can be checked against the strategy behind it
   (owner request 2026-08-21).

   To the LEFT of the avatar (owner request 2026-08-21). Above it the badge ran
   into the strip along the top of the page; out to the side it clears
   everything — the dealer button shares that column but sits at the avatar's
   top or bottom edge, while this is on its centre line.

   One list of keyframes, and the holds inside it are safe: a segment whose two
   ends are identical is a hold whatever curve is applied to it, so the
   per-segment easing trap the seat name documents cannot bite here. */
.seat-roll {
  position: absolute;
  /* Over everything a seat carries, including its own cards and the word
     riding across it. */
  z-index: 40;
  top: 50%;
  right: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  margin-right: 10px;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  background: var(--surface-panel);
  padding: 4px 9px;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  white-space: nowrap;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.5);
  animation: seat-roll-show 1000ms ease-out both;
}

/* The number that came up. */
.seat-roll b {
  font-size: 12px;
  font-weight: 900;
  color: var(--text-strong);
}

/* The band it fell in. Its WIDTH is the chosen action's own frequency, which is
   what makes the roll checkable against the panel without knowing the order the
   tree lays the actions out in — see MixDraw. */
.seat-roll i {
  font-size: 10px;
  font-style: normal;
  font-weight: 700;
  color: var(--text-muted);
}

/* Centred on the avatar and coming out of it: the badge starts a little to the
   right, under the disc, and slides clear. `translateY(-50%)` is the resting
   centring and has to be re-stated in every frame — a transform in an animation
   replaces the property outright rather than adding to it. */
@keyframes seat-roll-show {
  0% {
    opacity: 0;
    transform: translateY(-50%) translateX(10px) scale(0.9);
  }
  16%, 78% {
    opacity: 1;
    transform: translateY(-50%) translateX(0) scale(1);
  }
  100% {
    opacity: 0;
    transform: translateY(-50%) translateX(-4px) scale(0.97);
  }
}

.seat-dealer {
  position: absolute;
  z-index: 20;
  left: -22px;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: #f1f1f1;
  font-size: 11px;
  font-weight: 900;
  color: var(--text-on-accent);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.45);
}

/* Top seat: button sits at its BOTTOM-left corner (towards the felt). Both
   buttons keep being pulled further onto the table as the table grows: -4px sat
   on the old edge, -12px was still short of the new rail, and -20px is where
   they read as lying ON the table rather than beside a seat (owner requests
   2026-08-19 and 2026-08-20). Down for the seat above, up for the seat below —
   both towards the middle. The two numbers are NOT the same: the rail of the
   table image runs further under the villain than it does over the hero, so the
   top button goes 8px deeper than the bottom one (owner request 2026-08-20). */
.seat.is-top .seat-dealer {
  bottom: -28px;
}

/* Bottom seat: button sits at its TOP-left corner (towards the felt). */
.seat.is-bottom .seat-dealer {
  top: -20px;
}

/* Above the felt. The top seat is painted BEFORE the felt is, so without a
   z-index of its own the villain's hand ends up behind the green (owner report
   2026-08-17) — the hero's looked fine only because that seat comes after the
   felt in the markup. ANY positive number does that job: the felt is positioned
   with z-index auto, so it is painted under every positive layer here.
   12 keeps it over the avatar's own 10 — the avatar's ring glows outwards and
   would otherwise wash across the near card — and under .seat-action's 30,
   which is the one thing on a seat that must never be covered. */
.seat-cards {
  position: absolute;
  z-index: 12;
  top: 50%;
  left: 100%;
  transform: translateY(-50%);
  margin-left: 4px;
  display: flex;
}

.seat-card {
  /* Through the variables, NOT width/height: the rank and the watermark are
     calc()'d from --card-height, so setting the box directly left them sized
     for the 78px family default while the card was drawn at 58 — which is why
     the appearance panel had no effect out here (owner report 2026-08-17). */
  --card-width: 44px;
  --card-height: 58px;
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.5);
}

.seat-card + .seat-card {
  margin-left: -12px;
}

/* ── the muck ──────────────────────────────────────────────────────────────
   A folded hand slides a little way OUT, to the right, and is gone (owner
   request 2026-08-20). It used to be thrown into the middle of the table; that
   read as a second thing happening on the felt at the exact moment the chips
   were going the other way, so the hand now simply leaves the frame the seat
   owns and lets the money have the middle to itself.

   PracticeTable puts this class on as soon as the fold is ANNOUNCED — the money
   model turns it on inside the same paced step — so the cards leave on the word
   rather than a beat after it, and the pot is collected on that same step.

   Two animations rather than one keyframe list, for the reason .seat-name-slide
   documents further up: a CSS easing curve is applied to every SEGMENT of a
   list, so the fade's own hold would break the slide's velocity exactly where
   it sits. Split, the travel owns one curve and the fade owns another.

   `translateY(-50%)` has to be re-stated in the keyframes: it is the resting
   rule's own centring, and a transform in an animation replaces the property
   outright rather than adding to it. It measures the element's own height, not
   the scale's, so it goes on centring the box at every size.

   `both` is what keeps the hand gone. It stays folded until the next one is
   dealt, and the fill holds the last frame — opacity 0 — for as long as it
   does. */
.seat-cards.is-mucked {
  pointer-events: none;
  animation:
    muck-away 340ms cubic-bezier(0.35, 0, 0.6, 1) both,
    muck-fade 340ms ease-in both;
}

/* Out and slightly over, shrinking as it goes: a hand pushed away rather than
   a card sliding on a rail. 64px is not far on purpose — it has to be clear
   that the cards LEFT, not that they travelled anywhere. */
@keyframes muck-away {
  from {
    transform: translateY(-50%) translate(0, 0) scale(1) rotate(0deg);
  }
  to {
    transform: translateY(-50%) translate(64px, -6px) scale(0.82) rotate(8deg);
  }
}

/* Held at full strength for the first third, so the hand is READ leaving
   rather than dissolving on the spot. */
@keyframes muck-fade {
  0% {
    opacity: 1;
  }
  35% {
    opacity: 0.92;
  }
  100% {
    opacity: 0;
  }
}

/* ── chips in front of a seat ─────────────────────────────────────────────
   What a player has out on the CURRENT street: a pile between the seat and
   the felt with the amount beside it. It appears the moment the action is
   announced and is gone the moment the street is swept — no flight, no fade
   (owner request 2026-08-16). Chips that slide and blink read as a glitch;
   money is either on the table or it is not.

   OFF-CENTRE, and that is load-bearing. The felt keeps only 60px of padding
   (owner values 2026-08-17), so a pile hanging off a seat reaches 83px in
   while the pot line starts at 63px: dead centre, everything above a single
   chip would sit on top of it. 100px sideways clears the widest pot pill with
   room to spare, and bets flanking the middle is how a real client draws them
   anyway. Villain to the right, hero to the left, so the two never share a
   column either. */
.seat-bet {
  position: absolute;
  z-index: 15;
  display: flex;
  align-items: flex-end;
  gap: 6px;
  transform: translateX(-50%);
}

/* Chips ride OUT of the seat towards the middle as they are put in: the top
   seat's travel DOWN, the bottom seat's travel UP (owner request 2026-08-19).
   Each ends a few pixels past its resting place and settles back, the way a
   stack pushed across felt does — a pile that simply stops dead reads as a
   sprite being switched on.

   Only `opacity` and `transform`, so the whole thing is the compositor's work
   and the pile's drop-shadow is never re-rasterised. The `translateX(-50%)`
   that centres the pile is part of every frame, or it would be dropped for the
   length of the animation and the chips would jump sideways.

   It plays on MOUNT, and PracticeTable keys .seat-bet by the amount, so it
   plays again for every raise on the same street rather than only for the
   first chips out. Between streets the bet is 0, the element goes, and the
   next street's first chips ride out afresh. */
.seat.is-top .seat-bet {
  top: 100%;
  left: calc(50% + 100px);
  margin-top: 8px;
  animation: seat-bet-down 320ms cubic-bezier(0.22, 0.8, 0.24, 1) both;
}

.seat.is-bottom .seat-bet {
  bottom: 100%;
  left: calc(50% - 100px);
  margin-bottom: 8px;
  animation: seat-bet-up 320ms cubic-bezier(0.22, 0.8, 0.24, 1) both;
}

@keyframes seat-bet-down {
  0% {
    opacity: 0;
    transform: translateX(-50%) translateY(-22px) scale(0.8);
  }
  70% {
    opacity: 1;
    transform: translateX(-50%) translateY(3px) scale(1.04);
  }
  100% {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
  }
}

@keyframes seat-bet-up {
  0% {
    opacity: 0;
    transform: translateX(-50%) translateY(22px) scale(0.8);
  }
  70% {
    opacity: 1;
    transform: translateX(-50%) translateY(-3px) scale(1.04);
  }
  100% {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
  }
}

/* The street is over and the chips go in: each pile crosses the felt to the
   middle, where the pot's own pile is about to land (owner request
   2026-08-19). The money model zeroed these the instant the street ended — the
   piles are still on screen only because useTableReplay holds them for the
   length of this flight; see Sweep there.

   TWO animations, not one list. Travel is a single segment so the curve is
   applied once and the chips accelerate away and settle without a kink; the
   fade is its own list because it has to hold full strength for most of the
   trip and only go at the end. Put in one list, the easing would be applied to
   each SEGMENT and the 70% frame would break the travel's velocity in half —
   the same trap the seat name fell into (see .seat-name-slide).

   The offsets are the real distance from each pile to the middle in the
   current layout: 100px across, and down or up to the pot pile, which is not
   in the felt's own middle. They do not have to be exact — the chips are
   already fading as they arrive, so a few pixels either way is invisible. */
.seat.is-top .seat-bet.is-sweeping,
.seat.is-bottom .seat-bet.is-sweeping {
  pointer-events: none;
}

.seat.is-top .seat-bet.is-sweeping {
  animation:
    seat-bet-sweep-down 460ms cubic-bezier(0.5, 0, 0.3, 1) both,
    seat-bet-gone 460ms ease-in both;
}

.seat.is-bottom .seat-bet.is-sweeping {
  animation:
    seat-bet-sweep-up 460ms cubic-bezier(0.5, 0, 0.3, 1) both,
    seat-bet-gone 460ms ease-in both;
}

@keyframes seat-bet-sweep-down {
  from {
    transform: translateX(-50%) translate(0, 0) scale(1);
  }
  to {
    transform: translateX(-50%) translate(-100px, 134px) scale(0.7);
  }
}

@keyframes seat-bet-sweep-up {
  from {
    transform: translateX(-50%) translate(0, 0) scale(1);
  }
  to {
    transform: translateX(-50%) translate(100px, -82px) scale(0.7);
  }
}

@keyframes seat-bet-gone {
  0%, 70% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

.seat-bet-chips {
  width: 26px;
  height: auto;
  filter: drop-shadow(0 3px 5px rgba(0, 0, 0, 0.55));
}

.seat-bet-amount {
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.62);
  padding: 2px 7px;
  font-size: 12px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1.3;
  color: #f2f2f2;
}

/* ── action buttons ───────────────────────────────────────────────────── */
.action-bar {
  display: flex;
  width: 100%;
  max-width: 720px;
  /* Tall enough for the verdict panel that replaces the buttons at the end of
     a hand, so the bottom of the page does not grow the moment one finishes.
     Must match the height on .hand-verdict. */
  min-height: 72px;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.action-button {
  /* A row of its own, centred. A button leaves the browser to place its
     contents, and that placement stops being centring the moment the contents
     are more than one run of text — the refresh mark on Repeat hand sat in the
     top-left corner of it (owner report 2026-08-21). Stated here, every button
     carries its mark, its word and its key on one centred line. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  flex: 1;
  height: 50px;
  border: none;
  border-radius: 6px;
  font-size: 16px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
  transition: background-color 120ms ease;
}

/* The move is already sent and is being graded. Dim rather than gone: the
   buttons must not move out from under a finger that is still on its way down
   (owner report 2026-08-17). */
.action-button:disabled {
  cursor: default;
  opacity: 0.45;
}

.action-button.is-fold { background: var(--action-fold); }
.action-button.is-fold:hover { background: var(--action-fold-hover); }
.action-button.is-passive { background: var(--action-passive); }
.action-button.is-passive:hover { background: var(--action-passive-hover); }
.action-button.is-aggressive { background: var(--action-aggressive); }
.action-button.is-aggressive:hover { background: var(--action-aggressive-hover); }
.action-button.is-allin { background: var(--action-allin); }
.action-button.is-allin:hover { background: var(--action-allin-hover); }

/* "Next hand" and "Continue" stand in the same bar as fold/call/raise, because
   that is the one place the hand is played from (owner request 2026-08-16).
   They do NOT stretch across it: a single button 720px wide reads as a banner,
   not as something to click. Inside the verdict row the button shares the space
   with the score, so it gives up the fixed width there. */
.action-button.is-next,
.action-button.is-continue {
  display: flex;
  flex: 0 0 280px;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--text-on-accent);
}

/* The orange one is written in white, not in the near-black the green buttons
   use — see --text-on-brand. */
.action-button.is-next {
  background: var(--accent-brand-deep);
  color: var(--text-on-brand);
}

/* Hovers up to the brand orange itself rather than to --accent-brand-hover:
   from this deeper resting colour that IS the step lighter. */
.action-button.is-next:hover { background: var(--accent-brand); }
.action-button.is-continue { background: var(--grade-good); }
.action-button.is-continue:hover { background: var(--action-passive-hover); }

/* ── the verdict on a finished hand ───────────────────────────────────────
   Takes over the action bar when there is nothing left to decide: the score,
   the streets it was earned on, and the way out — one row, one place to look
   (owner request 2026-08-16), redrawn from the owner's mockup 2026-08-17.

   --verdict is the hand's own colour, set on this row by the component from the
   worst grade in it, and it runs through the ring, the headline and the rail.
   Every street keeps its OWN colour on its dot, so a clean flop stays green
   inside a hand named after a preflop blunder.

   The height is fixed and .action-bar carries the same number as its
   min-height: this panel replaces the action buttons the instant a hand ends,
   and a bar that resized at that moment would jump the table above it. */
/* ── the verdict on a finished hand ───────────────────────────────────────
   A card in three bands rather than a single row (owner request 2026-08-21,
   from a mockup): what the hand was worth, how far it got, and the two things
   worth doing next.

   --verdict is the hand's own colour and is set inline; the rgb twin beside it
   is the same colour as raw channels, which is the only way a custom property
   can be taken at an opacity. Both are declared here as well, so a hand that
   was never scored still has something to resolve against — see .is-idle,
   which puts the neutral edge back. */
.hand-verdict {
  display: flex;
  width: 100%;
  /* Narrower than the row of action buttons it replaces: the card carries three
     short readings and two buttons, and at the bar's full width they drifted
     apart (owner request 2026-08-21). */
  max-width: 600px;
  flex-direction: column;
  margin-top: 10px;
  border-radius: 12px;
  padding: 6px 14px 11px 14px;
}

/* ── band one: what the hand was worth ─────────────────────────────────── */
.hand-verdict-top {
  display: flex;
  align-items: center;
  gap: 14px;
}

/* The share of this hand's decisions that cost nothing — the same measure the
   session score uses — drawn as how far round the circle it got. */
.hand-score {
  position: relative;
  display: grid;
  flex-shrink: 0;
  place-items: center;
  width: 42px;
  height: 42px;
}

.hand-score-ring {
  position: absolute;
  inset: 0;
  width: 38px;
  height: 38px;
  /* A dash starts at three o'clock; the score is read from twelve. */
  transform: rotate(-90deg);
}

.hand-score-track {
  fill: none;
  stroke: rgba(255, 255, 255, 0.09);
  stroke-width: 4;
}

.hand-score-arc {
  fill: none;
  stroke: var(--verdict);
  stroke-width: 4;
  stroke-linecap: round;
}

/* Deliberately NOT the verdict colour: the ring already carries that, and a
   number in the same amber as the ring around it stops being legible. */
.hand-score-value {
  position: relative;
  font-size: 12px;
  font-weight: 900;
  /* Back onto the middle of the ring: the ring is smaller than the box it sits
     in and is pinned to its top-left corner, so the number follows it. */
  top: -2px;
  left: -2px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
}

/* One thing the hand is being reported on: a quiet heading and the number or
   phrase under it. Three of them share the row, spread left, middle and right,
   so each has a place of its own to be read from. */
.hand-fact {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 0;
}

.hand-fact.is-mid { text-align: center; }
.hand-fact.is-end { text-align: right; }

.hand-fact-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.hand-fact-value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  font-weight: 800;
  color: var(--text-strong);
}

.hand-fact-value.is-verdict {
  color: var(--verdict);
}

.hand-outcome-amount {
  font-variant-numeric: tabular-nums;
}

.hand-outcome-amount.is-win { color: var(--grade-good); }
.hand-outcome-amount.is-loss { color: var(--grade-bad); }
.hand-outcome-amount.is-flat { color: var(--text-soft); }

.hand-verdict-idle {
  flex: 1;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-soft);
}

/* ── band two: how far the hand got ────────────────────────────────────── */
.hand-streets {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  margin-top: 4px;
  padding: 9px 0;
}

/* A button, not a label: a street the hero was asked something on is the way
   back into the hand at that point (owner request 2026-08-21). One he was never
   asked on is drawn exactly the same and simply does not answer. */
.hand-street {
  --verdict: transparent;
  --verdict-rgb: 255, 255, 255;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 8px;
  padding: 6px 8px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.3);
}

/* The hero was asked something here, and this is what came of it. */
.hand-street.is-graded {
  border-color: rgba(var(--verdict-rgb), 0.42);
  background: rgba(var(--verdict-rgb), 0.1);
  color: var(--verdict);
}

/* The hand travelled through, but nothing was asked of the hero. */
.hand-street.is-reached {
  border-color: rgba(255, 255, 255, 0.13);
  color: var(--text-soft);
}

.hand-street:not(:disabled):hover {
  border-color: rgba(var(--verdict-rgb), 0.6);
  background: rgba(var(--verdict-rgb), 0.16);
}

.hand-street:disabled {
  cursor: default;
}

.hand-street-mark {
  display: grid;
  flex-shrink: 0;
  place-items: center;
  width: 16px;
  height: 16px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  color: rgba(255, 255, 255, 0.35);
}

.hand-street.is-reached .hand-street-mark {
  background: rgba(255, 255, 255, 0.12);
  color: var(--text-soft);
}

/* Filled, with the tick punched out of it: the one street the eye should find
   first is the one that went wrong. */
.hand-street.is-graded .hand-street-mark {
  background: var(--verdict);
  color: #1b1b1b;
}

/* ── band three: what to do next ───────────────────────────────────────── */
.hand-verdict-actions {
  display: flex;
  gap: 10px;
}

.hand-verdict-actions .action-button {
  height: 40px;
  border-radius: 8px;
  font-size: 13px;
}

/* The quieter of the two: an outline, because playing the hand again is a
   second thought and moving on is the default. */
.action-button.is-repeat {
  flex: 1;
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--text-strong);
}

.action-button.is-repeat:hover {
  background: var(--surface-hover);
}

.hand-verdict .action-button.is-next {
  flex: 1.4;
  /* The glow is the button's own orange, so it follows --accent-brand-deep. */
  box-shadow: 0 6px 16px rgba(252, 142, 41, 0.16);
}

/* The key that does the same thing, written on the button that does it. Set a
   little further off than the play mark is from the words: it is a note about
   the button, not part of its name. */
.action-key {
  margin-left: 5px;
  border: 1px solid rgba(255, 255, 255, 0.38);
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.2);
  padding: 3px 7px;
  font-family: inherit;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: none;
  /* Cut back from the label's white so the key reads as a note ON the button
     rather than as a second word of it. */
  color: rgba(255, 255, 255, 0.88);
}

/* A hand that never reached the hero — the SB folded on the button — has
   nothing to score, and an empty row would look like something failed. */
.hand-verdict-idle {
  flex: 1;
  font-size: 13px;
  color: var(--text-muted);
}

/* ── move review: a past decision, opened from the strip ──────────────────
   NOT a panel. The pieces stand free in the action bar exactly the way the
   game's own buttons do (owner request 2026-08-17): the actions that were on
   offer, the range bar under them, and the two ways out under that. Boxed into
   one card, a moment that has already been played read as a dialog rather than
   as the table. */
.action-bar.is-review {
  /* As wide as the felt above it (.table-stack), not as wide as the row of
     action buttons it replaces: this block carries four rows and the arrows
     that flank them, and at 720px the tiles were narrower than the moves they
     stand for (owner request 2026-08-17, trimmed to 880 on 2026-08-21). */
  max-width: 880px;
  align-items: center;
  gap: 12px;
  /* The system sans, not the app's Inter (owner request 2026-08-17): on macOS
     that is SF Pro, and -apple-system has to come FIRST or an installed Inter
     wins the stack in src/index.css. Set on the block so the tiles, the two
     buttons and the line between them are all in one face. */
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
}

/* The finished hand takes the SAME bar as the review panel: same width, same
   gap, arrows pushed to the same two edges. The pair of them is one place on
   the page, and an arrow that moved when the hand ended read as a different
   control (owner request 2026-08-21).

   `space-between` rather than the bar's own centring, because the card between
   them is capped at 600px and centring would gather all three in the middle
   instead of leaving the arrows where the panel's are. */
.action-bar.is-verdict {
  max-width: 880px;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* The two edges never move. Pinned a fixed way down from the top of the bar
   rather than centred in it: the bar is as tall as whatever it is holding, and
   the review panel and the verdict card are not the same height, so centred
   arrows shifted the moment one gave way to the other (owner report
   2026-08-21). One number, the same in both states, and they stay put whatever
   is between them. */
.action-bar.is-review .review-arrow,
.action-bar.is-verdict .review-arrow {
  align-self: flex-start;
  margin-top: 48px;
}

/* And the panel itself starts where the verdict card starts — .hand-verdict
   carries the same 10px — so the block between the arrows does not jump
   either. */
.action-bar.is-review .review-stack {
  margin-top: 10px;
}

/* Holds the pieces between the two arrows. NO background and NO border of its
   own — it is a layout column, not a card, so everything in it still stands
   free the way the game's own buttons do. */
.review-stack {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 10px;
}

/* One step back and one step forward through the hand's decisions, without
   going up to the carousel to click the next one (owner request 2026-08-17).
   Half the height of the panel beside them, so they read as a pair of edges
   rather than as two more buttons. */
.review-arrow {
  display: grid;
  width: 40px;
  height: 82px;
  flex-shrink: 0;
  place-items: center;
  border: none;
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
  color: var(--text-soft);
  transition: background-color 120ms ease, color 120ms ease;
}

.review-arrow:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

/* At the first or the last decision. Dimmed by COLOUR rather than by opacity
   (owner request 2026-08-17): a ghosted arrow read as a rendering fault, while
   a grey one reads as a road that ends. Still drawn, so the panel between them
   does not change width as you step through the hand. */
.review-arrow:disabled {
  cursor: default;
  color: var(--line-strong);
}

.review-arrow:disabled:hover {
  background: transparent;
}

.move-options {
  display: flex;
  gap: 8px;
}

/* One tile per action the seat had at that node, built like the buttons the
   game is played with — same height, same corners, same weight — because that
   is what they were. The percentage sits on the RIGHT inside the tile (owner
   request 2026-08-17), so a row reads name-then-number the way a strategy line
   does. */
.move-option {
  display: flex;
  height: 50px;
  min-width: 0;
  flex: 1;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  /* Outlined, never filled (owner request 2026-08-17): a filled tile reads as
     a button to press, and these are moves that were on offer at a moment
     already gone. The same 1px edge Change move wears, so the whole panel is
     one language. The colour of the action is carried by the text instead —
     see the inline `color` in MoveReview. */
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: #202020;
  padding: 0 14px;
  font-size: 14px;
  font-weight: 900;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  /* The words and the numbers are WHITE (owner request 2026-08-17); the tile's
     own `color` is the grade, and it is spent on the frame and the mark rather
     than on the text, which has to stay readable at any verdict. */
  color: var(--text-strong);
}

/* The verdict mark on a move tile — see GradeMark, which draws it with the
   shared GradeIcon. */
.move-option-mark {
  width: 17px;
  height: 17px;
}

/* The move actually made, framed in ITS OWN colour — red for a bet or a raise,
   green for a check or a call, blue for a fold, maroon for a jam — so the frame
   says WHAT was done as well as that something was (owner request 2026-08-17).
   currentColor is the action colour set on the tile.
   The padding gives back exactly the 3px the thicker border takes, the same
   trick .strip-step uses, so the tile does not change size when it is the one
   that was chosen. */
.move-option.is-taken {
  border-width: 3px;
  border-color: currentColor;
  /* Gives back exactly the 2px the thicker border takes, the same trick
     .strip-step uses, so the tile does not change size when it is the one that
     was chosen. */
  padding: 0 12px;
}

/* WHITE, explicitly. The tile's own `color` is the grade — it has to be, so
   that the frame and the mark can take it off currentColor — and everything
   inside a tile inherits it unless it says otherwise, which came out as red
   words on a red-framed tile (owner report 2026-08-17). */
.move-option-name {
  overflow: hidden;
  flex: 1;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-strong);
}

/* The percentage, and under it what the action is worth to the hand that was
   holding it. */
.move-option-figures {
  display: flex;
  flex-shrink: 0;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}

.move-option-share {
  font-size: 14px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
}

.move-option-ev {
  font-size: 10px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

/* The bar written out: one action per word, in the bar's own colours, centred
   under the tiles and above the bar it names. */
.move-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.03em;
  /* Sentence case, not caps (owner request 2026-08-17): the tiles above are
     shouting already, and this line is a caption for the bar under it. The
     capital comes from the component, so "All-in" keeps its lower-case half. */
  text-transform: none;
}

/* Says whose numbers these are. The tiles above carry the hand's own mix and
   this line carries the whole range's, and without a word between them a 44%
   under a 0% reads as a contradiction (owner report 2026-08-17). */
.move-legend-title {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.move-legend-item i {
  font-style: normal;
  font-variant-numeric: tabular-nums;
  opacity: 0.75;
}

.move-review-foot {
  display: flex;
  gap: 8px;
}

.review-button {
  display: flex;
  height: 42px;
  flex: 1;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: var(--surface-rail);
  font-size: 14px;
  font-weight: 900;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  cursor: pointer;
  color: var(--text-normal);
  transition: background-color 120ms ease;
}

.review-button:hover {
  background: var(--surface-hover);
}

.review-button.is-primary {
  border-color: transparent;
  background: var(--accent-brand-deep);
  color: var(--text-on-brand);
}

.review-button.is-primary:hover {
  background: var(--accent-brand);
}

.review-button:disabled {
  cursor: default;
  opacity: 0.45;
}

/* ── hand history, to the right of the felt ───────────────────────────── */
/* ── the info panel ───────────────────────────────────────────────────────
   The solution behind the node the table is standing on, in the right-hand
   rail above the feed (owner request 2026-08-21).

   The matrix is the STUDY's — one component for one thing — so only its size is
   set here: 716px of grid has to become the width of a rail without the cells
   losing their shape or their labels. Scoped to this panel, so nothing about
   the study's own matrix moves. */
.practice-info {
  width: 100%;
  flex-shrink: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
}

.info-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px;
}

.info-tabs {
  margin-top: 0;
}

/* Square, and as wide as it is given. The study's fixed 716x636 would keep its
   HEIGHT in a 278px column and hand every cell a 1:2 shape. */
.practice-info .matrix,
.practice-info .matrix-placeholder {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  border-radius: 5px;
}

.practice-info .matrix-cell {
  min-height: 0;
  padding: 0;
}

.practice-info .matrix-cell-label {
  font-size: 7px;
  font-weight: 800;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.9);
}

.practice-info .matrix-cell-label.is-compact {
  top: 1px;
  left: 2px;
  font-size: 7px;
}

/* No room for a second number in a cell this size; the panel's own list below
   carries the figures. */
.practice-info .matrix-cell-metric {
  display: none;
}

.info-freqs {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.info-freqs-title {
  margin-bottom: 2px;
  font-size: 12px;
  font-weight: 800;
  color: var(--text-muted);
}

/* Name on the left, share on the right, both in the action's own colour — the
   same colour the bar under them is drawn in. */
.info-freq {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: 13px;
  font-weight: 800;
}

.info-freq-name {
  /* One word and a number — see actionText — so this only ever raises the
     word, the same way the strip does it. */
  text-transform: capitalize;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.info-freq-value {
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

/* ── the history panel ────────────────────────────────────────────────────
   The session's record, in the right-hand rail. Rows go edge to edge and are
   separated by a line rather than by space: this is a list of many similar
   things, and gaps between them would cost the column half its rows. */
/* A COLUMN that is allowed to run out of room, with the rows as the part that
   gives: the head and the session line stay put and the list scrolls under
   them.

   It used to be one block in a scrolling rail, and it never scrolled at all
   (owner report 2026-08-20). `overflow: hidden` — which is here to keep the
   rows inside the rounded corner — also lets a flex item be squeezed below its
   own content, so with enough hands the panel was simply crushed to the height
   of the rail and the rest of the list clipped away, with no scrollbar
   anywhere. `max-height` rather than `flex: 1`, so a panel that has been
   collapsed stays the height of its own head instead of standing empty down
   the whole rail. */
.history {
  display: flex;
  width: 100%;
  /* Takes what the panel above it leaves, and gives the rest back by scrolling
     its own list — see .history-list. `0 1 auto` and not `1 1 auto`, so a
     collapsed feed stays the height of its own head instead of standing empty
     down the rail. */
  min-height: 0;
  flex: 0 1 auto;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
}

.history-head {
  display: flex;
  width: 100%;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
  border: none;
  border-bottom: 1px solid var(--line);
  background: transparent;
  padding: 11px 12px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-strong);
  cursor: pointer;
}

.history-head-icon {
  color: var(--text-muted);
}

.history-title {
  flex: 1;
  text-align: left;
}

/* The session the rows below belong to, headed by what it is worth so far. */
.history-session {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-sunken);
  padding: 8px 12px;
}

.history-session-score {
  font-size: 13px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
}

.history-session-score.is-good { color: var(--grade-good); }
.history-session-score.is-warn { color: var(--grade-warn); }
.history-session-score.is-bad { color: var(--grade-bad); }
.history-session-score.is-idle { color: var(--text-muted); }

.history-session-name {
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-soft);
}

.history-list {
  min-height: 0;
  overflow-y: auto;
  margin: 0;
  padding: 0;
  list-style: none;
}

.history-row + .history-row {
  border-top: 1px solid var(--line);
}

/* A finished hand UNROLLS at the top of the list (owner request 2026-08-20).
   It plays on MOUNT, and the rows are keyed by the hand's own id — see
   HandResult — so only the new one moves; keyed by position every row below it
   would be a new element and the whole column would come down at once.

   Growing the row's own height rather than sliding a finished row into place:
   a row that arrives at full height has to displace the ones under it in the
   same frame, which is the blink. Unrolled, the rows below are carried down by
   the layout itself, at exactly the rate the new row appears (owner report
   2026-08-20).

   `grid-template-rows` from 0fr to 1fr is what makes an unknown height
   animatable at all — a row is one line or twenty depending on whether it is
   open — and it only works on a CHILD, which is why there is a wrapper. The
   child needs `min-height: 0` or it refuses to be squeezed below its content,
   and `overflow: hidden` or the content spills out of the closed row. */
.history-row {
  display: grid;
  grid-template-rows: 1fr;
  animation: history-row-in 320ms cubic-bezier(0.22, 0.8, 0.24, 1) both;
}

.history-row-inner {
  min-height: 0;
  overflow: hidden;
  animation: history-row-fade 320ms ease-out both;
}

@keyframes history-row-in {
  from {
    grid-template-rows: 0fr;
  }
  to {
    grid-template-rows: 1fr;
  }
}

/* The height carries the movement, so this only has to bring the row out of
   nothing — a transform here would be clipped by the wrapper it lives in. */
@keyframes history-row-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.history-row-head {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 7px 10px;
}

/* A hand the hero was never asked anything in has no verdict, and the row still
   has to line up with the ones that do. */
.history-nomark {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}

.history-cards {
  display: flex;
  min-width: 0;
  flex: 1;
  align-items: center;
  gap: 2px;
}

/* Set off from the hand, so two cards and five read as two things. */
.history-board {
  display: flex;
  gap: 2px;
  margin-left: 7px;
}

.history-card {
  --card-width: 19px;
  --card-height: 25px;
  --card-radius: 2px;
}

.history-tools {
  display: flex;
  flex-shrink: 0;
  gap: 1px;
}

.history-tool {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 5px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 120ms ease, background-color 120ms ease;
}

.history-tool:hover {
  background: var(--surface-hover);
  color: var(--accent-brand);
}

.history-tool:disabled {
  cursor: default;
  opacity: 0.35;
}

/* Kept: the star fills in rather than only changing colour, so a marked hand
   can be picked out of a column of them at a glance. */
.history-tool.is-on {
  color: var(--accent-brand);
}

.history-tool.is-on svg {
  fill: currentColor;
}

.history-tool-chevron {
  transition: transform 180ms cubic-bezier(0.22, 0.8, 0.24, 1);
}

.history-row.is-open .history-tool-chevron {
  transform: rotate(180deg);
}

.history-body {
  padding: 0 8px 8px;
  font-size: 12px;
  color: var(--text-soft);
}

/* ── a hand, read back ────────────────────────────────────────────────────
   Street by street, in blocks: what the street put down and what the pot stood
   at, then who did what — with the hero's own moves priced (owner request
   2026-08-20). Everything here comes off the copy the trainer kept when the
   hand ended; see HandResult.steps. */
.hand-read {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.hand-read-card {
  border-radius: 8px;
  background: var(--surface-sunken);
  padding: 9px 10px;
}

.hand-read-title {
  font-size: 14px;
  font-weight: 800;
  color: var(--text-strong);
}

/* The street names come off the tree in lower case; they are headings here. */
.hand-read-street .hand-read-title {
  text-transform: uppercase;
}

.hand-read-sub {
  margin-top: 1px;
  font-size: 12px;
  color: var(--text-muted);
}

/* Who sat where and on what, in the seats' own colours — the same green and
   amber the felt lights them with. */
.hand-read-seats {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 8px;
  font-size: 13px;
  font-weight: 700;
}

.hand-read-seat {
  display: grid;
  grid-template-columns: 46px 1fr;
  gap: 8px;
}

.hand-read-seat.is-hero { color: var(--grade-good); }
.hand-read-seat.is-villain { color: var(--grade-warn); }

.hand-read-street {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.hand-read-cards {
  display: flex;
  flex-shrink: 0;
  gap: 3px;
}

.hand-read-face {
  --card-width: 23px;
  --card-height: 34px;
  --card-radius: 2px;
}

.hand-read-rows {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-top: 8px;
}

/* Seat, what was done, how often the solution does it, what it cost. The two
   numbers sit at the right edge in their own columns, so a column of moves can
   be read down rather than across. */
.hand-read-row {
  display: grid;
  grid-template-columns: 46px 1fr auto auto;
  align-items: baseline;
  gap: 8px;
  font-size: 13px;
  font-weight: 700;
}

.hand-read-seat-name {
  color: var(--text-muted);
}

.hand-read-action {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-strong);
}

.hand-read-freq,
.hand-read-ev {
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--text-soft);
}

.hand-read-ev {
  min-width: 56px;
}

/* The unit, small and beside the number rather than under it. */
.hand-read-unit {
  font-size: 10px;
  font-style: normal;
  font-weight: 700;
  color: var(--text-muted);
}

.hand-read-show {
  display: grid;
  grid-template-columns: 46px 1fr;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 700;
}

.history-outcome {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 5px;
}

.history-note {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-dim);
}

.history-amount {
  flex-shrink: 0;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.history-amount.is-win { color: var(--grade-good); }
.history-amount.is-loss { color: var(--grade-bad); }
.history-amount.is-flat { color: #b8b8b8; }

.history-empty {
  padding: 14px 12px;
  font-size: 12px;
  color: var(--text-muted);
}


/* ── restored, not dealt ──────────────────────────────────────────────────
   Everything that was already on the table when the page opened. Coming back
   from the study restores a hand the trainer saved rather than starting one, so
   the board, the strip and the chips must simply BE there: dealing them again
   on every tab change read as the hand being played from the top, sound and all
   (owner report 2026-08-20).

   `animation-duration: 0ms`, never `animation: none`. Two reasons. Every one of
   these animations carries `both` or `backwards`, so a zero-length run lands on
   its end frame in the first painted frame — exactly "already there". And the
   mark can be taken off again without the animation springing to life: only a
   change of `animation-name` creates a new animation, while a change of
   duration merely re-measures one that has long since finished. With
   `animation: none` the same removal would start every entrance on the felt at
   once.

   Which elements carry the mark is decided in JS, by identity rather than by a
   flag that flips: see `restored` in PracticeTable, useRestoredTiles in
   PracticePage and DealOrder.instant in useDealDelays. */
.strip-step.is-instant {
  animation-duration: 0ms;
}

/* The delay too: a board card waits its turn in the batch, and `backwards`
   holds it off screen for as long as it waits. */
.board-card.is-instant {
  --dur: 0ms;
  animation-delay: 0ms;
}

.pot-chips-image.is-instant,
.pot-chips-amount.is-instant {
  animation-duration: 0ms;
  animation-delay: 0ms;
}

.seat.is-top .seat-bet.is-instant,
.seat.is-bottom .seat-bet.is-instant {
  animation-duration: 0ms;
}

/* A hand folded before the user arrived is simply not there. Without this the
   villain threw his cards away again on every trip back from the study (owner
   report 2026-08-20) — the muck plays on the class arriving, and on a restored
   table it arrives at mount. */
.seat-cards.is-mucked.is-instant {
  animation-duration: 0ms;
}

/* Hands the feed was restored with were played before the user arrived. */
.history-row.is-instant,
.history-row.is-instant .history-row-inner {
  animation-duration: 0ms;
}


/* ── animations off ───────────────────────────────────────────────────────
   The whole page, held still (owner request 2026-08-20). Chips flying and
   cards dealing are the point of the felt for most people and noise for some,
   so it is a preference — see prefs.ts.

   Durations of zero rather than `animation: none`, for the reason the restored
   table documents further up: changing a duration never re-creates an
   animation, so turning motion back on cannot fire every entrance on the page
   at once. Everything with a fill lands on the frame it would have ended on,
   which is exactly "already there".

   This is the DRAWING, not the pace: the hand still plays out step by step,
   because that is the hand being dealt rather than an effect on it. */
.practice-page.is-still *,
.practice-page.is-still *::before,
.practice-page.is-still *::after {
  animation-duration: 0ms !important;
  animation-delay: 0ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0ms !important;
  transition-delay: 0ms !important;
}
/* ============================================================================
   Practice trainer — left rail: brand, nav, table info, pause mode, stats.
   ============================================================================ */

/* Two of these: the settings on the left, the session's own feed on the right,
   the felt between them (owner request 2026-08-20). Same width and same
   surface, so the page reads as a table with a rail on either side rather than
   as a sidebar and an afterthought. */
.rail {
  /* Above the middle of the page, so a hover panel that reaches past the card
     it belongs to is not painted over by the felt (owner report 2026-08-20).
     .practice-main comes after this in the markup and would otherwise win on
     document order alone. */
  position: relative;
  z-index: 2;
  display: flex;
  height: 100vh;
  width: 310px;
  flex-shrink: 0;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto;
  border-right: 1px solid var(--line);
  padding: 16px;
}

/* The feed manages its own overflow — the head stays and the rows scroll — so
   the rail itself does not scroll behind it. */
.rail.is-right {
  border-right: none;
  border-left: 1px solid var(--line);
  overflow: hidden;
}

/* The wings and the word are separate images (owner request 2026-08-17), so
   these three numbers are the whole layout: how far apart they sit, and how
   big each one is. Both are sized by HEIGHT so they share a baseline no matter
   what the word's aspect ratio is. */
.rail-brand {
  display: flex;
  align-items: center;
  /* Centred over the nav below it, not left-aligned to the rail's padding
     (owner request 2026-08-17). */
  justify-content: center;
  gap: 6px;
  padding: 0 2px 4px;
}

/* The logo in the rail head (Study and Practice): the mark and the name each sized here; 34px tall in all, as the old logo, so nothing
   under it moves. */
.rail-brand-logo {
  height: 34px;
  gap: 8px;
}

.rail-brand-logo .brand-logo-mark {
  height: 30px;
}

.rail-brand-logo .brand-logo-word {
  height: 21px;
}




/* Practice | Study in one row (RailNav.tsx; owner 2026-10-15: Custom Solve sits beside Solutions in the config card). */
.rail-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  border-radius: 6px;
  background: var(--surface-panel);
  padding: 4px;
}

.rail-nav-button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: none;
  border-radius: 5px;
  background: transparent;
  padding: 8px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.rail-nav-button:hover {
  background: var(--surface-hover);
}

/* The brand colour, not just a lighter grey: on a rail of quiet buttons the
   chosen one has to be obvious at a glance, and the icon carries it too —
   lucide draws with `currentColor`, so it follows this line for free (owner
   request 2026-08-20). Every selected control in the rail is marked the same
   way; see .pause-option.is-active. */
.rail-nav-button.is-active {
  background: var(--surface-active);
  color: var(--accent-brand);
}

/* AI Custom Solve (owner 2026-10-14; since 2026-10-15 beside Solutions in the
   config card): no frame, no wash (owner: the violet background looked off) -
   marked by its violet icon and «AI» in a badge of its own so it cannot be read
   as «Al» (Inter draws a capital I like a lowercase l; cv08 gives it serifs
   where Inter is in use). */
.rail-ai-icon { color: var(--ai-accent); }
.rail-ai-badge {
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--ai-accent-strong);
  color: var(--text-on-brand);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1.5px;
  line-height: 15px;
  font-feature-settings: "cv08";
}

/* ── cards inside the rail ────────────────────────────────────────────── */
.rail-card {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 12px;
}

.rail-card-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 900;
  color: var(--text-normal);
}

.rail-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.rail-reset {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.rail-reset:hover {
  background: var(--surface-raised);
}

.rail-list {
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
}

.rail-list li {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-soft);
}

/* ── table controls ───────────────────────────────────────────────────────
   A row of plain icon buttons under what the table IS: they act on it rather
   than describe it, so they are quiet until the pointer finds them. */
/* The captions below are positioned against THIS, so they start at the row's
   left edge whichever button is under the pointer. Anchored to the buttons
   they ran off the end of the rail — which scrolls, and therefore clips — and
   the last one lost its tail (owner report 2026-08-20). */
.table-controls {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
}

.table-control-wrap {
  position: relative;
  display: flex;
}

.table-control {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 6px;
  /* A raw value: the rail's own surfaces are darker than this and none of them
     is the tone these buttons were asked for (owner request 2026-08-20). */
  background: #373737;
  color: var(--text-strong);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.table-control:hover {
  background: var(--surface-active);
  color: var(--accent-brand);
}

.table-control.is-off {
  color: var(--text-soft);
}

/* What the control does, under the pointer. Rises into place rather than
   appearing: a caption that snaps on reads as a glitch on a row where the
   pointer crosses four of them on its way anywhere.

   `white-space: nowrap` and the left anchor for the same reason .table-volume
   has them — the rail scrolls, so it clips on both axes, and a caption centred
   on a button this close to its edge would lose its left end. */
.table-hint {
  position: absolute;
  z-index: 5;
  top: 100%;
  /* Under the icon it belongs to, centred on it. The two ENDS of the row are
     the exception: the rail scrolls and therefore clips, so a caption centred
     on the first or last button would lose the half that hangs past the card
     (owner report 2026-08-20). They hang from their own edge instead, which is
     the only placement that cannot overflow. */
  left: 50%;
  visibility: hidden;
  /* the look is every hint's (ui.css, «hover hints», owner 2026-10-17) */
  margin-top: 6px;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, -4px) scale(0.96);
  transform-origin: 50% 0;
  transition:
    opacity 150ms ease,
    transform 190ms cubic-bezier(0.22, 0.8, 0.24, 1),
    visibility 190ms;
}

.table-control-wrap:hover .table-hint,
.table-control-wrap:focus-within .table-hint {
  visibility: visible;
  opacity: 1;
  transform: translate(-50%, 0) scale(1);
}

.table-controls > .table-control-wrap:first-child .table-hint {
  left: 0;
  transform: translate(0, -4px) scale(0.96);
  transform-origin: 0 0;
}

.table-controls > .table-control-wrap:last-child .table-hint {
  left: auto;
  right: 0;
  transform: translate(0, -4px) scale(0.96);
  transform-origin: 100% 0;
}

.table-controls > .table-control-wrap:first-child:hover .table-hint,
.table-controls > .table-control-wrap:first-child:focus-within .table-hint,
.table-controls > .table-control-wrap:last-child:hover .table-hint,
.table-controls > .table-control-wrap:last-child:focus-within .table-hint {
  transform: translate(0, 0) scale(1);
}

.table-sound {
  position: relative;
  display: flex;
}

/* Over the button, not beside it, and anchored by its LEFT edge rather than
   centred: the rail scrolls, which makes it a clipping box on both axes, and a
   panel centred on a button this close to the rail's edge would lose its left
   end to that clip. */
.table-volume {
  position: absolute;
  z-index: 5;
  bottom: 100%;
  left: -6px;
  display: flex;
  visibility: hidden;
  align-items: center;
  opacity: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 9px 11px;
  margin-bottom: 6px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.45);
  transform: translateY(4px);
  transition: opacity 140ms ease, transform 140ms ease, visibility 140ms;
}

.table-sound:hover .table-volume,
.table-sound:focus-within .table-volume {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
}

.table-volume input {
  width: 104px;
  height: 4px;
  -webkit-appearance: none;
  appearance: none;
  border-radius: 999px;
  background: var(--surface-active);
  cursor: pointer;
}

.table-volume input::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 13px;
  height: 13px;
  border-radius: 999px;
  background: var(--accent-brand);
}

.table-volume input::-moz-range-thumb {
  width: 13px;
  height: 13px;
  border: none;
  border-radius: 999px;
  background: var(--accent-brand);
}

/* ── pause mode switch ────────────────────────────────────────────────── */
.table-setting {
  margin-top: 14px;
}

.table-setting-title {
  /* Just off the card's edge, roughly over the start of the switch below
     (owner request 2026-08-20). */
  padding-left: 2px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-normal);
}

.pause-switch {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  border-radius: 6px;
  background: #373737;
  margin-top: 3px;
}

.pause-switch.is-four {
  grid-template-columns: repeat(4, 1fr);
}

.pause-option {
  border: none;
  border-radius: 5px;
  background: transparent;
  padding: 6px 4px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.pause-option:hover:not(:disabled) {
  background: var(--surface-hover);
}

/* Not yet wired to anything, so it does not behave as though it were: no
   pointer, no hover. The chosen one still reads as chosen. */
.pause-option:disabled {
  cursor: default;
}

.pause-option.is-active {
  background: var(--surface-active);
  color: var(--accent-brand);
}

/* ── stats ────────────────────────────────────────────────────────────── */
.metric-row {
  display: grid;
  gap: 8px;
  margin-top: 8px;
  text-align: center;
}

.metric-row.is-three { grid-template-columns: repeat(3, 1fr); }
.metric-row.is-two { grid-template-columns: repeat(2, 1fr); }

.metric {
  border-radius: 6px;
  background: var(--surface-panel);
  padding: 6px 8px;
}

.metric-value {
  font-size: 16px;
  font-weight: 900;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
}

.metric-label {
  margin-top: 4px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

/* The two bars above the five rows. Same column widths as .grade-row, which is
   what puts a bar's left edge exactly under the first letter of the verdict
   names below it. */
.grade-bars {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 0;
}

.grade-track {
  overflow: hidden;
  height: 12px;
  flex: 1;
  border-radius: 4px;
  background: var(--surface-active);
}

/* Animated on `width` rather than on a transform. A transform is the cheaper
   of the two and is what the felt uses everywhere — but scaling a rounded box
   horizontally pulls its corners into ellipses, and these ends are round. Two
   bars in a sidebar cost nothing to lay out. */
.grade-fill {
  display: block;
  height: 100%;
  border-radius: 4px;
  transition: width 200ms cubic-bezier(0.22, 0.8, 0.24, 1);
}

.grade-list {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* Not space-between: that pushed the name to the far right, where five words
   of different lengths each started at a different place. The mark and its
   count hold a column of their own, so every name begins on the same line down
   the row and the block reads as one left-aligned column (owner request
   2026-08-20). */
.grade-row {
  display: flex;
  align-items: center;
  gap: 21px;
  font-size: 15px;
}

/* The mark and the count, together on the left. Fixed width, so a count that
   grows to two or three digits over a long session cannot push its own row's
   name out of the column. 46px is the icon, the gap and room for three
   digits. */
.grade-mark {
  display: flex;
  width: 54px;
  flex-shrink: 0;
  align-items: center;
  gap: 14px;
}

/* Drawn in its own verdict colour — the component sets that; see GradeIcon.
   Everything else about how it looks is here: bigger and heavier than a
   sidebar icon usually is, because these five marks are the block (owner
   request 2026-08-20). `stroke-width` inherits down to the paths, so one line
   sets the weight of all of them. */
/* Scoped to the rail, and by ancestor rather than by load order: the base rule
   lives in practice.css and both files are loaded together, so a bare
   `.grade-icon` here would win only by being second in the bundle. */
.rail .grade-icon {
  width: 18px;
  height: 18px;
  stroke-width: 2.3;
}

.grade-count {
  min-width: 16px;
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-normal);
}

.grade-name {
  color: var(--text-strong);
}

.stats-divider {
  border-top: 1px solid var(--line);
  padding-top: 8px;
}

.stats-note {
  margin: 8px 0 0;
  font-size: 11px;
  line-height: 1.45;
  color: var(--text-muted);
}

/* «Your progress» under the stats (owner 2026-10-20): the trainer's history on the account, pages/practice/ProgressPage.tsx. A full-width
   row in the brand colour, the arrow nudging right on hover (transform only, frontend_rules 5b.3). */
.stats-progress {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin-top: 12px;
  border: 1px solid color-mix(in srgb, var(--accent-brand) 28%, transparent);
  border-radius: 7px;
  background: color-mix(in srgb, var(--accent-brand) 10%, transparent);
  padding: 9px 12px;
  font-size: 13px;
  font-weight: 700;
  color: var(--accent-brand);
  cursor: pointer;
}

.stats-progress span {
  flex: 1;
  text-align: left;
}

.stats-progress:hover {
  background: color-mix(in srgb, var(--accent-brand) 18%, transparent);
}

.stats-progress-arrow {
  transition: transform 180ms cubic-bezier(0.2, 0, 0, 1);
}

.stats-progress:hover .stats-progress-arrow {
  transform: translateX(3px);
}

/* ── last move feedback ───────────────────────────────────────────────── */
.last-move-grade {
  font-size: 13px;
  font-weight: 900;
}

.last-move-detail {
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-soft);
}

/* Identical fixed brand/navigation and independently scrolling content on both pages. */
.rail-brand, .rail-nav { flex-shrink: 0; }
.rail-content-scroll { display: flex; flex: 1; min-height: 0; flex-direction: column; gap: 8px; overflow-y: auto; }   /* owner 2026-10-16: 8, not 12 */
.rail-content-scroll > * { flex-shrink: 0; }
/* ============================================================================
   Shared primitives: card, badge, button, input, tabs, tooltip.
   These are the building blocks every page reuses.
   ============================================================================ */

/* The logo (components/BrandLogo.tsx, owner 2026-10-20): the mark and the name, two images side by side. Their heights and the gap are
   set where the logo stands (the rails, the landing page, sign-in), so each can be moved or sized on its own. */
.brand-logo {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
}

.brand-logo > img {
  display: block;
  width: auto;
}

.ui-card {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  color: var(--text-normal);
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.24);
}

.ui-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px;
}

.ui-card-title {
  display: flex;
  align-items: center;
  /* Tightened with the header bar (owner edit 2026-09-21): this is the shared
     card title, so the sidebar's Dataset and Flop headings follow it too. */
  gap: 5px;
  font-size: 14px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.84);
}

.ui-card-content {
  padding: 0 12px 12px;
}

.ui-badge {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-rail);
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-soft);
}

/* ── buttons ──────────────────────────────────────────────────────────── */
.ui-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: none;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.ui-button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.ui-button--md { height: 36px; padding: 0 12px; }
.ui-button--sm { height: 30px; padding: 0 8px; font-size: 13px; }
.ui-button--icon { width: 36px; height: 36px; padding: 0; }

.ui-button--subtle {
  background: var(--surface-rail);
  color: var(--text-normal);
}

.ui-button--subtle:hover:not(:disabled) {
  background: var(--surface-active);
}

.ui-button--ghost {
  background: transparent;
  color: var(--text-muted);
}

.ui-button--ghost:hover:not(:disabled) {
  background: var(--surface-panel);
  color: var(--text-normal);
}

.ui-button--primary {
  background: var(--accent-brand);
  color: var(--text-on-accent);
}

.ui-button--primary:hover:not(:disabled) {
  background: var(--accent-brand-hover);
}

/* ── input ────────────────────────────────────────────────────────────── */
.ui-input {
  width: 100%;
  height: 36px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-panel);
  padding: 0 12px;
  font-size: 14px;
  color: var(--text-normal);
  outline: none;
}

.ui-input:focus {
  border-color: var(--accent-brand);
}

.ui-input::placeholder {
  color: var(--text-muted);
}

/* ── tabs ─────────────────────────────────────────────────────────────── */
.ui-tabs-list {
  display: grid;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 4px;
}

/* the details card puts the tabs on a bar of their own */
.details-tabs-list.ui-tabs-list {
  border: 0;
  background: transparent;
  padding: 0;
}

.ui-tab {
  display: inline-flex;
  height: 36px;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 0 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.ui-tab:hover {
  color: var(--text-normal);
}

.ui-tab[data-state="active"] {
  background: #3b3b3b;
  color: var(--accent-brand);
}

/* Tabs on the panel's toolbar bar: the same pill as `.toolbar-button` — 32px
   in a 36px bar, fully rounded — rather than a folder tab stuck to a border
   that no longer exists (owner request 2026-09-21). */
.details-tab {
  height: 32px;
  border-radius: 6px;
  font-size: 14px;
}

/* ── hover hints ──────────────────────────────────────────────────────── */
/* One look for every hint of the site (owner 2026-10-17: «у тултипов у всех должен быть один стиль, такой же как у тултипа вопросика
   в блоке конфига в сайдбаре, который сразу подсказку красиво показывает»): the config card's «?» panel (study.css .config-info-pop),
   the Radix tooltips (.ui-tooltip), the controls' titles drawn by components/HoverHints.tsx (.hover-hint) and the practice table's
   captions (practice-sidebar.css .table-hint). Their own rules say only where each one stands and how wide it may be. */
.config-info-pop,
.ui-tooltip,
.hover-hint,
.table-hint {
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 10px 12px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.45;
  color: var(--text-soft);
}

/* Comes in as the «?» panel does: 120ms, from 4px toward the control. */
.ui-tooltip,
.hover-hint {
  max-width: 280px;
  animation: hint-in 120ms ease both;
}

.ui-tooltip[data-side="top"],
.hover-hint.is-above {
  animation-name: hint-in-above;
}

.ui-tooltip {
  z-index: 50;
}

/* Over every dialog of the site (the Custom builder's backdrop is 60, its rake help 80). */
.hover-hint {
  position: fixed;
  z-index: 1000;
  pointer-events: none;
  white-space: pre-line;
  overflow-wrap: break-word;
}

@keyframes hint-in {
  from { opacity: 0; transform: translateY(-4px); }
}

@keyframes hint-in-above {
  from { opacity: 0; transform: translateY(4px); }
}

/* ── not-found route ──────────────────────────────────────────────────── */
.page-fallback {
  display: grid;
  min-height: 100vh;
  place-items: center;
  background: var(--surface-page);
  color: var(--text-normal);
}

.page-fallback-card {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 16px;
  text-align: center;
}

.page-fallback-title {
  font-size: 18px;
  font-weight: 800;
}

.page-fallback-button {
  margin-top: 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-rail);
  padding: 8px 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-normal);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.page-fallback-button:hover {
  background: var(--surface-raised);
}

/* small inline row used inside card titles */
.title-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* ============================================================================
   Study page — layout rail, toolbar, solution card and the spot/chance
   pickers.
   ============================================================================ */

/* ── page frame ───────────────────────────────────────────────────────── */
.study-page {
  display: grid;
  grid-template-columns: 310px minmax(0, 1fr);
  min-height: 100vh;
  background: var(--surface-page);
  color: var(--text-normal);
}

.study-main {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 8px;
  padding: 10px 14px 16px;
}

.study-columns {
  display: grid;
  grid-template-columns: minmax(0, 67fr) minmax(0, 45fr);
  /* Stretch, so the right rail ends exactly where the matrix ends. */
  align-items: stretch;
  min-width: 0;
  gap: 12px;
}

/* the matrix and its toolbar */
/* No padding and no gap under the toolbar: the matrix runs to the panel's own
   border, which is where the height freed on a laptop should go (owner edit
   2026-09-21, sent from DevTools). The Ranges view sets its own padding: 0
   and keeps working either way. */
.matrix-panel {
  container-type: inline-size;
  width: 100%;
  min-width: 0;
  max-width: 100%;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
}

.matrix-error {
  display: grid;
  min-height: 540px;
  place-items: center;
  border: 1px dashed var(--line);
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  color: #ff5d5d;
}

/* The rail is as tall as the matrix beside it and never taller (owner request
   2026-09-13). `height: 0` is what makes that true: an auto grid row is sized
   by the tallest item's CONTENT, and the Hands/Summary lists are thousands of
   pixels of content — they would set the row height and push the page into a
   scrollbar. With a specified height the rail contributes nothing to that
   measurement, the row is the matrix panel alone, and `min-height: 100%`
   stretches the rail back onto it. Everything inside then divides that height
   with flex, which is why none of the panels compute from `100vh` any more:
   those numbers could not know how tall the matrix actually is. */
.study-right {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 12px;
  height: 0;
  /* The 360px is a floor, not a design size: if a browser ever resolved the
     percentage against nothing the rail would be zero pixels tall and simply
     vanish, and a slightly-too-tall rail is a far better failure than a blank
     one. On any normal window the matrix is taller and the percentage wins. */
  min-height: max(360px, 100%);
}

/* The last node's Actions and tabs while the next node loads (owner 2026-10-15: dimmed, never emptied; StudyPage panelsStale): still,
   so nothing is picked on a node that is no longer the one in focus. */
.study-right.is-stale {
  opacity: 0.55;
  pointer-events: none;
}

/* ── left rail ────────────────────────────────────────────────────────── */
.study-rail {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  min-height: 100vh;
  /* the page grid's first column sets the width (310px, 64px folded - .study-page), so the rail follows its fold animation */
  min-width: 0;
  flex-direction: column;
  gap: 12px;
  border-right: 1px solid var(--line);
  background: var(--surface-rail);
  padding: 16px;
}



.study-section-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 900;
  color: var(--text-normal);
}

.icon-button {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-panel);
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.icon-button:hover {
  background: var(--surface-raised);
}

/* ── recent configs and flops (owner 2026-10-15, RecentSpots.tsx) ────── */
/* The Recent card folds (owner 2026-10-16 «чтобы вкладка осталась но чтобы она сворачивалась и разворачивалась»; RecentSpots.tsx): the
   .ui-card look; the list's own height runs to 0 and back while it fades (an accordion played by the Web Animations API - the one
   deliberate exception to 5b.3, owner: the transform-only fold «пропадает рывком»). */
/* Compare EV's two actions, the sidebar card under the config (CompareCard.tsx, owner 2026-10-16): two columns joined by a line from
   the chosen Action to the chosen Compared to, each action with its matrix colour, then the colour scale of the matrix and Hands. It
   slides in with the Compare EV display mode (frontend_rules 5b.5: always). Flat, as the sidebar's other cards (owner 2026-10-16:
   «Убери тень у блока компейр ев в сайдбаре»). */
.compare-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 12px;
  color: var(--text-normal);
  animation: compare-card-in 220ms cubic-bezier(0.2, 0, 0, 1);
}

@keyframes compare-card-in {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.compare-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.compare-card-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-normal);
}

.compare-card-title svg {
  color: var(--accent-brand);
}

.compare-card-help {
  display: inline-flex;
  color: var(--text-soft);
  cursor: help;
}

.compare-card-columns {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 20px;
}

.compare-card-column {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 0;   /* rows back to back, as in the strip */
}

.compare-card-head {
  padding: 0 2px 2px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-soft);
}

/* The actions are the Study strip's rows (CompareCard: .node-action, its swatch, its selected wash - study-strip.css), only without the
   strip's pull into the card's padding; the action the other column holds stays live (a click swaps the sides). Scoped by the column, so
   they win over study-strip.css, which loads after this file. */
.compare-card-column .node-action {
  min-width: 0;
  margin-inline: 0;
  border-radius: 0;
}

.compare-card-mark {
  flex: none;
  color: var(--accent-brand);
}

/* The rows while the node's actions load: the config card's outline (.config-skeleton, its light below) in a strip row's place - a
   swatch and a name, 22px as .node-action, so the card keeps its height when the actions land. */
.compare-card-skeleton {
  display: flex;
  min-height: 22px;
  align-items: center;
  gap: 6px;
  padding: 0 8px;
}

.compare-card-skeleton-swatch,
.compare-card-skeleton-line {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: 3px;
  background: var(--surface-raised);
}

.compare-card-skeleton-swatch {
  flex: none;
  width: 10px;
  height: 10px;
}

.compare-card-skeleton-line {
  width: 58%;
  height: 9px;
}

.compare-card-skeleton:nth-child(odd) .compare-card-skeleton-line {
  width: 44%;
}

.compare-card-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* the line between the two choices, drawn in the 20px between the columns */
.compare-card-link {
  position: absolute;
  top: 0;
  left: calc(50% - 10px);
  overflow: visible;
  pointer-events: none;
}

.compare-card-link path {
  fill: none;
  stroke: var(--accent-brand);
  stroke-width: 2px;
}

.compare-card-legend {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.compare-card-scale {
  display: flex;
  height: 8px;
  overflow: hidden;
  border-radius: 4px;
}

.compare-card-scale i {
  flex: 1;
}

.compare-card-ticks {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-soft);
}

.recent-card {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  color: var(--text-normal);
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.24);
}

.recent-head {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border: none;
  border-radius: 8px;
  background: transparent;
  padding: 12px;
  color: inherit;
  cursor: pointer;
}

.recent-head:focus-visible {
  outline: 2px solid var(--accent-brand);
  outline-offset: -2px;
}

.recent-title {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-normal);
}

.recent-count {
  margin-left: 3px;
  border-radius: 999px;
  background: var(--surface-rail);
  padding: 1px 7px;
  font-size: 11px;
  font-weight: 800;
  line-height: 16px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

.recent-chevron {
  color: var(--text-muted);
  transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
}

.recent-head:hover .recent-chevron {
  color: var(--text-strong);
}

.recent-card.is-closing .recent-chevron,
.recent-card.is-closed .recent-chevron {
  transform: rotate(-90deg);
}

/* clipped while its height runs; the padding lives inside, so the height can reach 0 */
.recent-body {
  overflow: hidden;
}

.recent-body-inner {
  padding: 0 12px 12px;
}

/* about 5 entries show; the rest (up to 20) scroll inside the card, so the sidebar does not grow (owner 2026-10-15) */
.recent-list {
  display: flex;
  max-height: 272px;
  flex-direction: column;
  gap: 6px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}

.recent-row {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 7px 10px;
  text-align: left;
  color: var(--text-normal);
  cursor: pointer;
}

.recent-row:hover {
  background: var(--surface-raised);
}

.recent-text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}

.recent-label {
  overflow: hidden;
  font-size: 12px;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.recent-meta {
  font-size: 11px;
  color: var(--text-muted);
}

.recent-board {
  display: flex;
  flex-shrink: 0;
  gap: 3px;
}

.playing-card--recent {         /* the flop of a Recent entry, the site's own cards */
  --card-width: 22px;
  --card-height: 30px;
}

/* ── solution card (sidebar + strip) ──────────────────────────────────── */
.config-card {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 12px;
}

/* The card inside the nav's panel, right under its tools (Sidebar: RailNav below; owner 2026-10-16: «объедини эти 2 блока, чтоб под
   кнопками сразу был блок конфига»): one panel - no frame or background of its own, a hairline above as the tools row has; 8px
   inside, 11px above (owner 2026-10-16: «padding: 11px 8px 8px»), so the text is 12px from the panel's sides (its 4px + 8px). */
.config-card.is-in-nav {
  grid-column: 1 / -1;
  border: none;
  border-top: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  padding: 11px 8px 8px;
}

.config-title {
  padding-right: 24px;
  font-size: 15px;
  font-weight: 900;
  line-height: 1.2;
  color: rgba(255, 255, 255, 0.88);
}

/* The administrator's «?» in the card's top-right corner (owner 2026-10-16): hover or focus opens the solution's label, its size and
   the solve times under it (ConfigCard). */
.config-info {
  position: absolute;
  z-index: 20;
  top: 10px;
  right: 10px;
  display: inline-flex;
  color: var(--text-muted);
  outline: none;
  cursor: help;
}

.config-info:hover,
.config-info:focus-visible {
  color: var(--accent-brand);
}

/* the panel's look is every hint's (ui.css, «hover hints») */
.config-info-pop {
  position: absolute;
  top: 24px;
  right: -4px;
  display: flex;
  width: 250px;
  flex-direction: column;
  gap: 4px;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-4px);
  transition: opacity 120ms ease, transform 120ms ease;
}

.config-info:hover .config-info-pop,
.config-info:focus-within .config-info-pop {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

.config-info-line strong {
  font-weight: 600;
  color: var(--text-normal);
}

.config-info-line.is-label {
  font-weight: 700;
  color: var(--text-normal);
}

.config-bullets {
  margin-top: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.config-bullet {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--text-soft);
}

/* The card while its solution loads: an outline in the size of a title and its three bullets, swept by a light (owner 2026-10-15: no
   stand-in text that is replaced a moment later); .is-admin keeps the admin solve times' line until they land. */
.config-skeleton {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 2px 0 2px;   /* owner 2026-10-16 */
}

.config-skeleton-title,
.config-skeleton-line {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: 3px;
  background: var(--surface-raised);
}

.config-skeleton-title {
  width: 108px;
  height: 14px;
  margin-bottom: 4px;
}

.config-skeleton-line {
  width: 62%;
  height: 9px;
}

.config-skeleton-line:nth-child(odd) {
  width: 48%;
}

.config-skeleton-line.is-admin {
  width: 82%;
  height: 8px;
  margin: 4px 0;
}

.config-skeleton-title::before,
.config-skeleton-line::before,
.compare-card-skeleton-swatch::before,
.compare-card-skeleton-line::before {
  content: "";
  position: absolute;
  top: -4px;
  bottom: -4px;
  left: -65%;
  width: 60%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--skeleton-sheen), transparent);
  animation: node-loading-row-sheen 900ms ease-in-out infinite;
}

/* Solutions and AI Custom Solve side by side, equal widths (owner 2026-10-15) */
.config-change {
  display: flex;
  gap: 8px;
  margin-top: auto;
  padding-top: 10px;   /* owner 2026-10-16 */
}

.config-change-button {
  display: flex;
  flex: 1;
  min-width: 0;
  height: 36px;
  width: 100%;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: none;
  border-radius: 6px;
  background: var(--surface-rail);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-normal);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.config-change-button:hover {
  background: var(--surface-active);
}

/* The study tools, a row under the Practice | Study tabs inside the .rail-nav panel (owner 2026-10-15: was the vertical rail left
   of the node strip): both nav columns, a hairline above, quiet icon buttons without frames. */
.rail-tools {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: repeat(6, 1fr);
  gap: 4px;
  border-top: 1px solid var(--line);
  padding-top: 4px;
}

.rail-tool-button {
  position: relative;
  isolation: isolate;
  display: grid;
  place-items: center;
  height: 30px;
  border: none;
  border-radius: 5px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: transform 120ms ease;
}

/* Hover (owner 2026-10-21: «Если на иконки этой панели сделать красивое что-то при наведении. Станет лучше? ЕСли да то сделай»): a warm
   plate comes up under the icon with a little spring, the icon lights with a soft glow and makes the move of its action - back and
   forward step aside, the bookmark lifts, the saved list grows, the gamepad tilts, reset turns back; a press sinks the button. The same
   for the keyboard's focus. Only transform, opacity and filter move (frontend_rules 5b.3); the plate is a pseudo-element (5b.3). */
.rail-tool-button::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  border-radius: 7px;
  background: radial-gradient(70% 90% at 50% 50%, rgba(255, 158, 69, 0.16) 0%, rgba(255, 158, 69, 0.05) 60%, rgba(255, 158, 69, 0) 100%),
    var(--surface-hover);
  opacity: 0;
  transform: scale(0.82);
  transition: opacity 180ms ease, transform 260ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.rail-tool-button svg {
  transition: transform 260ms cubic-bezier(0.34, 1.56, 0.64, 1), filter 200ms ease;
}
.rail-tool-button:hover:not(:disabled),
.rail-tool-button:focus-visible:not(:disabled) { color: var(--text-strong); }
.rail-tool-button:hover:not(:disabled)::before,
.rail-tool-button:focus-visible:not(:disabled)::before { opacity: 1; transform: none; }
.rail-tool-button:hover:not(:disabled) svg,
.rail-tool-button:focus-visible:not(:disabled) svg { filter: drop-shadow(0 0 5px rgba(255, 158, 69, 0.55)); }
.rail-tool-button.is-back:hover:not(:disabled) svg,
.rail-tool-button.is-back:focus-visible:not(:disabled) svg { transform: translateX(-2px); }
.rail-tool-button.is-forward:hover:not(:disabled) svg,
.rail-tool-button.is-forward:focus-visible:not(:disabled) svg { transform: translateX(2px); }
.rail-tool-button.is-save:hover:not(:disabled) svg,
.rail-tool-button.is-save:focus-visible:not(:disabled) svg { transform: translateY(-2px); }
.rail-tool-button.is-saved:hover:not(:disabled) svg,
.rail-tool-button.is-saved:focus-visible:not(:disabled) svg { transform: scale(1.12); }
.rail-tool-button.is-practice:hover:not(:disabled) svg,
.rail-tool-button.is-practice:focus-visible:not(:disabled) svg { transform: rotate(-10deg) scale(1.06); }
.rail-tool-button.is-reset:hover:not(:disabled) svg,
.rail-tool-button.is-reset:focus-visible:not(:disabled) svg { transform: rotate(-60deg); }
.rail-tool-button:active:not(:disabled) { transform: scale(0.92); }

/* Back / Forward with no study step there (owner 2026-10-16) */
.rail-tool-button:disabled {
  opacity: 0.35;
  cursor: default;
}

/* ── toolbar above the matrix ─────────────────────────────────────────── */
/* One row: the left group shrinks and its filter chips scroll (owner 2026-10-05); only a phone wraps. */
.toolbar {
  display: flex;
  flex-wrap: nowrap;
  min-height: 36px;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  border-radius: 6px;
  background: #202020;
  padding: 0 6px;
}

.toolbar-group {
  display: flex;
  flex-wrap: nowrap;
  min-width: 0;
  align-items: center;
  gap: 4px;
}

.toolbar-group:not(.is-tools) {
  flex: 1 1 auto;
}

.toolbar-group > * {
  flex: none;
}

.toolbar-group.is-tools {
  flex-shrink: 0;
}

@media (max-width: 650px) {
  .toolbar,
  .toolbar-group {
    flex-wrap: wrap;
  }
}

/* ── strategy display picker ──────────────────────────────────────────────
   Our own menu, not a <select>: the popup of a native one belongs to the OS
   and takes no styling at all (owner request 2026-08-17). */
.display-menu {
  position: relative;
  display: inline-flex;
}

.display-menu-trigger {
  display: flex;
  height: 32px;
  align-items: center;
  gap: 8px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: var(--surface-panel);
  padding: 0 10px 0 12px;
  font-size: 14px;
  font-weight: 800;
  color: rgba(255, 255, 255, 0.88);
  outline: none;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}

.display-menu-trigger:hover {
  background: #404040;
}

.display-menu-trigger.is-open {
  border-color: rgba(255, 158, 69, 0.7);
  background: #404040;
}

/* The caret turns over while the list is down — the one cue that says the
   button is the thing holding the menu open. */
.display-menu-caret {
  transition: transform 140ms ease;
}

.display-menu-trigger.is-open .display-menu-caret {
  transform: rotate(180deg);
}

.display-menu-list {
  position: absolute;
  z-index: 60;
  top: 38px;
  left: 0;
  display: flex;
  min-width: 196px;
  flex-direction: column;
  gap: 2px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 6px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
  animation: display-menu-open 120ms ease-out;
}

@keyframes display-menu-open {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.display-menu-item {
  display: flex;
  height: 30px;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 0 8px 0 10px;
  text-align: left;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.display-menu-item:hover {
  background: #404040;
  color: var(--text-normal);
}

.display-menu-item.is-selected {
  background: var(--surface-rail);
  color: var(--accent-brand);
}

.toolbar-button {
  position: relative;
  height: 32px;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 0 12px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.toolbar-button:hover {
  background: var(--surface-panel);
  color: rgba(255, 255, 255, 0.82);
}

.toolbar-link {
  display: flex;
  height: 28px;
  align-items: center;
  gap: 4px;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 0 8px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.toolbar-link:hover {
  background: var(--surface-panel);
  color: rgba(255, 255, 255, 0.82);
}

.toolbar-link.is-copied {
  background: #2f4d33;
  color: #8fe39a;
}

.toolbar-icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.toolbar-icon:hover {
  background: var(--surface-panel);
  color: rgba(255, 255, 255, 0.82);
}

.toolbar-icon.is-copied,
.toolbar-icon.is-copied:hover {
  background: #2f4d33;
  color: #8fe39a;
}

.toolbar-icon:disabled {
  opacity: 0.4;
  cursor: default;
}

.toolbar-icon:disabled:hover {
  background: transparent;
  color: var(--text-muted);
}

/* ── small-hands filter (owner 2026-10-14): the trash can left of the copy icon
   switches it; on (the default) it is amber with the number of hidden hands. */
.range-filter-trigger {
  display: inline-flex;
  height: 28px;
  min-width: 28px;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 0 7px;
  font-size: 12px;
  font-weight: 800;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.range-filter-trigger:hover {
  background: var(--surface-panel);
  color: rgba(255, 255, 255, 0.82);
}

.range-filter-trigger.is-active,
.range-filter-trigger.is-active:hover {
  background: rgba(255, 158, 69, 0.16);
  color: var(--accent-brand);
}

/* ── spot / chance pickers ────────────────────────────────────────────── */
.picker-panel {
  border: 1px dashed var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 16px;
}

.picker-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.picker-title {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 800;
  color: var(--text-normal);
}

.picker-subtitle {
  margin-top: 2px;
  font-size: 12px;
  color: var(--text-muted);
}

.picker-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.flop-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(188px, 1fr));
  gap: 8px;
  max-height: 540px;
  overflow: auto;
  padding-right: 4px;
}

.flop-tile {
  display: flex;
  min-height: 56px;
  align-items: center;
  justify-content: space-between;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-panel);
  padding: 8px 12px;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}

.flop-tile:hover {
  background: var(--surface-raised);
}

.flop-tile.is-active {
  border-color: var(--accent-brand);
  background: var(--surface-raised);
}

.flop-tile .card-chip {
  width: 28px;
  height: 32px;
}

.flop-tile-meta {
  font-size: 12px;
  color: var(--text-muted);
}

/* ── chance card picker ───────────────────────────────────────────────── */
.chance-rows {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.chance-row {
  display: grid;
  grid-template-columns: 22px repeat(4, 34px);
  align-items: center;
  gap: 8px;
}

.chance-rank {
  font-size: 12px;
  font-weight: 900;
  color: var(--text-muted);
}

.chance-card-button {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 0;
  cursor: pointer;
  transition: background-color 120ms ease;
}

.chance-card-button:hover:not(:disabled) {
  background: var(--surface-raised);
}

.chance-card-button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.chance-card-button.is-picked {
  background: var(--surface-raised);
  box-shadow: inset 0 0 0 1px var(--accent-brand);
}

.chance-card-button .card-chip {
  width: 28px;
  height: 32px;
  font-size: 13px;
}

/* ============================================================================
   Range matrix — the 13x13 hand grid.
   ============================================================================ */

.matrix {
  position: relative;
  display: grid;
  grid-template-columns: repeat(13, minmax(0, 1fr));
  grid-template-rows: repeat(13, minmax(0, 1fr));
  width: 100%;
  height: auto;
  aspect-ratio: 800 / 620;
  max-width: 100%;
  overflow: hidden;
  border: 1px solid var(--line);
  /* Square: the grid now sits against the panel's own rounded border, and a
     second radius inside it read as a seam (owner edit 2026-09-21). */
  background: #202020;
}

.matrix-placeholder {
  display: grid;
  width: 100%;
  height: auto;
  aspect-ratio: 800 / 620;
  max-width: 100%;
  place-items: center;
  border: 1px dashed var(--line);
  border-radius: 8px;
  font-size: 14px;
  color: var(--text-muted);
}

.matrix-placeholder.is-error {
  font-weight: 600;
  color: #ff5d5d;
}

/* ── one hand cell: left/bottom borders ───────────────────────────────── */
.matrix-cell {
  position: relative;
  min-height: 0;
  overflow: hidden;
  border: none;
  border-left: 1px solid #333;
  border-bottom: 1px solid #333;
  background: var(--surface-panel);
  padding: 4px;
  text-align: left;
  outline: none;
  cursor: default;
  transition: filter 300ms ease, transform 300ms ease;
}

/* A class with no combos here — none at all, or none left after the Actions
   filter — is a dead square: no click, no focus ring, no hover lift (owner
   report 2026-08-17). The `disabled` attribute does the work; this only makes
   sure nothing paints a highlight on it anyway. */
.matrix-cell:disabled {
  outline: none;
  filter: none;
  cursor: default;
}

.matrix-cell.has-reach {
  cursor: pointer;
}

.matrix-cell.has-reach:hover {
  z-index: 10;
  filter: brightness(0.78);
}

/* A class with no combos here reads as "off", not as a decorated square: it is
   the same flat dark tone as a hand hidden by the range filter. It used to
   carry a diagonal hatch, which drew the eye to exactly the cells that carry no
   information (owner request 2026-09-05). */
.matrix-cell.is-no-reach,
.matrix-cell.is-low-reach {
  background: #1f1f1f;
}

.matrix-cell.is-low-reach .matrix-cell-label {
  color: rgba(255, 255, 255, 0.26);
  text-shadow: none;
}

/* Range 0.03 or less (owner 2026-10-14): no colour fill, only the white label
   and number on the plain cell. */
.matrix-cell.is-faint .matrix-cell-label,
.matrix-cell.is-faint .matrix-cell-metric {
  color: var(--text-strong);
}

.matrix-cell.is-active {
  z-index: 10;
  filter: brightness(0.78);
}

.matrix-cell.is-selected {
  z-index: 20;
  border-color: transparent;
}

.matrix-cell-label {
  position: absolute;
  z-index: 10;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 15px;
  font-weight: 900;
  line-height: 1;
  color: var(--text-strong);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.95);
}

.matrix-cell-label.is-compact {
  inset: auto auto auto 0;
  top: 4px;
  left: 4px;
  display: block;
  font-size: 15px;
}

/* Scale Study hand labels with their matrix, including compact display modes. */
.matrix-panel .matrix-cell-label {
  font-size: clamp(12px, 2cqw, 22px);
}

/* Node-locked class (Custom, owner 2026-10-04): the node card's orange lock,
   in the cell's top-right corner, over the fill and the label. */
.matrix-cell-lock {
  position: absolute;
  top: 4px;
  right: 4px;
  z-index: 11;
  color: var(--accent-brand);
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.7));
  pointer-events: none;
}

.matrix-cell-label.is-dim {
  color: rgba(255, 255, 255, 0.32);
}

.matrix-cell-metric {
  position: absolute;
  z-index: 10;
  right: 4px;
  bottom: 4px;
  max-width: calc(100% - 8px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: right;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  color: var(--text-soft);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
}

/* EV, equity, EQR and range share this slot in every matrix display mode. */
.matrix-panel .matrix-cell-metric {
  font-size: clamp(10px, 1.6cqw, 18px);
}

.matrix-panel .matrix-placeholder,
.matrix-panel .matrix-error,
.matrix-panel .matrix-loader-title {
  font-size: clamp(12px, 1.8cqw, 20px);
}

.matrix-panel .matrix-loader-sub {
  font-size: clamp(11px, 1.6cqw, 18px);
}

.matrix-cell-selection {
  pointer-events: none;
  position: absolute;
  inset: 0;
  z-index: 30;
  border: 3px solid var(--accent-brand);
}

/* fill that rises from the bottom of a cell */
.cell-fill {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.cell-fill-band {
  display: flex;
  width: 100%;
  min-height: 1px;
  flex-shrink: 0;
}

/* ── skeleton + loader ────────────────────────────────────────────────── */
.matrix-skeleton-cell {
  position: relative;
  min-height: 0;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  border-right: 1px solid var(--line);
  background: #272727;
}

.matrix-skeleton-label {
  position: absolute;
  left: 4px;
  top: 4px;
  width: 28px;
  height: 12px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.08);
}

.matrix-skeleton-metric {
  position: absolute;
  right: 4px;
  bottom: 4px;
  width: 32px;
  height: 10px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.06);
}

.matrix-loading-veil {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  background: rgba(20, 20, 20, 0.42);   /* no backdrop-filter (owner 2026-10-16: the page under a window flickered over it while scrolling - see study-modal.css) */
}

.matrix-loader-panel {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid rgba(255, 158, 69, 0.28);
  border-radius: 8px;
  background: rgba(37, 37, 37, 0.95);
  padding: 12px 16px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.38);
}

.matrix-loader-mark {
  position: relative;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: var(--surface-rail);
}

.matrix-loader-ring {
  position: absolute;
  inset: 0;
  border: 1px solid rgba(255, 158, 69, 0.25);
  border-radius: 999px;
}

.matrix-loader-text {
  display: flex;
  flex-direction: column;
}

.matrix-loader-title {
  font-size: 14px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.88);
}

.matrix-loader-sub {
  font-size: 12px;
  color: var(--text-muted);
}

.matrix-loader-spinner {
  color: var(--accent-brand);
  animation: matrix-spin 1s linear infinite;
}

@keyframes matrix-spin {
  to { transform: rotate(360deg); }
}
.matrix-range-fill {
  width: 100%;
  background: #f0a334;
}

.solution-variant-control { position: relative; }
.solution-variant-trigger { display: flex; align-items: center; justify-content: center; width: auto; min-width: 64px; gap: 5px; padding-inline: 6px; }
.solution-variant-value { font-size: 11px; white-space: nowrap; }
.solution-variant-menu {
  position: absolute; right: 0; top: 34px; z-index: 90;
  width: 224px; padding: 6px 0; border-radius: 6px;
  background: var(--surface-panel); box-shadow: 0 5px 20px rgba(0, 0, 0, 0.4);
}
.solution-variant-option {
  display: flex; flex-direction: column; align-items: flex-start;
  width: 100%; gap: 4px; padding: 10px 12px; border: none;
  background: transparent; color: var(--text-normal); cursor: pointer; text-align: left;
}
.solution-variant-option small { font-size: 11px; }
.solution-variant-option:hover { background: #404040; }
.solution-variant-option.is-selected {
  background: linear-gradient(90deg, rgba(255, 158, 69, 0.34), rgba(255, 158, 69, 0.14));
  color: var(--text-strong); box-shadow: inset 2px 0 0 var(--accent-brand);
}

/* Transfer five percentage points from the matrix to details on laptop windows. */
@media (max-width: 1800px) {
  .study-columns { grid-template-columns: minmax(0, 61.4fr) minmax(0, 50.6fr); }
}

/* Summary hover is visual only: dim other classes without changing selection. */
.matrix.is-summary-preview .matrix-cell:not(.is-summary-focus) { filter: brightness(0.3); }
.matrix.is-summary-preview .matrix-cell.is-summary-focus { filter: brightness(1); }

/* Owner comparison: select the immutable poker configuration. */
.study-config-switcher select {
  min-width: 270px;
  max-width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--surface-raised);
  border-radius: 6px;
  background: var(--surface-panel);
  color: var(--text-normal);
  font-size: 14px;
}

/* ============================================================================
   Hand drawer — the panel that slides out of a locked matrix cell with that
   class's own action mix (owner request 2026-09-13). Not a popup: it is a
   child of `.matrix`, anchored to the square that was clicked, and it opens
   INTO the grid — right/down from the top-left half, left/up from the
   bottom-right half — so it never has to reach past an edge the matrix clips.
   ============================================================================ */
.matrix-hand-drawer {
  position: absolute;
  /* Above every cell (selected cells stack at 20) and below the loading veil
     at 30, so a node still resolving greys the panel out with the grid. */
  z-index: 25;
  width: 224px;
  max-width: 48%;
  padding: 8px 10px 9px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: rgba(28, 28, 28, 0.96);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.55);
  color: var(--text-normal);
  /* Where it comes from and whether it is visible are two separate roles, so
     they are two separate animations (frontend_rules 5b.1) and each movement
     is one uninterrupted segment (5b.2). Only transform and opacity move. */
  animation:
    hand-drawer-open 220ms cubic-bezier(0.18, 0.78, 0.28, 1) both,
    hand-drawer-fade 180ms linear both;
}

.matrix-hand-drawer.is-left {
  animation:
    hand-drawer-open-left 220ms cubic-bezier(0.18, 0.78, 0.28, 1) both,
    hand-drawer-fade 180ms linear both;
}

@keyframes hand-drawer-open {
  from { transform: translateX(-18px); }
  to { transform: translateX(0); }
}

@keyframes hand-drawer-open-left {
  from { transform: translateX(18px); }
  to { transform: translateX(0); }
}

@keyframes hand-drawer-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.hand-drawer-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 7px;
}

.hand-drawer-label {
  font-size: 15px;
  font-weight: 900;
  line-height: 1;
  color: var(--text-strong);
}

.hand-drawer-range {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11px;
  color: var(--text-muted);
}

.hand-drawer-close {
  display: grid;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  place-items: center;
  border: none;
  border-radius: 5px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.hand-drawer-close:hover {
  background: var(--surface-raised);
  color: var(--text-strong);
}

.hand-drawer-mix {
  display: flex;
  height: 6px;
  margin-bottom: 8px;
  overflow: hidden;
  border-radius: 3px;
  background: #2a2a2a;
}

.hand-drawer-mix i {
  display: block;
  height: 100%;
}

.hand-drawer-rows {
  display: flex;
  flex-direction: column;
}

/* The negative margin matches the drawer's own padding, so the hover band runs
   edge to edge while the text stays on the title's line (frontend_rules 5a). */
.hand-drawer-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-inline: -10px;
  padding: 3px 10px;
}

.hand-drawer-row:hover {
  background: #404040;
}

.hand-drawer-row.is-unused {
  opacity: 0.45;
}

.hand-drawer-name {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 7px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  color: var(--text-soft);
}

.hand-drawer-swatch {
  width: 8px;
  height: 8px;
  flex-shrink: 0;
  border-radius: 2px;
}

.hand-drawer-values {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

.hand-drawer-values strong {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-strong);
}

/* Per-action EV in bb, only printed when the node actually carries one. */
.hand-drawer-values em {
  font-size: 11px;
  font-style: normal;
  color: var(--text-muted);
}

/* ============================================================================
   One-viewport Study (owner report 2026-09-13: the page could be nudged a few
   pixels even when everything was visible).

   The cause is arithmetic, not a stray element: the left rail is exactly
   100vh, `.study-page` is at least 100vh, and the main column is the node
   strip plus the matrix panel — whose height comes from its WIDTH through
   `aspect-ratio: 800/620`. Nothing in that chain knows about the window, so
   at most window sizes the column lands a handful of pixels over 100vh and
   the page scrolls by exactly the overhang, which is bottom padding and
   therefore invisible.

   So the matrix gives those pixels back instead: the column is told its real
   height, and the matrix shrinks into it. Width stays full, the cells lose
   the fraction of a percent that did not fit, and the page has nothing left
   to scroll. Where it already fits, nothing changes at all.

   Not applied to the Ranges comparison — two matrices, a stats column and the
   equity chart are genuinely taller than one screen and must stay scrollable
   — nor to windows too short to hold the layout, which keep the scrollbar
   they need.
   ============================================================================ */
@media (min-height: 700px) {
  .study-page:not(.is-ranges) {
    height: 100vh;
    overflow: hidden;
  }

  /* Safety only: the rail is built to fit 100vh (its flop list scrolls on its
     own), but it must never become unreachable if it one day does not. */
  .study-page:not(.is-ranges) .study-rail {
    overflow-y: auto;
  }

  .study-page:not(.is-ranges) .study-main {
    min-height: 0;
  }

  /* Everything the node strip did not take, and one row of exactly that size:
     an `auto` row would grow back to the matrix's natural height. */
  .study-page:not(.is-ranges) .study-columns {
    flex: 1;
    min-height: 0;
    grid-template-rows: minmax(0, 1fr);
  }

  .study-page:not(.is-ranges) .matrix-panel {
    display: flex;
    min-height: 0;
    flex-direction: column;
  }

  /* `min-height: 0` is what allows the shrink: a flex item's automatic minimum
     size would otherwise hold the matrix at its full aspect-ratio height and
     push the overhang straight back out of the panel.

     `flex: 1` is the other direction, and the one a laptop needs (owner report
     2026-09-21): the panel's row is the whole leftover height, while the
     matrix only ever asked for the height its WIDTH implies through the
     aspect ratio. On a narrower screen that is less, and the difference sat
     under the last row of the grid as dead space inside the panel. Growing
     into it costs nothing — the thirteen rows are 1fr each and simply divide
     whatever height the box ends up with — and on a wide monitor, where the
     aspect height already fills the row, there is nothing to grow into and
     the matrix keeps exactly the size it had. */
  .study-page:not(.is-ranges) .matrix,
  .study-page:not(.is-ranges) .matrix-placeholder,
  .study-page:not(.is-ranges) .matrix-error {
    flex: 1;
    min-height: 0;
  }
}

/* ── drawer: seat note and the class EV line ──────────────────────────── */
.hand-drawer-note {
  margin-bottom: 7px;
  font-size: 11px;
  color: var(--text-muted);
}

.hand-drawer-row.is-total {
  margin-top: 4px;
  border-top: 1px solid var(--line);
  padding-top: 5px;
}

.hand-drawer-row.is-total .hand-drawer-name {
  color: var(--text-muted);
}

/* ── node that failed to load (owner 2026-10-01) ─────────────────────────
   NodeErrorCard: takes the .matrix-error area, but in place of the bare red
   server text it says what failed, keeps the server message behind "Details
   for support" and offers Back / Try again. */
.matrix-error.node-error {
  padding: 16px;
  font-weight: 400;
  color: var(--text-normal);
}

.matrix-panel .matrix-error.node-error {
  font-size: 14px;
}

.node-error-card {
  display: grid;
  max-width: 380px;
  justify-items: center;
  gap: 12px;
  text-align: center;
}

.node-error-icon {
  display: grid;
  width: 40px;
  height: 40px;
  place-items: center;
  border-radius: 999px;
  background: rgba(255, 93, 93, 0.12);
  color: #ff5d5d;
}

/* Administrators (owner 2026-10-18): the icon shows the error itself in a tooltip. */
.node-error-icon.has-detail {
  cursor: help;
}

.node-error-tooltip {
  max-width: 520px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* "This line is never played": information, not an error. */
.node-error-icon.is-info {
  background: rgba(255, 255, 255, 0.08);
  color: var(--text-soft);
}

.node-error-title {
  font-size: 17px;
  font-weight: 700;
  color: var(--text-strong);
}

.node-error-text {
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-muted);
}

.node-error-text b {
  font-weight: 600;
  color: var(--text-strong);
}

.node-error-buttons {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

.node-error-button {
  border: none;
  border-radius: 6px;
  background: var(--surface-raised);
  padding: 8px 14px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
  transition: filter 200ms ease;
}

.node-error-button.is-primary {
  background: var(--accent-brand);
  color: var(--text-on-brand);
}

.node-error-button:hover { filter: brightness(1.1); }
.node-error-button:focus-visible { outline: 2px solid var(--text-strong); outline-offset: 2px; }

.node-error-notice {
  display: flex;
  align-items: center;
  gap: 8px;
  border-radius: 6px;
  background: var(--surface-sunken);
  padding: 8px 12px;
  font-size: 12px;
  color: var(--text-soft);
}

.node-error-notice-dot {
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: 999px;
  background: var(--action-passive);
}

/* A line the solution never plays (owner 2026-10-05): a red note pinned to the
   top centre of the page for 4 s — over the node cards (45), under dialogs (50). */
.rare-line-banner {
  position: fixed;
  top: 14px;
  left: 50%;
  z-index: 48;
  display: flex;
  align-items: center;
  gap: 9px;
  transform: translateX(-50%);
  border: 1px solid rgba(239, 91, 100, 0.6);
  border-radius: 10px;
  background: linear-gradient(180deg, #57262a, #431d20);
  padding: 9px 16px;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 600;
  color: #fbe6e8;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.08);
  pointer-events: none;
  animation: rare-line-in 200ms ease both;
}

.rare-line-banner.is-leaving {
  animation: rare-line-out 300ms ease both;
}

.rare-line-banner svg {
  flex: none;
  color: #ef5b64;
}

@keyframes rare-line-in {
  from { opacity: 0; transform: translate(-50%, -4px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

@keyframes rare-line-out {
  from { opacity: 1; transform: translate(-50%, 0); }
  to { opacity: 0; transform: translate(-50%, -4px); }
}

/* Compare EV's floating window is a narrow window's only (below); a wider one keeps the card in the rail. */
.compare-float { display: none; }

.compare-float-grip {
  display: flex;
  height: 16px;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  cursor: grab;
  touch-action: none;
}

.compare-float-grip:active { cursor: grabbing; }

/* ── narrow window (owner 2026-10-19) ─────────────────────────────────────
   «если я отдельное окно браузера сильно сузил, чтобы сайдбар при сужении уменьшался до вертикальной полоски где будут иконки ...
   чтобы основная матрица, блоки правые с руками и тд не кривились и узлы тоже». At 1400px and below the rail is a 64px strip of icons:
   the W mark, Practice / Study, the study tools in a column, Solutions and AI Custom Solve, the account; a hovered icon names itself
   on the right (data-rail-label, the site's hint look - ui.css .hover-hint). Recent and the Compare EV card need the full rail and wait
   for a wider window. The matrix and the right rail keep a floor width (536 / 340px) instead of squeezing: below it the page scrolls
   sideways (body min-width, index.css). */

.study-page.is-rail-collapsed { grid-template-columns: 64px minmax(0, 1fr); }
.study-page.is-rail-narrow .study-columns { grid-template-columns: minmax(536px, 61.4fr) minmax(340px, 50.6fr); }

.study-page.is-rail-collapsed .study-rail {
  z-index: 20;
  gap: 10px;
  padding: 12px 8px;
  /* the icons' names stand outside the strip (data-rail-label below): its tall-window overflow-y: auto (also clipping sideways) hid them
     (owner 2026-10-21: «тултип в свернутом виде сайдбара сделай для неё Solutions и для иконки AI ... AI solve»); the strip's short
     column of icons needs no scrolling (its Recent list is hidden) */
  overflow: visible;
}

.study-page.is-rail-collapsed .study-rail .rail-brand { padding: 0 0 4px; }
/* the strip keeps the mark alone (owner 2026-10-20: «в скрытом сайдбаре должен быть только логотип»), within its 48px */
.study-page.is-rail-collapsed .study-rail .rail-brand-logo { height: 28px; }
.study-page.is-rail-collapsed .study-rail .rail-brand-logo .brand-logo-word { display: none; }
.study-page.is-rail-collapsed .study-rail .rail-brand-logo .brand-logo-mark { height: 20px; }

.study-page.is-rail-collapsed .study-rail .rail-nav { grid-template-columns: 1fr; }
/* the words go, the icons stay: lucide icons carry their size in attributes, not in the font */
.study-page.is-rail-collapsed .study-rail .rail-nav-button {
  gap: 0;
  padding: 10px 0;
  font-size: 0;
}

.study-page.is-rail-collapsed .study-rail .rail-tools { grid-template-columns: 1fr; }

.study-page.is-rail-collapsed .study-rail .config-card.is-in-nav { padding: 6px 0 0; }
.study-page.is-rail-collapsed .study-rail .config-title,
.study-page.is-rail-collapsed .study-rail .config-bullets,
.study-page.is-rail-collapsed .study-rail .config-info,
.study-page.is-rail-collapsed .study-rail .config-skeleton,
.study-page.is-rail-collapsed .study-rail .rail-ai-badge { display: none; }
.study-page.is-rail-collapsed .study-rail .config-change {
  flex-direction: column;
  gap: 4px;
  padding-top: 0;
}
/* Solutions and AI Custom Solve look like the study tools above them (owner 2026-10-19: «должны выглядеть так же как и все кнопки
   выше»): a 30px quiet icon button, no frame, no fill (.rail-tool-button) */
.study-page.is-rail-collapsed .study-rail .config-change-button {
  flex: none;
  height: 30px;
  gap: 0;
  border-radius: 5px;
  background: transparent;
  padding: 0;
  font-size: 0;
  color: var(--text-muted);
}
.study-page.is-rail-collapsed .study-rail .config-change-button:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}
/* Solutions lit like the active Study's icon, always, but without its plate (owner 2026-10-21: «иконка solutions должна всегда
   подсвечиваться оранжевым как иконка стади когда она активна. но без выделения активной иконки») */
.study-page.is-rail-collapsed .study-rail .config-change-button.is-solutions,
.study-page.is-rail-collapsed .study-rail .config-change-button.is-solutions:hover { color: var(--accent-brand); }

.study-page.is-rail-collapsed .study-rail .rail-content-scroll { display: none; }

/* Compare EV's card leaves the rail: a window under the matrix toolbar's mode button, moved by its grip (CompareCard.tsx) */
.study-page.is-rail-collapsed .matrix-panel { position: relative; }
.study-page.is-rail-collapsed .compare-float {
  position: absolute;
  z-index: 15;
  top: 50px;
  left: 8px;
  display: block;
  width: 280px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface-panel);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
}
.study-page.is-rail-collapsed .compare-float .compare-card {
  border: none;
  background: transparent;
}

.study-page.is-rail-collapsed .study-rail .sidebar-account-row {
  flex-direction: column;
  gap: 6px;
}
.study-page.is-rail-collapsed .study-rail .sidebar-account-open {
  justify-content: center;
  margin-left: 0;
  padding: 4px;
}
.study-page.is-rail-collapsed .study-rail .sidebar-account-info,
.study-page.is-rail-collapsed .study-rail .sidebar-account-gear { display: none; }

/* the icon's name beside it, in the site's hint look (ui.css .hover-hint) */
.study-page.is-rail-collapsed .study-rail [data-rail-label] { position: relative; }
.study-page.is-rail-collapsed .study-rail [data-rail-label]::after {
  content: attr(data-rail-label);
  position: absolute;
  z-index: 40;
  top: 50%;
  left: calc(100% + 12px);
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 6px 10px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  color: var(--text-soft);
  pointer-events: none;
  opacity: 0;
  transform: translateY(-50%);
  transition: opacity 120ms ease;
}
.study-page.is-rail-collapsed .study-rail [data-rail-label]:hover::after { opacity: 1; }

/* The rail folded by its button on a wide window (owner 2026-10-19: «иконку чтобы сайдбар сузить и он красиво анимированно уехал в
   узкий сайдбар ... матрица и узлы расширились и съехали к сайдбару левее»; railCollapse.ts). The matrix and the right column (Actions,
   Hands / Summary / Blockers) share what the rail gives back in their own proportions, 61.4 : 50.6 (67 : 45 from 1801px), so the page is
   the one beside the full rail, only wider (owner the same day: «чтобы ... правый блок где Actions и нижний блок хендс/саммари/блокеры тоже
   расширялись влево в таких же пропорциях»; the right column first kept its width). is-rail-manual (folded, and through the unfold -
   StudyPage) only keeps the letters' sizes below.

   The letters keep their size when the rail folds (owner 2026-10-19: «когда я нажимаю скрыть сайдбар, чтобы не увеличивались шрифты в
   матрице. А оставались такими же»). They follow their panel's width (2cqw ...), which grows with the fold; folded by the button they
   follow instead the width the panel has beside the full rail in the same window: the matrix column (100vw - 350px) x 61.4 / 112
   (67 / 112 from 1801px; 350px = 310 rail + 28 padding + 12 gap), less its 2px of border; a Range comparison seat is half of that, less
   the 8px between the two (its labels and its Combos / EV / Equity / EQR numbers); the Actions cards' row is the right column
   (100vw - 350px) x 50.6 / 112 (45 / 112), less the card's 2px of border and 8px of padding.
   Only the hand labels are then 2px larger while the rail is folded (owner 2026-10-19: «чтобы шрифт увеличивался на 2пх в матрице ...
   но только шрифт комбинаций ... внизу шрифт увеличивать не надо»): they step up when the fold starts and back when the unfold starts. */
.study-page.is-rail-manual .matrix-panel .matrix-cell-label { font-size: clamp(12px, calc(((100vw - 350px) * 61.4 / 112 - 2px) * 0.02), 22px); }
.study-page.is-rail-manual .matrix-panel .matrix-cell-metric { font-size: clamp(10px, calc(((100vw - 350px) * 61.4 / 112 - 2px) * 0.016), 18px); }
.study-page.is-rail-manual .matrix-panel .matrix-placeholder,
.study-page.is-rail-manual .matrix-panel .matrix-error,
.study-page.is-rail-manual .matrix-panel .matrix-loader-title { font-size: clamp(12px, calc(((100vw - 350px) * 61.4 / 112 - 2px) * 0.018), 20px); }
.study-page.is-rail-manual .matrix-panel .matrix-loader-sub { font-size: clamp(11px, calc(((100vw - 350px) * 61.4 / 112 - 2px) * 0.016), 18px); }
.study-page.is-rail-manual .ranges-player.matrix-panel .matrix-cell-label {
  font-size: clamp(9px, calc(((100vw - 350px) * 61.4 / 112 - 10px) / 2 * 0.015), 16.5px);
}
.study-page.is-rail-manual .ranges-player.matrix-panel .matrix-placeholder,
.study-page.is-rail-manual .ranges-player.matrix-panel .matrix-error,
.study-page.is-rail-manual .ranges-player.matrix-panel .matrix-loader-title {
  font-size: clamp(12px, calc(((100vw - 350px) * 61.4 / 112 - 10px) / 2 * 0.018), 20px);
}
.study-page.is-rail-manual .ranges-player.matrix-panel .matrix-loader-sub {
  font-size: clamp(11px, calc(((100vw - 350px) * 61.4 / 112 - 10px) / 2 * 0.016), 18px);
}
.study-page.is-rail-manual .ranges-player.matrix-panel .ranges-stat strong {
  font-size: clamp(13px, calc(((100vw - 350px) * 61.4 / 112 - 10px) / 2 * 0.032), 18px);
}
.study-page.is-rail-manual .action-cards.is-calm .action-card-value {
  font-size: clamp(15px, calc((((100vw - 350px) * 50.6 / 112 - 34px) / 4 - 24px) * 0.165), 24px);
}
.study-page.is-rail-manual.is-rail-collapsed .matrix-panel .matrix-cell-label {
  font-size: clamp(14px, calc(((100vw - 350px) * 61.4 / 112 - 2px) * 0.02 + 2px), 24px);
}
.study-page.is-rail-manual.is-rail-collapsed .ranges-player.matrix-panel .matrix-cell-label {
  font-size: clamp(11px, calc(((100vw - 350px) * 61.4 / 112 - 10px) / 2 * 0.015 + 2px), 18.5px);
}

@media (min-width: 1801px) {
  .study-page.is-rail-manual .matrix-panel .matrix-cell-label { font-size: clamp(12px, calc(((100vw - 350px) * 67 / 112 - 2px) * 0.02), 22px); }
  .study-page.is-rail-manual .matrix-panel .matrix-cell-metric { font-size: clamp(10px, calc(((100vw - 350px) * 67 / 112 - 2px) * 0.016), 18px); }
  .study-page.is-rail-manual .matrix-panel .matrix-placeholder,
  .study-page.is-rail-manual .matrix-panel .matrix-error,
  .study-page.is-rail-manual .matrix-panel .matrix-loader-title { font-size: clamp(12px, calc(((100vw - 350px) * 67 / 112 - 2px) * 0.018), 20px); }
  .study-page.is-rail-manual .matrix-panel .matrix-loader-sub { font-size: clamp(11px, calc(((100vw - 350px) * 67 / 112 - 2px) * 0.016), 18px); }
  .study-page.is-rail-manual .ranges-player.matrix-panel .matrix-cell-label {
    font-size: clamp(9px, calc(((100vw - 350px) * 67 / 112 - 10px) / 2 * 0.015), 16.5px);
  }
  .study-page.is-rail-manual .ranges-player.matrix-panel .matrix-placeholder,
  .study-page.is-rail-manual .ranges-player.matrix-panel .matrix-error,
  .study-page.is-rail-manual .ranges-player.matrix-panel .matrix-loader-title {
    font-size: clamp(12px, calc(((100vw - 350px) * 67 / 112 - 10px) / 2 * 0.018), 20px);
  }
  .study-page.is-rail-manual .ranges-player.matrix-panel .matrix-loader-sub {
    font-size: clamp(11px, calc(((100vw - 350px) * 67 / 112 - 10px) / 2 * 0.016), 18px);
  }
  .study-page.is-rail-manual .ranges-player.matrix-panel .ranges-stat strong {
    font-size: clamp(13px, calc(((100vw - 350px) * 67 / 112 - 10px) / 2 * 0.032), 18px);
  }
  .study-page.is-rail-manual .action-cards.is-calm .action-card-value {
    font-size: clamp(15px, calc((((100vw - 350px) * 45 / 112 - 34px) / 4 - 24px) * 0.165), 24px);
  }
  .study-page.is-rail-manual.is-rail-collapsed .matrix-panel .matrix-cell-label {
    font-size: clamp(14px, calc(((100vw - 350px) * 67 / 112 - 2px) * 0.02 + 2px), 24px);
  }
  .study-page.is-rail-manual.is-rail-collapsed .ranges-player.matrix-panel .matrix-cell-label {
    font-size: clamp(11px, calc(((100vw - 350px) * 67 / 112 - 10px) / 2 * 0.015 + 2px), 18.5px);
  }
}

/* The fold and the unfold move (owner 2026-10-19): the rail's column narrows / widens and the page follows it - an exception to 5b.3 at
   the owner's request, as the Recent accordion's height. While it moves the rail clips its content, which comes back by opacity once
   the new layout stands. */
.study-page { transition: grid-template-columns 320ms cubic-bezier(0.22, 1, 0.36, 1); }
.study-page.is-rail-moving .study-rail { overflow: hidden; }
.study-page.is-rail-moving .study-rail > * { animation: rail-content-in 380ms ease both; }

@keyframes rail-content-in {
  0%, 40% { opacity: 0; }
  100% { opacity: 1; }
}

/* The fold handle (owner 2026-10-21: «иконка скрытия сайдбара выглядит как-то некрасиво и как будто не в том месте. можно сделать
   красивее?»): a round handle in the rail's head at the logo's middle (its 34px logo: 17px - half the handle), its chevron pointing
   where the rail goes, inside the rail's own box (owner, the same day: «а как сайдбар то теперь свернуть?» - on the rail's edge, placed in
   the page's grid, it was not found). Folded, it stands under the mark. On its hover a warm glow comes up and the chevron turns orange - it
   does not move aside (owner 2026-10-21: «не нужно чтобы она съезжала в сторону при наводке»); a press sinks it. Only transform, opacity and filter move (frontend_rules 5b.3). */
.rail-head {
  position: relative;
  flex-shrink: 0;
}

.rail-edge {
  position: absolute;
  isolation: isolate;
  top: 3px;
  right: -6px;
  display: grid;
  width: 28px;
  height: 28px;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: var(--surface-raised);
  color: var(--text-soft);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  cursor: pointer;
  transition: transform 220ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.study-page.is-rail-collapsed .rail-edge {
  position: relative;
  top: auto;
  right: auto;
  margin: 6px auto 0;
}
/* the warm glow round it, on its own hover */
.rail-edge::before {
  content: "";
  position: absolute;
  inset: -5px;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 158, 69, 0.28) 0%, rgba(255, 158, 69, 0.1) 55%, rgba(255, 158, 69, 0) 72%);
  opacity: 0;
  transform: scale(0.7);
  transition: opacity 180ms ease, transform 260ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.rail-edge:hover,
.rail-edge:focus-visible { color: var(--accent-brand); }
.rail-edge:hover::before,
.rail-edge:focus-visible::before { opacity: 1; transform: none; }
.rail-edge:active { transform: scale(0.9); }
/* ============================================================================
   Node strip — the horizontal carousel of decision cards above the matrix.
   ============================================================================ */

/* A press-and-drag or a double click on a card no longer paints its text blue (owner 2026-10-17: «убери выделение мышкой в узлах
   действий в стади»); the opened copy of a card lives in <body> and says the same. */
.node-strip,
.node-card-overlay {
  -webkit-user-select: none;
  user-select: none;
}

.node-strip {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.node-strip-viewport {
  position: relative;
  min-width: 0;
  flex: 1;
}

.node-strip-track {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 4px;
}

/* ── hover arrows on both edges ───────────────────────────────────────── */
.strip-arrow {
  position: absolute;
  inset-block: 0;
  z-index: 10;
  display: flex;
  width: 56px;
  align-items: center;
  cursor: pointer;
  transition: opacity 300ms ease-out;
}

/* The fade has to be the colour of whatever the strip is lying on, or it draws
   a grey smear across it. The study's strip sits on the page; the practice
   table's sits on the felt's surround, which sets these two for itself. */
.strip-arrow.is-left {
  left: 0;
  justify-content: flex-start;
  padding-left: 4px;
  background: linear-gradient(
    to right,
    var(--strip-fade, var(--surface-page)),
    var(--strip-fade-soft, rgba(36, 36, 36, 0.7)),
    transparent
  );
}

.strip-arrow.is-right {
  right: 0;
  justify-content: flex-end;
  padding-right: 4px;
  background: linear-gradient(
    to left,
    var(--strip-fade, var(--surface-page)),
    var(--strip-fade-soft, rgba(36, 36, 36, 0.7)),
    transparent
  );
}

.strip-arrow.is-active {
  opacity: 1;
}

.strip-arrow.is-active:hover {
  opacity: 0.3;
}

.strip-arrow.is-hidden {
  pointer-events: none;
  opacity: 0;
}

.strip-arrow-icon {
  width: 28px;
  height: 28px;
  color: rgba(255, 255, 255, 0.92);
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.85));
}

/* ── cards ────────────────────────────────────────────────────────────── */

/* Card dimensions: edit here in DevTools; no inline size overrides. */
.node-card,
.node-card-center,
.node-card-pending,
.node-card-failed,
.node-card-empty {
  width: 116px;
  height: 170px;
}

/* Wider cards for FLOP / TURN / RIVER. */
.node-card.is-board,
.node-card-center.is-board {
  width: 134px;
}

.node-card {
  position: relative;
  display: flex;
  flex-shrink: 0;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 8px;
  text-align: left;
  cursor: pointer;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 3px 0 rgba(0, 0, 0, 0.38);
  transition: background-color 120ms ease, border-color 120ms ease;
}

.node-card:hover {
  background: var(--surface-rail);
}

/* The card being viewed carries a 2px ring — drawn as an OUTLINE, not as a
   thicker border (owner report 2026-08-17). border-box keeps the card's outer
   size fixed, but a 2px border still eats a pixel off the CONTENT box on each
   side, so everything inside the card crept when it was selected. An outline
   takes no layout space at all, and a negative offset paints it exactly where
   the border would have been. */
.node-card.is-focused {
  outline: 2px solid var(--accent-brand);
  outline-offset: -2px;
  background: var(--surface-raised);
}

/* ── opened Custom card: content column + tool rail ───────────────────── */
/* The card keeps its column layout in the normal 116px width; opening it in a
   Custom solution turns it into a row so the edit / lock / compare rail can
   stand beside the actions instead of covering them (owner request
   2026-09-15). The extra width is exactly the rail plus its gap. */
.node-card-main {
  position: relative;
  display: flex;
  min-width: 0;
  min-height: 0;
  flex: 1;
  flex-direction: column;
}

.node-card.is-expanded {
  width: 152px;
  flex-direction: row;
  gap: 6px;
}

/* The selected-action band runs to the card's padding edge (5a). With the rail
   beside it, "the edge" is now the rail's border, so the band gives up its
   right overhang instead of sliding under the tools. */
.node-card.is-expanded .node-action {
  margin-inline: -8px 0;
  padding-inline: 8px 0;
}

.node-card-tools {
  display: flex;
  width: 24px;
  flex-shrink: 0;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  border-left: 1px solid rgba(255, 255, 255, 0.07);
  padding-left: 6px;
}

.node-card-tool {
  display: grid;
  width: 24px;
  height: 24px;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 6px;
  background: rgba(15, 15, 15, 0.45);
  padding: 0;
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color 120ms ease, color 120ms ease, background-color 120ms ease;
}

.node-card-tool:disabled {
  opacity: 0.4;
  cursor: default;
}

.node-card-tool.is-enabled:hover {
  border-color: var(--accent-brand);
  background: var(--surface-raised);
  color: var(--text-strong);
}

/* Marker on a node whose frequencies are frozen. */
.node-card-lock {
  flex-shrink: 0;
  color: var(--accent-brand);
}

.node-card.is-static {
  cursor: default;
}

.node-card.is-static:hover {
  background: var(--surface-panel);
}

.node-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* Inline row, not a plain <strong>: the preflight makes every svg a block, so
   the lock badge of a node with frozen frequencies dropped onto its own line
   under the seat (owner report 2026-09-15). */
.node-card-seat {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 14px;
  color: var(--text-normal);
}

.node-card-seat.is-dim {
  color: var(--text-soft);
}

.node-card-stack,
.node-card-meta {
  font-size: 11px;
  color: var(--text-muted);
}

.node-card-meta {
  margin: 2px 0 6px;
}

.node-card-body {
  display: grid;
  flex: 1;
  place-items: center;
}

.node-card-footer {
  text-align: right;
  font-size: 11px;
  color: var(--text-muted);
}

/* «AI solve this spot» on the FLOP card (owner 2026-10-18): one box holds the card and the button, which lies over the card's footer
   line (a button cannot sit inside the card's own button). Violet like AI Custom Solve in the config card (.rail-ai-icon). */
.node-card-flop {
  position: relative;
  flex-shrink: 0;
}

/* the card keeps its hover while the pointer is on the button over it */
.node-card-flop:hover .node-card:not(.is-focused) {
  background: var(--surface-rail);
}

/* compact, in the middle of the card's foot (owner 2026-10-18: «Custom solve», the full-width bar was too much). At rest only its words
   and icon in the colour of the pot's figures (.node-card-stack); the violet button shows on hover / keyboard focus (owner 2026-10-18). */
.node-card-solve {
  position: absolute;
  bottom: 10px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  height: 22px;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border: 1px solid transparent;
  border-radius: 6px;
  background-color: transparent;
  padding: 0 8px;
  font-size: 11px;
  font-weight: 600;
  /* Inter's capital I reads as «l» without it: «AI», not «Al» (see .rail-ai-badge) */
  font-feature-settings: "cv08";
  white-space: nowrap;
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease, color 120ms ease;
}

/* the violet wash: a layer of its own under the words (the transform makes the button a stacking context), shown by opacity only (5b.3) */
.node-card-solve::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  border-radius: inherit;
  background-image: linear-gradient(90deg, rgba(124, 92, 240, 0.4), rgba(124, 92, 240, 0.14));
  opacity: 0;
  pointer-events: none;
  transition: opacity 120ms ease;
}

.node-card-solve svg {
  flex-shrink: 0;
  color: var(--text-muted);
  transition: color 120ms ease;
}

.node-card-solve:hover,
.node-card-solve:focus-visible {
  border-color: var(--ai-accent);
  background-color: rgba(124, 92, 240, 0.32);
  color: var(--text-strong);
}

.node-card-solve:hover::before,
.node-card-solve:focus-visible::before {
  opacity: 1;
}

.node-card-solve:hover svg,
.node-card-solve:focus-visible svg {
  color: var(--ai-accent);
}

.node-card-solve.is-busy {
  opacity: 0.7;
  cursor: progress;
}

.node-card-solve.is-failed {
  border-color: rgba(255, 93, 93, 0.6);
}

.node-card-center {
  display: flex;
  flex-shrink: 0;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 8px;
  text-align: center;
  font-size: 12px;
  color: var(--text-muted);
  cursor: pointer;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 3px 0 rgba(0, 0, 0, 0.38);
  transition: background-color 120ms ease;
}

.node-card-center:hover {
  background: var(--surface-rail);
}

.node-card-center.is-static {
  cursor: default;
}

.node-card-center strong {
  font-size: 14px;
  color: var(--text-normal);
}

.node-card-chance {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 14px;
  color: var(--text-normal);
}

/* ── action list inside a decision card ───────────────────────────────── */
.node-actions {
  display: flex;
  min-height: 0;
  flex: 1;
  flex-direction: column;
  gap: 0px;
  padding-bottom: 16px;
}

/* ── more actions than the card holds (owner 2026-10-02) ─────────────────
   Hovering the card opens the same card over the strip (.node-card-overlay,
   a portal: the strip scrolls sideways and would clip it), grown down to
   show every action. Leaving the card folds it back. */
/* Clipped at the card's own edge, so the selected band can still reach it. */
.node-card.is-decision {
  overflow: hidden;
}

/* The height is animated from script (NodeStrip DecisionCard); only the
   shadow eases here. */
/* z-index 45: over the matrix layers (up to 30) it grows across, under every
   dialog (.modal-backdrop 50, Custom Solutions 60, its pickers 65-80),
   tooltips (50) and menus (owner 2026-10-02: it covered a dialog at 85). */
.node-card-overlay {
  position: fixed;
  z-index: 45;
  overflow: hidden;
  transition: box-shadow 300ms ease;
}

.node-card-overlay.is-grown {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 18px 40px rgba(0, 0, 0, 0.6);
}



.node-explain-button {
  position: absolute;
  right: 5px;
  bottom: 4px;
  display: grid;
  width: 20px;
  height: 20px;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 50%;
  background: rgba(15, 15, 15, 0.55);
  padding: 0;
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color 120ms ease, color 120ms ease, background-color 120ms ease;
}

.node-explain-button:hover {
  border-color: var(--accent-brand);
  background: var(--surface-raised);
  color: var(--text-strong);
}

/* No border at all, and the row runs the full inner width of the card: the
   negative margin takes it out to the card's padding edge on both sides and
   the padding puts the text back on the same line as the card's own title
   (owner request 2026-08-17). Selecting an action then lights up a band from
   edge to edge instead of drawing a pill inside the card. */
.node-action {
  display: flex;
  min-height: 22px;
  align-items: center;
  gap: 6px;
  border: none;
  background: transparent;
  margin-inline: -8px;
  padding: 0px 8px;
  text-align: left;
  font-size: 13px;
  line-height: 1.15;
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease, box-shadow 120ms ease;
}

.node-action:hover {
  background: #404040;
}

.node-action.is-selected {
  background: linear-gradient(
    90deg,
    rgba(255, 158, 69, 0.34),
    rgba(255, 158, 69, 0.14)
  );
  color: var(--text-strong);
  box-shadow: inset 2px 0 0 var(--accent-brand);
}

.node-action-swatch {
  width: 10px;
  height: 10px;
  flex-shrink: 0;
  border-radius: 3px;
}

/* ── board cards inside a strip card ──────────────────────────────────── */
.strip-board {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
}

/* ── pending card ─────────────────────────────────────────────────────── */
.node-card-pending {
  position: relative;
  display: grid;
  flex-shrink: 0;
  place-items: center;
  overflow: hidden;
  border: 1px solid rgba(255, 158, 69, 0.45);
  border-radius: 8px;
  background: var(--surface-panel);
  box-shadow:
    0 0 0 1px rgba(255, 158, 69, 0.08),
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 3px 0 rgba(0, 0, 0, 0.38);
}

.node-card-empty {
  flex-shrink: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 12px;
  font-size: 14px;
  color: var(--text-muted);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 3px 0 rgba(0, 0, 0, 0.38);
}

/* Approved node loading style: neutral shimmer, always animated. */
.node-card-pending { border-color: #515151; }
.node-loading-skeleton { position: absolute; inset: 13px 9px; z-index: 1; }
.node-loading-heading, .node-loading-subheading { position: relative; overflow: hidden; display: block; height: 6px; width: 58px; border-radius: 2px; background: #414141; }
.node-loading-subheading { width: 40px; height: 5px; margin-top: 7px; background: #383838; }
.node-loading-rows { display: flex; flex-direction: column; gap: 9px; margin-top: 24px; }
.node-loading-rows > span { position: relative; display: block; height: 24px; overflow: hidden; border: 1px solid #484848; border-radius: 4px; background: #343434; }
.node-card-pending .node-loading-heading::before,
.node-card-pending .node-loading-subheading::before,
.node-card-pending .node-loading-rows > span::before { content: ""; position: absolute; z-index: 1; top: -6px; bottom: -6px; left: -65%; width: 60%; pointer-events: none; background: linear-gradient(90deg, transparent, #ffffff18, #ffffff50, #ffffff18, transparent); animation: node-loading-row-sheen 700ms ease-in-out infinite; }
.node-card-pending .node-loading-subheading::before,
.node-card-pending .node-loading-rows > span:nth-child(2)::before { animation-delay: 50ms; }
.node-card-pending .node-loading-rows > span:nth-child(3)::before { animation-delay: 100ms; }
@keyframes node-loading-row-sheen { 0% { transform: translateX(0) skewX(-18deg); opacity: 0; } 15% { opacity: 1; } 80%, 100% { transform: translateX(300%) skewX(-18deg); opacity: 0; } }

/* A node that failed to load: same box as the loading card, red outline and
   a short label instead of the shimmer (owner 2026-10-01). */
.node-card-failed {
  display: grid;
  flex-shrink: 0;
  place-content: center;
  justify-items: center;
  gap: 8px;
  border: 1px solid #ff5d5d;
  border-radius: 8px;
  background: rgba(255, 93, 93, 0.1);
  font-size: 13px;
  font-weight: 600;
  color: #ff5d5d;
}

/* Turn / river card: the FLOP card layout with one card, so narrower
   (owner 2026-10-01): fits "RIVER" and a three-digit pot in the head. */
.node-card.is-board.is-chance {
  width: 108px;
}

/* The cards still to come on a board card (owner 2026-10-18): the flop's three at the end of a preflop line, the turn's / river's
   one - empty places of the strip cards' size (.playing-card--strip) with what a click does under them. */
/* the places stand where the picked cards will (.strip-board centred in the body); the caption hangs under them */
.node-card-slots {
  position: relative;
  display: block;
}

/* A card not picked yet (owner 2026-10-21: «вместо плюсика и оранжевой обводки сделай что-то красивое с нашим логотипом (буква м), чтоб
   было очень красиво когда карта еще не выбрана»): a card's back - warm dark, a thin inner frame, our mark in the middle breathing
   (brightness), a light crossing the places one after another; on the card's hover / focus the mark comes up and a warm frame shows.
   Only transform, opacity and filter move (frontend_rules 5b.3). */
.node-card-slot {
  position: relative;
  display: grid;
  width: 34px;
  height: 56px;
  place-items: center;
  overflow: hidden;
  border-radius: 5px;
  background:
    radial-gradient(80% 45% at 50% 50%, rgba(255, 140, 50, 0.16) 0%, rgba(255, 140, 50, 0) 75%),
    linear-gradient(160deg, #36312d 0%, #221f1d 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 176, 110, 0.16), 0 2px 6px rgba(0, 0, 0, 0.35);
}
/* the inner frame of a card's back, warmer on hover / focus */
.node-card-slot::before {
  content: "";
  position: absolute;
  inset: 3px;
  border: 1px solid rgba(255, 176, 110, 0.55);
  border-radius: 3px;
  opacity: 0.22;
  transition: opacity 160ms ease;
}
/* a light crossing the places in turn */
.node-card-slot::after {
  content: "";
  position: absolute;
  top: -8px;
  bottom: -8px;
  left: 0;
  width: 70%;
  background: linear-gradient(105deg, rgba(255, 236, 210, 0) 20%, rgba(255, 236, 210, 0.18) 50%, rgba(255, 236, 210, 0) 80%);
  transform: translateX(-120%);
  animation: node-card-slot-sheen 3600ms 600ms infinite;
}
.node-card-slot:nth-child(2)::after { animation-delay: 750ms; }
.node-card-slot:nth-child(3)::after { animation-delay: 900ms; }
@keyframes node-card-slot-sheen {
  0% { transform: translateX(-120%); animation-timing-function: cubic-bezier(0.45, 0, 0.2, 1); }
  22%, 100% { transform: translateX(220%); }
}
.node-card-slot-mark {
  position: relative;
  display: block;
  width: 24px;
  max-width: none;
  height: auto;
  opacity: 0.62;
  transition: opacity 160ms ease, transform 160ms ease;
  animation: node-card-slot-breathe 2400ms ease-in-out infinite alternate both;
}
.node-card-slot:nth-child(2) .node-card-slot-mark { animation-delay: 300ms; }
.node-card-slot:nth-child(3) .node-card-slot-mark { animation-delay: 600ms; }
@keyframes node-card-slot-breathe {
  from { filter: brightness(0.82) drop-shadow(0 0 0 rgba(255, 140, 50, 0)); }
  to { filter: brightness(1.12) drop-shadow(0 0 4px rgba(255, 140, 50, 0.45)); }
}

.node-card:hover .node-card-slot::before,
.node-card.is-focused .node-card-slot::before { opacity: 1; }
.node-card:hover .node-card-slot-mark,
.node-card.is-focused .node-card-slot-mark { opacity: 1; transform: scale(1.1); }

.node-card-slot-caption {
  position: absolute;
  top: 100%;
  left: 50%;
  margin-top: 6px;
  transform: translateX(-50%);
  font-size: 11px;
  white-space: nowrap;
  color: var(--text-soft);
}

/* The flop card's footer: the pot's name on the right, a 6-max spot's players on the left. */
.node-card-footer.is-spot {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
  white-space: nowrap;
}

/* The pot's short name (owner 2026-10-21: «Single-raised pot пиши в нижнем правом углу красиво вместо текста как SRP, 3BP, 4BP»): a small
   tag tinted by the pot - limped quiet, a single-raised pot in the brand's orange, a 3-bet pot warmer, a 4-bet pot and beyond red. */
.node-card-pot-tag {
  display: inline-block;
  /* 17px tall, held to the footer's own 13px line, so the FLOP card stays as tall as the turn / river cards */
  margin: -2px 0;
  padding: 1px 7px;
  border: 1px solid rgba(255, 158, 69, 0.3);
  border-radius: 999px;
  background: rgba(255, 158, 69, 0.12);
  font-size: 11px;
  font-weight: 700;
  line-height: 13px;
  letter-spacing: 0.5px;
  color: #ffb46e;
}
.node-card-pot-tag.is-limped {
  border-color: rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-soft);
}
.node-card-pot-tag.is-3bp {
  border-color: rgba(255, 112, 64, 0.34);
  background: rgba(255, 112, 64, 0.14);
  color: #ff9270;
}
.node-card-pot-tag.is-4bp {
  border-color: rgba(247, 52, 63, 0.36);
  background: rgba(247, 52, 63, 0.14);
  color: #ff7a82;
}

.node-card-footer-seats {
  min-width: 0;
  margin-right: auto;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-soft);
}
/* ============================================================================
   Right-hand panels: Actions summary, Hands / Summary / Blockers tabs and the
   per-combo cards.
   ============================================================================ */

.panel-empty {
  font-size: 14px;
  color: var(--text-muted);
}

/* "No strategy for this node" (a node that failed to load): centred in the
   Actions card, about as tall as the row of action tiles it stands in for. */
.panel-empty.is-centered {
  display: grid;
  min-height: 112px;
  place-items: center;
  text-align: center;
}

.panel-placeholder {
  display: grid;
  /* Fills the tab body instead of forcing a height into it: the rail is sized
     by the matrix now, so a panel that insisted on 220px could overflow it. */
  flex: 1;
  min-height: 0;
  place-items: center;
  padding: 16px;
  text-align: center;
}

.panel-placeholder-title {
  font-size: 14px;
  font-weight: 900;
  color: rgba(255, 255, 255, 0.84);
}

.panel-placeholder-text {
  margin-top: 4px;
  max-width: 260px;
  font-size: 12px;
  line-height: 1.55;
  color: var(--text-muted);
}

.panel-message {
  display: grid;
  min-height: 96px;
  place-items: center;
  font-size: 14px;
  color: var(--text-muted);
}

.panel-message.is-error {
  font-weight: 600;
  color: #ff5d5d;
}

/* Same bar as `.details-tabs-bar` and `.toolbar` — see the note there. */
.actions-card > .ui-card-header {
  min-height: 36px;
  gap: 8px;
  border-radius: 6px;
  background: #202020;
  padding: 0 8px;
}

/* An even 4px all round: enough to separate the tiles from the card's border
   without the wide gutter the shared card content had (owner edit 2026-09-21,
   sent from DevTools). */
.actions-card > .ui-card-content {
  padding: 4px;
}

/* ── Actions layouts: calm cards, 2 × 2 cards, one bar (owner 2026-10-05) ─
   The button in front of the title steps through calm → chart → one bar (the
   old tiles and the 2 × 2 cards were removed). Every card is a matrix filter switch; the action colour
   always comes from the shared .action-fill classes (tokens.css), and the
   greys are the site's own --surface-* palette, never a new tint. */
.action-head-meta {
  flex: none;
  margin-left: auto;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
}

/* Sits where the panel icon was: pulled left so the glyph lines up with it. */
.action-layout-switch {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  margin-left: -4px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}

.action-layout-switch:hover {
  border-color: var(--line-strong);
  background: var(--surface-hover);
  color: var(--text-strong);
}

.action-layout-switch:focus-visible {
  outline: 2px solid var(--accent-brand);
  outline-offset: 1px;
}

.action-cards {
  display: grid;
  gap: 8px;
}

/* At most four in a row, as the old tiles were (owner 2026-10-05); narrower
   than 112px a card wraps to the next row instead. */
.action-cards.is-calm {
  grid-template-columns: repeat(auto-fit, minmax(max(112px, calc((100% - 24px) / 4)), 1fr));
}

.action-card,
.action-cell {
  container-type: inline-size;
  position: relative;
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 4px;
  border: none;
  background: var(--surface-rail);
  padding: 12px;
  text-align: left;
  color: var(--text-strong);
  cursor: pointer;
  transition: background 200ms ease, opacity 300ms ease, box-shadow 200ms ease;
}

.action-card {
  overflow: hidden;
  border-radius: 8px;
  box-shadow: inset 0 0 0 1px var(--line);
}

.action-card:hover,
.action-cell:hover {
  background: var(--surface-raised);
}

/* Calm cards are painted in the action colour, like the tiles (owner 2026-10-05:
   no animation; picking works as on the tiles — the chosen card is ringed, the
   others fade). The paint is its own layer so the card keeps the shared
   .action-fill colour classes; the text stays above it. */
.action-card-paint {
  position: absolute;
  inset: 0;
}

.action-cards.is-calm .action-card > :not(.action-card-paint) {
  position: relative;
  z-index: 1;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}

.action-cards.is-calm .action-card-combos {
  color: rgba(255, 255, 255, 0.86);
}

/* On the coloured card the share line is white on a dark groove. */
.action-cards.is-calm .action-card-track {
  background: rgba(0, 0, 0, 0.28);
}

.action-cards.is-calm .action-card-track i {
  background: #ffffff;
}

/* Calm cards are tighter (owner 2026-10-05): 8px top/bottom, the share 25 %
   smaller than the shared clamp (max 24px instead of 32px), combos 12px. */
.action-cards.is-calm .action-card {
  padding-top: 8px;
  padding-bottom: 8px;
}

/* Actions while a node loads (owner 2026-10-19: «заглушка анимированная красивая как в узлах действий только для Actions кнопок»):
   three cards in the strip's approved loading look (.node-card-pending in study-strip.css: dark boxes, lighter lines). One light passes
   over them exactly as over the Hands tiles - the same 1100ms, the same path (owner 2026-10-19: «чтобы время анимации одинаковое было у
   Actions / Hands ... а то екшенс быстрая анимация а хендс медленная»; each card had its own 700ms light) - and so over the last node's
   cards, shown dimmed while the next one loads (.study-right.is-stale). */
/* The real card's box, lines and sizes (DetailsPanels ActionsSkeleton); only its paint differs - the border is the card's own inset
   ring, so not a pixel of height changes. Stand-in text is transparent, each line a bar the width of its text. */
.action-cards.is-calm .action-card.action-card-skeleton {
  /* the strip's loading node card's own (.node-card-pending, owner 2026-10-19: «цвет бекграунда такой, как у узлов карточек действий в
     стади (во время загрузки когда они анимируются скелетоном)»; #252525 was tried before) */
  background: var(--surface-panel);
  box-shadow: inset 0 0 0 1px #484848;
  cursor: default;
}

.action-cards.is-calm .action-card.action-card-skeleton > * {
  color: transparent;
  text-shadow: none;
}

.action-card-skeleton i {
  display: inline-block;
  height: 0.62em;
  overflow: hidden;
  vertical-align: middle;
  border-radius: 3px;
  background: #414141;
  font-style: normal;
}

.action-card-skeleton .action-card-combos i {
  background: #3b3b3b;
}

.action-cards.is-calm .action-card-skeleton .action-card-track {
  background: #3b3b3b;
}

.action-cards.is-loading,
.study-right.is-stale .actions-card > .ui-card-content {
  position: relative;
  overflow: hidden;
}

.action-cards.is-loading::after,
.study-right.is-stale .actions-card > .ui-card-content::after {
  content: "";
  position: absolute;
  z-index: 5;
  top: -10%;
  bottom: -10%;
  left: 0;
  width: 40%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.24), rgba(255, 255, 255, 0.08), transparent);
  transform: translateX(-120%) skewX(-18deg);
  animation: combo-grid-sheen 1100ms ease-in-out infinite;
}

/* The share's size is that of a row of four whatever the number of actions (owner 2026-10-15: «выровняй чтобы в двух случаях шрифт был
   как в случае когда 4 действия, даже если действий 3»): it was 16.5 % of its own card, so three wider cards drew a larger number and a
   taller card. The row is the size container now, and the number reads the width a card has in a row of four (gap 8px, padding 12px). */
.action-cards.is-calm {
  container-type: inline-size;
}

.action-cards.is-calm .action-card {
  container-type: normal;
}

.action-cards.is-calm .action-card-value {
  margin-top: 4px;
  font-size: clamp(15px, calc(((100cqw - 24px) / 4 - 24px) * 0.165), 24px);
}

.action-cards.is-calm .action-card-combos {
  font-size: 12px;
}

/* The chosen action is ringed in the brand orange, 2px, like the node card in view (study-strip.css .node-card.is-focused;
   owner 2026-10-21: «сделай такую же обводку как в наших карточках узлах ... оранжевую»; it was white). */
.action-cards.is-calm .action-card.is-on {
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.12),
    0 0 0 2px var(--accent-brand);
}

.action-card-head {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 8px;
}

.action-card-name {
  overflow: hidden;
  min-width: 0;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  font-weight: 800;
  line-height: 1.2;
  text-transform: capitalize;
}

.action-card-unit {
  margin-left: 4px;
  text-transform: none;
}

.action-card-value {
  margin-top: 6px;
  white-space: nowrap;
  font-size: clamp(20px, 22cqw, 32px);
  font-weight: 900;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}

.action-card-combos {
  white-space: nowrap;
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

.action-card-track {
  display: block;
  height: 6px;
  overflow: hidden;
  border-radius: 3px;
  background: var(--surface-page);
  margin-top: 4px;
}

.action-card-track i {
  display: block;
  height: 100%;
  border-radius: 3px;
  transition: background 300ms ease;
}

/* Frequency columns (owner 2026-10-05): each action a column — dot and name,
   the share, a bar on a shared 0–50–100 % scale, combos underneath. Rows of up
   to four, every row with its own scale on the left. The top block and the
   plot have fixed heights so the scale lines up with every column's plot. */
.action-chart {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-rail);
}

.action-chart-row {
  display: flex;
}

.action-chart-row + .action-chart-row {
  border-top: 1px solid var(--line);
}

.action-chart-axis {
  position: relative;
  flex: none;
  width: 38px;
}

/* 12px column padding + 58px top block + 10px gap = where every plot starts. */
.action-chart-scale {
  position: absolute;
  top: 80px;
  right: 0;
  left: 0;
  height: 96px;
  border-right: 1px solid var(--line-strong);
}

.action-chart-scale i {
  position: absolute;
  right: 6px;
  font-size: 10px;
  font-style: normal;
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  transform: translateY(-50%);
}

.action-chart-scale i:nth-child(1) { top: 0; }
.action-chart-scale i:nth-child(2) { top: 50%; }
.action-chart-scale i:nth-child(3) { top: 100%; }

.action-chart-cols {
  display: grid;
  flex: 1;
  min-width: 0;
}

.action-chart-col {
  container-type: inline-size;
  display: flex;
  min-width: 0;
  flex-direction: column;
  border: none;
  background: transparent;
  padding: 12px 10px;
  text-align: left;
  color: var(--text-strong);
  cursor: pointer;
  transition: background 200ms ease, opacity 300ms ease, box-shadow 200ms ease;
}

.action-chart-col + .action-chart-col {
  box-shadow: inset 1px 0 0 var(--line);
}

.action-chart-col:hover {
  background: var(--surface-raised);
}

.action-chart-top {
  display: flex;
  height: 58px;
  min-width: 0;
  flex-direction: column;
  gap: 8px;
}

.action-chart-col .action-card-value {
  margin-top: 0;
  font-size: 24px;
}

/* Dashed 100 % and 50 % lines, a solid baseline at 0 %. */
.action-chart-plot {
  position: relative;
  display: block;
  height: 96px;
  margin-top: 10px;
  border-bottom: 1px solid var(--line-strong);
  background:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.14) 0 4px, transparent 4px 8px) top / 100% 1px no-repeat,
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.14) 0 4px, transparent 4px 8px) center / 100% 1px no-repeat;
}

.action-chart-plot i {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 50%;
  max-width: 56px;
  border-radius: 3px 3px 0 0;
  transform: translateX(-50%);
}

.action-chart-col .action-card-combos {
  margin-top: 8px;
  font-size: 12px;
  text-align: center;
}

.action-chart-col.is-on {
  box-shadow: inset 0 0 0 2px var(--accent-brand);
}

.action-chart-col.is-off {
  opacity: 0.36;
}

/* One bar: the tall pill on top, then one block of cells split by hairlines. */
.action-barview {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.mix-bar.is-large {
  height: 26px;
  border-radius: 13px;
  margin-top: 0;
}

.mix-bar.is-large i + i {
  box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.35);
}

/* The block clips the grid by 1px on the right and bottom, so every cell can draw
   its own right/bottom hairline and the outer ones vanish under the edge; an
   unfilled last row shows the same grey as the cells. At most four per row. */
.action-cells {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-rail);
}

.action-cells-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(max(112px, calc((100% - 4px) / 4)), 1fr));
  margin: 0 -1px -1px 0;
}

.action-cell {
  box-shadow: inset -1px 0 0 var(--line), inset 0 -1px 0 var(--line);
}

.action-cell-dot {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
}

/* Filter state reads like the tiles: the chosen ones ringed in the brand orange, the rest faded. */
.action-card.is-on,
.action-cell.is-on {
  box-shadow: inset 0 0 0 2px var(--accent-brand);
}

.action-card.is-off,
.action-cell.is-off {
  opacity: 0.36;
}

/* ── active filters, next to the panel title ──────────────────────────── */
/* The title row is 23px from the start — the height a filter chip needs —
   whether or not there is a filter on. Sized by its own content it grew the
   moment one appeared and shrank again when it was cleared, and the whole
   panel twitched with it (owner report 2026-08-17). The chips themselves are
   untouched; only the room they land in is reserved.

   23px is arithmetic, not a guess: the chips below pin their line-height, so a
   chip is 12px x 1.2 + 6px padding + 2px border = 22.4px and Clear is
   11px x 1.2 + 8px padding = 21.2px. Change either and change this. */
.action-title {
  min-height: 23px;
}

.action-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-left: 4px;
}

.action-filter {
  display: flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface-raised);
  padding: 3px 9px;
  font-size: 12px;
  font-weight: 700;
  /* Pinned so the row above can reserve exactly the right height. */
  line-height: 1.2;
  color: var(--text-normal);
  cursor: pointer;
}

.action-filter:hover {
  border-color: #f5f5f5;
}

.action-filter-clear {
  border: none;
  border-radius: 999px;
  background: #e05a52;
  padding: 4px 12px;
  font-size: 11px;
  font-weight: 900;
  line-height: 1.2;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #ffffff;
  cursor: pointer;
}

.action-filter-clear:hover {
  background: #c9483f;
}

/* ── horizontal mix bar ───────────────────────────────────────────────── */
.mix-bar {
  display: flex;
  height: 16px;
  overflow: hidden;
  border-radius: 6px;
  background: var(--surface-raised);
  margin-top: 8px;
}

.mix-bar.is-tight {
  border-radius: 3px;
  margin-top: 0;
}

.mix-bar i {
  display: block;
}

.mix-bar-empty {
  display: block;
  width: 100%;
  background: var(--surface-page);
}

/* ── tabs ─────────────────────────────────────────────────────────────── */
.details-card {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.details-tabs {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
}

/* Both right-hand headers are the matrix toolbar: the same 36px bar, the same
   #202020, the same 6px radius and 0 6px padding, so the three read as one
   strip of controls instead of three different panels (owner request
   2026-09-21). Keep them in step with `.toolbar` in study.css. */
.details-tabs-bar {
  display: flex;
  min-height: 36px;
  align-items: center;
  border-radius: 6px;
  background: #202020;
  padding: 0 6px;
}

.details-tabs-list {
  display: grid;
  width: 100%;
  grid-template-columns: repeat(4, 1fr);
  border: 0;
  background: transparent;
  padding: 0;
}

.details-tab {
  height: 32px;
  border-radius: 6px 6px 0 0;
  font-size: 12px;
}

.details-tabs-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}

/* Radix renders each tab's panel as a plain div; it has to pass the height on
   to the list inside rather than wrap it. */
.details-tabs-body > [role="tabpanel"][data-state="active"] {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}

/* ── action breakdown list ────────────────────────────────────────────── */
.breakdown-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.breakdown-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--line);
  padding-bottom: 6px;
  font-size: 14px;
}

.breakdown-name {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text-soft);
}

.breakdown-swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
}

.breakdown-value {
  color: var(--text-normal);
}

.breakdown-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 12px;
  font-size: 12px;
  color: var(--text-muted);
}

/* ── scrolling tables (summary, blockers) ─────────────────────────────── */
.data-table {
  max-height: calc(100vh - 300px);
  min-height: 220px;
  overflow: auto;
}

.data-table-head {
  position: sticky;
  top: 0;
  z-index: 10;
  display: grid;
  align-items: center;
  gap: 8px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-page);
  padding: 8px 12px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.data-table-head.is-tight {
  gap: 4px;
  font-size: 11px;
}

.data-table-row {
  display: grid;
  align-items: center;
  gap: 8px;
  border-bottom: 1px solid var(--line);
  padding: 6px 12px;
  font-size: 14px;
}

.data-table-row.is-tight {
  gap: 4px;
  padding: 4px 12px;
  font-size: 13px;
}

.data-table-row.is-selected {
  background: #33302a;
}

.data-table-row:hover {
  background: #262626;
}

.cell-right {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-soft);
}

.cell-right.is-strong {
  color: var(--text-normal);
}

.cell-center {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: center;
}

.cell-cards {
  display: flex;
  align-items: center;
  gap: 2px;
}

.cell-cards .card-chip,
.combo-cards .card-chip {
  width: 18px;
  height: 24px;
  font-size: 12px;
}



/* ── combo drill-down list ────────────────────────────────────────────── */
.combo-scroll {
  max-height: 390px;
  overflow: auto;
  padding-right: 4px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.combo-line {
  display: grid;
  grid-template-columns: 54px 54px 1fr;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-panel);
  padding: 6px 8px;
  font-size: 12px;
}

.combo-line-combo { color: var(--text-normal); }
.combo-line-reach { color: var(--text-muted); }

.combo-line-actions {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: right;
  color: rgba(255, 255, 255, 0.68);
}

/* ── hands panel ──────────────────────────────────────────────────────── */
/* GTOWizard-style Hands (owner request 2026-09-28): every combo of the class
   gets a fixed seat and the tiles share the whole panel — no scroll. The line
   font is fitted to the tile in DetailsPanels.tsx (handsFonts); the gap,
   padding and head height below are the numbers it assumes. */
.hands-panel {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.hands-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  padding-top: 6px;
}

/* Its notes («Hands appear when the node loads», «Hover a hand class in the matrix», «The hands could not be loaded») stand in the
   middle of the tab, as Summary's and Blockers' do (owner 2026-10-19: «должен быть в середине окна текст»), not in a 96px band on top. */
.hands-body > .panel-message {
  flex: 1;
  min-height: 0;
  padding: 16px;
  text-align: center;
}

.combo-grid {
  display: grid;
  flex: 1;
  min-height: 0;
  /* No spacing between tiles: the 1px gap shows the black grid background
     as a divider (owner 2026-09-28). */
  gap: 1px;
  overflow: hidden;
  border-radius: 6px;
  background: #000;
}

/* ── one combo tile ───────────────────────────────────────────────────── */
/* A combo in range: its fill rises to its own range, and the part above it is light grey so the dark text stays readable there
   (owner 2026-10-05). A combo not in range keeps the dark .is-dead tile. */
.combo-tile {
  position: relative;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: #b0b0b0;
  padding: 8px;
  color: #1e1e1e;
}

/* Blocked by the board or not in range at this node: the seat stays, only
   the dimmed label is left (GTOWizard's dark tiles). */
.combo-tile.is-dead {
  background: #1d1d1d;
}

.combo-tile.is-dead .combo-label {
  background: #5a5a5a;
  opacity: 0.7;
}

.combo-tile.is-pending {
  background: #8c8c8c;
}

/* Waiting for the hands (owner 2026-10-19: «в нодлокинге у нас очень красивая анимация при загрузке матриц ... такую же красивую
   анимацию ... в блок hands который на странице Study»): one light passes over the tiles, as over the waiting matrices of Compare
   nodes (custom-compare.css .custom-compare-sheen) - while a class's numbers load (.is-pending, the tiles in their seats, the
   values dashed) and while a node loads (its old tiles stand dimmed in .study-right.is-stale). It replaced a pulse of each tile. */
.combo-grid.is-pending,
.study-right.is-stale .combo-grid {
  position: relative;
}

.combo-grid.is-pending::after,
.study-right.is-stale .combo-grid::after {
  content: "";
  position: absolute;
  z-index: 5;
  top: -10%;
  bottom: -10%;
  left: 0;
  width: 40%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.24), rgba(255, 255, 255, 0.08), transparent);
  transform: translateX(-120%) skewX(-18deg);
  animation: combo-grid-sheen 1100ms ease-in-out infinite;
}

@keyframes combo-grid-sheen {
  from { transform: translateX(-120%) skewX(-18deg); }
  to { transform: translateX(300%) skewX(-18deg); }
}

/* No class picked yet while the node loads: twelve blank seats, two quiet lines each where the label and a value go. */
.combo-tile.is-pending.is-blank {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.combo-tile.is-blank > i {
  display: block;
  width: 46%;
  height: 8px;
  border-radius: 2px;
  background: rgba(0, 0, 0, 0.16);
}

.combo-tile.is-blank > i + i {
  width: 30%;
  height: 6px;
}

/* The combo's fill rises from the bottom to its own range on the matrix scale, like .cell-fill / .cell-fill-band in the matrix. */
.combo-tile-fill {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.combo-tile-band {
  display: flex;
  width: 100%;
  min-height: 1px;
  flex-shrink: 0;
}

.combo-tile-band i {
  display: block;
  height: 100%;
}

.combo-tile-content {
  position: relative;
  z-index: 1;
  display: flex;
  height: 100%;
  flex-direction: column;
  justify-content: space-between;
}

/* Pulled out over the tile padding so the card label sits flush in the
   top-left corner (owner 2026-09-28). */
.combo-tile-head {
  display: flex;
  height: 28px;
  flex: none;
  align-items: flex-start;
  gap: 6px;
  margin: -8px -8px 0;
}

.combo-label {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  border-radius: 0 0 5px 0;
  background: #f2f5f8;
  padding: 2px 6px;
  font-size: 15px;
  font-weight: 800;
  line-height: 1.25;
}

/* Blocker badges: a second light pill with two shields and their counts. */
.combo-blockers {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  border-radius: 0 0 5px 5px;
  background: #f2f5f8;
  padding: 2px 6px;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.25;
  color: #1e1e1e;
  font-variant-numeric: tabular-nums;
}

.combo-shield {
  width: 14px;
  height: 16px;
}

.combo-blocker {
  display: inline-flex;
  align-items: center;
  gap: 3px;
}

.combo-blocker + .combo-blocker {
  margin-left: 4px;
}

.combo-shield.is-up { fill: #ef7a3c; }
.combo-shield.is-down { fill: #f3a13c; }

.combo-shield-mark {
  fill: none;
  stroke: #fff;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.combo-label-card.is-spade { color: #2b2f35; }
.combo-label-card.is-heart { color: #c23845; }
.combo-label-card.is-diamond { color: #2879d0; }
.combo-label-card.is-club { color: #1e8a58; }

.combo-tile.is-dead .combo-label-card { color: #d0d0d0; }

.combo-tag {
  margin-left: auto;
  padding: 4px 8px 0 0;
  font-size: 18px;
  font-weight: 600;
  line-height: 1;
  color: #1e1e1e;
}

/* font-size comes from .combo-grid (fitted at runtime); rows inherit it. */
.combo-lines {
  display: flex;
  flex-direction: column;
  font-weight: 400;
  line-height: 1.15;
  color: #1e1e1e;
  font-variant-numeric: tabular-nums;
}

.combo-line-row {
  display: flex;
  justify-content: space-between;
  gap: 8px;
}

.combo-line-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.combo-line-value {
  flex: none;
  font-weight: 400;
  text-align: right;
}

.combo-metric {
  align-self: flex-end;
  font-weight: 400;
  line-height: 1;
  color: #1e1e1e;
  font-variant-numeric: tabular-nums;
}


/* Calm cards hover like the old tiles did: the painted card dims a little. */
.action-cards.is-calm .action-card:not(.is-on):not(:active):hover { filter: brightness(0.78); }
/* Selection takes over immediately, even while the pointer stays on the card. */
.action-cards.is-calm .action-card.is-on,
.action-cards.is-calm .action-card:active {
  filter: brightness(1);
  transition: opacity 300ms ease;
}

/* Takes whatever the rail has left, so the box is the same size whether it
   lists one hand class or the whole node — that is what stopped the page
   jumping when the list switched (owner report 2026-09-13) — and the rail
   itself is the height of the matrix. */
.summary-scroll { flex: 1; min-height: 0; overflow: auto; }
.summary-scroll.is-centered { display: grid; place-items: center; padding: 16px; text-align: center; }
.summary-table { width: 100%; min-width: 430px; border-collapse: collapse; table-layout: fixed; color: var(--text-soft); font-size: 13px; font-variant-numeric: tabular-nums; }
.summary-table th { position: sticky; top: 0; z-index: 1; height: 32px; padding: 4px 8px; background: var(--surface-page); text-align: right; color: var(--text-normal); font-weight: 600; white-space: nowrap; }
.summary-table th:first-child { width: 76px; text-align: left; }
.summary-table th:nth-child(2) { width: 28%; text-align: left; }
.summary-table th button { border: none; padding: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; }
.summary-table td { height: 30px; padding: 0 8px; border-bottom: 1px solid var(--line); text-align: right; }
.summary-table td:first-child { text-align: left; }
.summary-table .summary-strategy { padding: 0; }
.summary-row:hover { background: #191919; }
.summary-row.is-selected { background: #302a22; }
.summary-hand { display: inline-flex; gap: 3px; font-weight: 600; white-space: nowrap; }
.summary-card.is-spade { color: #c5c5c5; }
.summary-card.is-heart { color: #f05252; }
.summary-card.is-diamond { color: #568bff; }
.summary-card.is-club { color: #58b967; }
.summary-mix { display: flex; height: 30px; width: 100%; overflow: hidden; background: #191919; }
.summary-mix i { display: block; height: 100%; }

/* Blockers (owner 2026-10-16: «сделай вкладку блокеров красивее ... колонки большие и шрифт ... большой и хеадер ... стремновато
   выглядит»; then «верни цвета как были в блокерах и столбик cards стремно выглядит»): the cells keep their colour - yellow at 0 mixing to
   green / red (DetailsPanels blockerColor, tokens.css --blocker-*) in a grid, white figures - at the Summary table's size (13 px, 30 px
   rows); each action heads its column with its matrix colour as a dot, the name on up to two lines; the cards are the site's own. */
.blockers-scroll { flex: 1; min-height: 0; overflow: auto; }
.blockers-table {
  width: 100%;
  min-width: 360px;
  border-collapse: collapse;
  table-layout: fixed;
  color: var(--text-soft);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.blockers-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  height: 40px;
  padding: 4px;
  border-bottom: 1px solid var(--line-strong);
  background: var(--surface-page);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.15;
  text-align: center;
  color: var(--text-soft);
}
.blockers-table thead th:first-child { width: 56px; }
.blocker-sort-button {
  display: inline-flex;
  max-width: 100%;
  align-items: center;
  gap: 5px;
  border: none;
  padding: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.blocker-dot { flex: none; width: 8px; height: 8px; border-radius: 2px; }
.blocker-sort-icon { flex: none; margin-left: -2px; }
.blocker-sort-icon.is-idle { opacity: 0.45; }
.blocker-head-text { min-width: 0; text-align: left; }
/* the card in the middle of its column (owner 2026-10-16: «поставь карты по центру») */
.blockers-table tbody th { height: 30px; padding: 0; border-bottom: 1px solid var(--line); background: var(--surface-panel); }
.blockers-table tbody th .playing-card { margin: 0 auto; }
.playing-card--blocker {        /* a Blockers row's card, the site's own */
  --card-width: 19px;
  --card-height: 25px;
}
.blockers-table td { height: 30px; padding: 0; border: 1px solid var(--line-strong); }
.blocker-value {
  display: block;
  width: 100%;
  height: 30px;
  border: none;
  background: var(--blocker-color);
  padding: 0 4px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  cursor: help;
  transition: filter 120ms ease;
}
.blocker-value:hover { filter: brightness(1.08); }
.blocker-value:focus-visible { outline: 2px solid var(--text-strong); outline-offset: -3px; }
/* the look is every hint's (ui.css, «hover hints», owner 2026-10-17) */
.blocker-tooltip { max-width: 320px; }

.table-sort-controls { display: flex; align-items: center; gap: 3px; }
.table-sort-controls select, .table-strategy-sort select { min-width: 0; max-width: 100%; border: none; padding: 0; background: var(--surface-page); color: var(--text-normal); font: inherit; cursor: pointer; }
.table-sort-controls button, .blocker-sort-button { border: none; padding: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; }
.table-strategy-sort { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.table-strategy-sort select { font-size: 11px; color: var(--text-muted); }
.summary-table th:first-child { width: 92px; }
.blocker-sort-button:hover, .summary-table th button:hover { color: var(--accent-brand); }


/* Keep wheel/touch scrolling without visible table scrollbars. */
.summary-scroll,
.blockers-scroll {
  scrollbar-width: none;
}

.summary-scroll::-webkit-scrollbar,
.blockers-scroll::-webkit-scrollbar {
  display: none;
}

/* Blockers follow the matrix: the rows for the two cards the selected hand
   class holds are lit, so the table stops reading as static while the cursor
   moves over the grid (owner request 2026-09-13). Numbers are untouched. */
/* The value buttons paint their own blocker colour over the whole cell, so the
   row is lit by brightening THEM plus an amber edge on the card header — a td
   background would sit behind the button and never show. */
.blockers-row.is-hand-card > th { background: color-mix(in srgb, var(--accent-brand) 14%, var(--surface-panel)); box-shadow: inset 2px 0 0 var(--accent-brand); }
.blockers-row.is-hand-card .blocker-value { filter: brightness(1.3); }
.blockers-row.is-hand-card .blocker-value:hover { filter: brightness(1.42); }
/* ============================================================================
   Board card picker — the full-screen dialog that chooses a flop or a
   turn/river card.
   ============================================================================ */

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.78);
  padding: 32px;
}

/* An open window holds the page under it still (owner 2026-10-16: «в попапах кастом солюшенс, три едит ... при скролле ... моргает
   экран и матрица под попапом и другие данные прорисовываются поверх и моргают»). The windows' backdrops blur nothing any more: a
   backdrop-filter re-samples the page under it every frame, and with a second one under it (a window over the Custom window, the
   matrix's loading veil) and the page's endless loaders, Chrome drew page layers over the window while it scrolled. The page does not
   scroll while a window is open (its scrollbar's place is kept, so nothing moves), and a window's own scroll does not pass on to it
   at its end. Every window here is in the page only while it is open. */
html:has(.modal-backdrop, .custom-backdrop, .news-editor-backdrop) {
  overflow: hidden;
  scrollbar-gutter: stable;
}

:where(.modal-backdrop, .custom-backdrop, .news-editor-backdrop) * {
  overscroll-behavior: contain;
}

/* The board picker (owner 2026-10-16 «сделай как-то этот попап выбора карт красивее»): a titled panel exactly as wide as the deck - thirteen
   34px cards and twelve 6px gaps, 514px, plus 20px of padding either side - so the first slot, the first card of every row and the
   footer share one left edge. Change a card size or a gap and the width has to move with it. */
.modal-panel {
  width: min(554px, calc(100vw - 64px));
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-page);
  padding: 20px;
  box-shadow: 0 28px 90px rgba(0, 0, 0, 0.62);
}

.board-picker {
  animation: board-picker-in 140ms ease-out;
}

@keyframes board-picker-in {
  from { opacity: 0; transform: translateY(6px) scale(0.985); }
  to { opacity: 1; transform: none; }
}

.board-picker-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

.board-picker-title {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-size: 18px;
  font-weight: 900;
  line-height: 24px;
  text-transform: capitalize;
  color: var(--text-strong);
}

.board-picker-count {
  border-radius: 999px;
  background: var(--surface-rail);
  padding: 2px 8px;
  font-size: 12px;
  font-weight: 800;
  line-height: 16px;
  font-variant-numeric: tabular-nums;
  text-transform: none;
  color: var(--text-soft);
}

.board-picker-hint {
  margin: 4px 0 0;
  font-size: 13px;
  line-height: 18px;
  color: var(--text-muted);
}

.board-picker-close {
  width: 32px;
  height: 32px;
  margin: -4px -6px 0 0;
}

.modal-close {
  display: grid;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  place-items: center;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-normal);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.modal-close:hover {
  background: var(--surface-rail);
}

/* ── the board being built ───────────────────────────────────────────── */
.board-picker-board {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 18px;
}

.board-picker-slots {
  display: flex;
  gap: 8px;
}

.board-picker-tools {
  display: flex;
  gap: 6px;
}

.board-picker-tool {
  display: inline-flex;
  height: 32px;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-rail);
  padding: 0 12px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-soft);
  cursor: pointer;
}

.board-picker-tool:hover:not(:disabled) {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.board-picker-tool:disabled {
  opacity: 0.4;
  cursor: default;
}

.picked-slot {
  position: relative;
  display: block;
  width: 48px;
  height: 66px;
  flex-shrink: 0;
  border: none;
  border-radius: 7px;
  background: transparent;
  padding: 0;
  cursor: pointer;
}

/* a picked card: a click takes it back, the cross says so on hover */
.picked-slot-remove {
  position: absolute;
  top: -6px;
  right: -6px;
  display: grid;
  width: 20px;
  height: 20px;
  place-items: center;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface-raised);
  color: var(--text-strong);
  opacity: 0;
  transform: scale(0.8);
  transition: opacity 120ms ease, transform 120ms ease;
}

.picked-slot.is-filled:hover .picked-slot-remove,
.picked-slot.is-filled:focus-visible .picked-slot-remove {
  opacity: 1;
  transform: none;
}

.picked-slot-empty {
  display: grid;
  width: 100%;
  height: 100%;
  place-items: center;
  border: 1px dashed var(--line-strong);
  border-radius: 7px;
  background: var(--surface-panel);
  color: var(--text-muted);
}

/* the slot the next card goes to */
.picked-slot.is-active .picked-slot-empty {
  border: 2px solid var(--accent-brand);
  background: color-mix(in srgb, var(--accent-brand) 10%, transparent);
  color: var(--accent-brand);
}

.picked-slot:focus-visible,
.deck-card:focus-visible,
.board-picker-tool:focus-visible {
  outline: 2px solid var(--accent-brand);
  outline-offset: 2px;
}

/* ── the 4x13 deck ────────────────────────────────────────────────────── */
/* Thirteen fixed 34px columns, the size of a card in the study node strip (owner request 2026-08-17), left-aligned under the slots. */
.deck-grid {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.deck-row {
  display: grid;
  grid-template-columns: repeat(13, 34px);
  justify-content: start;
  gap: 6px;
}

/* Same 34x60 as .playing-card--strip; the slots above stay bigger - they are the board being built. */
.deck-card {
  position: relative;
  width: 34px;
  height: 60px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  padding: 0;
  line-height: 1;
  cursor: pointer;
}

/* A light wash laid OVER the card, not a lift: the row used to hop under the cursor while picking, which made a 52-card grid tiring to
   aim at (owner report 2026-08-17). */
.deck-card::after {
  content: "";
  pointer-events: none;
  position: absolute;
  inset: 0;
  border-radius: var(--card-radius, 6px);
  background: var(--text-strong);
  opacity: 0;
  transition: opacity 120ms ease;
}

.deck-card:hover:not(:disabled)::after {
  opacity: 0.18;
}

.deck-card:disabled {
  cursor: default;
}

/* a card this board already took: still there, faded */
.deck-card.is-taken .playing-card {
  opacity: 0.22;
  filter: grayscale(0.6);
}

/* a card the line already holds (an earlier street): a quiet outline */
.deck-card-unavailable {
  display: block;
  width: 100%;
  height: 100%;
  border: 1px dashed var(--line-strong);
  border-radius: 6px;
  opacity: 0.55;
}

/* ── footer ───────────────────────────────────────────────────────────── */
.board-picker-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 20px;
  border-top: 1px solid var(--line);
  padding-top: 16px;
}

.board-picker-note {
  font-size: 12px;
  color: var(--text-muted);
}

.modal-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.modal-button {
  height: 40px;
  padding: 0 20px;
}

/* White, not the near-black --text-on-accent: on this orange the default token reads as a black label with a black tick (owner report
   2026-08-17). */
.modal-button.is-confirm {
  min-width: 140px;
  gap: 8px;
  color: var(--text-on-brand);
}

/* ── persisted sizing explanation ───────────────────────────────────── */
.sizing-explanation {
  width: min(700px, calc(100vw - 48px));
  max-height: calc(100vh - 48px);
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-page);
  box-shadow: 0 28px 90px rgba(0, 0, 0, 0.62);
}

.sizing-explanation-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  border-bottom: 1px solid var(--line);
  padding: 20px 22px 16px;
}

.sizing-explanation-head h2 {
  margin: 2px 0 0;
  font-size: 22px;
  font-weight: 800;
  color: var(--text-strong);
}

.sizing-explanation-kicker {
  margin: 0;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--brand);
}

.sizing-explanation-state {
  display: flex;
  min-height: 220px;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 30px;
  font-size: 15px;
  color: var(--text-muted);
}

.sizing-explanation-state.is-error {
  color: var(--danger);
}

.sizing-explanation-body {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 20px 22px 22px;
}

.sizing-explanation-context {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: capitalize;
}

.sizing-explanation-comparison {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.sizing-candidate {
  display: flex;
  min-height: 116px;
  flex-direction: column;
  justify-content: center;
  gap: 7px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-rail);
  padding: 16px;
}

.sizing-candidate.is-selected {
  border-color: var(--brand);
  background: color-mix(in srgb, var(--brand) 10%, var(--surface-rail));
}

.sizing-candidate > span,
.sizing-candidate > small {
  font-size: 12px;
  color: var(--text-muted);
}

.sizing-candidate > strong {
  font-size: 20px;
  font-weight: 800;
  color: var(--text-strong);
}

.sizing-explanation-gap {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 16px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px 14px;
  font-size: 13px;
  color: var(--text-normal);
}

.sizing-explanation-gap strong {
  grid-column: 2;
  grid-row: 1 / 3;
  align-self: center;
  font-size: 18px;
  color: var(--text-strong);
}

.sizing-explanation-gap small {
  color: var(--text-muted);
}

.sizing-explanation-reason {
  margin: 0;
  border-left: 3px solid var(--brand);
  padding: 4px 0 4px 13px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-normal);
}

.sizing-explanation-table {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
}

.sizing-explanation-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 16px;
  min-height: 42px;
  border-top: 1px solid var(--line);
  padding: 8px 12px;
  font-size: 13px;
}

.sizing-explanation-row:first-child {
  border-top: 0;
}

.sizing-explanation-row.is-head {
  min-height: 36px;
  background: var(--surface-rail);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.sizing-explanation-row em {
  margin-left: 8px;
  border-radius: 999px;
  background: var(--brand);
  padding: 2px 7px;
  font-size: 10px;
  font-style: normal;
  font-weight: 800;
  color: var(--text-on-brand);
}

.sizing-explanation-row strong {
  color: var(--text-strong);
}

.sizing-explanation-note {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 12px;
  color: var(--text-muted);
}

@media (max-width: 620px) {
  .sizing-explanation-comparison {
    grid-template-columns: 1fr;
  }

  .sizing-explanation-context {
    flex-direction: column;
    gap: 4px;
  }
}
/* ============================================================================
   Appearance panel — tuning how the playing cards are drawn. Three columns:
   what the card is made of, what each suit does, and what it all looks like.
   Reuses .modal-backdrop / .modal-close from study-modal.css.
   ============================================================================ */

.appearance-panel {
  display: flex;
  width: min(1180px, 96vw);
  max-height: 90vh;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  background: var(--surface-panel);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
}

.appearance-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--line);
  padding: 14px 16px;
}

.appearance-title {
  font-size: 16px;
  font-weight: 900;
  color: var(--text-normal);
}

.appearance-body {
  display: grid;
  grid-template-columns: 260px 300px minmax(280px, 1fr);
  gap: 14px;
  overflow-y: auto;
  padding: 14px 16px 16px;
}

@media (max-width: 1100px) {
  .appearance-body {
    grid-template-columns: 1fr;
  }
}

.appearance-column {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 12px;
}

.appearance-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-page);
  padding: 12px;
}

.appearance-section-title {
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ── Colored / Blank ──────────────────────────────────────────────────── */
.appearance-toggle {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 3px;
}

.appearance-toggle-option {
  height: 28px;
  border: none;
  border-radius: 6px;
  background: transparent;
  font-size: 12px;
  font-weight: 800;
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.appearance-toggle-option:hover {
  background: #404040;
}

.appearance-toggle-option.is-on {
  background: var(--surface-raised);
  color: var(--accent-brand);
}

/* ── one labelled control ─────────────────────────────────────────────────
   Three columns so every row lines up down the panel: what it is, the control,
   and what it currently reads. */
.knob {
  display: grid;
  grid-template-columns: 78px 1fr 48px;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-soft);
}

.knob-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.knob-value {
  text-align: right;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

.knob-range {
  width: 100%;
  height: 4px;
  appearance: none;
  border-radius: 999px;
  background: var(--surface-raised);
  cursor: pointer;
}

.knob-range::-webkit-slider-thumb {
  appearance: none;
  width: 14px;
  height: 14px;
  border: none;
  border-radius: 999px;
  background: var(--accent-brand);
  cursor: pointer;
}

.knob-range::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border: none;
  border-radius: 999px;
  background: var(--accent-brand);
  cursor: pointer;
}

.appearance-select,
.appearance-input {
  width: 100%;
  height: 26px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-panel);
  padding: 0 8px;
  font-size: 12px;
  color: var(--text-normal);
  outline: none;
}

.appearance-color {
  width: 100%;
  height: 26px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-panel);
  padding: 2px;
  cursor: pointer;
}

.appearance-color:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* The "back to automatic" affordance next to a colour: it has to read as an
   action AND as the current state, so it says which one is in force. */
.knob-clear {
  border: none;
  border-radius: 4px;
  background: transparent;
  padding: 0;
  text-align: right;
  font-size: 10px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
}

.knob-clear:hover {
  color: var(--accent-brand);
}

.appearance-check {
  width: 16px;
  height: 16px;
  accent-color: var(--accent-brand);
  cursor: pointer;
}

/* ── per-suit block ───────────────────────────────────────────────────── */
.suit-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  border-top: 1px solid var(--line);
  padding-top: 8px;
}

.suit-row:first-of-type {
  border-top: none;
  padding-top: 0;
}

.suit-row-head {
  display: grid;
  grid-template-columns: 20px 1fr 48px;
  align-items: center;
  gap: 8px;
}

.suit-row-glyph {
  font-size: 16px;
  line-height: 1;
}

.suit-row-name {
  font-size: 12px;
  font-weight: 800;
  color: var(--text-normal);
}

/* ── suit set chooser ─────────────────────────────────────────────────── */
.suit-sets {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}

.suit-set {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 8px;
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.suit-set:hover {
  background: #404040;
}

.suit-set.is-on {
  border-color: var(--accent-brand);
  background: var(--surface-raised);
}

.suit-set-name {
  font-size: 11px;
  font-weight: 800;
  color: var(--text-soft);
}

.suit-set.is-on .suit-set-name {
  color: var(--accent-brand);
}

.suit-set-sample {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 16px;
  line-height: 1;
  color: var(--text-normal);
}

.suit-set-glyph {
  font-style: normal;
}

/* Drawn samples are the same masks the cards use, at chooser size. */
.suit-set-glyph.is-drawn {
  display: block;
  width: 16px;
  height: 16px;
  background: var(--text-normal);
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/* ── preview ──────────────────────────────────────────────────────────── */
.appearance-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  border-radius: 8px;
  background: #1d1d1d;
  padding: 14px 10px;
}

.appearance-preview-row {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

/* ── the CSS it comes down to ─────────────────────────────────────────── */
/* Fixed, not max-height: the block grows a line every time a knob leaves its
   default, and a growing block moved the whole panel under the cursor (owner
   report 2026-08-17). It scrolls instead. */
.appearance-css {
  height: 190px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-panel);
  padding: 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  line-height: 1.5;
  white-space: pre;
  color: var(--text-soft);
}

.appearance-actions {
  display: flex;
  gap: 8px;
}

.appearance-button {
  display: flex;
  flex: 1;
  height: 32px;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: none;
  border-radius: 6px;
  background: var(--accent-brand);
  font-size: 12px;
  font-weight: 900;
  color: var(--text-on-accent);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.appearance-button:hover {
  background: var(--accent-brand-hover);
}

.appearance-button.is-reset {
  background: var(--surface-raised);
  color: var(--text-normal);
}

.appearance-button.is-reset:hover {
  background: #404040;
}
.auth-page {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--surface-page);
}
.auth-card {
  width: 420px;
  max-width: 100%;
  padding: 36px;
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  background: var(--surface-panel);
  color: var(--text-strong);
  text-align: center;
}
.auth-logo { display: flex; justify-content: center; gap: 12px; margin: 0 auto 28px; }
.auth-logo .brand-logo-mark { height: 44px; }
.auth-logo .brand-logo-word { height: 32px; }
.auth-card h1 { margin: 0 0 12px; font-size: 24px; font-weight: 700; }
.auth-card p { margin: 12px 0; font-size: 14px; line-height: 1.5; }
.auth-google-button {
  width: 100%;
  height: 44px;
  margin: 20px 0 8px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--text-strong);
  color: var(--surface-page);
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}
.auth-google-button:hover { opacity: 0.9; }
/* the 18+ confirmation and the Terms / Privacy links under the Google button (owner 2026-10-20; the card's foot of the four documents is
   gone, owner 2026-10-21) */
.auth-card .auth-legal { margin: 4px 0 12px; font-size: 12px; line-height: 1.5; color: var(--text-dim); }
.auth-card a { color: var(--accent-brand); font-weight: 600; text-decoration: none; }
.auth-card a:hover { text-decoration: underline; }
.auth-error { color: var(--grade-bad); }
.sidebar-account {
  flex-shrink: 0;
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--line-strong);
}
.sidebar-account-row { display: flex; align-items: center; gap: 4px; }
/* The avatar and the name are one button to Settings (owner 2026-10-17): a hover wash over the row and the gear; Sign out keeps its own
   button beside it. */
.sidebar-account-open {
  display: flex;
  min-width: 0;
  flex: 1;
  align-items: center;
  gap: 10px;
  border: none;
  border-radius: 8px;
  background: transparent;
  margin-left: -6px;
  padding: 4px 6px;
  text-align: left;
  color: inherit;
  cursor: pointer;
  transition: background-color 120ms ease;
}
.sidebar-account-open:hover,
.sidebar-account-open:focus-visible { background: var(--surface-hover); outline: none; }
/* The gear (owner 2026-10-17: «колесико настроек в футере сайдбара с другой анимацией сделай, и она должна быть одна и в практис и в
   стади»): always in its place and dim; with the pointer on the row it turns two teeth round with a small overshoot and lights up, and
   turns back when the pointer leaves. Both sidebars show this one SidebarAccount (AuthGate.tsx), so Study and Practice move it the same
   way. Only transform and opacity move (frontend_rules 5b.3); the gear has six teeth, so 120deg ends on the same outline. */
.sidebar-account-gear {
  flex-shrink: 0;
  color: var(--text-strong);
  opacity: 0.55;
  transition: opacity 200ms ease, transform 600ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.sidebar-account-open:hover .sidebar-account-gear,
.sidebar-account-open:focus-visible .sidebar-account-gear {
  opacity: 1;
  transform: rotate(120deg);
}
.sidebar-account-avatar {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  overflow: hidden;
  border-radius: 50%;
  background: var(--surface-panel);
  color: var(--accent-brand);
  font-size: 16px;
  font-weight: 700;
}
.sidebar-account-avatar img { width: 100%; height: 100%; object-fit: cover; }
.sidebar-account-info { min-width: 0; flex: 1; }
.sidebar-account-info strong,
.sidebar-account-info span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar-account-info strong { color: var(--text-strong); font-size: 13px; }
.sidebar-account-info span { margin-top: 3px; color: var(--text-muted); font-size: 11px; }
.sidebar-account-logout {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}
.sidebar-account-logout:hover { background: var(--surface-hover); color: var(--text-strong); }
.sidebar-account-logout:disabled { opacity: 0.5; cursor: wait; }
.sidebar-account .auth-error { margin: 8px 0 0; font-size: 12px; }

/* A page file that did not arrive (owner 2026-10-19, app/pages.tsx): «This page could not be loaded. Reload». */
.auth-reload {
  margin-left: 8px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: transparent;
  padding: 4px 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
}
.auth-reload:hover { background: var(--surface-rail); }

/* The app's error boundary (owner 2026-10-20, components/ErrorBoundary.tsx): a calm card with Reload where the page stopped. */
.app-crash {
  width: 420px;
  max-width: 100%;
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  background: var(--surface-panel);
  padding: 32px;
  text-align: center;
  color: var(--text-normal);
  animation: app-crash-in 240ms cubic-bezier(0.2, 0, 0, 1) both;
}
.app-crash h1 { margin: 0 0 10px; font-size: 20px; font-weight: 700; color: var(--text-strong); }
.app-crash p { margin: 0 0 22px; font-size: 14px; line-height: 1.5; color: var(--text-dim); }
.app-crash-reload {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  border: none;
  border-radius: 8px;
  background: var(--accent-brand);
  padding: 0 18px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-on-brand);
  cursor: pointer;
}
.app-crash-reload:hover { background: var(--accent-brand-hover); }
@keyframes app-crash-in {
  from { opacity: 0; transform: translateY(8px); }
}
.solutions-backdrop { position: fixed; inset: 0; z-index: 100; display: grid; place-items: center; padding: 28px; background: #000a; }
/* owner 2026-10-14 («слишком большой по ширине ... поубирать лишние места ... компактнее»): 860px wide and dense; one fixed height
   (owner 2026-10-14: no jumps) - the header and filters stay put and only the list scrolls. */
.solutions-library { display: flex; width: 860px; max-width: 100%; height: calc(100vh - 80px); max-height: 660px; flex-direction: column; overflow: hidden; border: 1px solid var(--line-strong); border-radius: 14px; background: #1d1d1d; color: var(--text-normal); box-shadow: 0 20px 80px #0009; }
.solutions-loading.is-first { margin: auto; padding: 0; }
/* the header: the title, the tabs in the middle, the close button */
.solutions-header { display: grid; flex-shrink: 0; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 12px; padding: 10px 12px 10px 18px; border-bottom: 1px solid var(--line); background: #171717; }
.solutions-header h2 { display: flex; align-items: center; gap: 10px; margin: 0; color: var(--text-strong); font-size: 16px; font-weight: 700; white-space: nowrap; }
.solutions-header h2 svg { color: var(--accent-brand); }
.solutions-close { display: grid; justify-self: end; place-items: center; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--text-soft); cursor: pointer; }
.solutions-close:hover { background: var(--surface-hover); color: var(--text-strong); }
/* the tabs: one segmented control, a pill slides under the picked tab (transform only, frontend_rules 5b.3) */
.solutions-tabs { position: relative; display: grid; grid-template-columns: 1fr 1fr; padding: 3px; border: 1px solid var(--line); border-radius: 10px; background: #262626; }
/* the picked tab in the brand colour, as the picked filter value (owner 2026-10-14) */
.solutions-tabs-pill { position: absolute; top: 3px; bottom: 3px; left: 3px; width: calc(50% - 3px); border-radius: 7px; background: color-mix(in srgb, var(--accent-brand) 17%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-brand) 45%, transparent); transition: transform 260ms cubic-bezier(0.25, 0.8, 0.25, 1); }
.solutions-tabs.is-custom .solutions-tabs-pill { transform: translateX(100%); }
.solutions-tab { position: relative; z-index: 1; min-width: 128px; border: none; border-radius: 7px; padding: 5px 12px; background: transparent; color: var(--text-muted); font-size: 13px; font-weight: 700; cursor: pointer; transition: color 200ms ease; }
.solutions-tab:hover { color: var(--text-strong); }
.solutions-tab.is-active { color: var(--accent-brand); }
/* the body: filters in three rows (players / postflop, the stacks, rake and opening size), then the list */
.solutions-body { display: flex; flex: 1; min-height: 0; flex-direction: column; gap: 12px; padding: 14px 18px 0; }
.solutions-filters { display: flex; flex-shrink: 0; flex-wrap: wrap; align-items: flex-start; gap: 10px 18px; }
.solution-filter { min-width: 0; margin: 0; padding: 0; border: none; }
.solution-filter.is-stack { flex-basis: 100%; }
.solution-filter legend { display: flex; align-items: center; gap: 4px; margin-bottom: 5px; padding: 0; color: var(--text-muted); font-size: 11px; font-weight: 700; letter-spacing: 0.8px; text-transform: uppercase; }
.solutions-results { display: flex; flex: 1; min-width: 0; min-height: 0; flex-direction: column; gap: 6px; padding-top: 10px; border-top: 1px solid var(--line); }
/* The rake schedule (owner 2026-10-13): an info icon next to Rake opens what each NL level means in % and cap. */
.solution-filter-help { position: relative; display: inline-flex; }
.solution-filter-info { display: grid; place-items: center; width: 18px; height: 18px; border: none; border-radius: 50%; padding: 0; background: transparent; color: var(--text-muted); cursor: pointer; }
.solution-filter-info:hover, .solution-filter-info.is-open { background: #383838; color: var(--text-strong); }
.rake-levels { position: absolute; top: 26px; left: -10px; z-index: 5; width: 280px; padding: 12px 14px 14px; border: 1px solid var(--line-strong); border-radius: 10px; background: #232323; box-shadow: 0 14px 40px #000a; color: var(--text-normal); font-size: 13px; }
.rake-levels-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; color: var(--text-strong); font-size: 14px; font-weight: 600; }
.rake-levels-close { display: grid; place-items: center; width: 24px; height: 24px; border: none; border-radius: 5px; padding: 0; background: transparent; color: var(--text-muted); cursor: pointer; }
.rake-levels-close:hover { background: #383838; color: var(--text-strong); }
.rake-levels table { width: 100%; border-collapse: collapse; }
.rake-levels th { padding: 0 0 6px; border-bottom: 1px solid var(--line); color: var(--text-soft); font-size: 11px; font-weight: 600; text-align: left; }
.rake-levels td { padding: 6px 0; border-bottom: 1px solid #2e2e2e; }
.rake-levels tr:last-child td { border-bottom: none; }
.rake-levels td:first-child { color: var(--text-strong); font-weight: 600; }
.rake-levels-note { margin: 10px 0 0; color: var(--text-muted); font-size: 12px; line-height: 1.45; }
/* the filter buttons: one framed group per filter, the picked value in the brand colour */
/* the group's radius = the button's 6px + its 1px border: a flush end button then follows the frame's curve exactly (owner 2026-10-14:
   with 9px the frame clipped the corner of a picked end button and its amber ring looked cut and dark) */
.solution-filter-options { display: flex; flex-wrap: wrap; gap: 2px; width: fit-content; max-width: 100%; padding: 0; overflow: hidden; border: 1px solid var(--line); border-radius: 7px; background: #262626; }
.solution-filter-button { height: 30px; border: none; border-radius: 6px; padding: 0 7px; background: transparent; color: var(--text-dim); font-size: 13px; font-weight: 400; white-space: nowrap; cursor: pointer; transition: background-color 120ms ease, color 120ms ease; }
.solution-filter-button:hover { background: #333; color: var(--text-strong); }
.solution-filter-button.is-selected { background: color-mix(in srgb, var(--accent-brand) 17%, transparent); color: var(--accent-brand); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-brand) 45%, transparent); font-weight: 600; }
/* owner 2026-10-17 («если кнопка выделена (выбрана) то чтоб шрифт был жирный»): the picked value is bold; each label keeps room for its bold
   self (an invisible bold copy under it, height 0), so the buttons beside it do not move when a value is picked */
.solution-filter-text { display: inline-grid; }
.solution-filter-text::after { content: attr(data-text); height: 0; overflow: hidden; visibility: hidden; font-weight: 600; pointer-events: none; user-select: none; }
.solutions-list-heading { display: flex; justify-content: space-between; gap: 12px; color: var(--text-muted); font-size: 11px; font-weight: 700; letter-spacing: 0.8px; text-transform: uppercase; }
.solutions-list { flex: 1; min-width: 0; min-height: 0; overflow: auto; padding-bottom: 14px; }
.solution-row-head, .solution-row { display: grid; grid-template-columns: 58px 66px 48px 40px 68px 118px minmax(0, 1fr); align-items: center; gap: 8px; min-width: 640px; width: 100%; padding: 8px 10px; text-align: left; }
.solution-row-head, .custom-solve-row-head { position: sticky; z-index: 1; top: 0; background: #1d1d1d; }
.solution-row-head { color: var(--text-muted); font-size: 11px; font-weight: 700; }
/* owner 2026-10-15: each column's name sorts the list; the sorted one is bright with its direction arrow */
.solution-sort { display: inline-flex; align-items: center; gap: 3px; min-width: 0; padding: 0; border: none; background: none; color: inherit; font: inherit; text-align: left; white-space: nowrap; cursor: pointer; }
.solution-sort > span { overflow: hidden; text-overflow: ellipsis; }
.solution-sort > svg { flex-shrink: 0; }
.solution-sort:hover, .solution-sort.is-sorted { color: var(--text-strong); }
.solution-sort:focus-visible { outline: 1px solid var(--accent-brand); outline-offset: 2px; border-radius: 3px; }
.solution-row { height: 40px; padding: 4px 10px; line-height: 15px; margin-bottom: 4px; border: none; border-radius: 7px; background: #2a2a2a; color: var(--text-normal); font-size: 12px; cursor: pointer; transition: background-color 150ms ease; }
.solution-row > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.solution-row:hover { background: #383838; }
.solution-row.is-selected { background: linear-gradient(90deg, rgba(255,158,69,.34), rgba(255,158,69,.14)); color: var(--text-strong); box-shadow: inset 2px 0 0 var(--accent-brand); }
.solution-row small { display: block; margin-top: 2px; color: var(--text-muted); font-size: 11px; }
.solution-availability { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.solution-name { min-width: 0; }
.solution-name strong { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.solution-name small { margin-top: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.solution-availability > svg { flex-shrink: 0; }
.solutions-empty { padding: 30px 12px; color: var(--text-muted); font-size: 14px; }
.solutions-empty button { display: block; margin-top: 12px; border: none; padding: 0; background: transparent; color: var(--accent-brand); font-size: 13px; cursor: pointer; }
.solutions-results.is-custom { padding-top: 0; border-top: none; }
.solutions-loading { margin: 0; padding: 24px 12px; color: var(--text-muted); font-size: 14px; }
.custom-solve-row-head, .custom-solve-row { display: grid; grid-template-columns: 110px 100px 120px minmax(150px, 1.4fr) minmax(130px, 1fr) 32px; align-items: center; gap: 10px; min-width: 650px; width: 100%; text-align: left; }
.custom-solve-row-head { padding: 8px 10px; color: var(--text-muted); font-size: 11px; font-weight: 700; }
.custom-solve-row { min-height: 40px; margin-bottom: 4px; padding: 6px 10px; border-radius: 6px; background: #2c2c2c; color: var(--text-normal); font-size: 12px; line-height: 16px; cursor: pointer; transition: background-color 150ms ease; }
.custom-solve-row:hover, .custom-solve-row:focus-visible { background: #383838; outline: none; }
.custom-solve-row.is-unavailable { cursor: default; color: var(--text-muted); }
.custom-solve-board { color: var(--text-strong); font-weight: 600; letter-spacing: 1px; }
.custom-solve-engine small { display: block; margin-top: 2px; color: var(--text-muted); font-size: 11px; }
.custom-solve-settings { display: flex; align-items: center; justify-content: center; width: 28px; height: 28px; border: none; border-radius: 5px; padding: 0; background: transparent; color: var(--text-muted); cursor: pointer; }
.custom-solve-settings:hover, .custom-solve-settings:focus-visible { background: #484848; color: var(--text-strong); outline: none; }
@media (max-width: 760px) { .solutions-filters { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; } .solutions-backdrop { padding: 12px; } .solutions-library { max-height: calc(100vh - 24px); } }
@media (max-width: 480px) { .solutions-filters { grid-template-columns: 1fr; } }

.solutions-error { margin: 0; color: var(--text-muted); font-size: 13px; }

.solution-limp { display: flex; align-items: center; color: var(--text-strong); }
.solutions-close svg { width: 20px; height: 20px; }
.run-page { min-height: 100vh; background: #17191d; color: #e8eaf0; padding: 24px 32px; font-size: 14px; }
.run-header { display: flex; align-items: center; justify-content: space-between; padding-bottom: 24px; border-bottom: 1px solid #34373e; }
.run-header > div { display: flex; align-items: baseline; gap: 22px; }
.run-header h1 { font-size: 22px; margin: 0; }
.run-header span, .run-title p, .run-library-note { color: #939baa; }
.run-header a { color: #c5cbd6; text-decoration: none; }
.run-brand { font-weight: 800; letter-spacing: 2px; }
.run-workspace { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 28px; max-width: 1550px; margin: 28px auto; }
.run-library { background: #202329; border-radius: 10px; align-self: start; overflow: hidden; }
.run-section-title { display: flex; align-items: center; justify-content: space-between; font-weight: 600; padding: 16px; }
.run-section-title span { font-size: 12px; font-weight: 400; color: #939baa; }
.run-solution { display: flex; flex-direction: column; gap: 7px; width: 100%; border: 0; background: transparent; padding: 16px; text-align: left; color: #dddfe7; cursor: pointer; }
.run-solution:hover { background: #404040; }
.run-solution.is-selected { background: linear-gradient(90deg, rgba(255,158,69,.34), rgba(255,158,69,.14)); box-shadow: inset 2px 0 0 var(--accent-brand); color: var(--text-strong); }
.run-solution span { font-size: 12px; color: #c7cbd4; }
.run-solution small { color: #929baa; }
.run-library-note { margin: 20px 16px; font-size: 12px; line-height: 1.7; }
.run-title { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.run-title h2 { font-size: 22px; margin: 0 0 8px; }
.run-title p { margin: 0; font-size: 13px; }
.run-badge { padding: 7px 12px; border-radius: 18px; background: #26392f; color: #97d4ab; white-space: nowrap; font-size: 12px; }
.run-stages { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(140px,1fr); margin: 26px 0; border: 1px solid #393d45; border-radius: 10px; overflow-x: auto; }
.run-stage { display: grid; grid-template-columns: 26px 1fr; gap: 6px 9px; padding: 16px 12px; border-right: 1px solid #393d45; color: #929baa; }
.run-stage:last-child { border-right: none; }
.run-stage strong { font-size: 12px; align-self: center; }
.run-stage small { grid-column: 2; font-size: 11px; }
.run-stage-number { display: grid; place-items: center; width: 25px; height: 25px; border-radius: 50%; background: #30353f; font-size: 12px; }
.run-stage.is-done { color: #b3d8bf; background: #202b25; }
.run-stage.is-done .run-stage-number { background: #355840; }
.run-stage.is-partial { color: #e9c18c; }
.run-metrics { display: grid; grid-template-columns: repeat(4,1fr); gap: 12px; }
.run-metrics > div { padding: 16px; border-radius: 8px; background: #22252b; }
.run-metrics span { display: block; color: #929baa; margin-bottom: 10px; font-size: 12px; }
.run-metrics strong { font-size: 23px; }
.run-metrics small { font-size: 13px; font-weight: 400; color: #929baa; }
.run-controls { margin-top: 22px; background: #22252b; border-radius: 10px; padding: 4px 4px 12px; }
.run-fields { display: grid; grid-template-columns: 130px 190px 150px 1fr; gap: 14px; align-items: end; padding: 0 16px; }
.run-fields label { color: #a4acb9; font-size: 12px; display: flex; flex-direction: column; gap: 8px; }
.run-fields input, .run-fields select { width: 100%; height: 36px; border: 1px solid #454b56; background: #191c22; color: #eee; padding: 0 10px; border-radius: 6px; font-size: 13px; }
.run-continue { justify-self: end; height: 36px; padding: 0 22px; border: 0; border-radius: 6px; background: #c7853d; color: #161616; font-weight: 600; }
.run-continue:disabled { opacity: .45; cursor: not-allowed; }
.run-controls p { padding: 0 16px; color: #949dab; font-size: 12px; margin: 14px 0 0; }
.run-controls .run-hold { color: #d1b387; }
.run-files { padding: 18px 0; color: #aab2bf; }
.run-files summary { cursor: pointer; }
.run-files dl { background: #202329; padding: 16px; border-radius: 8px; font-size: 12px; }
.run-files dt { color: #919bad; margin-top: 12px; }
.run-files dd { margin: 5px 0; overflow-wrap: anywhere; font-family: monospace; color: #ccd2dc; }
.run-console { border: 1px solid #343941; border-radius: 10px; overflow: hidden; }
.run-console pre { background: #121519; margin: 0; padding: 20px; color: #a7b5c6; font-size: 12px; line-height: 1.9; min-height: 130px; white-space: pre-wrap; }
.run-error { background: #4a272a; padding: 16px; border-radius: 8px; }
.run-loading { color: #939baa; }
@media (max-width: 1050px) { .run-page { padding: 18px; } .run-workspace { grid-template-columns: 210px minmax(0,1fr); gap: 18px; } .run-fields { grid-template-columns: repeat(2, minmax(0,1fr)); } .run-metrics { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) { .run-workspace { grid-template-columns: 1fr; } .run-header span { display: none; } .run-title { align-items: start; flex-direction: column; } }
.run-control-buttons { display: flex; justify-content: end; gap: 8px; }
.run-prepare { height: 36px; border: 1px solid #596170; border-radius: 6px; padding: 0 12px; color: #dbe2ed; background: #303741; cursor: pointer; }
.run-prepare:disabled { opacity: .5; cursor: wait; }
.run-fleet { max-width: 1550px; margin: 28px auto 0; background: #202329; border-radius: 10px; }
.run-section-title .run-fleet-heading { display: flex; align-items: center; gap: 9px; color: #e8eaf0; font-size: 14px; font-weight: 600; }
.run-fleet-heading i { width: 6px; height: 6px; background: #6ba980; border-radius: 50%; }
.run-fleet-heading i.is-stale { background: #d7a667; }
.run-fleet-summary { display: flex; align-items: baseline; gap: 25px; padding: 0 16px 16px; }
.run-fleet-summary strong { font-size: 21px; }
.run-fleet-summary small, .run-fleet-summary > span { font-size: 12px; color: #929baa; font-weight: 400; }
.run-fleet-summary > span { margin-left: auto; }
.run-fleet-empty { padding: 26px 16px; text-align: center; border-top: 1px solid #343942; color: #aeb7c5; }
.run-fleet-empty span { display: block; margin-top: 7px; font-size: 12px; color: #8590a1; }
.run-fleet-error { padding: 0 16px 12px; color: #d7a667; font-size: 12px; }
/* A task group's head folds and unfolds its servers (owner 2026-10-20, RunFleet.tsx readFoldedTasks): the whole line is the button,
   the chevron points right while folded and down while open. */
.run-fleet-group-head { display: flex; width: 100%; align-items: center; gap: 8px; border: none; background: transparent; padding: 4px 16px 8px;
  font-size: 13px; text-align: left; color: inherit; cursor: pointer; }
.run-fleet-group-head strong { min-width: 0; color: #e7ebf0; font-family: monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.run-fleet-group-head span { flex: none; color: #8993a1; font-size: 11px; }
.run-fleet-group-head:hover strong { color: #ffffff; }
.run-fleet-group-head:hover .run-fleet-group-chevron { color: #e7ebf0; }
.run-fleet-group-head:focus-visible { outline: 2px solid #6b8fd6; outline-offset: -2px; border-radius: 6px; }
.run-fleet-group-chevron { flex: none; color: #8993a1; transform: rotate(90deg); transition: transform 160ms ease; }
.run-fleet-group.is-folded .run-fleet-group-chevron { transform: none; }
.run-fleet-group.is-folded .run-fleet-group-head { padding-bottom: 12px; }
.run-fleet-hosts { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; padding: 0 16px 16px; }
.run-host { padding: 12px; background: #191c21; border: 1px solid #363c45; border-radius: 8px; }
.run-host header { display: flex; justify-content: space-between; gap: 10px; font-size: 12px; }
.run-host header span { color: #8fb29b; }
.run-host-note { margin: 8px 0 0; padding: 8px 10px; color: #aeb7c2; background: #20242a; border-radius: 6px; font-size: 12px; }
.run-host-address { display: flex; justify-content: space-between; gap: 10px; margin-top: 5px; color: #8993a1; font-family: monospace; font-size: 11px; }
.run-host-task { color: #b8a489; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; margin: 10px 0; }
.run-host-gpus { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; margin-top: 12px; }
.run-gpu { padding: 10px; border-radius: 6px; background: #252a31; }
.run-gpu-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: 11px; }
.run-gpu strong { font-size: 16px; color: #9bcdac; }
.run-gpu progress { display: block; appearance: none; border: 0; width: 100%; height: 5px; margin: 10px 0; background: #39434a; border-radius: 3px; }
.run-gpu progress::-webkit-progress-bar { background: #39434a; border-radius: 3px; }
.run-gpu progress::-webkit-progress-value { background: #75ac88; border-radius: 3px; }
.run-gpu progress::-moz-progress-bar { background: #75ac88; border-radius: 3px; }
.run-gpu small { font-size: 11px; color: #99a3b1; }
.run-gpu.is-stale { opacity: .5; }
.run-host-progress { margin-top: 12px; border-radius: 3px; cursor: pointer; user-select: none; }
.run-host-progress:focus-visible { outline: 1px solid #5b8fd6; outline-offset: 3px; }
.run-host-progress-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: 11px; }
.run-gpu .run-host-progress strong { font-size: 16px; color: #8ab4e8; }
.run-gpu .run-host-progress:hover strong { color: #aecbf0; }
.run-gpu .run-host-progress progress { display: block; appearance: none; border: 0; width: 100%; height: 5px; margin: 10px 0 0; background: #39434a; border-radius: 3px; transition: margin-bottom 220ms ease; }
.run-host-progress-details { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows 220ms ease, opacity 220ms ease; }
.run-host-progress-details > div { overflow: hidden; min-height: 0; }
.run-host-progress.is-open .run-host-progress-details { grid-template-rows: 1fr; opacity: 1; }
.run-gpu .run-host-progress small { display: block; font-size: 11px; color: #99a3b1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.run-gpu .run-host-progress.is-open progress { margin-bottom: 8px; }
.run-gpu .run-host-progress progress::-webkit-progress-bar { background: #39434a; border-radius: 3px; }
.run-gpu .run-host-progress progress::-webkit-progress-value { background: #5b8fd6; border-radius: 3px; }
.run-gpu .run-host-progress progress::-moz-progress-bar { background: #5b8fd6; border-radius: 3px; }
.run-host-progress-card { margin-top: 10px; }
.run-host-progress-card .run-host-progress { margin-top: 0; }
.run-new-button { margin: 0 16px 16px; width: calc(100% - 32px); padding: 9px; border: 1px solid #525a67; border-radius: 6px; background: #2d333d; color: #d7deea; font-size: 13px; cursor: pointer; }
.run-modal-backdrop { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; background: rgba(0,0,0,.68); padding: 20px; }
.run-modal { width: 550px; max-width: 100%; max-height: calc(100vh - 40px); overflow-y: auto; background: #24272e; border: 1px solid #454b55; border-radius: 12px; padding: 24px; box-shadow: 0 18px 70px rgba(0,0,0,.5); }
.run-modal header { display: flex; justify-content: space-between; align-items: start; }
.run-modal h2 { margin: 0; font-size: 22px; }
.run-modal header p { color: #929baa; margin: 7px 0 22px; font-size: 13px; }
.run-modal header button { background: transparent; color: #a5adbb; border: 0; font-size: 26px; cursor: pointer; }
.run-new-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.run-new-fields label { display: flex; flex-direction: column; gap: 7px; color: #b1b8c5; font-size: 12px; }
.run-new-fields .run-name-field { grid-column: 1 / -1; }
.run-new-fields input, .run-new-fields select { height: 37px; border: 1px solid #505763; border-radius: 6px; background: #191c22; color: #e5e8ef; padding: 0 10px; font-size: 13px; }
.run-new-fields input:disabled, .run-new-fields select:disabled { opacity: .5; cursor: not-allowed; }
.run-preset-detail { color: #9da6b5; font-size: 11px; }
.run-new-fields .run-learning-field { grid-column: 1 / -1; flex-direction: row; align-items: flex-start; gap: 10px; padding-top: 4px; }
.run-new-fields .run-learning-field input { width: 17px; height: 17px; margin: 2px 0 0; padding: 0; flex-shrink: 0; accent-color: var(--accent-brand); }
.run-learning-copy { display: flex; flex-direction: column; gap: 4px; }
.run-learning-copy strong { color: #e5e8ef; font-size: 13px; font-weight: 600; }
.run-learning-copy small { color: #9da6b5; font-size: 12px; line-height: 1.4; }
.run-settings-error .run-error { margin-top: 0; }
.run-recipe { display: flex; flex-wrap: wrap; gap: 7px; margin: 20px 0 14px; }
.run-recipe span { padding: 5px 9px; border-radius: 5px; background: #343941; color: #c3cbd7; font-size: 11px; }
.run-new-note { font-size: 12px; color: #9da6b5; line-height: 1.6; }
.run-modal footer { display: flex; align-items: center; justify-content: space-between; gap: 18px; border-top: 1px solid #3e444e; margin-top: 22px; padding-top: 18px; }
.run-modal footer span { font-size: 11px; color: #8f9aab; max-width: 240px; }
.run-header { display: grid; grid-template-columns: auto 1fr auto; gap: 25px; }
.run-header .run-header-costs { display: flex; justify-content: center; align-items: center; gap: 35px; }
.run-header-costs > div { display: flex; flex-direction: column; gap: 5px; }
.run-header-costs span { font-size: 11px; }
.run-header-costs strong { font-size: 19px; font-weight: 600; }
.run-header-costs.is-stale > :not(.run-balances) { opacity: .6; }
.run-header-costs small { font-size: 11px; color: #d5b17f; }
.run-config-cost { display: flex; align-items: center; justify-content: space-between; margin-top: 12px; padding: 14px 16px; border-radius: 8px; background: #272c32; }
.run-config-cost > div { display: flex; align-items: baseline; gap: 14px; }
.run-config-cost span { color: #a8b2bf; font-size: 12px; }
.run-config-cost strong { color: #c9ddcf; font-size: 23px; }
.run-config-cost p { margin: 0; font-size: 12px; color: #98a5b4; }
@media (max-width: 850px) { .run-header { grid-template-columns: 1fr auto; } .run-header .run-header-costs { grid-column: 1 / -1; grid-row: 2; justify-content: start; } .run-header-costs span { display: block; } .run-config-cost { align-items: start; flex-direction: column; gap: 10px; } }
.run-stage.is-running { background: #30302b; color: #e6c28d; }
.run-stage.is-running .run-stage-number { background: #695234; color: #fff0d3; }

.run-config-id { font-family: monospace; font-size: 11px; overflow-wrap: anywhere; user-select: text; }
.run-config-identity { margin: 8px 0 16px; color: #939baa; font-size: 13px; overflow-wrap: anywhere; user-select: text; }
.run-config-identity code { color: #dddfe7; }

/* /run top bar: GPU host of the website Custom solve (owner 2026-10-04) */
.run-header-side { display: flex; align-items: center; gap: 22px; }
.run-gpu-gateway { display: flex; align-items: center; gap: 11px; padding: 7px 8px 7px 13px; border: 1px solid #3a3f48; border-radius: 10px; background: #23272d; min-width: 0; }
.run-header .run-gpu-gateway .run-gpu-gateway-dot { display: block; width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; background: #6b7280; }
.run-gpu-gateway.is-ready { border-color: #2f5a43; background: #1f2a25; }
.run-gpu-gateway.is-ready .run-gpu-gateway-dot { background: #4ade80; box-shadow: 0 0 0 3px rgba(74, 222, 128, .18); }
.run-gpu-gateway.is-busy .run-gpu-gateway-dot { background: #f2c26b; animation: run-gpu-gateway-pulse 1.2s ease-in-out infinite; }
.run-gpu-gateway.is-error .run-gpu-gateway-dot { background: #f07a6a; }
.run-gpu-gateway-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; max-width: 300px; }
.run-gpu-gateway-text strong { color: #e5e8ef; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.run-header .run-gpu-gateway-text small { display: block; color: #9da6b5; font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.run-gpu-gateway-buttons { display: flex; gap: 6px; }
.run-gpu-gateway-buttons button { padding: 6px 11px; border-radius: 7px; border: 1px solid transparent; font-size: 12px; font-weight: 600; cursor: pointer; }
.run-gpu-gateway-buttons button:disabled { opacity: .4; cursor: default; }
.run-gpu-gateway-raise { background: #2f6b4a; color: #eafff1; }
.run-gpu-gateway-raise:not(:disabled):hover { background: #37805a; }
.run-gpu-gateway-delete { background: transparent; border-color: #5a3a3a; color: #f0a59a; }
.run-gpu-gateway-delete:not(:disabled):hover { background: #3a2626; }
@keyframes run-gpu-gateway-pulse { 50% { opacity: .35; } }
@media (max-width: 850px) { .run-header-side { grid-column: 1 / -1; flex-wrap: wrap; } .run-gpu-gateway { flex: 1 1 100%; } .run-gpu-gateway-text { max-width: none; flex: 1; } }

/* /run top bar: the providers' balances right of All configs (owner 2026-10-17, ProviderBalances.tsx): a dot per answer - green answered,
   amber the last balance kept while the provider does not answer, red no answer, grey no balance API (Nebius, a console link) */
.run-header-costs .run-balances { gap: 8px; padding: 9px 10px 10px; border: 1px solid #3a3f48; border-radius: 10px; background: linear-gradient(180deg, #23272d, #1f2227); }
.run-balances-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 0 2px; }
.run-header .run-balances-head span { display: block; font-size: 11px; font-weight: 600; letter-spacing: 1px; text-transform: uppercase; color: #939baa; }
.run-header-costs .run-balances-head small { font-size: 11px; color: #7f8897; }
.run-balances-grid { display: grid; grid-template-columns: repeat(4, minmax(96px, auto)); gap: 6px; }
.run-balance { display: flex; flex-direction: column; gap: 4px; min-width: 0; padding: 7px 10px 8px; border-radius: 7px; background: #2a2f36; }
.run-header .run-balance-name { display: flex; align-items: center; gap: 6px; font-size: 11px; color: #a8b2bf; white-space: nowrap; }
.run-balance-dot { width: 7px; height: 7px; flex-shrink: 0; border-radius: 50%; background: #4ade80; box-shadow: 0 0 0 3px rgba(74, 222, 128, .14); }
.run-header-costs .run-balance-amount { font-size: 15px; font-weight: 600; color: #e8eaf0; font-variant-numeric: tabular-nums; white-space: nowrap; }
.run-header-costs .run-balance small { font-size: 10px; color: #8f9aab; white-space: nowrap; }
.run-header .run-balance-console { font-size: 13px; font-weight: 600; color: #c5cbd6; white-space: nowrap; }
.run-header .run-balance-console:hover { color: #ffffff; }
.run-balance.is-loading .run-balance-dot { background: #6b7280; box-shadow: none; }
.run-balance.is-loading .run-balance-amount { color: #6b7280; }
.run-balance.is-stale .run-balance-dot { background: #f2c26b; box-shadow: 0 0 0 3px rgba(242, 194, 107, .16); }
.run-balance.is-stale .run-balance-amount { color: #c9c2b2; }
.run-balance.is-error .run-balance-dot { background: #f07a6a; box-shadow: 0 0 0 3px rgba(240, 122, 106, .16); }
.run-balance.is-error .run-balance-amount { color: #8f9aab; }
.run-balance.is-no-api .run-balance-dot { background: #6b7280; box-shadow: none; }
@media (max-width: 850px) { .run-header .run-header-costs { flex-wrap: wrap; gap: 18px 35px; } }
@media (max-width: 640px) { .run-balances-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* ── Range comparison (owner 2026-10-05, laid out after the owner's mock-up) ──
   The two seats side by side — each with its Combos / EV / Equity / EQR
   columns over its own matrix (the site's own RangeMatrix, in the site's
   colours, with no card behind them) — and the equity distribution
   underneath, BB red (owner 2026-10-05, was cyan) and SB green. The node JSON export is an admin
   toolbar icon. */
.study-columns.is-ranges > .matrix-panel > .toolbar .toolbar-group.is-tools > button:first-child { display: none; }
.toolbar-button.is-active { background: #383838; color: var(--text-strong); border-radius: 5px; }

/* The toolbar entry reads as a tab while the comparison is open. */
.toolbar-button.is-ranges-tab.is-active {
  border-radius: 0;
  background: transparent;
  color: var(--accent-brand);
  box-shadow: inset 0 -2px 0 var(--accent-brand);
}

.ranges-view {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 5px;
  animation: none;
}

.ranges-view button:not(.matrix-cell) {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: var(--surface-panel);
  padding: 6px 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}

.ranges-view button:not(.matrix-cell):hover {
  background: var(--surface-raised);
  color: var(--text-strong);
}

.ranges-view button:not(.matrix-cell):disabled {
  opacity: 0.35;
  cursor: default;
}

/* ── a seat's numbers: four centred columns over its matrix ── */
/* Flat #252525 with a #393939 hairline frame (owner edits 2026-10-05); the values in plain white. */
.ranges-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  background: #252525;
  border: 1px solid #393939;
  border-radius: 0;
  padding: 10px 0;
  margin: 5px 0 8px;
}

.ranges-stat {
  display: flex;
  min-width: 0;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 0 6px;
  text-align: center;
}

.ranges-stat + .ranges-stat {
  border-left: 1px solid var(--line-strong);
}

.ranges-stat span {
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
}

.ranges-stat strong {
  white-space: nowrap;
  font-size: clamp(13px, 3.2cqw, 18px);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
}

/* ── the two seats ── */
/* The matrices sit on the page itself, 8px apart (owner 2026-10-05). */
.ranges-comparison {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  align-items: start;
}

.ranges-player.matrix-panel {
  min-width: 0;
  border: 0;
  background: transparent;
  padding: 0;
}

.ranges-player-header {
  display: flex;
  min-height: 28px;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}

.ranges-player-header strong {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 16px;
  padding-left: 6px;
  font-weight: 800;
  color: var(--text-strong);
}

.ranges-actor {
  font-size: 11px;
  font-weight: 700;
  color: var(--accent-brand);
}

/* 6-max (owner 2026-10-17): the seat the acting one is compared with - every seat still in the hand, the picked one in the brand
   colour, as the Solutions library's filter values */
.ranges-seat-switch {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 2px;
  border-radius: 8px;
  background: #262626;
  box-shadow: inset 0 0 0 1px var(--line);
  padding: 2px;
}

.ranges-view button.ranges-seat-option {
  height: 24px;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 0 9px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
}

.ranges-view button.ranges-seat-option:hover {
  background: #333;
  color: var(--text-strong);
}

.ranges-view button.ranges-seat-option.is-selected {
  background: color-mix(in srgb, var(--accent-brand) 17%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-brand) 45%, transparent);
  color: var(--accent-brand);
}

/* The buttons above a matrix are compact (owner 2026-10-05); Copy is an icon
   at the right end of the row. */
.ranges-view button.ranges-mode {
  padding: 3px 10px;
  font-size: 12px;
}

.ranges-view button.ranges-copy {
  flex-shrink: 0;
  width: 28px;
  height: 24px;
  justify-content: center;
  margin-left: auto;
  padding: 0;
}

.ranges-view button.ranges-copy.is-copied {
  border-color: #44664e;
  background: #2c4233;
  color: #91d5a2;
}

/* Range / Strategy / EV for this seat's matrix. */
.ranges-modes {
  display: flex;
  min-width: 0;
  flex: 1;
  gap: 6px;
}

.ranges-view button.ranges-mode {
  flex: 1;
  max-width: 112px;
  justify-content: center;
}

.ranges-view button.ranges-mode.is-active {
  border-color: var(--accent-brand);
  background: rgba(255, 158, 69, 0.16);
  color: var(--accent-brand);
}

.ranges-player .matrix-cell { min-height: 0; }
.ranges-player .matrix-cell-label { position: absolute; inset: 0; display: grid; place-items: center; }
/* Hand labels 25 % smaller than the main matrix's clamp(12px, 2cqw, 22px), on every screen (owner 2026-10-05: on a
   MacBook the letters filled the whole cell). cqw is this seat's own matrix panel. */
.ranges-player.matrix-panel .matrix-cell-label { font-size: clamp(9px, 1.5cqw, 16.5px); }
.ranges-player .matrix-cell-label.is-compact { inset: 0; }
.ranges-player .matrix-cell-metric { display: none; }

/* ── equity distribution ── */
.ranges-equity-chart {
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-sunken);
  padding: 14px 16px 10px;
}

.ranges-equity-chart header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

.ranges-equity-chart h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 800;
  color: var(--text-strong);
}

/* Each seat: its line colour, its name and, for the seat to act, the orange
   "To act" (owner 2026-10-05: here instead of in the tooltip). */
.ranges-chart-legend {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-soft);
}

.ranges-chart-legend-item {
  display: flex;
  align-items: center;
  gap: 7px;
}

.ranges-chart-legend i {
  width: 18px;
  height: 3px;
  border-radius: 2px;
  background: #ef5b64;
}

.ranges-chart-legend i.is-sb {
  background: #58bb77;
}

.ranges-chart-plot {
  position: relative;
  height: 260px;
  margin-left: 58px;
}

.ranges-chart-plot svg { display: block; width: 100%; height: 100%; overflow: hidden; }
.ranges-chart-line { fill: none; stroke: #ef5b64; stroke-width: 2; vector-effect: non-scaling-stroke; stroke-linejoin: round; animation: ranges-line-enter 350ms ease-out both; }
.ranges-chart-line.is-sb { stroke: #58bb77; animation-delay: 40ms; }
.ranges-chart-grid { stroke: rgba(255, 255, 255, 0.1); stroke-width: 1; stroke-dasharray: 4 4; vector-effect: non-scaling-stroke; }
.ranges-chart-cursor { stroke: #ffffff50; stroke-width: 1; vector-effect: non-scaling-stroke; }

.ranges-chart-y {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -38px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  font-size: 11px;
  color: var(--text-muted);
}

/* "Equity" written up the y axis. */
.ranges-chart-y-title {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -58px;
  display: flex;
  align-items: center;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-size: 11px;
  color: var(--text-muted);
}

.ranges-chart-x {
  display: flex;
  justify-content: space-between;
  margin: 8px 0 0 58px;
  font-size: 11px;
  color: var(--text-muted);
}

.ranges-equity-chart p {
  margin: 6px 0 0;
  font-size: 11px;
  text-align: center;
  color: var(--text-muted);
}

.ranges-chart-tooltip strong { font-weight: 800; }
.ranges-chart-tooltip { position: absolute; top: 8px; right: 8px; display: flex; flex-direction: column; gap: 6px; padding: 9px; border: 1px solid var(--line); border-radius: 5px; background: #202020ed; color: var(--text-strong); font-size: 12px; pointer-events: none; }
.ranges-chart-empty { min-height: 180px; display: grid; place-items: center; color: var(--text-muted); font-size: 13px; }

/* Owner temporarily disabled chart entrance animation; retain keyframes. */
.ranges-equity-chart.is-animation-paused .ranges-chart-line { animation: none; }
@keyframes ranges-enter { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
@keyframes ranges-line-enter { from { clip-path: inset(0 100% 0 0); opacity: 0; } to { clip-path: inset(0 0 0 0); opacity: 1; } }

@media (max-width: 650px) {
  .ranges-comparison { grid-template-columns: minmax(0, 1fr); }
  .study-columns.is-ranges > .study-right { grid-template-columns: 1fr; }
  .ranges-chart-plot { height: 200px; }
}
/* ── Hand filters (owner 2026-10-05, after the owner's mock-up) ───────────
   The Filters button of the matrix toolbar opens a window that lies over the
   node strip; the active conditions follow the button as removable chips.
   Component: features/strategy/components/HandFiltersPanel.tsx. */

/* The window lies exactly over the node strip: the zone keeps the strip's own
   height whether the window is open or not, so nothing below it moves when
   the window opens or closes (owner 2026-10-05: closing made Strategy and
   Actions jump up). The window is laid out to fit; anything taller scrolls. */
.study-strip-zone {
  position: relative;
  min-width: 0;
}

/* Plain block, not flex (owner edit 2026-10-05: flex left almost no room at the
   bottom). As wide as its options need — every column as wide as its longest
   label, nothing stretched over the whole strip and nothing cut — and never
   wider than the strip. */
.hand-filters {
  position: absolute;
  inset: 0 auto 0 0;
  z-index: 30;
  width: max-content;
  max-width: 100%;
  overflow: auto;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  background: var(--surface-panel);
  padding: 6px 12px 10px;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.45);
  animation: hand-filters-in 180ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}

.hand-filters.is-closing {
  pointer-events: none;
  animation: hand-filters-out 160ms ease both;
}

@keyframes hand-filters-in {
  from { opacity: 0; transform: translateY(-8px) scale(0.985); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes hand-filters-out {
  from { opacity: 1; transform: translateY(0) scale(1); }
  to { opacity: 0; transform: translateY(-6px) scale(0.99); }
}

/* ── head ── */
.hand-filters-head {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 12px;
  margin-bottom: 6px;
}

/* "Hand filters" in bold, "· SB · Flop" after it smaller and quieter (owner mock-up 2026-10-05). */
.hand-filters-head h2 {
  margin: 0;
  white-space: nowrap;
  font-size: 17px;
  font-weight: 800;
  color: var(--text-strong);
}

.hand-filters-head h2 span {
  margin-left: 4px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
}

.hand-filters-board {
  display: flex;
  gap: 5px;
  margin-right: auto;
}

/* The board in the site's own card style, small. */
.playing-card--filters {
  --card-width: 20px;
  --card-height: 26px;
}

/* The combos the filter keeps, at the right with Live / Reset. */
.hand-filters-matched {
  flex: none;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent-brand);
}

.hand-filters-live {
  display: flex;
  flex: none;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-soft);
}

.hand-filters-live i {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: var(--grade-good);
  box-shadow: 0 0 6px rgba(88, 185, 103, 0.6);
}

.hand-filters-reset,
.hand-filters-close {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  padding: 3px 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
}

.hand-filters-reset:hover:not(:disabled),
.hand-filters-close:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.hand-filters-reset:disabled {
  opacity: 0.4;
  cursor: default;
}

/* ── sections ── */
.hand-filters-body {
  display: grid;
  grid-template-columns: repeat(4, auto);
  justify-content: start;
}

.hand-filters-section {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 4px;
  padding: 0 14px;
}

.hand-filters-section:first-child {
  padding-left: 0;
}

.hand-filters-section:last-child {
  padding-right: 0;
}

.hand-filters-section + .hand-filters-section {
  border-left: 1px solid var(--line);
}

.hand-filters-section.is-off {
  opacity: 0.45;
}

.hand-filters-section h3 {
  margin: 0;
  font-size: 12px;
  font-weight: 800;
  color: var(--text-strong);
}

/* Owner edits 2026-10-05: two equal columns, no gaps, options without a frame. */
.hand-filters-checks {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
}

/* Options after the owner's mock-up (2026-10-05): a plain row with an outlined
   square; a ticked one gets a soft orange wash with rounded corners and an
   orange square with a white tick. */
.hand-filters-check {
  display: flex;
  min-width: 0;
  height: 24px;
  align-items: center;
  gap: 8px;
  overflow: hidden;
  border: 0;
  border-radius: 6px;
  background: transparent;
  padding: 0 8px;
  white-space: nowrap;
  text-align: left;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-normal);
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
}

.hand-filters-check:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.04);
  color: var(--text-strong);
}

.hand-filters-check:disabled {
  cursor: default;
}

.hand-filters-check.is-on,
.hand-filters-check.is-on:hover:not(:disabled) {
  background: rgba(255, 158, 69, 0.18);
  color: var(--text-strong);
}

.hand-filters-box {
  display: grid;
  width: 15px;
  height: 15px;
  flex: none;
  place-items: center;
  border: 1.5px solid #6a6a6a;
  border-radius: 4px;
  transition: background 150ms ease, border-color 150ms ease;
}

.hand-filters-check.is-on .hand-filters-box {
  border-color: var(--accent-brand);
  background: var(--accent-brand);
  color: var(--text-on-brand);
}

/* Cards: the four suits in the deck's own colours, then two switches. */
.hand-filters-suits {
  display: grid;
  grid-template-columns: repeat(4, minmax(34px, 1fr));
  gap: 5px;
}

.hand-filters-suit {
  height: 26px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface-sunken);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease;
}

.hand-filters-suit.is-s { color: #e8e8e8; }
.hand-filters-suit.is-h { color: #ef5b64; }
.hand-filters-suit.is-d { color: #4a9bf0; }
.hand-filters-suit.is-c { color: #3fbf7c; }

.hand-filters-suit:hover {
  border-color: #5a5a5a;
}

.hand-filters-suit.is-on {
  border-color: var(--accent-brand);
  background: rgba(255, 158, 69, 0.16);
}

.hand-filters-segment,
.hand-filters-presets {
  display: grid;
  grid-auto-columns: minmax(max-content, 1fr);
  grid-auto-flow: column;
  gap: 5px;
}

.hand-filters-segment button,
.hand-filters-presets button {
  height: 24px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  padding: 0 10px;
  background: transparent;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}

.hand-filters-segment button:hover:not(:disabled),
.hand-filters-presets button:hover {
  border-color: #5a5a5a;
  color: var(--text-strong);
}

.hand-filters-segment button:disabled {
  opacity: 0.4;
  cursor: default;
}

.hand-filters-segment button.is-on,
.hand-filters-presets button.is-on {
  border-color: var(--accent-brand);
  background: var(--accent-brand);
  color: var(--text-on-brand);
}

/* Equity: From / To in per cent, and four quarters. */
.hand-filters-range {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.hand-filters-range label {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-soft);
}

.hand-filters-range label span {
  display: flex;
  min-width: 0;
  flex: 1;
  height: 28px;
  align-items: center;
  gap: 4px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface-sunken);
  padding: 0 8px;
  color: var(--text-muted);
}

/* The number takes the whole box up to the "%" (owner 2026-10-05: "100" was cut
   in a 34px input inside a long box), without the browser's spin arrows. */
.hand-filters-range input {
  width: 100%;
  min-width: 0;
  flex: 1;
  appearance: textfield;
  -moz-appearance: textfield;
  border: 0;
  background: transparent;
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
  outline: none;
}

.hand-filters-range input::-webkit-inner-spin-button,
.hand-filters-range input::-webkit-outer-spin-button {
  margin: 0;
  -webkit-appearance: none;
}

.hand-filters-range label span:focus-within {
  border-color: var(--accent-brand);
}

/* ── toolbar: Filters button and chips ── */
/* A notch smaller than the other toolbar buttons (owner 2026-10-05). */
.toolbar-filters {
  display: inline-flex;
  height: 26px;
  flex: none;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: transparent;
  padding: 0 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}

.toolbar-filters:hover {
  border-color: #5a5a5a;
  color: var(--text-strong);
}

.toolbar-filters.is-active {
  border-color: var(--accent-brand);
  background: var(--accent-brand);
  color: var(--text-on-brand);
}

.toolbar-filters-count {
  display: grid;
  min-width: 16px;
  height: 16px;
  place-items: center;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.28);
  padding: 0 4px;
  font-size: 10px;
  font-weight: 800;
  color: var(--text-on-brand);
}

/* Many chips scroll sideways in the toolbar instead of starting a second row (owner 2026-10-05). */
.toolbar-group > .toolbar-chips {
  display: flex;
  min-width: 0;
  flex: 0 1 auto;
  align-items: center;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
}

.toolbar-group > .toolbar-chips::-webkit-scrollbar {
  display: none;
}

.toolbar-chip {
  display: inline-flex;
  height: 26px;
  flex: none;
  align-items: center;
  gap: 4px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  padding: 0 3px 0 9px;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-normal);
  animation: hand-filters-in 160ms ease both;
}

.toolbar-chip button {
  display: grid;
  width: 18px;
  height: 18px;
  place-items: center;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.toolbar-chip button:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.toolbar-chips-clear {
  flex: none;
  border: 0;
  background: transparent;
  padding: 0 4px;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 700;
  color: var(--action-fold-hover);
  cursor: pointer;
}

.toolbar-chips-clear:hover {
  color: #7fb2e6;
}

@media (max-width: 1150px) {
  .hand-filters-body { grid-template-columns: repeat(2, auto); row-gap: 8px; }
  .hand-filters-section:nth-child(3) { padding-left: 0; border-left: 0; }
  .hand-filters-section:nth-child(2) { padding-right: 0; }
}
/* ============================================================================
   Custom Solutions — the solve builder.

   It is a DIALOG, not a page: it opens over the study page and gives it back
   untouched when it closes (owner request 2026-09-15). Everything below is
   plain px and semantic class names, per docs/frontend_rules.md.

   The dialog carries its own green accent rather than the app's orange: it is
   a workbench laid over the product, and the green marks "this control is on"
   without competing with the orange that means "this is the line you are
   studying" underneath.
   ============================================================================ */

.custom-backdrop {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.8);   /* no backdrop-filter (owner 2026-10-16: the page under a window flickered over it while scrolling - see study-modal.css) */
  padding: 24px;
}

/* One fixed size whatever tab is open (owner 2026-10-02: it jumped between
   Hand Details, Rake and Bet Sizes); a longer tab scrolls inside. */
.custom-shell {
  display: flex;
  width: min(1320px, 100%);
  height: min(920px, 100%);
  flex-direction: column;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 14px;
  background: #1b1b1b;
  color: var(--text-normal);
  font-size: 14px;
  box-shadow: 0 32px 110px rgba(0, 0, 0, 0.7);
}

/* ── head ─────────────────────────────────────────────────────────────── */
.custom-shell-head {
  display: flex;
  align-items: center;
  gap: 14px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  padding: 16px 16px 16px 24px;
}

.custom-shell-head h1 {
  margin: 0;
  font-size: 24px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: #ffffff;
}

.custom-badge {
  border-radius: 6px;
  background: var(--accent-brand);
  padding: 5px 12px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-on-brand);
}

.custom-shell-head-right {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

/* ── body: left rail + panel ──────────────────────────────────────────── */
.custom-shell-body {
  display: grid;
  min-height: 0;
  flex: 1;
  grid-template-columns: 268px 1fr;
}

.custom-nav {
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
  border-right: 1px solid rgba(255, 255, 255, 0.07);
  padding: 16px;
}

.custom-nav-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  border-radius: 10px;
  background: #242424;
  padding: 4px;
  margin-bottom: 8px;
}

.custom-nav-tab {
  border: none;
  border-radius: 8px;
  background: transparent;
  padding: 9px 8px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.custom-nav-tab.is-active {
  background: #333333;
  color: var(--text-strong);
}

.custom-nav-tab.is-disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

.custom-nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  padding: 12px 14px;
  text-align: left;
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}

.custom-nav-item:hover:not(:disabled) {
  background: #242424;
}

.custom-nav-item.is-active {
  border-color: rgba(255, 255, 255, 0.08);
  background: #2b2b2b;
  color: var(--text-strong);
}

.custom-nav-item:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}

.custom-nav-item span {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}

.custom-nav-item strong {
  font-size: 15px;
  font-weight: 700;
}

.custom-nav-item small {
  overflow: hidden;
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-muted);
}

.custom-main {
  min-height: 0;
  overflow-y: auto;
  /* The scrollbar's room is kept even when it is not shown, so a tab change
     never shifts the content sideways. */
  scrollbar-gutter: stable;
  padding: 24px 28px;
}

.custom-panel {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* ── fields, pills, steppers ──────────────────────────────────────────── */
.custom-field {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 8px;
}

.custom-field-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
}

.custom-hint {
  display: grid;
  width: 15px;
  height: 15px;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 50%;
  background: transparent;
  padding: 0;
  font-size: 10px;
  font-style: normal;
  font-weight: 700;
  line-height: 1;
  color: var(--text-muted);
  cursor: help;
}

/* The same ? as a real button when its help is a tooltip (Rake Type): it opens
   on hover and on keyboard focus. */
button.custom-hint:hover,
button.custom-hint:focus-visible {
  border-color: var(--accent-brand);
  color: var(--accent-brand);
  outline: none;
}

.custom-top-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 20px 28px;
}

.custom-pill-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.custom-pill-row.is-right {
  justify-content: flex-end;
}

/* A long pill list (Auto iterations) wraps instead of overflowing the seat card. */
.custom-pill-row.is-wrap {
  flex-wrap: wrap;
  row-gap: 6px;
}

.custom-pill {
  border: 1px solid transparent;
  border-radius: 999px;
  background: #2c2c2c;
  padding: 8px 18px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}

.custom-pill:hover:not(:disabled) {
  background: #363636;
}

.custom-pill.is-active {
  border-color: var(--accent-brand);
  background: transparent;
  color: var(--accent-brand);
}

.custom-pill.is-disabled,
.custom-pill:disabled {
  cursor: not-allowed;
  opacity: 0.38;
}

.custom-round {
  display: grid;
  width: 38px;
  height: 38px;
  place-items: center;
  border: 1px solid transparent;
  border-radius: 50%;
  background: #2c2c2c;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-round.is-active {
  border-color: var(--accent-brand);
  background: transparent;
  color: var(--accent-brand);
}

.custom-round.is-disabled,
.custom-round:disabled {
  cursor: not-allowed;
  opacity: 0.38;
}

.custom-stepper {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 6px;
}

.custom-stepper-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
}

.custom-stepper-box {
  display: flex;
  align-items: center;
  height: 42px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 10px;
  background: #2c2c2c;
}

.custom-stepper-box > button {
  width: 40px;
  height: 100%;
  flex-shrink: 0;
  border: none;
  background: transparent;
  font-size: 19px;
  line-height: 1;
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.custom-stepper-box > button:hover:not(:disabled) {
  background: #383838;
  color: var(--text-strong);
}

.custom-stepper-box > input {
  width: 100%;
  min-width: 0;
  border: none;
  background: transparent;
  padding: 0;
  text-align: right;
  font-size: 16px;
  font-weight: 700;
  color: var(--text-strong);
  outline: none;
}

.custom-stepper-box > em {
  padding: 0 4px 0 6px;
  font-size: 13px;
  font-style: normal;
  color: var(--text-muted);
}

.custom-stepper.is-disabled {
  opacity: 0.4;
}

.custom-input {
  height: 36px;
  min-width: 0;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 8px;
  background: #2c2c2c;
  padding: 0 10px;
  font-size: 14px;
  color: var(--text-strong);
  outline: none;
}

.custom-input:focus {
  border-color: var(--accent-brand);
}

.custom-textarea {
  width: 100%;
  min-height: 84px;
  resize: vertical;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 8px;
  background: #2c2c2c;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-strong);
  outline: none;
}

.custom-chip-button,
.custom-ghost-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 8px;
  background: #2c2c2c;
  padding: 0 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}

.custom-chip-button:hover:not(:disabled),
.custom-ghost-button:hover:not(:disabled) {
  background: #383838;
  color: var(--text-strong);
}

.custom-chip-button:disabled,
.custom-ghost-button:disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

.custom-ghost-button {
  border-color: transparent;
  background: transparent;
}

.custom-icon-button {
  display: grid;
  width: 42px;
  height: 42px;
  flex-shrink: 0;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 10px;
  background: #2c2c2c;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-icon-button:hover {
  background: #383838;
  color: var(--text-strong);
}

.custom-toggle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  border: none;
  background: transparent;
  padding: 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-toggle-track {
  display: block;
  position: relative;
  width: 42px;
  height: 24px;
  flex-shrink: 0;
  border-radius: 999px;
  background: #414141;
  transition: background-color 150ms ease;
}

.custom-toggle-track > b {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #d8d8d8;
  transition: transform 150ms ease, background-color 150ms ease;
}

.custom-toggle.is-on .custom-toggle-track {
  background: #8a4f1c;
}

.custom-toggle.is-on .custom-toggle-track > b {
  background: var(--accent-brand);
  transform: translateX(18px);
}

.custom-toggle.is-on {
  color: var(--text-strong);
}

/* A native select dressed as the stepper box; the chevron is an icon laid over
   it, so the whole box stays the click target. */
.custom-select {
  position: relative;
  display: flex;
  align-items: center;
}

.custom-select > select {
  width: 100%;
  height: 42px;
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 10px;
  background: #2c2c2c;
  padding: 0 38px 0 14px;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-strong);
  color-scheme: dark;
  cursor: pointer;
  outline: none;
  transition: background-color 120ms ease, border-color 120ms ease;
}

.custom-select > select:hover {
  background: #333333;
}

.custom-select > select:focus-visible {
  border-color: var(--accent-brand);
}

.custom-select > svg {
  position: absolute;
  right: 14px;
  color: var(--text-muted);
  pointer-events: none;
}

.custom-note {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
}

.custom-error {
  margin: 0;
  border-left: 3px solid #ff6b6b;
  padding-left: 10px;
  font-size: 13px;
  color: #ff9d9d;
}

/* ── hand details: board and player rows ──────────────────────────────── */
/* As tall as the Pot Size field (owner 2026-10-02); the cards shrink to fit. */
.custom-board-button {
  display: flex;
  align-items: center;
  height: 42px;
  gap: 4px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 10px;
  background: #2c2c2c;
  padding: 0 10px;
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.custom-board-button:hover {
  border-color: var(--accent-brand);
  background: #333333;
}

.custom-board-cards .playing-card--strip {
  --card-width: 22px;
  --card-height: 32px;
}

.custom-board-empty {
  font-size: 13px;
  color: var(--text-muted);
}

.custom-default-stack {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.custom-players {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.custom-players-head,
.custom-player-row {
  display: grid;
  grid-template-columns: 236px 1fr 1fr 1fr;
  align-items: center;
  gap: 20px;
}

.custom-players-head {
  padding: 0 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
}

.custom-player-row {
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  background: #212121;
  padding: 14px 16px;
}

.custom-range-card {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 10px;
  background: #2a2a2a;
  padding: 8px 14px 8px 8px;
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.custom-range-card:hover {
  border-color: var(--accent-brand);
  background: #303030;
}

.custom-range-card-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
}

.custom-range-card-combos {
  font-size: 12px;
  color: var(--text-muted);
}

.custom-range-card-combos strong {
  font-size: 13px;
  color: var(--text-normal);
}

.custom-range-card-percent {
  font-size: 22px;
  font-weight: 800;
  color: var(--text-strong);
}

.custom-range-card-percent em {
  font-size: 13px;
  font-style: normal;
  font-weight: 600;
  color: var(--text-muted);
}

.custom-cell {
  min-width: 0;
}

.custom-position,
.custom-profile {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 42px;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 10px;
  background: #2a2a2a;
  padding: 0 14px;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.custom-position em {
  font-size: 13px;
  font-style: normal;
  font-weight: 600;
  color: var(--text-muted);
}

.custom-profile > i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent-brand);
}

/* ── the 13x13 postage stamp ──────────────────────────────────────────── */
.range-thumb {
  display: grid;
  width: 74px;
  height: 74px;
  flex-shrink: 0;
  grid-template-columns: repeat(13, 1fr);
  gap: 1px;
  overflow: hidden;
  border-radius: 6px;
  background: #1d1d1d;
  padding: 2px;
}

.range-thumb-cell {
  border-radius: 1px;
  background: #313131;
}

.range-thumb-cell.is-on {
  background: var(--accent-brand);
}

.custom-range-tab-thumb,
.custom-range-card-thumb {
  width: 66px;
  height: 66px;
}

/* ── advanced blocks ──────────────────────────────────────────────────── */
.custom-advanced {
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 12px;
  background: #202020;
  padding: 4px 18px;
}

.custom-advanced > summary {
  padding: 14px 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
  cursor: pointer;
  list-style: none;
}

.custom-advanced > summary::-webkit-details-marker {
  display: none;
}

.custom-advanced > summary::after {
  content: "▾";
  float: right;
  color: var(--text-muted);
}

.custom-advanced[open] > summary::after {
  content: "▴";
}

.custom-advanced-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 18px 24px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  padding: 18px 0;
}

/* ── rake ─────────────────────────────────────────────────────────────── */
.custom-rake-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 20px 28px;
}

.custom-preset-menu {
  position: relative;
}

.custom-preset-list {
  position: absolute;
  z-index: 5;
  top: 38px;
  left: 0;
  display: none;
  min-width: 190px;
  flex-direction: column;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 10px;
  background: #2c2c2c;
  padding: 6px;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.55);
}

/* The footer's Load/Save open UPWARD and on a click, not on hover: a menu that
   drops out of the bottom bar would fall off the dialog. */
.custom-preset-list.is-up {
  top: auto;
  bottom: 40px;
}

.custom-preset-list.is-open {
  display: flex;
}

.custom-preset-row {
  display: flex;
  align-items: center;
  gap: 2px;
}

.custom-preset-row > button:first-child {
  flex: 1;
  overflow: hidden;
  border: none;
  border-radius: 7px;
  background: transparent;
  padding: 8px 10px;
  text-align: left;
  font-size: 13px;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-preset-row > button:first-child:hover {
  background: #3a3a3a;
  color: var(--text-strong);
}

.custom-preset-delete {
  display: grid;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  place-items: center;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-preset-delete:hover {
  background: #444444;
  color: #ff9d9d;
}

.custom-preset-empty {
  padding: 8px 10px;
  font-size: 12px;
  color: var(--text-muted);
}

.custom-preset-save {
  display: flex;
  gap: 6px;
  padding: 4px;
}

.custom-preset-save .custom-input {
  width: 180px;
}

/* ── "Choose rake": rooms on the left, the room's tables on the right ─── */
.custom-rake-backdrop {
  z-index: 65;
}

/* One height whatever the room or the filters (owner 2026-10-21: «Окно choose rake попап не должно прыгать в зависимости от того какое
   количество рейков в таблице ... надо чтобы одна высота была»): the tallest table (12 rows) with its filters fits; a longer one scrolls
   in its column, a shorter one leaves room below. Never taller than the window. */
.custom-rake-picker {
  display: flex;
  width: min(940px, 100%);
  height: min(740px, 100%);
  max-height: 100%;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 14px;
  background: #1b1b1b;
  color: var(--text-normal);
  font-size: 14px;
  box-shadow: 0 32px 110px rgba(0, 0, 0, 0.7);
}

.custom-rake-picker-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  padding: 12px 12px 12px 20px;
}

.custom-rake-picker-head h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 800;
  color: #ffffff;
}

.custom-rake-picker-body {
  display: grid;
  min-height: 0;
  flex: 1;
  grid-template-columns: 190px minmax(0, 1fr);
  /* the window's height, not the tables' own: an auto row grew with them, so their column never scrolled under the window's fixed
     height (owner 2026-10-21: «скролл в таблице тут не работает в окне рейка») */
  grid-template-rows: minmax(0, 1fr);
}

.custom-rake-rooms {
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow-y: auto;
  border-right: 1px solid rgba(255, 255, 255, 0.07);
  padding: 12px;
}

/* A list with one chosen item: the full-width strip of frontend_rules 5a, not
   a frame. The negative margin matches the rail's 12px padding. */
.custom-rake-room {
  margin-inline: -12px;
  border: none;
  background: transparent;
  padding: 10px 12px;
  text-align: left;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-rake-room:hover {
  background: #404040;
}

.custom-rake-room.is-selected {
  background: linear-gradient(90deg, rgba(255, 158, 69, 0.34), rgba(255, 158, 69, 0.14));
  color: var(--text-strong);
  box-shadow: inset 2px 0 0 var(--accent-brand);
}

.custom-rake-tables {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto;
  padding: 16px 20px 20px;
}

.custom-rake-filter {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.custom-rake-filter-title {
  width: 44px;
  flex-shrink: 0;
  padding-top: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
}

.custom-rake-filter-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.custom-rake-filter-pills .custom-pill {
  padding: 5px 12px;
  font-size: 13px;
}

/* flex-shrink 0: with overflow hidden it would otherwise shrink and clip rows
   instead of letting the column scroll. */
.custom-rake-table {
  display: flex;
  flex-shrink: 0;
  flex-direction: column;
  overflow: hidden;
  margin-top: 4px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 10px;
}

.custom-rake-table-head,
.custom-rake-row {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.9fr) minmax(0, 0.8fr) minmax(0, 0.9fr) minmax(0, 1.4fr);
  align-items: center;
  gap: 12px;
  padding: 0 14px;
}

.custom-rake-table-head {
  height: 34px;
  background: #242424;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
}

.custom-rake-row {
  height: 38px;
  border: none;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  background: transparent;
  text-align: left;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-rake-row > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.custom-rake-row:hover {
  background: #404040;
  color: var(--text-strong);
}

.custom-rake-row.is-selected {
  background: linear-gradient(90deg, rgba(255, 158, 69, 0.34), rgba(255, 158, 69, 0.14));
  color: var(--text-strong);
  box-shadow: inset 2px 0 0 var(--accent-brand);
}

.custom-rake-empty {
  margin: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  padding: 14px;
  font-size: 13px;
  color: var(--text-muted);
}

.custom-rake-picker-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  padding: 12px 20px;
}

/* Rake Type help. The tooltip is portalled to <body>, so it has to clear the
   builder's own backdrop (z-index 60) to be seen at all. */
/* the look is every hint's (ui.css, «hover hints», owner 2026-10-17) */
.custom-rake-tooltip {
  z-index: 80;
  display: flex;
  max-width: 380px;
  flex-direction: column;
  gap: 6px;
}

.custom-rake-tooltip p {
  margin: 0;
}

.custom-rake-tooltip strong {
  color: var(--text-strong);
}

/* ── bet sizes ────────────────────────────────────────────────────────── */
.custom-street-bar {
  display: flex;
  align-items: center;
  gap: 20px;
}

.custom-seat-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

.custom-seat-card {
  display: flex;
  flex-direction: column;
  gap: 16px;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 12px;
  background: #212121;
  padding: 18px 20px;
}

.custom-seat-card.is-mirrored {
  background: #1e1e1e;
}

.custom-seat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.custom-seat-head strong {
  font-size: 18px;
  font-weight: 800;
  color: var(--text-strong);
}

.custom-size-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  padding-top: 14px;
}

.custom-size-row.is-disabled {
  opacity: 0.45;
}

.custom-size-row-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-soft);
}

.custom-size-row-values {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.custom-size-row-note {
  font-size: 11px;
  color: var(--text-muted);
}

.custom-size-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 36px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 8px;
  background: #2c2c2c;
  padding: 0 8px 0 12px;
}

.custom-size-chip b {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.custom-size-chip em {
  font-size: 12px;
  font-style: normal;
  color: var(--text-muted);
}

.custom-size-chip > button {
  display: grid;
  width: 20px;
  height: 20px;
  place-items: center;
  border: none;
  border-radius: 5px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-size-chip > button:hover {
  background: #444444;
  color: #ff9d9d;
}

.custom-size-add-inline {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.custom-size-add-inline .custom-input {
  width: 74px;
  text-align: right;
}

/* ── tree editor (TreeEditModal, owner 2026-10-16) ────────────────────
   Its own window over the Custom window, opened by «Tree Edit» on the Bet
   Sizes tab: a head, a bar of the tree's shape, the strip, the open node's
   sizes under it and a foot. It rises in (5b.5: always). */
.custom-tree-editor-backdrop {
  z-index: 65;
}

.custom-tree-editor {
  display: flex;
  width: min(1180px, 100%);
  max-height: 100%;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: var(--surface-sunken);
  color: var(--text-normal);
  font-size: 14px;
  box-shadow: 0 32px 110px rgba(0, 0, 0, 0.7);
  animation: custom-tree-editor-in 200ms cubic-bezier(0.2, 0, 0, 1);
}

@keyframes custom-tree-editor-in {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.custom-tree-editor-head {
  display: flex;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid var(--line);
  padding: 14px 16px 14px 20px;
}

.custom-tree-editor-icon {
  display: grid;
  width: 34px;
  height: 34px;
  flex: none;
  place-items: center;
  border-radius: 9px;
  background: var(--surface-raised);
  color: var(--accent-brand);
}

.custom-tree-editor-title {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.custom-tree-editor-title h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 800;
  color: var(--text-strong);
}

.custom-tree-editor-title small {
  font-size: 12px;
  color: var(--text-muted);
}

/* the tree's shape: raises per street, the all-in, one menu for both players, the first street's sizes later */
.custom-tree-editor-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 28px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-page);
  padding: 12px 20px;
}

.custom-tree-editor-setting {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-soft);
}

.custom-tree-strip {
  display: flex;
  min-height: 0;
  flex-direction: column;
  gap: 14px;
  overflow-y: auto;
  padding: 16px 20px;
}

/* The strip lives on the editor, so its edge fades have to be that colour and
   not the page's (see .strip-arrow in study-strip.css). */
.custom-tree-strip .node-strip-viewport {
  --strip-fade: var(--surface-sunken);
  --strip-fade-soft: rgba(31, 31, 31, 0.7);
}

.custom-board-card {
  cursor: default;
}

.custom-preview-card .node-actions {
  padding-bottom: 18px;
}

/* every size of a node fits its card (owner 2026-10-16: «должно вмещаться в карточку всё количество сайзингов»): the strip's cards keep
   their 170px as the least height and grow with their actions */
.custom-tree-strip .custom-preview-card {
  height: auto;
  min-height: 170px;
}

/* the nodes whose sizes are open in the panel under the strip */
.custom-preview-card.is-editing {
  box-shadow: inset 0 0 0 1px var(--accent-brand);
}

.custom-tree-editor-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  border-top: 1px solid var(--line);
  padding: 12px 16px 12px 20px;
}

.custom-tree-editor-note {
  margin-right: auto;
  font-size: 12px;
  color: var(--text-muted);
}

/* «Tree Edit» at the end of the Bet Sizes street bar */
.custom-tree-edit-button {
  margin-left: auto;
}

/* ── the open node's sizes, under the strip ───────────────────────────── */
.custom-size-panel {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-page);
  padding: 14px 16px;
}

.custom-size-panel.is-empty {
  font-size: 13px;
  color: var(--text-muted);
}

.custom-size-panel-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 12px;
}

.custom-size-panel-head strong {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.custom-size-panel-head small {
  font-size: 12px;
  color: var(--text-muted);
}

/* a new size: its unit (% of the pot or bb), the number, Add, and what it is in the other unit */
.custom-size-add {
  display: flex;
  align-items: center;
  gap: 8px;
}

.custom-size-add .custom-input {
  width: 120px;
}

.custom-size-unit {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-sunken);
  padding: 2px;
}

.custom-size-unit-option {
  height: 28px;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 0 10px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-size-unit-option:hover {
  color: var(--text-strong);
}

.custom-size-unit-option.is-active {
  background: var(--surface-raised);
  color: var(--text-strong);
}

.custom-size-convert {
  font-size: 12px;
  color: var(--text-muted);
}

/* the node's sizes as switches: the common ones and every size it has */
.custom-size-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-bottom: 12px;
}

.custom-preset {
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 7px;
  background: #313131;
  padding: 5px 9px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-preset:hover {
  background: #3d3d3d;
}

.custom-preset.is-on {
  border-color: var(--accent-brand);
  background: rgba(255, 158, 69, 0.14);
  color: var(--accent-brand);
}

/* ── foot ─────────────────────────────────────────────────────────────── */
.custom-shell-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  background: #191919;
  padding: 14px 24px;
}

.custom-foot-left,
.custom-foot-right {
  display: flex;
  align-items: center;
  gap: 10px;
}

.custom-estimate {
  font-size: 12px;
  color: var(--text-muted);
}

.custom-estimate.is-problem {
  color: #ffbe7a;
}

/* Orange like the Apply of Edit bet sizes (owner 2026-10-02): white label,
   lifts and glows on hover. */
.custom-primary-button {
  background: var(--accent-brand);
  color: var(--text-on-brand);
  transition: transform 180ms ease-out, filter 180ms ease-out;
}

.custom-primary-button:hover:not(:disabled) {
  background: var(--accent-brand);
  color: var(--text-on-brand);
  transform: translateY(-1px);
  filter: brightness(1.07) drop-shadow(0 4px 10px rgba(255, 158, 69, 0.45));
}

/* ── range picker ─────────────────────────────────────────────────────── */
.custom-range-backdrop {
  z-index: 65;
}

/* As wide as the grid and the tool column need (owner 2026-10-02: no empty
   space, the grid fits without scrolling). */
.custom-range-panel {
  display: flex;
  width: fit-content;
  max-width: 100%;
  max-height: 100%;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 14px;
  background: #1b1b1b;
  box-shadow: 0 32px 110px rgba(0, 0, 0, 0.7);
}

.custom-range-head-slot {
  display: flex;
  align-items: center;
  gap: 12px;
}

.custom-range-tab {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid transparent;
  border-bottom: 2px solid transparent;
  border-radius: 10px;
  background: #242424;
  padding: 8px 16px 8px 8px;
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.custom-range-tab.is-active {
  border-bottom-color: var(--accent-brand);
  background: #2c2c2c;
}

.custom-range-tab-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  text-align: left;
}

.custom-range-tab-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.custom-range-tab-title em {
  font-size: 13px;
  font-style: normal;
  color: var(--text-muted);
}

.custom-range-tab-meta {
  font-size: 12px;
  color: var(--text-muted);
}

.custom-range-tab-percent {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-normal);
}

.custom-range-swap {
  display: grid;
  width: 38px;
  height: 38px;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 9px;
  background: #2c2c2c;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-range-swap:hover {
  background: #383838;
  color: var(--text-strong);
}

.custom-range-body {
  display: grid;
  min-height: 0;
  flex: 1;
  grid-template-columns: 240px auto;
  gap: 20px;
  overflow: hidden;
  /* 24px over the grid and the seat cards (owner 2026-10-17, from DevTools; was 16) */
  padding: 24px 20px 20px;
}

.custom-range-left {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 12px;
}

.custom-range-note:empty {
  display: none;
}

.custom-range-note {
  margin: 0;
  font-size: 12px;
  color: var(--accent-brand);
}

.custom-range-transfer {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.custom-range-transfer-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* Range editor grid: the study matrix's own .matrix / .matrix-cell /
   .cell-fill / .matrix-cell-label (study.css), like node locking
   (custom-lock.css), so all three grids look the same (owner 2026-10-02).
   Only the brush cursor and the one-colour weight band belong here. */
/* Fitted to the window HEIGHT like node locking: 327px is the backdrop
   padding, the brush row and the Close / Confirm row under the grid, and
   the body padding (305 until the brush row got 8px more room under its
   sliders and 6px more over them and the body 8px more on top, owner
   2026-10-17: the grid gave those 22px); 1.15 keeps the
   popup narrower than the 800/620 grid would (owner 2026-10-02), the cells
   just get a little taller. It also leaves the tool column its width. */
.custom-range-matrix {
  width: clamp(420px, min(calc((100vh - 327px) * 1.15), calc(100vw - 390px)), 780px);
  aspect-ratio: 1.15;
  /* The labels scale with the grid (cqw). On the grid itself, which has its
     own width: on the auto-width column it collapsed that column to nothing. */
  container-type: inline-size;
  touch-action: none;
  user-select: none;
}

.custom-range-matrix .matrix-cell-label {
  font-size: clamp(11px, 2cqw, 15px);
}

.matrix-cell.custom-range-cell {
  cursor:
    url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M3%2021c0-2.2%201.1-3.4%202.2-3.9l2.7%202.7C7.4%2020.9%206.2%2022%204%2022H3z'%20fill='%23ffffff'%20stroke='%23111111'%20stroke-width='1.1'%20stroke-linejoin='round'/%3E%3Cpath%20d='M9.1%2018.2%205.8%2014.9%2016.4%204.3l3.3%203.3z'%20fill='%23f0921f'%20stroke='%23111111'%20stroke-width='1.1'%20stroke-linejoin='round'/%3E%3C/svg%3E")
      3 21,
    crosshair;
}

/* No hover tint: the brush preview itself is the hover cue. */
.matrix-cell.custom-range-cell:hover {
  z-index: 10;
  filter: none;
}

/* Hover preview of the brush: the band as a click would leave it, a little
   see-through so it reads as "not painted yet". */
.matrix-cell.custom-range-cell.is-preview .custom-range-cell-fill {
  opacity: 0.6;
}

.custom-range-cell-fill {
  width: 100%;
  background: var(--accent-brand);
}

/* Tools on the left, the grid on the right (owner 2026-10-02). */
.custom-range-seats {
  display: flex;
  flex-direction: column;
}

.custom-range-seats .custom-range-head-slot {
  flex-direction: column;
  align-items: stretch;
  gap: 0;
}

.custom-range-seats .custom-range-tab {
  width: 100%;
  border: 1px solid transparent;
  border-radius: 12px;
}

.custom-range-seats .custom-range-tab.is-active {
  border-color: var(--accent-brand);
}

/* Between the two seats: Export, Swap (arrows up/down), Import. */
.custom-range-seat-tools {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 8px;
  margin: 10px 0;
}

.custom-range-seat-tools .custom-chip-button {
  justify-content: center;
  padding: 0 8px;
}

.custom-range-seats .custom-range-swap {
  width: 32px;
  height: 28px;
}

.custom-range-seats .custom-range-swap svg {
  transform: rotate(90deg);
}

/* height 0 + min-height 100%: the column takes the grid's height and never
   sets it, so a long Saved ranges list scrolls instead of growing the popup
   (owner 2026-10-02). */
.custom-range-side {
  order: -1;
  display: flex;
  min-width: 0;
  height: 0;
  min-height: 100%;
  flex-direction: column;
  gap: 14px;
}

/* Under the grid: [brush weight] [top hands] [select all / clear], all
   aligned to the bottom so both sliders sit on one line. Exactly as wide as
   the grid (owner 2026-10-17: «по ширине матрицу выравняй с блоком где Hands
   by strength»): width 0 + min-width 100% - the column takes the grid's width
   and the fields' own widths no longer widen it past the grid. */
.custom-range-tools {
  width: 0;
  min-width: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 110px;
  align-items: end;
  gap: 16px;
  border-radius: 12px;
  background: #222222;
  /* 20px under the sliders (owner 2026-10-17: «чтобы под полосками веса и силы было больше места снизу»): their 14px knobs hang 5px
     under the 4px track, so the room under a knob matches the room over the labels */
  padding: 12px 12px 20px;
}

/* Compact controls inside the brush card (owner 2026-10-02: they took too
   much room): 32px fields and 28px buttons instead of 42 / 34. */
.custom-range-tools .custom-stepper {
  gap: 4px;
}

.custom-range-tools .custom-stepper-label,
.custom-range-tools .custom-readout {
  font-size: 11px;
}

.custom-range-tools .custom-stepper-box {
  height: 32px;
  border-radius: 8px;
}

.custom-range-tools .custom-stepper-box > button {
  width: 30px;
  font-size: 16px;
}

.custom-range-tools .custom-stepper-box > input {
  font-size: 14px;
}

.custom-range-tools .custom-readout {
  gap: 4px;
}

.custom-range-tools .custom-readout strong {
  height: 30px;
  border-radius: 8px;
  padding: 0 10px;
  font-size: 13px;
}

.custom-range-tools .custom-chip-button,
.custom-range-seat-tools .custom-chip-button {
  height: 28px;
  border-radius: 7px;
  font-size: 12px;
}

.custom-range-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

/* The brush weight slider takes a press 8px above and below its 4px track (owner 2026-10-17: a press had to hit the track exactly): a
   20px input drawing its track as a 4px band in the middle, pulled back to a 4px footprint by the margins, so the columns stay level. */
.custom-range-tools .custom-range-brush .custom-edit-slider {
  height: 20px;
  margin: -8px 0;
  background-color: transparent;
  background-position: center;
  background-repeat: no-repeat;
  background-size: 100% 4px;
}

.custom-range-tools .custom-range-brush .custom-edit-slider::-moz-range-track {
  background: transparent;
}

/* 16px between the box and its slider (owner 2026-10-17, from DevTools; was 10) */
.custom-range-brush,
.custom-range-top {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 16px;
}

/* Hands by strength is laid out as Brush weight beside it (owner 2026-10-17: «некрасиво выглядит ползунок где hands by strenght, почему
   он съехал?»): the label on top as the brush label, the from - to fields as tall as the brush stepper (32px), the track on the brush
   slider's line - both columns are 11 + 4 + 32 + 16 + 4 px, so the bottom-aligned row puts the labels, boxes and tracks level. */
.custom-range-top-head {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
}

/* From / To fields of the strength band. */
.custom-range-band-fields {
  display: flex;
  height: 32px;
  align-items: center;
  gap: 6px;
}

.custom-range-band-fields em {
  font-size: 13px;
  font-style: normal;
  color: var(--text-muted);
}

.custom-input.custom-range-band-input {
  width: 0;
  flex: 1;
  height: 32px;
  border-radius: 8px;
  padding: 0 10px;
  text-align: right;
  font-size: 14px;
  font-weight: 700;
  -moz-appearance: textfield;
}

.custom-range-band-input::-webkit-inner-spin-button,
.custom-range-band-input::-webkit-outer-spin-button {
  margin: 0;
  -webkit-appearance: none;
}

/* Two knobs on one track: both inputs lie on the drawn track, transparent and
   click-through; only their knobs take the pointer (a press elsewhere is the
   track's, below). The track is the brush slider's 4px at top 0; the 20px
   inputs at top -8px centre their knobs on it, as the brush slider does. The
   inputs were 14px over a track at top 5px, but the later 4px slider rule took
   their height and the knobs floated 5px above the track (owner 2026-10-17). */
.custom-range-dual {
  position: relative;
  height: 4px;
  cursor: pointer;
  touch-action: none;
}

/* The track takes a press 8px above and below it (RangePickerModal pressBand: the nearer knob comes there), not only on its 4px. */
.custom-range-dual::before {
  content: "";
  position: absolute;
  inset: -8px 0;
}

.custom-range-dual-track {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  height: 4px;
  border-radius: 999px;
}

/* three classes: custom-node-edit.css's :is(.custom-edit-row, .custom-range-tools) .custom-edit-slider (4px) comes later */
.custom-range-tools .custom-range-dual .custom-range-dual-input {
  position: absolute;
  top: -8px;
  left: 0;
  width: 100%;
  height: 20px;
  margin: 0;
  background: transparent;
  pointer-events: none;
}

.custom-range-tools .custom-range-dual-input.is-raised {
  z-index: 1;
}

.custom-range-dual-input::-webkit-slider-thumb {
  pointer-events: auto;
}

.custom-range-dual-input::-moz-range-thumb {
  pointer-events: auto;
}

.custom-range-dual-input::-moz-range-track {
  background: transparent;
}

.custom-range-top-head strong {
  color: var(--text-strong);
}

.custom-range-bulk {
  display: grid;
  gap: 6px;
}

.custom-range-bulk .custom-chip-button {
  justify-content: center;
}

/* Saved ranges take what is left of the column and scroll on their own. */
.custom-range-saved {
  display: flex;
  min-height: 0;
  flex: 1;
  flex-direction: column;
  gap: 10px;
}

.custom-range-saved .custom-saved-list {
  min-height: 0;
  overflow-y: auto;
}

.custom-range-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

.custom-range-actions button {
  min-width: 120px;
}

.custom-range-side-head h3 {
  margin: 0 0 8px;
  font-size: 17px;
  font-weight: 700;
  color: var(--text-strong);
}

.custom-range-side-save {
  display: flex;
  gap: 6px;
}

.custom-range-side-save .custom-input {
  width: 100%;
}

.custom-saved-empty {
  margin: 0;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 10px;
  background: #212121;
  padding: 16px;
  font-size: 13px;
  color: var(--text-muted);
}

.custom-saved-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
  list-style: none;
  padding: 0;
}

.custom-saved-list > li {
  display: flex;
  align-items: center;
  gap: 4px;
}

.custom-saved-row {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  border: none;
  border-radius: 8px;
  background: #242424;
  padding: 9px 12px;
  text-align: left;
  font-size: 13px;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-saved-row:hover {
  background: #303030;
  color: var(--text-strong);
}

.custom-saved-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.custom-saved-delete {
  display: grid;
  width: 30px;
  height: 30px;
  place-items: center;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-saved-delete:hover {
  background: #3a3a3a;
  color: #ff9d9d;
}

.custom-slider {
  width: 100%;
  height: 6px;
  appearance: none;
  border-radius: 999px;
  background: linear-gradient(90deg, #4a4a4a, var(--accent-brand));
  outline: none;
}

.custom-slider::-webkit-slider-thumb {
  width: 18px;
  height: 18px;
  appearance: none;
  border: none;
  border-radius: 50%;
  background: var(--accent-brand);
  cursor: pointer;
}

.custom-slider::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border: none;
  border-radius: 50%;
  background: var(--accent-brand);
  cursor: pointer;
}

.custom-readout {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12px;
  color: var(--text-muted);
}

.custom-readout strong {
  display: flex;
  align-items: center;
  height: 38px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 10px;
  background: #2c2c2c;
  padding: 0 14px;
  font-size: 16px;
  font-weight: 700;
  color: var(--text-strong);
}

/* ── solution ─────────────────────────────────────────────────────────── */
.custom-solution-head {
  display: flex;
  align-items: center;
  gap: 14px;
}

.custom-status {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 999px;
  background: #242424;
  padding: 7px 16px;
  font-size: 13px;
  color: var(--text-muted);
}

.custom-status strong {
  font-size: 14px;
  color: var(--text-strong);
}

.custom-status.is-done {
  border-color: rgba(255, 158, 69, 0.5);
}

.custom-status.is-error {
  border-color: rgba(255, 107, 107, 0.5);
}

.custom-spin {
  animation: custom-spin 900ms linear infinite;
}

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

.custom-solution-id {
  margin-left: auto;
  font-size: 12px;
  color: var(--text-muted);
}

.custom-solution-progress {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.custom-progress-bar {
  height: 8px;
  overflow: hidden;
  border-radius: 999px;
  background: #2c2c2c;
}

.custom-progress-bar > i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #b8661f, var(--accent-brand));
  transition: width 400ms ease;
}

.custom-solution-board {
  display: flex;
  align-items: center;
  gap: 6px;
}

.custom-solution-money {
  margin-left: 12px;
  font-size: 13px;
  color: var(--text-muted);
}

.custom-solution-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.custom-action-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 9px;
  background: #2a2a2a;
  padding: 0 14px;
  font-size: 14px;
  color: var(--text-normal);
  cursor: pointer;
}

.custom-action-button:hover {
  background: #343434;
}

.custom-action-button b {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
}

.custom-card-button {
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
}

.custom-table-scroll {
  overflow: auto;
  max-height: 420px;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 10px;
}

.custom-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.custom-table th,
.custom-table td {
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  padding: 7px 12px;
  text-align: right;
  white-space: nowrap;
}

.custom-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: #262626;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.custom-table tbody th {
  text-align: left;
  font-weight: 700;
  color: var(--text-strong);
}

.custom-table tbody tr:hover,
.custom-table tbody tr.is-selected {
  background: #2b2b2b;
}

.custom-table-mix {
  position: relative;
}

.custom-mix-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  opacity: 0.22;
}

.custom-table-mix > span {
  position: relative;
  z-index: 1;
}

.custom-table-mix em {
  margin-left: 8px;
  font-size: 11px;
  font-style: normal;
  color: var(--text-muted);
}

/* ── narrow screens ───────────────────────────────────────────────────── */
@media (max-width: 1080px) {
  .custom-backdrop { padding: 10px; }
  .custom-shell-body { grid-template-columns: 1fr; }
  .custom-nav { flex-direction: row; overflow-x: auto; border-right: none; border-bottom: 1px solid rgba(255, 255, 255, 0.07); }
  .custom-nav-tabs { display: none; }
  .custom-nav-item { flex-shrink: 0; }
  .custom-players-head { display: none; }
  .custom-player-row { grid-template-columns: 1fr; }
  .custom-seat-grid { grid-template-columns: 1fr; }
  .custom-range-panel { width: 100%; }
  .custom-range-body { grid-template-columns: 1fr; overflow-y: auto; }
  .custom-range-matrix { width: 100%; }
  .custom-main { padding: 16px; }
  .custom-rake-picker-body { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
  .custom-rake-rooms { flex-direction: row; border-right: none; border-bottom: 1px solid rgba(255, 255, 255, 0.07); }
  .custom-rake-room { margin-inline: 0; }
}

@media (max-width: 720px) {
  .custom-shell-foot { flex-direction: column; align-items: stretch; }
  .custom-foot-right { justify-content: flex-end; }
}


/* Admin-only engine controls (owner 2026-09-28): GPU state, iterations, measured solve time. */
.custom-admin-engine {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  color: var(--text-muted);
}

.custom-admin-engine.is-gpu {
  color: var(--accent-brand);
}

.custom-admin-engine.is-cpu {
  color: var(--grade-warn);
}

/* The GPU state itself (owner 2026-10-04): green when connected, the orange
   of the block when not. The one green allowed in this dialog. */
.custom-admin-engine.is-gpu .custom-admin-engine-state {
  color: var(--grade-good);
}

.custom-admin-iterations {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--text-muted);
}

.custom-iteration-button {
  height: 24px;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 6px;
  background: #2c2c2c;
  padding: 0 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-iteration-button:hover {
  background: #383838;
  color: var(--text-strong);
}

.custom-iteration-button.is-active {
  border-color: var(--accent-brand);
  background: #8a4f1c;
  color: var(--text-strong);
}

/* ── Starting Street "Preflop": the preflop network block (owner 2026-10-06) ── */
.custom-preflop {
  display: grid;
  gap: 16px;
  margin-top: 24px;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 10px;
  background: #222222;
  padding: 16px 18px;
}

.custom-preflop-head {
  display: flex;
  align-items: center;
  gap: 10px;
}

.custom-preflop-head h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.custom-preflop-tag {
  border: 1px solid var(--accent-brand);
  border-radius: 6px;
  padding: 2px 8px;
  font-size: 12px;
  font-weight: 700;
  color: var(--accent-brand);
}

/* The fixed parts of the preflop network tree (open, 3-bet, 4-bet, limp): pills to read, not to press. */
.custom-pill.is-static {
  cursor: default;
}

/* The preflop size lists (owner 2026-10-09): the postflop editor's rows, one per raise level. */
.custom-preflop-sizes {
  display: grid;
  gap: 6px;
}
/* ============================================================================
   Custom Solutions — "Set Frequencies": the node-locking dialog opened from the
   lock icon of a node card in the study carousel.

   Left: the brush — one probability row over this node's actions.
   Right: the 13x13 grid of the acting player's range, where a square is
   painted with that row and pinned. Apply sends the pinned squares to the
   solver; nothing here edits a strategy on its own.
   ============================================================================ */

.custom-lock-backdrop {
  z-index: 70;
}

.custom-lock-panel {
  display: flex;
  max-width: 100%;
  max-height: 100%;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 14px;
  background: #1b1b1b;
  box-shadow: 0 32px 110px rgba(0, 0, 0, 0.7);
}

.custom-lock-panel.is-busy {
  pointer-events: none;
}

/* ── brush column ─────────────────────────────────────────────────────── */
.custom-lock-side {
  display: flex;
  width: 300px;
  flex-shrink: 0;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto;
  border-right: 1px solid rgba(255, 255, 255, 0.07);
  padding: 16px;
}

.custom-lock-side-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.custom-lock-side-head h3 {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-strong);
}

.custom-lock-hint {
  display: grid;
  place-items: center;
  color: var(--text-muted);
  cursor: help;
}

.custom-lock-tabs {
  display: flex;
  gap: 4px;
  border-radius: 8px;
  background: #242424;
  padding: 3px;
}

.custom-lock-tab {
  flex: 1;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-lock-tab.is-active {
  background: #333333;
  color: var(--text-strong);
}

.custom-lock-tab:disabled {
  opacity: 0.4;
  cursor: default;
}

.custom-lock-note {
  font-size: 12px;
  color: var(--text-muted);
}

.custom-lock-paint {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.custom-lock-paint-title {
  font-size: 12px;
  color: var(--text-soft);
}

/* Shared readout of a mix: horizontal segments, red-first, like the study
   matrix band. */
.custom-lock-bar {
  display: flex;
  height: 10px;
  overflow: hidden;
  border-radius: 999px;
  background: #2b2b2b;
}

.custom-lock-bar > i {
  height: 100%;
}

.custom-lock-row {
  display: grid;
  align-items: center;
  gap: 4px 10px;
  grid-template-columns: 1fr 70px;
}

.custom-lock-row-name {
  display: flex;
  flex-direction: column;
  grid-column: 1 / -1;
}

.custom-lock-row-name strong {
  font-size: 13px;
  color: var(--text-normal);
}

.custom-lock-row-name small {
  font-size: 11px;
  color: var(--text-muted);
}

.custom-lock-percent {
  width: 70px;
  height: 30px;
  padding: 0 8px;
  text-align: center;
}

.custom-lock-side-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.custom-lock-scope {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12px;
  color: var(--text-muted);
}

.custom-lock-clear {
  align-self: flex-start;
}

/* ── matrix column ────────────────────────────────────────────────────── */
.custom-lock-main {
  display: flex;
  min-width: 0;
  /* As wide as the matrix (+ padding), but never narrower than the header
     row (board, pot, seat, view tabs, close) needs. The container makes the
     hand labels scale with the grid, as in the study matrix panel. */
  width: max(calc(clamp(420px, calc((100vh - 300px) * 1.29), 760px) + 32px), 560px);
  container-type: inline-size;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto;
  padding: 16px;
}

.custom-lock-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
}

.custom-lock-head .custom-lock-tab {
  white-space: nowrap;
}

.custom-lock-board {
  display: flex;
  align-items: center;
  gap: 4px;
}

.custom-lock-pot,
.custom-lock-seat {
  margin-left: 6px;
  border-radius: 6px;
  background: #2b2b2b;
  padding: 4px 8px;
  font-size: 12px;
  color: var(--text-soft);
}

.custom-lock-head .custom-lock-tabs {
  margin-left: auto;
}

.custom-lock-current {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12px;
  color: var(--text-muted);
}

.custom-lock-blocked {
  border-radius: 8px;
  background: rgba(255, 158, 69, 0.12);
  padding: 8px 10px;
  font-size: 12px;
  color: var(--text-soft);
}

.custom-lock-matrix {
  /* The cells are the study matrix's own (.matrix / .matrix-cell /
     .cell-fill / .matrix-cell-label in study.css), so both grids look the
     same (owner 2026-10-01). Only the size is this dialog's: the 800x620
     grid is fitted to the window HEIGHT so the dialog, header to Apply, fits
     a laptop screen; 300px is what the backdrop padding, header, strategy
     bar, footer and gaps take, 1.29 = 800 / 620. */
  width: clamp(420px, calc((100vh - 300px) * 1.29), 760px);
  align-self: center;
  touch-action: none;
  user-select: none;
}

/* Hand labels scale with the grid exactly as in the study matrix panel. */
.custom-lock-matrix .matrix-cell-label {
  font-size: clamp(12px, 2cqw, 22px);
}

/* A brush, so it is obvious the square is about to be painted rather than
   selected. The hotspot sits on the bristle tip. */
.matrix-cell.custom-lock-cell.is-paintable {
  cursor:
    url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M3%2021c0-2.2%201.1-3.4%202.2-3.9l2.7%202.7C7.4%2020.9%206.2%2022%204%2022H3z'%20fill='%23ffffff'%20stroke='%23111111'%20stroke-width='1.1'%20stroke-linejoin='round'/%3E%3Cpath%20d='M9.1%2018.2%205.8%2014.9%2016.4%204.3l3.3%203.3z'%20fill='%23f0921f'%20stroke='%23111111'%20stroke-width='1.1'%20stroke-linejoin='round'/%3E%3C/svg%3E")
      3 21,
    crosshair;
}

/* A pinned class: the study matrix's selection frame colour, drawn inside the
   square so neighbours do not shift. */
.matrix-cell.custom-lock-cell.is-locked {
  box-shadow: inset 0 0 0 2px var(--accent-brand);
}

.custom-lock-cell-pin {
  position: absolute;
  z-index: 20;
  top: 2px;
  right: 2px;
  display: grid;
  width: 17px;
  height: 17px;
  place-items: center;
  border: none;
  border-radius: 3px;
  background: rgba(15, 15, 15, 0.55);
  padding: 0;
  color: rgba(255, 255, 255, 0.45);
  cursor: pointer;
  opacity: 0;
  transition: opacity 120ms ease, color 120ms ease;
}

.custom-lock-cell:hover .custom-lock-cell-pin,
.custom-lock-cell-pin.is-on {
  opacity: 1;
}

.custom-lock-cell-pin.is-on {
  background: var(--accent-brand);
  color: #1d1205;
}

.custom-lock-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  padding-top: 12px;
}

.custom-lock-count {
  margin-right: auto;
  font-size: 12px;
  color: var(--text-muted);
}

@media (max-width: 900px) {
  .custom-lock-panel {
    flex-direction: column;
    overflow-y: auto;
  }

  .custom-lock-side {
    width: 100%;
    border-right: none;
    border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  }

  /* One column: the grid takes the dialog's width instead of the height fit. */
  .custom-lock-main,
  .custom-lock-matrix {
    width: 100%;
  }
}

/* Each brush slider wears its own action colour, so the row reads like the
   mix bar above it instead of three identical greys. */
.custom-lock-row .custom-slider.is-fold { background: linear-gradient(90deg, #4a4a4a, var(--action-fold)); }
.custom-lock-row .custom-slider.is-call { background: linear-gradient(90deg, #4a4a4a, var(--action-passive)); }
.custom-lock-row .custom-slider.is-bet { background: linear-gradient(90deg, #4a4a4a, var(--action-aggressive)); }
.custom-lock-row .custom-slider.is-raise { background: linear-gradient(90deg, #4a4a4a, var(--action-raise)); }
.custom-lock-row .custom-slider.is-allin { background: linear-gradient(90deg, #4a4a4a, var(--action-allin)); }
/* ============================================================================
   Custom Solutions — "Edit bet sizes": the pencil of a node card in the study
   carousel (C06, owner 2026-10-01). One row per bet/raise size (slider, value,
   % / bb, remove), an all-in switch, Add size; Apply re-solves the street.
   Same surface and controls as Set Frequencies (custom-lock.css).
   ============================================================================ */

.custom-edit-backdrop {
  z-index: 70;
}

/* Compact look settled on the under-the-card panel (owner 2026-10-01) and
   now used by the centred dialog: 420px, tight padding, no meta line. */
.custom-edit-panel {
  display: flex;
  width: min(420px, 100%);
  max-height: 100%;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 12px;
  background: #1b1b1b;
  padding: 8px 10px 12px 12px;
  box-shadow:
    0 22px 60px rgba(0, 0, 0, 0.62),
    0 2px 10px rgba(0, 0, 0, 0.4);
}

.custom-edit-panel.is-busy {
  pointer-events: none;
}

.custom-edit-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.custom-edit-head h3 {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.custom-edit-close {
  display: grid;
  width: 28px;
  height: 28px;
  place-items: center;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-edit-close:hover:not(:disabled) {
  background: #2b2b2b;
  color: var(--text-strong);
}

.custom-edit-message {
  border-radius: 8px;
  background: #242424;
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-soft);
}

.custom-edit-message.is-error {
  background: rgba(255, 93, 93, 0.12);
  color: #ff8a8a;
}

.custom-edit-rows {
  display: flex;
  /* Fixed height (five sizes, owner 2026-10-04; was three) with its own
     scroll: adding a size never resizes the dialog, so Add size below stays
     under the cursor (owner 2026-10-01). A row is 38px (30px field + 4px
     padding top and bottom), 4px apart: 5 x 38 + 4 x 4 = 206px. */
  height: 212px;
  flex-direction: column;
  gap: 4px;
  overflow-y: auto;
  padding-right: 4px;
  scrollbar-width: thin;
  scrollbar-color: #3a3a3a transparent;
}

.custom-edit-empty {
  display: grid;
  flex: 1;
  place-items: center;
  border: 1px dashed rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  padding: 16px;
  text-align: center;
  font-size: 13px;
  color: var(--text-muted);
}

/* Add size (left) and the all-in switch (right) share one row. */
.custom-edit-actions {
  display: flex;
  align-items: stretch;
  gap: 10px;
}

.custom-edit-actions .custom-edit-add {
  flex: 1;
}

.custom-edit-actions .custom-edit-allin {
  flex: none;
  padding: 0 14px;
}

/* Inputs focus in the site orange, not the shared green. */
.custom-edit-panel .custom-input:focus {
  border-color: var(--accent-brand);
  box-shadow: 0 0 0 2px rgba(255, 158, 69, 0.22);
}

.custom-edit-row {
  display: flex;
  flex: none;
  flex-direction: column;
  border-radius: 10px;
  background: #222222;
  padding: 4px 10px;
}

/* Slider, value, unit switch and remove on ONE line (owner 2026-10-01). */
.custom-edit-row-controls {
  display: grid;
  align-items: center;
  gap: 10px;
  grid-template-columns: 80px minmax(0, 1fr) 76px auto 20px;
}

.custom-edit-row-name {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-normal);
}

/* Value field with its own arrows: the native spinners are hidden (too small,
   and they sat on the digits); the digits keep clear of the arrows. */
.custom-edit-value-box {
  position: relative;
}

.custom-edit-value-box .custom-edit-value {
  width: 100%;
  padding: 0 26px 0 8px;
  -moz-appearance: textfield;
}

.custom-edit-value-box .custom-edit-value::-webkit-outer-spin-button,
.custom-edit-value-box .custom-edit-value::-webkit-inner-spin-button {
  margin: 0;
  -webkit-appearance: none;
}

.custom-edit-stepper {
  position: absolute;
  top: 2px;
  right: 2px;
  bottom: 2px;
  display: flex;
  width: 22px;
  flex-direction: column;
}

.custom-edit-stepper button {
  display: grid;
  flex: 1;
  place-items: center;
  border: none;
  border-radius: 4px;
  background: transparent;
  padding: 0;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-edit-stepper button:hover:not(:disabled) {
  background: #3a3a3a;
  color: var(--accent-brand);
}

.custom-edit-value {
  height: 30px;
  text-align: right;
}

.custom-edit-value.is-invalid {
  border-color: #ff5d5d;
}

.custom-edit-unit {
  display: flex;
  gap: 2px;
  border-radius: 8px;
  background: #2c2c2c;
  padding: 2px;
}

.custom-edit-unit-button {
  min-width: 32px;
  height: 26px;
  border: none;
  border-radius: 6px;
  background: transparent;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-edit-unit-button.is-active {
  background: #3d3d3d;
  color: var(--text-strong);
}

/* All-in: a switch, since it is one fixed size that is either in or out. */
.custom-edit-allin {
  display: flex;
  align-items: center;
  gap: 10px;
  border-radius: 10px;
  background: #222222;
  padding: 12px;
  font-size: 14px;
  color: var(--text-normal);
  cursor: pointer;
}

.custom-edit-allin input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

/* The switch: grey track, an orange layer that fades in when on (opacity, not
   a background transition), a white knob that slides, grows on hover and
   stretches while pressed. Only transform/opacity/filter animate (5b.3). */
.custom-edit-allin-switch {
  position: relative;
  width: 36px;
  height: 20px;
  flex: none;
  overflow: hidden;
  border-radius: 999px;
  background: #3a3a3a;
}

.custom-edit-allin-switch::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: var(--accent-brand);
  opacity: 0;
  transition: opacity 220ms ease;
}

.custom-edit-allin-switch::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 14px;
  height: 14px;
  border-radius: 999px;
  background: #f5f5f5;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
  transition: transform 260ms cubic-bezier(0.3, 1.4, 0.5, 1), filter 200ms ease;
}

.custom-edit-allin.is-on .custom-edit-allin-switch::before {
  opacity: 1;
}

.custom-edit-allin.is-on .custom-edit-allin-switch::after {
  transform: translateX(16px);
}

.custom-edit-allin:hover .custom-edit-allin-switch::after {
  transform: scale(1.12);
  filter: drop-shadow(0 0 4px rgba(255, 158, 69, 0.75));
}

.custom-edit-allin.is-on:hover .custom-edit-allin-switch::after {
  transform: translateX(16px) scale(1.12);
}

.custom-edit-allin:active .custom-edit-allin-switch::after {
  transform: scaleX(1.35);
}

.custom-edit-allin.is-on:active .custom-edit-allin-switch::after {
  transform: translateX(16px) scaleX(1.35);
}

.custom-edit-add {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 36px;
  border: 1px dashed rgba(255, 255, 255, 0.18);
  border-radius: 10px;
  background: transparent;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-edit-add:hover:not(:disabled) {
  border-color: var(--accent-brand);
  color: var(--text-strong);
}

.custom-edit-add:disabled {
  opacity: 0.4;
  cursor: default;
}

.custom-edit-hint {
  font-size: 12px;
  color: var(--text-muted);
}

.custom-edit-hint.is-warning {
  color: var(--accent-brand);
}

.custom-edit-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  padding-top: 14px;
}

.custom-edit-footer-actions {
  display: flex;
  gap: 8px;
}


/* Remove: a plain red cross, no button chrome and no motion. */
.custom-edit-remove {
  display: grid;
  width: 24px;
  height: 24px;
  place-items: center;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 0;
  color: #e5534b;
  cursor: pointer;
}

.custom-edit-remove svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

.custom-edit-remove:hover:not(:disabled) {
  color: #ff6b63;
}

.custom-edit-remove:focus-visible {
  outline: 2px solid var(--text-strong);
  outline-offset: 2px;
}

/* Apply in the site orange (the shared custom primary button is green). */
.custom-edit-footer .custom-primary-button {
  background: var(--accent-brand);
  color: var(--text-on-brand);
  transition: transform 180ms ease-out, filter 180ms ease-out;
}

/* Hover keeps the white label (the shared rule turns it near-black): the
   button lifts a pixel, brightens and glows softly; a press sinks it. */
.custom-edit-footer .custom-primary-button:hover:not(:disabled) {
  background: var(--accent-brand);
  color: var(--text-on-brand);
  transform: translateY(-1px);
  filter: brightness(1.07) drop-shadow(0 4px 10px rgba(255, 158, 69, 0.45));
}

.custom-edit-footer .custom-primary-button:active:not(:disabled) {
  transform: translateY(0) scale(0.98);
  filter: brightness(0.97);
}

/* Size slider (owner 2026-10-01): a thin neutral track filled in orange up to
   the knob (gradient set at runtime), a small white knob that grows slightly on
   hover and a little more while dragged, with a soft orange glow. Calm easing,
   transform/filter only (5b.3). */
/* Shared with the range editor's brush weight (owner 2026-10-02). */
:is(.custom-edit-row, .custom-range-tools) .custom-edit-slider {
  height: 4px;
  border-radius: 999px;
  cursor: pointer;
}

:is(.custom-edit-row, .custom-range-tools) .custom-edit-slider::-webkit-slider-thumb {
  width: 14px;
  height: 14px;
  border: none;
  border-radius: 50%;
  background: #f5f5f5;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
  transition: transform 160ms ease-out, filter 160ms ease-out;
}

:is(.custom-edit-row, .custom-range-tools) .custom-edit-slider::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border: none;
  border-radius: 50%;
  background: #f5f5f5;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
  transition: transform 160ms ease-out, filter 160ms ease-out;
}

:is(.custom-edit-row, .custom-range-tools) .custom-edit-slider:hover:not(:disabled)::-webkit-slider-thumb {
  transform: scale(1.15);
  filter: drop-shadow(0 0 4px rgba(255, 158, 69, 0.7));
}

:is(.custom-edit-row, .custom-range-tools) .custom-edit-slider:hover:not(:disabled)::-moz-range-thumb {
  transform: scale(1.15);
  filter: drop-shadow(0 0 4px rgba(255, 158, 69, 0.7));
}

:is(.custom-edit-row, .custom-range-tools) .custom-edit-slider:active::-webkit-slider-thumb {
  cursor: grabbing;
  transform: scale(1.25);
  filter: drop-shadow(0 0 6px rgba(255, 158, 69, 0.85));
}

:is(.custom-edit-row, .custom-range-tools) .custom-edit-slider:active::-moz-range-thumb {
  cursor: grabbing;
  transform: scale(1.25);
  filter: drop-shadow(0 0 6px rgba(255, 158, 69, 0.85));
}

:is(.custom-edit-row, .custom-range-tools) .custom-edit-slider:focus-visible {
  outline: 2px solid var(--text-strong);
  outline-offset: 4px;
}

/* The all-in row (owner 2026-10-05) looks and works like every size: live orange slider, value field with arrows, % / bb. A
   value under the stack typed there turns it into that bet/raise (NodeEditModal allinBelow). */

/* ----------------------------------------------------------------------------
   Anchored "Edit bet sizes" (owner 2026-10-01; switched off, Study uses the
   dialog): the same editor fixed under the opened card with an arrow.
   It appears and disappears at once, without animation. Position comes from
   the card at runtime (top/left/arrow); everything else lives here.
   ---------------------------------------------------------------------------- */

.custom-edit-anchor {
  position: fixed;
  z-index: 70;
  display: flex;
  width: min(420px, calc(100vw - 32px));
  flex-direction: column;
  visibility: hidden;
}

/* No animation (owner 2026-10-01): the panel appears and disappears at once.
   It stays hidden only until its place under the card is known. */
.custom-edit-anchor.is-placed {
  visibility: visible;
}

.custom-edit-anchor .custom-edit-panel {
  width: 100%;
  min-height: 0;
}

/* The arrow joins the panel to the card: drawn over the panel's top border so
   the two read as one shape. */
.custom-edit-arrow {
  position: absolute;
  top: -7px;
  z-index: 1;
  width: 14px;
  height: 14px;
  margin-left: -7px;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  border-left: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 3px 0 0 0;
  background: #1b1b1b;
  transform: rotate(45deg);
}

/* Check / call / fold rows (owner 2026-10-01): shaped like a size row, the
   slider and value replaced by a quiet placeholder line. A removed move stays
   in the list, dimmed, with a green plus to bring it back. */
.custom-edit-row.is-passive .custom-edit-row-controls {
  min-height: 30px;
}

.custom-edit-passive-track {
  grid-column: 2 / 5;
  height: 4px;
  border-radius: 999px;
  background: #2e2e2e;
}

.custom-edit-row.is-removed {
  background: transparent;
  outline: 1px dashed #333333;
  outline-offset: -1px;
}

.custom-edit-row.is-removed .custom-edit-row-name {
  color: var(--text-muted);
  text-decoration: line-through;
}

.custom-edit-row.is-removed .custom-edit-passive-track {
  background: transparent;
}

/* Restore: a plain green plus, the counterpart of the red cross. */
.custom-edit-restore {
  display: grid;
  width: 24px;
  height: 24px;
  place-items: center;
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 0;
  color: #3fb950;
  cursor: pointer;
}

.custom-edit-restore svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

.custom-edit-restore:hover:not(:disabled) {
  color: #56d364;
}
/* ============================================================================
   Custom Solutions — «Compare nodes»: the columns icon of a node card in the
   study carousel (C12, owner 2026-10-19). The node as Study shows it now next
   to the same node in its earlier solve, before the user's locks and size
   edits on its line (features/custom/NodeCompareModal.tsx).

   Redrawn after GTO Wizard's compare (owner 2026-10-19: «гораздо красивее,
   интуитивно понятнее ... сделать аналог»): two full matrices — Current on
   the left, the earlier solve on the right — and one column between them.
   Every line of that column reads both: the current number on the left, the
   earlier one on the right, a bar growing from the middle to each side.
   Same surface as Set Frequencies (custom-lock.css).
   ============================================================================ */

.custom-compare-backdrop {
  z-index: 70;
  padding: 20px;
}

.custom-compare-panel {
  display: flex;
  width: min(1760px, 100%);
  height: 100%;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 14px;
  background: #1b1b1b;
  box-shadow: 0 32px 110px rgba(0, 0, 0, 0.7);
  /* where it is and whether it is seen: two animations (frontend_rules 5b.1) */
  animation:
    custom-compare-rise 240ms cubic-bezier(0.22, 1, 0.36, 1) both,
    custom-compare-fade 160ms linear both;
}

/* The windows' rule gives every element inside a window overscroll-behavior:
   contain (study-modal.css). In Chrome every overflow: hidden box is a scroll
   container, so the wheel stopped at whatever such box was under the pointer
   - a bar, a number, a group's name - and the middle column did not scroll
   over its rows (owner 2026-10-19: «когда я навожу на какое-то поле, например
   Straight ... скролл вертикальный не блокировался»). Here only the real
   scrollers keep it: the column, and the body on a narrow window. */
.custom-compare-panel * {
  overscroll-behavior: auto;
}

.custom-compare-panel .custom-compare-center-scroll,
.custom-compare-panel .custom-compare-body {
  overscroll-behavior: contain;
}

@keyframes custom-compare-rise {
  from { transform: translateY(12px) scale(0.985); }
  to { transform: translateY(0) scale(1); }
}

@keyframes custom-compare-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ── head ─────────────────────────────────────────────────────────────── */
.custom-compare-head {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 12px 10px 20px;
}

.custom-compare-head h3 {
  white-space: nowrap;
  font-size: 16px;
  font-weight: 800;
  color: var(--text-strong);
}

.custom-compare-node {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.custom-compare-board {
  display: flex;
  gap: 3px;
  margin-right: 4px;
}

.custom-compare-chip {
  border-radius: 6px;
  background: #2b2b2b;
  padding: 4px 8px;
  font-size: 12px;
  color: var(--text-soft);
}

.custom-compare-chip.is-seat {
  font-weight: 700;
  color: var(--text-strong);
}

.custom-compare-pick {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  color: var(--text-muted);
}

/* Two or three options in one rail, like the lock dialog's tabs. */
.custom-compare-segment {
  display: flex;
  gap: 4px;
  border-radius: 8px;
  background: #242424;
  padding: 3px;
}

.custom-compare-segment-option {
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 6px 12px;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-compare-segment.is-small .custom-compare-segment-option {
  padding: 4px 9px;
  font-size: 11px;
}

.custom-compare-segment-option:hover {
  color: var(--text-strong);
}

.custom-compare-segment-option.is-active {
  background: #333333;
  color: var(--text-strong);
}

/* What changed between the two solves. */
/* One height whatever it holds - a sentence, the change chips or the loading
   line - so switching Original solve / Previous step moves nothing under it
   (owner 2026-10-19: «на пиксель-два ездит всё в попапе»; the chips were a
   pixel taller than the sentence). */
.custom-compare-note {
  display: flex;
  min-height: 34px;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 20px;
  border-radius: 8px;
  background: rgba(255, 158, 69, 0.08);
  padding: 7px 12px;
  font-size: 13px;
  line-height: 20px;
  color: var(--text-normal);
}

.custom-compare-note > svg {
  flex-shrink: 0;
  color: var(--accent-brand);
}

.custom-compare-change-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-left: auto;
}

.custom-compare-change-chip {
  border-radius: 999px;
  background: #2b2b2b;
  padding: 2px 8px;
  font-size: 11px;
  line-height: 16px;
  color: var(--text-soft);
}

.custom-compare-skeleton-line {
  position: relative;
  width: 220px;
  height: 10px;
  overflow: hidden;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.08);
}

.custom-compare-skeleton-line::before {
  content: "";
  position: absolute;
  top: -6px;
  bottom: -6px;
  left: 0;
  width: 40%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, #ffffff18, #ffffff50, #ffffff18, transparent);
  animation: custom-compare-sheen 900ms ease-in-out infinite;
}

/* ── body: matrix | the column | matrix ───────────────────────────────── */
.custom-compare-body {
  display: grid;
  min-height: 0;
  flex: 1;
  gap: 18px;
  grid-template-columns: minmax(0, 1fr) 320px minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  padding: 12px 20px 20px;
}

.custom-compare-slot {
  display: flex;
  min-width: 0;
  min-height: 0;
  flex-direction: column;
  gap: 8px;
}

.custom-compare-slot-head {
  display: flex;
  height: 30px;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
}

.custom-compare-slot-head strong {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-strong);
}

.custom-compare-locks {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border-radius: 999px;
  background: rgba(255, 158, 69, 0.14);
  padding: 3px 8px;
  font-size: 11px;
  font-weight: 700;
  color: var(--accent-brand);
}

/* The matrix takes all the slot gives: the full width while its cells stay
   between the study matrix's 800 x 620 and square-ish, the full height while
   it stays at least that wide. */
.custom-compare-matrix-box {
  display: flex;
  min-height: 0;
  flex: 1;
  align-items: flex-start;
  justify-content: center;
  container-type: size;
}

.custom-compare-matrix-box > .matrix {
  width: min(100cqw, calc(100cqh * 800 / 620));
  height: min(100cqh, calc(100cqw * 1.05));
  aspect-ratio: auto;
}

.custom-compare-matrix-box > .custom-compare-missing {
  width: min(100cqw, calc(100cqh * 800 / 620));
}

/* The cells are the study matrix's own (.matrix / .matrix-cell / .cell-fill /
   .matrix-cell-label in study.css); only the label size fits this grid. */
.custom-compare-matrix {
  user-select: none;
}

.custom-compare-matrix .matrix-cell-label.is-compact {
  top: 4px;
  left: 4px;
  font-size: clamp(8px, min(2.25cqw, 2.95cqh), 14px);
}

.custom-compare-matrix .matrix-cell-metric {
  right: 4px;
  bottom: 3px;
  font-size: clamp(9px, min(2.1cqw, 2.7cqh), 13px);
  color: var(--text-strong);
}

.custom-compare-matrix .matrix-cell-lock {
  top: 4px;
  right: 4px;
}

.matrix-cell.custom-compare-cell {
  transition: opacity 160ms ease;
}

.matrix-cell.custom-compare-cell.has-reach {
  cursor: pointer;
}

/* The class in focus (under the pointer, or clicked) in both matrices at
   once: a light frame inside the square, drawn OVER the fill. As the cell's
   own inset shadow it lay under .cell-fill, so a fully filled class showed no
   frame and a partly filled one only its top (owner 2026-10-19: «на некоторых
   комбинациях в матрице есть белая обводка а на некоторых нету»). */
.matrix-cell.custom-compare-cell.is-highlight {
  z-index: 20;
}

.matrix-cell.custom-compare-cell.is-highlight::after {
  content: "";
  position: absolute;
  z-index: 30;
  inset: 0;
  pointer-events: none;
  box-shadow: inset 0 0 0 2px var(--text-strong);
}

/* Outside the hand group under the pointer, or unchanged with «Changes» on. */
.matrix-cell.custom-compare-cell.is-quiet {
  opacity: 0.22;
}

/* Loading: the empty grid with one light passing over it. */
.custom-compare-matrix.is-loading .matrix-skeleton-cell {
  border-right: none;
  border-left: 1px solid #2c2c2c;
  border-bottom: 1px solid #2c2c2c;
}

.custom-compare-sheen {
  position: absolute;
  z-index: 5;
  top: -10%;
  bottom: -10%;
  left: 0;
  width: 40%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.05), transparent);
  transform: translateX(-120%) skewX(-18deg);
  animation: custom-compare-sheen 1100ms ease-in-out infinite;
}

@keyframes custom-compare-sheen {
  from { transform: translateX(-120%) skewX(-18deg); }
  to { transform: translateX(300%) skewX(-18deg); }
}

.custom-compare-missing {
  display: flex;
  aspect-ratio: 800 / 620;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border: 1px dashed rgba(255, 255, 255, 0.12);
  background: #1f1f1f;
  padding: 24px;
  text-align: center;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-soft);
}

.custom-compare-missing > svg {
  color: var(--text-muted);
}

/* ── the column between the matrices ──────────────────────────────────── */
.custom-compare-center {
  display: flex;
  min-width: 0;
  min-height: 0;
  flex-direction: column;
  gap: 8px;
}

.custom-compare-center-bar {
  display: flex;
  height: 30px;
  flex-shrink: 0;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.custom-compare-toggle {
  display: inline-flex;
  height: 30px;
  align-items: center;
  gap: 6px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 8px;
  background: #242424;
  padding: 0 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-compare-toggle:hover {
  color: var(--text-strong);
}

.custom-compare-toggle.is-on {
  border-color: rgba(255, 158, 69, 0.5);
  background: rgba(255, 158, 69, 0.14);
  color: var(--accent-brand);
}

/* Which side is which: over the left and right numbers of every line. */
.custom-compare-sides {
  display: flex;
  flex-shrink: 0;
  overflow: hidden;
  scrollbar-gutter: stable both-edges;
  justify-content: space-between;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  padding: 2px 12px 7px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-muted);
}

.custom-compare-center-scroll {
  display: flex;
  min-height: 0;
  flex: 1;
  flex-direction: column;
  gap: 10px;
  overflow-y: auto;
  /* the bar's place is kept (on both sides, as over the «Current / earlier» line) while the shorter loading lines stand in,
     so the column does not move sideways */
  scrollbar-gutter: stable both-edges;
  scrollbar-width: thin;
}

.custom-compare-card {
  display: flex;
  flex-shrink: 0;
  flex-direction: column;
  gap: 8px;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 10px;
  background: #222222;
  padding: 10px 12px 8px;
}

.custom-compare-card-head {
  display: flex;
  min-height: 24px;
  align-items: center;
  gap: 8px;
}

.custom-compare-card-head h4 {
  flex: 1;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-muted);
}

.custom-compare-class {
  font-size: 17px;
  font-weight: 900;
  color: var(--text-strong);
}

.custom-compare-card-meta {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.custom-compare-unpin {
  display: grid;
  width: 24px;
  height: 24px;
  place-items: center;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.custom-compare-unpin:hover {
  background: #333333;
  color: var(--text-strong);
}

.custom-compare-message {
  display: flex;
  align-items: center;
  gap: 8px;
  border-radius: 8px;
  background: #242424;
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-soft);
}

.custom-compare-hint {
  padding-bottom: 4px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
}

/* ── a line: current | name | earlier, the bar under it ────────────────── */
.custom-compare-rows {
  display: flex;
  flex-direction: column;
}

.custom-compare-rows.is-nested {
  margin-top: 2px;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  padding-top: 2px;
}

.custom-compare-row {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 5px 0;
}

.custom-compare-row-line,
.custom-compare-group-head {
  display: grid;
  align-items: center;
  gap: 8px;
  grid-template-columns: 56px minmax(0, 1fr) 56px;
}

.custom-compare-value {
  overflow: hidden;
  white-space: nowrap;
  font-size: 14px;
  font-weight: 800;
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}

.custom-compare-value.is-left {
  text-align: left;
}

.custom-compare-value.is-right {
  text-align: right;
}

.custom-compare-value.is-none {
  font-weight: 600;
  color: var(--text-muted);
}

.custom-compare-row-name {
  display: flex;
  min-width: 0;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-soft);
}

.custom-compare-row-name > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.custom-compare-swatch {
  width: 9px;
  height: 9px;
  flex-shrink: 0;
  border-radius: 3px;
}

/* Two halves meeting in the middle; each fill grows out of the middle. */
.custom-compare-track {
  display: grid;
  height: 6px;
  gap: 2px;
  grid-template-columns: 1fr 1fr;
}

.custom-compare-track > span {
  overflow: hidden;
  background: #2c2c2c;
}

.custom-compare-track > .is-left {
  border-radius: 3px 0 0 3px;
}

.custom-compare-track > .is-right {
  border-radius: 0 3px 3px 0;
}

.custom-compare-track i {
  display: block;
  width: 100%;
  height: 100%;
  transition: transform 280ms cubic-bezier(0.22, 1, 0.36, 1);
}

.custom-compare-track > .is-left i {
  transform-origin: right center;
}

.custom-compare-track > .is-right i {
  transform-origin: left center;
}

/* a number with no colour of its own (equity, EQR, combos) */
.custom-compare-fill {
  background: rgba(255, 255, 255, 0.42);
}

/* +/- between the two: green up, red down. */
.custom-compare-delta {
  flex-shrink: 0;
  border-radius: 5px;
  padding: 1px 5px;
  font-size: 11px;
  font-style: normal;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.custom-compare-delta.is-up {
  background: rgba(88, 185, 103, 0.15);
  color: #7fd68c;
}

.custom-compare-delta.is-down {
  background: rgba(247, 52, 63, 0.15);
  color: #ff7d84;
}

.custom-compare-delta.is-flat {
  color: var(--text-muted);
}

/* Two mixes back to back, the current one on the left. */
.custom-compare-mixbar {
  display: grid;
  height: 10px;
  flex-shrink: 0;
  gap: 2px;
  grid-template-columns: 1fr 1fr;
}

.custom-compare-mix-half {
  display: flex;
  overflow: hidden;
  background: #2c2c2c;
}

.custom-compare-mix-half.is-left {
  border-radius: 5px 0 0 5px;
}

.custom-compare-mix-half.is-right {
  border-radius: 0 5px 5px 0;
}

.custom-compare-mix-half.is-empty {
  background: repeating-linear-gradient(135deg, #262626 0 4px, #303030 4px 8px);
}

.custom-compare-mix-half > i {
  height: 100%;
}

/* ── hand groups ──────────────────────────────────────────────────────── */
.custom-compare-groups {
  display: flex;
  flex-direction: column;
  margin-inline: -12px;
}

/* A group runs to the card's edges and lights like every list of the site. */
.custom-compare-group {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 6px 12px 8px;
}

.custom-compare-group:hover {
  background: #2a2a2a;
}

.custom-compare-group > .custom-compare-row {
  padding: 0;
}

.custom-compare-group-head {
  border: none;
  background: transparent;
  padding: 0;
  text-align: inherit;
  cursor: pointer;
}

.custom-compare-chevron {
  flex-shrink: 0;
  color: var(--text-muted);
  transition: transform 160ms ease;
}

.custom-compare-group.is-open .custom-compare-chevron {
  transform: rotate(90deg);
}

.custom-compare-group-head:hover .custom-compare-row-name {
  color: var(--text-strong);
}

/* how far the group's mix moved, in points */
.custom-compare-moved {
  flex-shrink: 0;
  border-radius: 5px;
  background: rgba(255, 158, 69, 0.14);
  padding: 1px 5px;
  font-size: 11px;
  font-style: normal;
  font-weight: 700;
  color: var(--accent-brand);
  font-variant-numeric: tabular-nums;
}

/* ── biggest changes ──────────────────────────────────────────────────── */
.custom-compare-moves {
  display: flex;
  flex-direction: column;
  padding-bottom: 2px;
}

.custom-compare-move {
  display: grid;
  align-items: center;
  gap: 8px;
  grid-template-columns: 38px minmax(0, 1fr) auto;
  margin-inline: -12px;
  border: none;
  background: transparent;
  padding: 5px 12px;
  text-align: left;
  font-size: 12px;
  color: var(--text-soft);
  cursor: pointer;
}

.custom-compare-move strong {
  font-size: 13px;
  font-weight: 800;
  color: var(--text-strong);
}

.custom-compare-move-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.custom-compare-move:hover,
.custom-compare-move.is-hovered {
  background: #404040;
}

.custom-compare-move.is-selected {
  background: linear-gradient(90deg, rgba(255, 158, 69, 0.34), rgba(255, 158, 69, 0.14));
  color: var(--text-strong);
  box-shadow: inset 2px 0 0 var(--accent-brand);
}

/* Loading: the column's lines shaped as its own - a number, a name, a
   number, the bar - and one light passing over them all, as over the waiting
   matrices (owner 2026-10-19: «такую же красивую анимацию сделать в блок
   hands»). */
.custom-compare-skeleton {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.custom-compare-skeleton-mix {
  height: 10px;
  margin-bottom: 4px;
  border-radius: 5px;
  background: #2c2c2c;
}

.custom-compare-skeleton-row {
  display: grid;
  align-items: center;
  gap: 9px 8px;
  grid-template-columns: 56px minmax(0, 1fr) 56px;
  padding: 7px 0;
}

.custom-compare-skeleton-row > span {
  height: 12px;
  border-radius: 4px;
  background: #2c2c2c;
}

.custom-compare-skeleton-row > .is-value {
  width: 42px;
}

.custom-compare-skeleton-row > .is-value:nth-child(3) {
  justify-self: end;
}

.custom-compare-skeleton-row > .is-name {
  width: 48%;
  justify-self: center;
}

.custom-compare-skeleton-row:nth-child(3n + 2) > .is-name {
  width: 64%;
}

.custom-compare-skeleton-row:nth-child(3n) > .is-name {
  width: 36%;
}

.custom-compare-skeleton-row > .is-bar {
  height: 6px;
  grid-column: 1 / -1;
  border-radius: 3px;
}

/* a hand group: its two mixes under it */
.custom-compare-skeleton.is-groups .custom-compare-skeleton-row {
  padding: 6px 0 8px;
}

.custom-compare-skeleton.is-groups .custom-compare-skeleton-row > .is-bar {
  height: 10px;
  border-radius: 5px;
}

/* a Biggest changes row: the class, its move, the change */
.custom-compare-skeleton.is-moves .custom-compare-skeleton-row {
  grid-template-columns: 38px minmax(0, 1fr) 34px;
  padding: 6px 0;
}

.custom-compare-skeleton.is-moves .custom-compare-skeleton-row > .is-value {
  width: 30px;
}

.custom-compare-skeleton.is-moves .custom-compare-skeleton-row > .is-name {
  width: 72%;
  justify-self: start;
}

/* ── narrower windows ─────────────────────────────────────────────────── */
@media (max-width: 1360px) {
  .custom-compare-body {
    gap: 14px;
    grid-template-columns: minmax(0, 1fr) 290px minmax(0, 1fr);
  }
}

/* The two matrices side by side, the column under them; the body scrolls. */
@media (max-width: 1080px) {
  .custom-compare-body {
    overflow-y: auto;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: none;
  }

  .custom-compare-center {
    order: 3;
    grid-column: 1 / -1;
  }

  .custom-compare-center-scroll {
    overflow: visible;
  }

  .custom-compare-slot:last-child {
    order: 2;
  }

  .custom-compare-matrix-box {
    flex: none;
    container-type: inline-size;
  }

  .custom-compare-matrix-box > .matrix,
  .custom-compare-matrix-box > .custom-compare-missing {
    width: 100%;
    height: auto;
    aspect-ratio: 800 / 620;
  }

  .custom-compare-matrix .matrix-cell-label.is-compact {
    font-size: clamp(8px, 2.25cqw, 14px);
  }

  .custom-compare-matrix .matrix-cell-metric {
    font-size: clamp(9px, 2.1cqw, 13px);
  }
}

@media (max-width: 760px) {
  .custom-compare-head {
    flex-wrap: wrap;
  }

  .custom-compare-body {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* ============================================================================
   Landing page at "/" (owner 2026-10-14). Our palette (tokens.css): the brand
   orange where the reference screenshot had green, the app's dark surfaces,
   and the action colours in the product previews.
   ============================================================================ */

.landing-page {
  position: relative;
  min-height: 100vh;
  overflow: hidden;
  padding: 0 32px;
  background: var(--surface-sunken);
  color: var(--text-normal);
}

/* Warm light behind the hero and down the sides instead of the screenshot's green haze. */
.landing-glow {
  pointer-events: none;
  position: absolute;
  inset: 0;
  background:
    radial-gradient(900px 520px at 72% 4%, rgba(255, 158, 69, 0.13), transparent 70%),
    radial-gradient(700px 600px at -6% 40%, rgba(255, 158, 69, 0.07), transparent 70%),
    radial-gradient(700px 600px at 106% 52%, rgba(255, 158, 69, 0.06), transparent 70%);
}

.landing-page > *:not(.landing-glow):not(.landing-side) {
  position: relative;
  max-width: 1120px;
  margin-left: auto;
  margin-right: auto;
}

/* Margin words of the reference, only where the screen has room for them. */
.landing-side {
  position: absolute;
  top: 300px;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: 3px;
  text-transform: uppercase;
}
.landing-side i { display: block; width: 22px; height: 2px; margin-top: 16px; background: var(--accent-brand); }
.landing-side.is-left { left: 48px; }
.landing-side.is-right { right: 48px; top: 420px; text-align: right; }
.landing-side.is-right i { margin-left: auto; }
@media (max-width: 1500px) { .landing-side { display: none; } }

/* ---- header ---- */
.landing-header {
  display: flex;
  align-items: center;
  gap: 32px;
  padding: 22px 0;
}
.landing-logo { display: flex; align-items: center; gap: 10px; }
/* the logo in the header and the footer: the mark and the name each sized here (owner 2026-10-20) */
.landing-logo-brand { gap: 9px; }
.landing-logo-brand .brand-logo-mark { height: 28px; }
.landing-logo-brand .brand-logo-word { height: 20px; }
.landing-nav { display: flex; gap: 28px; margin: 0 auto; }
.landing-nav a { color: var(--text-soft); font-size: 14px; font-weight: 500; text-decoration: none; }
.landing-nav a:hover { color: var(--text-strong); }
.landing-account { display: flex; align-items: center; gap: 14px; }

/* ---- buttons ---- */
.landing-button {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 24px;
  border-radius: 9px;
  font-size: 16px;
  font-weight: 600;
  text-decoration: none;
  transition: background-color 150ms ease, border-color 150ms ease;
}
.landing-button.is-primary { background: var(--accent-brand-deep); color: var(--text-on-brand); }
.landing-button.is-primary:hover { background: var(--accent-brand); }
.landing-button.is-outline { border: 1px solid var(--line-strong); color: var(--text-strong); }
.landing-button.is-outline:hover { border-color: var(--accent-brand); }
.landing-button.is-small { padding: 9px 16px; font-size: 14px; }

/* ---- hero ---- */
.landing-hero {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.2fr);
  align-items: center;
  gap: 48px;
  padding: 48px 0 64px;
}
.landing-hero h1 {
  margin: 0;
  color: var(--text-strong);
  font-size: 60px;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -1px;
}
.landing-accent { color: var(--accent-brand); }
.landing-hero-text > p { margin: 22px 0 32px; color: var(--text-soft); font-size: 18px; line-height: 1.5; }
.landing-actions { display: flex; flex-wrap: wrap; gap: 16px; }
.landing-points {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 24px;
  margin: 40px 0 0;
  padding: 0;
  list-style: none;
  color: var(--text-dim);
  font-size: 13px;
}
.landing-points li { display: flex; align-items: center; gap: 10px; }
.landing-points svg { flex-shrink: 0; color: var(--accent-brand); }

/* ---- the Study preview (illustration, aria-hidden) ---- */
.landing-preview {
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: var(--surface-page);
  box-shadow: 0 24px 80px #000a;
  font-size: 11px;
}
.landing-preview-bar {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  color: var(--text-muted);
}
.landing-preview-brand { display: flex; align-items: center; gap: 6px; color: var(--text-strong); font-weight: 700; letter-spacing: 1px; }
.landing-preview-brand .brand-logo { gap: 4px; }
.landing-preview-brand .brand-logo-mark { height: 12px; }
.landing-preview-brand .brand-logo-word { height: 9px; }
.landing-preview-tab.is-active { color: var(--accent-brand); font-weight: 600; }
.landing-preview-search {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  padding: 4px 10px;
  border-radius: 6px;
  background: var(--surface-panel);
}
.landing-preview-body { display: grid; grid-template-columns: 110px minmax(0, 1fr) 190px; }
.landing-preview-side { padding: 12px 10px; border-right: 1px solid var(--line); color: var(--text-dim); }
.landing-preview-select {
  margin-bottom: 12px;
  padding: 6px 8px;
  border-radius: 6px;
  background: var(--surface-panel);
  color: var(--text-strong);
  font-weight: 600;
}
.landing-preview-street { margin: 0 -10px; padding: 5px 10px; }
.landing-preview-street.is-active {
  background: linear-gradient(90deg, rgba(255, 158, 69, 0.34), rgba(255, 158, 69, 0.14));
  box-shadow: inset 2px 0 0 var(--accent-brand);
  color: var(--text-strong);
}
.landing-preview-label { margin: 14px 0 6px; color: var(--text-soft); font-weight: 600; }
.landing-preview-filter { display: flex; justify-content: space-between; padding: 4px 0; }
.landing-preview-filter b { color: var(--text-soft); font-weight: 500; }
.landing-preview-main { padding: 10px; }
.landing-preview-tabs { display: flex; gap: 14px; margin-bottom: 8px; color: var(--text-muted); }
.landing-preview-tabs b { color: var(--text-strong); font-weight: 600; }
.landing-preview-panel { padding: 10px; border-left: 1px solid var(--line); color: var(--text-dim); }
.landing-preview-board { display: flex; align-items: center; gap: 4px; margin-bottom: 12px; }
.landing-preview-board small { margin-left: auto; color: var(--text-muted); font-size: 10px; }
.landing-preview-action, .landing-preview-hand {
  display: grid;
  grid-template-columns: 74px minmax(0, 1fr) 30px 30px;
  align-items: center;
  gap: 6px;
  padding: 4px 0;
}
.landing-preview-hand { grid-template-columns: 48px minmax(0, 1fr) 26px 30px; }
.landing-preview-action em, .landing-preview-hand em { color: var(--text-muted); font-style: normal; text-align: right; }
.landing-preview-bar-track { height: 9px; overflow: hidden; border-radius: 3px; background: var(--surface-panel); }
.landing-preview-bar-track .action-fill { display: block; height: 100%; }
.landing-preview-hand-action.is-call { color: var(--action-passive); }
.landing-preview-hand-action.is-bet { color: var(--action-aggressive); }
.landing-preview-hand-action.is-raise { color: var(--action-raise); }
.landing-preview-panel .landing-preview-tabs { margin-top: 10px; }

.landing-card {
  display: inline-block;
  padding: 1px 4px;
  border-radius: 3px;
  background: #f2f2f2;
  font-weight: 700;
}
.landing-card.is-s { color: #1f1f1f; }
.landing-card.is-c { color: #1d7a37; }
.landing-card.is-d { color: #1f5fbf; }
.landing-card.is-h { color: #c8202a; }

/* The 13x13 matrix: each class split into check (green) and bet (red), the
   share widths set per cell (runtime values). */
.landing-matrix { display: grid; grid-template-columns: repeat(13, minmax(0, 1fr)); gap: 1px; }
.landing-cell { position: relative; display: flex; height: 21px; overflow: hidden; border-radius: 2px; background: var(--surface-panel); }
.landing-cell .action-fill { height: 100%; }
.landing-cell em {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: rgba(255, 255, 255, 0.92);
  font-size: 8px;
  font-style: normal;
  font-weight: 600;
}
.landing-matrix.is-compact .landing-cell { height: 9px; }

/* ---- feature cards ---- */
.landing-features { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
.landing-feature {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px;
  gap: 16px;
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-panel);
}
.landing-feature h3 { display: flex; align-items: center; gap: 12px; margin: 0 0 12px; color: var(--text-strong); font-size: 20px; }
.landing-feature h3 svg { color: var(--accent-brand); }
.landing-feature p { margin: 0 0 18px; color: var(--text-dim); font-size: 13px; line-height: 1.5; }
.landing-feature a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--accent-brand);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}
.landing-feature a:hover { color: var(--accent-brand-hover); }
.landing-mini {
  align-self: start;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-sunken);
  color: var(--text-dim);
  font-size: 10px;
}
.landing-mini p { margin: 0 0 8px; color: var(--text-soft); font-weight: 600; }
.landing-mini-progress { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.landing-mini-progress span { flex: 1; height: 3px; border-radius: 2px; background: linear-gradient(90deg, var(--accent-brand) 30%, var(--surface-raised) 30%); }
.landing-mini-option { display: flex; align-items: center; gap: 6px; margin-top: 5px; padding: 5px 6px; border-radius: 4px; background: var(--surface-panel); }
.landing-mini-dot { width: 7px; height: 7px; border-radius: 2px; }
.landing-mini-dot.is-call { background: var(--action-passive); }
.landing-mini-dot.is-bet { background: var(--action-aggressive); }
.landing-mini-dot.is-raise { background: var(--action-raise); }
.landing-mini-dot.is-allin { background: var(--action-allin); }
.landing-mini-tabs { display: flex; gap: 10px; margin-bottom: 8px; color: var(--text-muted); }
.landing-mini-tabs b { color: var(--accent-brand); font-weight: 600; }
.landing-mini-node { display: inline-block; padding: 2px 6px; border-radius: 3px; background: var(--surface-raised); color: var(--text-strong); font-weight: 700; }
.landing-mini-branch { margin: 4px 0 0 12px; padding: 4px 6px; border-left: 2px solid var(--line-strong); background: var(--surface-panel); }
.landing-mini-branch.is-add { border-left-color: var(--accent-brand); color: var(--text-muted); }

/* ---- how it works ---- */
.landing-steps {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) repeat(3, minmax(0, 1fr));
  align-items: center;
  gap: 28px;
  padding: 64px 0 40px;
  border-bottom: 1px solid var(--line);
}
.landing-steps h2, .landing-faq h2, .landing-facts h2 { margin: 0; color: var(--text-strong); font-size: 30px; font-weight: 700; }
.landing-steps-title p, .landing-faq > div > p { margin: 8px 0 0; color: var(--text-dim); font-size: 14px; }
.landing-step { display: flex; align-items: flex-start; gap: 16px; }
.landing-step-number {
  display: grid;
  flex-shrink: 0;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  color: var(--accent-brand);
  font-size: 18px;
  font-weight: 700;
}
.landing-step h3 { margin: 0 0 6px; color: var(--text-strong); font-size: 15px; }
.landing-step p { margin: 0; color: var(--text-dim); font-size: 13px; line-height: 1.45; }

/* ---- facts ---- */
.landing-facts {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) repeat(4, minmax(0, 1fr));
  align-items: center;
  gap: 24px;
  padding: 36px 0;
  border-bottom: 1px solid var(--line);
}
.landing-facts h2 { font-size: 22px; line-height: 1.25; }
.landing-fact b { display: block; color: var(--accent-brand); font-size: 26px; font-weight: 700; }
.landing-fact span { color: var(--text-dim); font-size: 13px; }

/* ---- FAQ ---- */
.landing-faq {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: 40px;
  padding: 48px 0;
  border-bottom: 1px solid var(--line);
}
.landing-faq-item { border-bottom: 1px solid var(--line); }
.landing-faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 0;
  color: var(--text-soft);
  font-size: 14px;
  cursor: pointer;
  list-style: none;
}
.landing-faq-item summary::-webkit-details-marker { display: none; }
.landing-faq-item summary:hover { color: var(--text-strong); }
.landing-faq-item svg { flex-shrink: 0; color: var(--text-muted); transition: transform 150ms ease; }
.landing-faq-item[open] svg { transform: rotate(180deg); }
.landing-faq-item p { margin: 0 0 14px; color: var(--text-dim); font-size: 13px; line-height: 1.55; }

/* ---- footer ---- */
/* one line under the FAQ's own rule (owner 2026-10-21: «почему там две полоски? одна лишняя», more room above, less below): the
   logo, the four documents and the cookie choice */
.landing-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 20px; padding: 32px 0 20px; color: var(--text-muted); font-size: 13px; }
.landing-legal { display: flex; flex-basis: 100%; flex-wrap: wrap; align-items: center; gap: 12px 18px; }
.landing-legal-links { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-left: auto; }
.landing-legal-links a, .landing-legal-links button { border: none; background: none; padding: 0; color: var(--text-soft); font-size: 13px; text-decoration: none; cursor: pointer; }
.landing-legal-links a:hover, .landing-legal-links button:hover { color: var(--text-strong); }

/* ---- phones and tablets (owner 2026-10-14: «Под мобильную верстку сделай лендинг полностью ... и на айфоны и на андроиды»).
   The app's body keeps a desktop min-width for Study (index.css: 1120 / 980px); the landing, the news and the sign-in page are built
   for any width, so on them it is lifted - otherwise a phone lays the page out 980px wide and shrinks it, and none of the rules below
   ever applies. ---- */
body:has(.landing-page), body:has(.auth-page) { min-width: 0; }
.landing-page { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
.landing-page a, .landing-page button, .landing-page summary { -webkit-tap-highlight-color: transparent; }

@media (max-width: 1100px) {
  .landing-hero { grid-template-columns: minmax(0, 1fr); gap: 36px; }
  .landing-features { grid-template-columns: minmax(0, 1fr); }
  .landing-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .landing-steps-title { grid-column: 1 / -1; }
  .landing-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .landing-facts h2 { grid-column: 1 / -1; }
  .landing-faq { grid-template-columns: minmax(0, 1fr); gap: 20px; }
}

@media (max-width: 700px) {
  .landing-page { padding: 0 16px; }

  /* header: the logo and Open Study on the first row, the pages as a row of pills under them (scrolls sideways if it must) */
  .landing-header { flex-wrap: wrap; justify-content: space-between; gap: 12px 16px; padding: 14px 0 6px; }
  .landing-logo-brand .brand-logo-mark { height: 24px; }
  .landing-logo-brand .brand-logo-word { height: 17px; }
  .landing-header .landing-nav {
    order: 3;
    width: 100%;
    margin: 0;
    gap: 8px;
    overflow-x: auto;
    padding-bottom: 4px;
    scrollbar-width: none;
  }
  .landing-header .landing-nav::-webkit-scrollbar { display: none; }
  .landing-header .landing-nav a {
    flex-shrink: 0;
    border: 1px solid var(--line-strong);
    border-radius: 999px;
    padding: 8px 15px;
    font-size: 14px;
  }
  .landing-header .landing-nav a.is-active { border-color: var(--accent-brand); }

  /* hero: one column, buttons the full width */
  .landing-hero { gap: 28px; padding: 22px 0 40px; }
  .landing-hero h1 { font-size: 40px; letter-spacing: -0.6px; }
  .landing-hero-text > p { margin: 16px 0 24px; font-size: 16px; }
  .landing-actions { flex-direction: column; gap: 12px; }
  .landing-actions .landing-button { justify-content: center; }
  .landing-points { grid-template-columns: minmax(0, 1fr); gap: 12px; margin-top: 28px; font-size: 14px; }

  /* the Study preview: the matrix only */
  .landing-preview { border-radius: 12px; }
  .landing-preview-bar { gap: 12px; }
  .landing-preview-search, .landing-preview-tab:not(.is-active) { display: none; }
  .landing-preview-body { grid-template-columns: minmax(0, 1fr); }
  .landing-preview-side, .landing-preview-panel { display: none; }
  .landing-cell { height: 18px; }
  .landing-cell em { font-size: 7px; }

  /* features, steps, facts, FAQ, footer */
  .landing-features { gap: 14px; }
  .landing-feature { grid-template-columns: minmax(0, 1fr); padding: 18px; }
  .landing-feature p { font-size: 14px; }
  .landing-steps { grid-template-columns: minmax(0, 1fr); gap: 20px; padding: 44px 0 32px; }
  .landing-steps h2, .landing-faq h2 { font-size: 26px; }
  .landing-step p { font-size: 14px; }
  .landing-facts { gap: 18px 16px; padding: 28px 0; }
  .landing-fact b { font-size: 22px; }
  .landing-faq { padding: 36px 0; }
  .landing-faq-item summary { min-height: 48px; gap: 12px; font-size: 15px; }
  .landing-faq-item p { font-size: 14px; }
  .landing-footer { flex-direction: column; gap: 14px; padding: 28px 0 20px; text-align: center; }
  .landing-legal { flex-direction: column; gap: 12px; }
  .landing-legal-links { justify-content: center; margin: 0; }
}

@media (max-width: 380px) {
  .landing-hero h1 { font-size: 34px; }
  .landing-cell em { display: none; }
}
/* ============================================================================
   News (owner 2026-10-14): /news, /news/<post>, the admin editor and the
   landing's «Latest from the lab». The page reuses the landing's frame
   (landing.css: background, glow, header, 1120px column); every post has a
   cover colour (is-amber / violet / green / blue / red) from tokens.css.
   ============================================================================ */

.is-amber  { --news-accent: var(--accent-brand); }
.is-violet { --news-accent: var(--ai-accent); }
.is-green  { --news-accent: var(--action-passive); }
.is-blue   { --news-accent: var(--neural-text); }
.is-red    { --news-accent: var(--action-aggressive); }

.landing-nav a.is-active { color: var(--accent-brand); }

.news-shell { padding-bottom: 96px; }

.news-kicker {
  display: inline-block;
  margin-bottom: 12px;
  color: var(--accent-brand);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 3px;
  text-transform: uppercase;
}

/* ---- list page ---- */
.news-hero {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  padding: 44px 0 26px;
}
.news-hero h1 { margin: 0; color: var(--text-strong); font-size: 48px; font-weight: 800; line-height: 1.05; letter-spacing: -1px; }
.news-hero p { max-width: 620px; margin: 14px 0 0; color: var(--text-dim); font-size: 16px; line-height: 1.6; }

.news-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 26px; }
.news-filter {
  height: 32px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: transparent;
  padding: 0 16px;
  color: var(--text-soft);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
.news-filter:hover { color: var(--text-strong); border-color: var(--text-muted); }
.news-filter.is-active { border-color: var(--accent-brand); background: color-mix(in srgb, var(--accent-brand) 14%, transparent); color: var(--accent-brand); }

.news-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 120px 0;
  color: var(--text-dim);
  font-size: 15px;
}
.news-empty a { color: var(--accent-brand); }

.news-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px; margin-top: 22px; }

/* ---- card ---- */
.news-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: linear-gradient(180deg, var(--surface-panel), var(--surface-sunken));
  color: inherit;
  text-decoration: none;
  transition: transform 200ms ease;
}
/* a mouse only: on a phone a tap would leave the card lifted */
@media (hover: hover) {
  .news-card:hover { transform: translateY(-4px); border-color: color-mix(in srgb, var(--news-accent) 45%, transparent); }
}
.news-card h3, .news-article-head h1 { overflow-wrap: break-word; }
.news-card-text { display: flex; flex: 1; flex-direction: column; gap: 10px; padding: 20px 22px 22px; }
/* the landing keeps the room of three cards while the posts load (no jump of the FAQ below) */
.news-card.is-placeholder { min-height: 340px; background: linear-gradient(180deg, var(--surface-panel), var(--surface-sunken)); }
.news-card h3 { margin: 0; color: var(--text-strong); font-size: 19px; font-weight: 800; line-height: 1.3; }
.news-card p { margin: 0; color: var(--text-dim); font-size: 14px; line-height: 1.55; }
.news-card-foot { display: flex; align-items: center; justify-content: space-between; margin-top: auto; padding-top: 10px; }
.news-read { display: inline-flex; align-items: center; gap: 6px; color: var(--news-accent); font-size: 13px; font-weight: 800; }

.news-card.is-large { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); min-height: 330px; }
.news-card.is-large .news-card-text { justify-content: center; gap: 14px; padding: 36px 40px; }
.news-card.is-large h3 { font-size: 30px; line-height: 1.2; letter-spacing: -0.4px; }
.news-card.is-large p { font-size: 16px; }

/* ---- cover: the post colour, a quiet grid and the topic icon ---- */
.news-cover {
  position: relative;
  display: grid;
  min-height: 168px;
  overflow: hidden;
  place-items: center;
  background:
    radial-gradient(520px 260px at 18% 0%, color-mix(in srgb, var(--news-accent) 46%, transparent), transparent 70%),
    radial-gradient(420px 240px at 100% 100%, color-mix(in srgb, var(--news-accent) 22%, transparent), transparent 70%),
    linear-gradient(135deg, color-mix(in srgb, var(--news-accent) 24%, var(--surface-sunken)), var(--surface-sunken));
}
.news-cover.is-large { min-height: 100%; }
.news-cover-pattern {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(color-mix(in srgb, var(--news-accent) 18%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--news-accent) 18%, transparent) 1px, transparent 1px);
  background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(circle at 50% 50%, black, transparent 72%);
  mask-image: radial-gradient(circle at 50% 50%, black, transparent 72%);
}
.news-cover-icon {
  position: relative;
  display: grid;
  width: 84px;
  height: 84px;
  place-items: center;
  border: 1px solid color-mix(in srgb, var(--news-accent) 55%, transparent);
  border-radius: 24px;
  background: color-mix(in srgb, var(--news-accent) 16%, var(--surface-sunken));
  color: var(--news-accent);
  filter: drop-shadow(0 10px 30px color-mix(in srgb, var(--news-accent) 45%, transparent));
}
.news-cover.is-large .news-cover-icon { width: 128px; height: 128px; border-radius: 34px; }

.news-tag {
  align-self: flex-start;
  border-radius: 999px;
  background: color-mix(in srgb, var(--news-accent) 15%, transparent);
  padding: 4px 11px;
  color: var(--news-accent);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.news-meta { display: inline-flex; align-items: center; gap: 6px; color: var(--text-muted); font-size: 12px; font-weight: 600; }
.news-meta i { width: 3px; height: 3px; margin: 0 4px; border-radius: 999px; background: var(--text-muted); }

/* ---- one post ---- */
.news-article { max-width: 780px; margin: 0 auto; }
.news-article-top { display: flex; align-items: center; justify-content: space-between; padding: 28px 0 20px; }
.news-back { display: inline-flex; align-items: center; gap: 8px; color: var(--text-soft); font-size: 14px; font-weight: 700; text-decoration: none; }
.news-back:hover { color: var(--accent-brand); }
.news-article > .news-cover { min-height: 250px; border: 1px solid var(--line); border-radius: 22px; }
.news-article-head { display: flex; flex-direction: column; gap: 14px; padding: 34px 0 10px; }
.news-article-head h1 { margin: 0; color: var(--text-strong); font-size: 42px; font-weight: 800; line-height: 1.12; letter-spacing: -0.8px; }
.news-lead { margin: 6px 0 0; color: var(--text-soft); font-size: 19px; line-height: 1.6; }

.news-body { color: var(--text-normal); font-size: 17px; line-height: 1.75; }
.news-body p { margin: 0 0 20px; }
.news-body h2 {
  margin: 44px 0 16px;
  border-left: 3px solid var(--news-accent, var(--accent-brand));
  padding-left: 14px;
  color: var(--text-strong);
  font-size: 26px;
  font-weight: 800;
  line-height: 1.25;
}
.news-body h3 { margin: 30px 0 12px; color: var(--text-strong); font-size: 20px; font-weight: 800; }
.news-body ul, .news-body ol { margin: 0 0 22px; padding-left: 24px; }
.news-body li { margin: 6px 0; }
.news-body li::marker { color: var(--news-accent, var(--accent-brand)); font-weight: 800; }
.news-body strong { color: var(--text-strong); }
.news-body a { color: var(--accent-brand); }
.news-body code {
  border-radius: 6px;
  background: var(--surface-rail);
  padding: 2px 7px;
  color: var(--text-strong);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 14px;
}
.news-body blockquote {
  margin: 0 0 24px;
  border: 1px solid color-mix(in srgb, var(--news-accent, var(--accent-brand)) 30%, transparent);
  border-left-width: 4px;
  border-radius: 14px;
  background: color-mix(in srgb, var(--news-accent, var(--accent-brand)) 9%, transparent);
  padding: 16px 20px;
  color: var(--text-strong);
  font-size: 16px;
}
.news-body hr { margin: 36px 0; border: none; border-top: 1px solid var(--line-strong); }
.news-table { margin: 0 0 26px; overflow-x: auto; border: 1px solid var(--line); border-radius: 14px; }
.news-table table { width: 100%; border-collapse: collapse; font-size: 15px; }
.news-table th {
  background: var(--surface-panel);
  padding: 12px 16px;
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1px;
  text-align: left;
  text-transform: uppercase;
}
.news-table td { border-top: 1px solid var(--line); padding: 12px 16px; }

.news-more { margin-top: 70px; }
.news-more h2 { margin: 0; color: var(--text-strong); font-size: 24px; font-weight: 800; }

/* ---- buttons ---- */
.news-button {
  display: inline-flex;
  height: 40px;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
  border: 1px solid transparent;
  border-radius: 10px;
  padding: 0 16px;
  font-size: 14px;
  font-weight: 800;
  cursor: pointer;
}
.news-button:disabled { opacity: 0.5; cursor: default; }
.news-button.is-primary { background: var(--accent-brand-deep); color: var(--text-on-brand); }
.news-button.is-primary:hover:not(:disabled) { background: var(--accent-brand); }
.news-button.is-ghost { border-color: var(--line-strong); background: transparent; color: var(--text-soft); }
.news-button.is-ghost:hover:not(:disabled) { border-color: var(--text-muted); color: var(--text-strong); }
.news-button.is-danger { margin-right: auto; background: transparent; color: var(--action-aggressive); }
.news-button.is-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--action-aggressive) 12%, transparent); }
.news-icon-button {
  display: grid;
  width: 34px;
  height: 34px;
  place-items: center;
  border: none;
  border-radius: 9px;
  background: transparent;
  color: var(--text-soft);
  cursor: pointer;
}
.news-icon-button:hover { background: var(--surface-hover); color: var(--text-strong); }
.news-spin { animation: news-spin 900ms linear infinite; }
@keyframes news-spin { to { transform: rotate(360deg); } }

/* ---- editor ---- */
.news-editor-backdrop {
  position: fixed;
  z-index: 200;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(0, 0, 0, 0.72);   /* no backdrop-filter (owner 2026-10-16: the page under a window flickered over it while scrolling - see study-modal.css) */
}
.news-editor {
  display: flex;
  width: calc(100vw - 64px);
  max-width: 1280px;
  height: calc(100vh - 64px);
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 18px;
  background: var(--surface-page);
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.6);
}
.news-editor-head { display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--line); padding: 14px 20px; }
.news-editor-head h2 { margin: 0; color: var(--text-strong); font-size: 18px; font-weight: 800; }
.news-editor-grid { display: grid; flex: 1; min-height: 0; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.news-editor-form { display: flex; min-height: 0; flex-direction: column; gap: 14px; overflow-y: auto; border-right: 1px solid var(--line); padding: 18px 20px; }
.news-editor-preview { min-height: 0; overflow-y: auto; background: var(--surface-sunken); padding: 18px 26px 40px; }
.news-editor-preview-label { display: block; margin-bottom: 14px; color: var(--text-muted); font-size: 11px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; }
.news-article-preview { display: flex; flex-direction: column; gap: 12px; }
.news-article-preview h1 { margin: 0; color: var(--text-strong); font-size: 30px; font-weight: 800; line-height: 1.15; }
.news-article-preview .news-body { font-size: 15px; }
.news-field { display: flex; flex-direction: column; gap: 6px; color: var(--text-muted); font-size: 12px; font-weight: 700; }
.news-field.is-grow { flex: 1; }
.news-field input, .news-field textarea, .news-field select {
  border: 1px solid var(--line-strong);
  border-radius: 9px;
  background: var(--surface-sunken);
  padding: 9px 12px;
  color: var(--text-strong);
  font-size: 14px;
  outline: none;
}
.news-field input:focus, .news-field textarea:focus, .news-field select:focus { border-color: var(--accent-brand); }
.news-field textarea { resize: none; line-height: 1.55; }
.news-field textarea.is-short { height: 70px; }
.news-field textarea.is-body {
  flex: 1;
  min-height: 300px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
}
.news-field-row { display: flex; align-items: flex-end; gap: 18px; }
.news-swatches { display: flex; gap: 8px; height: 38px; align-items: center; }
.news-swatch {
  width: 26px;
  height: 26px;
  border: 2px solid transparent;
  border-radius: 999px;
  background: var(--news-accent);
  cursor: pointer;
}
.news-swatch.is-selected { border-color: var(--text-strong); }
.news-check { display: flex; height: 38px; align-items: center; gap: 8px; color: var(--text-soft); font-size: 13px; font-weight: 700; }
.news-editor-foot { display: flex; align-items: center; gap: 10px; border-top: 1px solid var(--line); padding: 14px 20px; }
.news-editor-error { margin-right: auto; color: var(--action-aggressive); font-size: 13px; font-weight: 700; }

/* ---- the landing's «Latest from the lab» ---- */
.landing-news { margin-top: 96px; }
.landing-news-title { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; }
.landing-news-title h2 { margin: 0; color: var(--text-strong); font-size: 30px; font-weight: 700; }
.landing-news-title p { margin: 8px 0 0; color: var(--text-dim); font-size: 14px; }
.landing-news-title .landing-button { gap: 8px; }

@media (max-width: 1000px) {
  .news-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .news-card.is-large { grid-template-columns: minmax(0, 1fr); }
  .news-cover.is-large { min-height: 220px; }
  .news-editor-grid { grid-template-columns: minmax(0, 1fr); }
  .news-editor-preview { display: none; }
}
/* phones (owner 2026-10-14: the landing «и на айфоны и на андроиды»; landing.css lifts the app's desktop min-width on these pages) */
@media (max-width: 680px) {
  .news-grid { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .news-hero { flex-direction: column; align-items: stretch; gap: 20px; padding: 22px 0 20px; }
  .news-hero h1 { font-size: 36px; }
  .news-hero p { font-size: 15px; }
  .news-hero .news-button { justify-content: center; }
  .news-filters { flex-wrap: nowrap; overflow-x: auto; margin: 0 -16px 20px; padding: 0 16px 4px; scrollbar-width: none; }
  .news-filters::-webkit-scrollbar { display: none; }
  .news-filter { flex-shrink: 0; }
  .news-cover { min-height: 140px; }
  .news-cover.is-large { min-height: 180px; }
  .news-cover-icon { width: 72px; height: 72px; border-radius: 20px; }
  .news-cover.is-large .news-cover-icon { width: 96px; height: 96px; border-radius: 26px; }
  .news-card.is-large .news-card-text { padding: 20px 20px 22px; }
  .news-card.is-large h3 { font-size: 24px; }
  .news-card.is-large p { font-size: 15px; }
  .news-article-top { padding: 18px 0 14px; }
  .news-article > .news-cover { min-height: 170px; border-radius: 16px; }
  .news-article-head { padding-top: 24px; }
  .news-article-head h1 { font-size: 30px; letter-spacing: -0.4px; }
  .news-lead { font-size: 17px; }
  .news-body { font-size: 16px; line-height: 1.7; }
  .news-body h2 { margin-top: 34px; font-size: 22px; }
  .news-body h3 { font-size: 18px; }
  .news-body blockquote { padding: 14px 16px; font-size: 15px; }
  .news-table table { font-size: 14px; }
  .news-table th, .news-table td { padding: 10px 12px; }
  .news-more { margin-top: 48px; }
  .landing-news { margin-top: 64px; }
  .landing-news-title { flex-direction: column; align-items: flex-start; }
  .landing-news-title h2 { font-size: 26px; }
  .news-editor { width: calc(100vw - 16px); height: calc(100vh - 16px); height: calc(100dvh - 16px); border-radius: 14px; }
  .news-editor-form { padding: 14px; }
  .news-field-row { flex-wrap: wrap; gap: 12px; }
  .news-editor-foot { flex-wrap: wrap; padding: 12px 14px; }
}
/* The account's settings page (owner 2026-10-17; pages/settings/SettingsPage.tsx): a column of sections on the left with the way back
   to Study or Practice, the open section's cards on the right. Rows are a label and its control; the hotkeys are keycaps that record the next key pressed. Colours are the theme's tokens and their mixes;
   only transform and opacity move (frontend_rules 5b.3), and always (5b.5). */

/* the left column is the sidebars' width (.study-rail, .rail: 310px), so its account line sits where theirs does */
.settings-page {
  display: grid;
  grid-template-columns: 310px minmax(0, 1fr);
  min-height: 100vh;
  background: var(--surface-page);
  color: var(--text-normal);
}

/* ── the left column ─────────────────────────────────────────────────── */
.settings-nav {
  position: sticky;
  top: 0;
  display: flex;
  height: 100vh;
  flex-direction: column;
  gap: 4px;
  border-right: 1px solid var(--line);
  background: var(--surface-sunken);
  padding: 24px 16px 16px;
}

.settings-back {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 8px;
  height: 34px;
  border: none;
  border-radius: 8px;
  background: var(--surface-raised);
  padding: 0 14px 0 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.settings-back svg {
  transition: transform 180ms cubic-bezier(0.2, 0, 0, 1);
}

.settings-back:hover {
  background: var(--line-strong);
}

.settings-back:hover svg {
  transform: translateX(-3px);
}

.settings-nav-title {
  margin: 28px 0 10px;
  font-size: 22px;
  font-weight: 800;
  color: var(--text-strong);
}

.settings-nav-list {
  display: flex;
  flex-direction: column;
}

/* a picked section is lit as the Study strip's rows are (frontend_rules 5a): an amber wash edge to edge, a 2px bar on the left */
.settings-nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  border: none;
  background: transparent;
  margin-inline: -16px;
  padding: 10px 16px;
  text-align: left;
  color: var(--text-soft);
  cursor: pointer;
}

.settings-nav-item:hover {
  background: #404040;
}

.settings-nav-item.is-selected {
  background: linear-gradient(90deg, rgba(255, 158, 69, 0.34), rgba(255, 158, 69, 0.14));
  box-shadow: inset 2px 0 0 var(--accent-brand);
  color: var(--text-strong);
}

.settings-nav-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: var(--surface-raised);
  color: var(--text-soft);
}

.settings-nav-item.is-selected .settings-nav-icon {
  background: color-mix(in srgb, var(--accent-brand) 22%, transparent);
  color: var(--accent-brand);
}

.settings-nav-text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}

.settings-nav-text strong {
  font-size: 14px;
  font-weight: 700;
}

.settings-nav-text small {
  font-size: 12px;
  color: var(--text-muted);
}

/* The account line at the very height of the sidebars' (owner 2026-10-17: «полоска ... должна быть на той же высоте что и в странице
   настроек, а то немного прыгает»): there it is 16px (the rail) + 4px + 36px avatar + 4px (the account button) + 14px above the row,
   here 16px (.settings-nav) + 4px + 36px + 18px - the line and the avatar stay put between the pages. */
.settings-nav-user {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: auto;
  border-top: 1px solid var(--line-strong);
  padding: 18px 0 4px;
}

.settings-nav-user-text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 3px;
}

.settings-nav-user-text strong,
.settings-nav-user-text small {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.settings-nav-user-text strong {
  font-size: 13px;
  color: var(--text-strong);
}

.settings-nav-user-text small {
  font-size: 11px;
  color: var(--text-muted);
}

.settings-avatar {
  display: grid;
  flex: none;
  place-items: center;
  width: 36px;
  height: 36px;
  overflow: hidden;
  border-radius: 50%;
  background: var(--surface-panel);
  font-size: 16px;
  font-weight: 700;
  color: var(--accent-brand);
}

.settings-avatar.is-large {
  width: 64px;
  height: 64px;
  font-size: 26px;
  box-shadow: 0 0 0 3px var(--surface-panel), 0 0 0 4px color-mix(in srgb, var(--accent-brand) 45%, transparent);
}

.settings-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ── the open section ────────────────────────────────────────────────── */
.settings-main {
  min-width: 0;
  padding: 44px 48px 64px;
}

/* a new section slides in (keyed on the section) */
.settings-content {
  max-width: 760px;
  animation: settings-in 280ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes settings-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.settings-head h1 {
  margin: 0 0 6px;
  font-size: 28px;
  font-weight: 800;
  color: var(--text-strong);
}

.settings-head p {
  margin: 0 0 24px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-dim);
}

.settings-card {
  margin-bottom: 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-panel);
  padding: 18px 20px;
}

.settings-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
}

.settings-card-head h2 {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.settings-card-icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent-brand) 14%, transparent);
  color: var(--accent-brand);
}

/* ── rows ────────────────────────────────────────────────────────────── */
.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  border-top: 1px solid var(--line);
  padding: 14px 0;
}

.settings-card-head + .settings-row {
  border-top: none;
  padding-top: 6px;
}

.settings-row:last-child {
  padding-bottom: 2px;
}

.settings-row.is-stacked {
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
}

.settings-row-text {
  min-width: 0;
}

.settings-row-text strong {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-strong);
}

.settings-row-text small {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
}

.settings-row-control {
  display: flex;
  flex: none;
  align-items: center;
}

.settings-row.is-stacked .settings-row-control {
  display: block;
}

.settings-changed {
  border-radius: 4px;
  padding: 2px 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.settings-changed {
  background: color-mix(in srgb, var(--accent-brand) 12%, transparent);
  color: var(--accent-brand);
}

/* ── controls ────────────────────────────────────────────────────────── */
.settings-switch {
  position: relative;
  flex: none;
  width: 42px;
  height: 24px;
  border: none;
  border-radius: 999px;
  background: var(--surface-raised);
  padding: 0;
  cursor: pointer;
  transition: background-color 160ms ease;
}

.settings-switch i {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--text-soft);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  transition: transform 220ms cubic-bezier(0.2, 0, 0, 1);
}

.settings-switch.is-on {
  background: var(--accent-brand);
}

.settings-switch.is-on i {
  background: var(--text-on-brand);
  transform: translateX(18px);
}

.settings-switch:disabled {
  opacity: 0.45;
  cursor: default;
}

.settings-button {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 7px;
  height: 34px;
  border: none;
  border-radius: 8px;
  background: var(--surface-raised);
  padding: 0 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.settings-button:hover:not(:disabled) {
  background: var(--line-strong);
}

.settings-button:disabled {
  opacity: 0.4;
  cursor: default;
}

.settings-choices {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}

.settings-choice,
.settings-tile {
  border: none;
  background: var(--surface-sunken);
  box-shadow: inset 0 0 0 1px var(--line);
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.settings-choice {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 38px;
  border-radius: 8px;
  font-size: 13px;
}

.settings-choice:hover,
.settings-tile:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.settings-choice.is-selected,
.settings-tile.is-selected {
  background: color-mix(in srgb, var(--accent-brand) 15%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-brand) 55%, transparent);
  color: var(--accent-brand);
}

.settings-tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.settings-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  border-radius: 10px;
  padding: 16px 10px 14px;
  font-size: 13px;
}

.settings-segment {
  display: inline-flex;
  gap: 2px;
  border-radius: 9px;
  background: var(--surface-sunken);
  box-shadow: inset 0 0 0 1px var(--line);
  padding: 3px;
}

.settings-segment-option {
  height: 30px;
  border: none;
  border-radius: 7px;
  background: transparent;
  padding: 0 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.settings-segment-option:hover {
  color: var(--text-strong);
}

.settings-segment-option.is-selected {
  background: var(--surface-raised);
  color: var(--text-strong);
}

/* Card design (owner 2026-10-21): one tile per design with its four cards drawn in it, picked like the Actions panel tiles. */
.settings-designs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 10px;
}

.settings-design,
.settings-look {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  border: none;
  border-radius: 10px;
  background: var(--surface-sunken);
  box-shadow: inset 0 0 0 1px var(--line);
  padding: 14px 10px 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease, box-shadow 120ms ease;
}

.settings-design:hover,
.settings-look:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.settings-design.is-selected,
.settings-look.is-selected {
  background: color-mix(in srgb, var(--accent-brand) 12%, transparent);
  box-shadow: inset 0 0 0 2px var(--accent-brand);
  color: var(--accent-brand);
}

.settings-design-cards {
  display: flex;
  gap: 5px;
}

.settings-design-name {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Table (owner 2026-10-21): one tile per look of the practice table, the table drawn small in its colours (practice.css .is-table-*) */
.settings-looks {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
}

.settings-table-preview {
  display: block;
  width: 120px;
  height: 55px;
  border-radius: 28px;
}

.settings-table-preview.is-table-classic {
  background: url("/assets/poker-table-J1DhjKE4.webp") no-repeat center / contain;
}

.settings-table-preview:not(.is-table-classic) {
  border: 5px solid transparent;
  background:
    radial-gradient(ellipse 62% 75% at 50% 45%, var(--table-felt-light) 0%, var(--table-felt) 52%, var(--table-felt-dark) 100%) padding-box,
    linear-gradient(180deg, var(--table-rail-light) 0%, var(--table-rail) 38%, var(--table-rail-dark) 100%) border-box;
  box-shadow:
    inset 0 0 0 1px var(--table-trim),
    0 4px 10px rgba(0, 0, 0, 0.4);
}

.playing-card--settings {          /* the four cards of a Card design tile */
  --card-width: 32px;
  --card-height: 44px;
}

.settings-volume {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text-muted);
}

.settings-volume.is-muted {
  opacity: 0.45;
}

.settings-volume-value {
  width: 38px;
  font-size: 12px;
  font-weight: 600;
  text-align: right;
  color: var(--text-soft);
}

/* the track is filled up to the value (--fill, set by the page) */
.settings-range {
  width: 180px;
  height: 4px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-brand) var(--fill), var(--surface-raised) var(--fill));
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}

.settings-range::-webkit-slider-thumb {
  width: 16px;
  height: 16px;
  border: none;
  border-radius: 50%;
  background: var(--text-strong);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
  -webkit-appearance: none;
  appearance: none;
}

.settings-range::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border: none;
  border-radius: 50%;
  background: var(--text-strong);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}

.settings-range:disabled {
  cursor: default;
}

.settings-fineprint {
  margin: 12px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
}

/* ── Account & Subscription ──────────────────────────────────────────── */
.settings-profile {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 8px 0 4px;
}

.settings-profile-text {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
}

.settings-profile-text strong {
  font-size: 18px;
  font-weight: 700;
  color: var(--text-strong);
}

.settings-profile-text > span:not(.settings-chip) {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  color: var(--text-muted);
}

.settings-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--grade-good) 14%, transparent);
  padding: 3px 9px;
  font-size: 11px;
  font-weight: 600;
  color: var(--grade-good);
}

/* the plan: a warm wash from the top-left corner */
.settings-card.is-plan {
  border-color: color-mix(in srgb, var(--accent-brand) 30%, transparent);
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent-brand) 11%, var(--surface-panel)), var(--surface-panel) 62%);
}

.settings-plan-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-top: 6px;
}

.settings-plan-eyebrow {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-muted);
}

.settings-plan-name {
  display: block;
  margin-top: 4px;
  font-size: 24px;
  font-weight: 800;
  color: var(--text-strong);
}

.settings-status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--grade-good) 14%, transparent);
  padding: 5px 11px;
  font-size: 12px;
  font-weight: 700;
  color: var(--grade-good);
}

/* a live dot: the ring is its own pseudo-element, so only it repaints (5b.3) */
.settings-status i {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--grade-good);
}

.settings-status i::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  box-shadow: 0 0 0 2px var(--grade-good);
  pointer-events: none;
  animation: settings-live 1.8s ease-out infinite;
}

@keyframes settings-live {
  from {
    opacity: 0.7;
    transform: scale(0.4);
  }
  to {
    opacity: 0;
    transform: scale(1.4);
  }
}

.settings-plan-lead {
  margin: 12px 0 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-soft);
}

.settings-plan-list {
  display: grid;
  gap: 10px;
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
}

.settings-plan-list li {
  display: flex;
  gap: 10px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-soft);
}

.settings-plan-list li svg {
  flex: none;
  margin-top: 2px;
  color: var(--accent-brand);
}

.settings-plan-list strong {
  color: var(--text-strong);
}

/* ── Hotkeys ─────────────────────────────────────────────────────────── */
.settings-hotkey {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  border-top: 1px solid var(--line);
  padding: 11px 0;
}

.settings-hotkey:first-child {
  border-top: none;
  padding-top: 4px;
}

.settings-hotkey:last-child {
  padding-bottom: 0;
}

.settings-card.is-off .settings-hotkeys {
  opacity: 0.45;
}

.settings-hotkey-keys {
  display: flex;
  flex: none;
  align-items: center;
  gap: 4px;
}

.settings-key-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 72px;
  height: 34px;
  border: none;
  border-radius: 8px;
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--line);
  padding: 0 8px;
  cursor: pointer;
  transition: background-color 120ms ease;
}

.settings-key-button:hover:not(:disabled) {
  background: var(--surface-hover);
}

.settings-key-button:disabled {
  cursor: default;
}

/* recording: an amber frame breathing on its own layer */
.settings-key-button.is-recording {
  background: color-mix(in srgb, var(--accent-brand) 10%, transparent);
  box-shadow: inset 0 0 0 1px var(--accent-brand);
}

.settings-key-button.is-recording::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 10px;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-brand) 55%, transparent);
  pointer-events: none;
  animation: settings-recording 1.1s ease-in-out infinite alternate;
}

@keyframes settings-recording {
  from {
    opacity: 0.15;
  }
  to {
    opacity: 1;
  }
}

.settings-keycap {
  display: inline-grid;
  place-items: center;
  min-width: 26px;
  height: 24px;
  border-radius: 6px;
  background: var(--surface-raised);
  box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.35), inset 0 0 0 1px var(--line);
  padding: 0 7px 2px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-strong);
}

.settings-key-prompt {
  font-size: 12px;
  font-weight: 700;
  color: var(--accent-brand);
}

.settings-key-none {
  font-size: 12px;
  color: var(--text-muted);
}

.settings-icon-button {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.settings-icon-button:hover:not(:disabled) {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.settings-icon-button:disabled {
  opacity: 0.3;
  cursor: default;
}

.settings-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
}

.settings-notice {
  flex: 1;
  font-size: 12px;
  color: var(--text-dim);
}

/* ── Your data and Privacy (owner 2026-10-20) ────────────────────────── */
a.settings-button {
  text-decoration: none;
}

/* «Delete account»: the red of a wrong move, quiet until pointed at */
.settings-button.is-danger {
  background: color-mix(in srgb, var(--grade-bad) 14%, transparent);
  color: var(--grade-bad);
}

.settings-button.is-danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--grade-bad) 24%, transparent);
}

/* the Delete account window (features/account/DeleteAccountDialog.tsx) over the site's .modal-backdrop, in the look of Saved spots */
.account-delete-backdrop {
  z-index: 100;
}

.account-delete {
  width: 480px;
  max-width: 100%;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: #1d1d1d;
  box-shadow: 0 20px 80px rgba(0, 0, 0, 0.6);
  color: var(--text-normal);
  animation: account-delete-in 240ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes account-delete-in {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.account-delete-head {
  display: flex;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid var(--line);
  background: #171717;
  padding: 12px 12px 12px 18px;
}

.account-delete-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: color-mix(in srgb, var(--grade-bad) 16%, transparent);
  color: var(--grade-bad);
}

.account-delete-title {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.account-delete-title h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--text-strong);
}

.account-delete-title small {
  font-size: 12px;
  color: var(--text-muted);
}

.account-delete-body {
  padding: 16px 18px 4px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-soft);
}

.account-delete-body p {
  margin: 0 0 10px;
}

.account-delete-body ul {
  margin: 0 0 12px;
  padding-left: 18px;
}

.account-delete-body li {
  margin-bottom: 4px;
}

.account-delete-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: none;
  background: none;
  padding: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent-brand);
  cursor: pointer;
}

.account-delete-link:hover:not(:disabled) {
  text-decoration: underline;
}

.account-delete-link:disabled {
  opacity: 0.6;
  cursor: default;
}

.account-delete-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 14px 0 6px;
  font-size: 12px;
  color: var(--text-dim);
}

.account-delete-field b {
  color: var(--text-strong);
  letter-spacing: 0.6px;
}

.account-delete-field input {
  height: 38px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  outline: none;
  background: var(--surface-sunken);
  padding: 0 12px;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--text-strong);
}

.account-delete-field input:focus {
  border-color: var(--grade-bad);
}

.account-delete-field input::placeholder {
  color: var(--text-muted);
  font-weight: 600;
  opacity: 0.5;
}

.account-delete-error {
  color: var(--grade-bad);
}

.account-delete-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 18px 16px;
}

.account-delete-confirm {
  height: 34px;
  border: none;
  border-radius: 8px;
  background: var(--grade-bad);
  padding: 0 16px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-on-brand);
  cursor: pointer;
}

.account-delete-confirm:hover:not(:disabled) {
  background: var(--action-aggressive-hover);
}

.account-delete-confirm:disabled {
  opacity: 0.4;
  cursor: default;
}
/* The Saved spots popup (owner 2026-10-17; features/strategy/components/SavedSpotsModal.tsx), in the Solutions library's own look
   (solutions.css): a dark panel of one fixed height - the header, the spot open and the search stay, only the list scrolls - and rows
   on plates that light up as the library's do. Tags take one of four tones of the theme, the same tag always the same. Only transform
   and opacity move (frontend_rules 5b.3). */

.saved-spots-backdrop {
  z-index: 100;
}

.saved-spots {
  position: relative;
  display: flex;
  width: 80vw;   /* owner 2026-10-17: a fifth narrower than the screen, whatever the screen (was 1040px, then 1144px) */
  max-width: 100%;
  height: calc(100vh - 80px);
  max-height: 760px;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: #1d1d1d;
  box-shadow: 0 20px 80px rgba(0, 0, 0, 0.6);
  color: var(--text-normal);
  animation: saved-spots-in 240ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes saved-spots-in {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* ── header ──────────────────────────────────────────────────────────── */
.saved-spots-head {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid var(--line);
  background: #171717;
  padding: 10px 12px 10px 18px;
}

.saved-spots-icon {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: color-mix(in srgb, var(--accent-brand) 15%, transparent);
  color: var(--accent-brand);
}

.saved-spots-title {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.saved-spots-title h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--text-strong);
}

.saved-spots-title small {
  font-size: 12px;
  color: var(--text-muted);
}

/* «Add spot» in the header: an amber button whose plus turns into a cross while the panel is out */
.saved-add {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 6px;
  height: 32px;
  border: none;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent-brand) 16%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-brand) 40%, transparent);
  padding: 0 13px 0 10px;
  font-size: 13px;
  font-weight: 700;
  color: var(--accent-brand);
  cursor: pointer;
  transition: background-color 140ms ease, color 140ms ease;
}

.saved-add:hover:not(:disabled) {
  background: color-mix(in srgb, var(--accent-brand) 26%, transparent);
}

.saved-add.is-active {
  background: var(--accent-brand);
  color: var(--text-on-brand);
}

.saved-add:disabled {
  opacity: 0.4;
  cursor: default;
}

.saved-add-icon {
  transition: transform 240ms cubic-bezier(0.2, 0, 0, 1);
}

.saved-add.is-active .saved-add-icon {
  transform: rotate(45deg);
}

/* ── the add panel: it slides out under the header over the list, which dims, and slides back (transform and opacity only, 5b.3;
   hidden it is invisible to the keyboard too, its visibility switching after the slide) ── */
.saved-shade {
  position: absolute;
  z-index: 3;
  top: 55px;
  right: 0;
  bottom: 0;
  left: 0;
  background: rgba(0, 0, 0, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms ease;
}

.saved-shade.is-on {
  opacity: 1;
  pointer-events: auto;
}

.saved-drawer {
  position: absolute;
  z-index: 4;
  top: 55px;
  right: 0;
  left: 0;
  padding: 12px 18px 0;
  pointer-events: none;
  visibility: hidden;
  transition: visibility 0s linear 280ms;
}

.saved-drawer.is-open {
  pointer-events: auto;
  visibility: visible;
  transition: visibility 0s linear 0s;
}

.saved-drawer > .saved-current {
  box-shadow: 0 22px 50px rgba(0, 0, 0, 0.55);
  opacity: 0;
  transform: translateY(-22px) scale(0.98);
  transform-origin: top center;
  transition: opacity 200ms ease, transform 280ms cubic-bezier(0.2, 0, 0, 1);
}

.saved-drawer.is-open > .saved-current {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* ── the spot open ───────────────────────────────────────────────────── */
.saved-current {
  display: grid;
  flex-shrink: 0;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  gap: 20px;
  border: 1px solid color-mix(in srgb, var(--accent-brand) 28%, transparent);
  border-radius: 12px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent-brand) 10%, #232323), #232323 58%);
  padding: 14px 16px;
}

.saved-current.is-saved {
  border-color: color-mix(in srgb, var(--grade-good) 30%, transparent);
  background: linear-gradient(135deg, color-mix(in srgb, var(--grade-good) 9%, #232323), #232323 58%);
}

.saved-current-info {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 6px;
}

.saved-current-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--accent-brand);
}

.saved-current.is-saved .saved-current-eyebrow {
  color: var(--grade-good);
}

.saved-current-label {
  font-size: 17px;
  font-weight: 700;
  color: var(--text-strong);
}

.saved-current-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

/* the Line: each street a small grey name over its moves, one letter a move (owner 2026-10-17, after a screenshot) */
.saved-line {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 14px;
}

.saved-line-street {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.saved-line-street small {
  font-size: 10px;
  line-height: 12px;
  color: var(--text-muted);
}

.saved-line-street b {
  font-size: 13px;
  font-weight: 600;
  line-height: 15px;
  letter-spacing: 2.5px;
  color: var(--text-strong);
}

.saved-current-form {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 8px;
}

.saved-current-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
}

/* «Spot saved» fades in beside the button and out again */
.saved-flash {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 600;
  color: var(--grade-good);
  opacity: 0;
  transform: translateX(6px);
  transition: opacity 180ms ease, transform 220ms cubic-bezier(0.2, 0, 0, 1);
}

.saved-flash.is-on {
  opacity: 1;
  transform: translateX(0);
}

/* ── fields ──────────────────────────────────────────────────────────── */
.saved-note-input {
  width: 100%;
  resize: none;
  border: none;
  border-radius: 8px;
  background: #171717;
  box-shadow: inset 0 0 0 1px var(--line);
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-strong);
  outline: none;
  transition: box-shadow 120ms ease;
}

.saved-note-input::placeholder,
.saved-tags-input::placeholder,
.saved-search input::placeholder {
  color: var(--text-muted);
}

.saved-note-input:focus,
.saved-tags-editor:focus-within {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-brand) 60%, transparent);
}

.saved-tags-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.saved-tags-editor {
  display: flex;
  min-height: 36px;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  border-radius: 8px;
  background: #171717;
  box-shadow: inset 0 0 0 1px var(--line);
  padding: 5px 8px;
  transition: box-shadow 120ms ease;
}

.saved-tags-icon {
  flex: none;
  color: var(--text-muted);
}

.saved-tags-input {
  min-width: 120px;
  flex: 1;
  border: none;
  background: transparent;
  padding: 2px 2px;
  font: inherit;
  font-size: 13px;
  color: var(--text-strong);
  outline: none;
}

.saved-tags-offer {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

/* a tag: its tone's wash and ink (four tones of the theme) */
.saved-tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  max-width: 100%;
  border: none;
  border-radius: 999px;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 600;
  line-height: 16px;
  white-space: nowrap;
}

.saved-tag button {
  display: grid;
  place-items: center;
  width: 14px;
  height: 14px;
  margin-right: -4px;
  border: none;
  border-radius: 50%;
  background: transparent;
  padding: 0;
  color: inherit;
  cursor: pointer;
  opacity: 0.7;
}

.saved-tag button:hover {
  opacity: 1;
}

.saved-tag.is-offer {
  cursor: pointer;
  opacity: 0.7;
  transition: opacity 120ms ease;
}

.saved-tag.is-offer:hover {
  opacity: 1;
}

.saved-spots .is-tone-0 { --tone: var(--accent-brand); }
.saved-spots .is-tone-1 { --tone: var(--ai-accent); }
.saved-spots .is-tone-2 { --tone: var(--grade-good); }
.saved-spots .is-tone-3 { --tone: var(--neural-text); }

.saved-tag[class*="is-tone-"] {
  background: color-mix(in srgb, var(--tone) 16%, transparent);
  color: var(--tone);
}

/* ── buttons ─────────────────────────────────────────────────────────── */
.saved-primary {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  border: none;
  border-radius: 8px;
  background: var(--accent-brand);
  padding: 0 16px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-on-brand);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.saved-primary:hover:not(:disabled) {
  background: var(--accent-brand-hover);
}

.saved-primary:disabled {
  opacity: 0.5;
  cursor: default;
}

.saved-ghost {
  height: 34px;
  border: none;
  border-radius: 8px;
  background: transparent;
  padding: 0 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
}

.saved-ghost:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.saved-icon-button {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.saved-icon-button:hover {
  background: #444;
  color: var(--text-strong);
}

.saved-icon-button.is-danger:hover {
  color: var(--grade-bad);
}

.saved-delete-confirm {
  height: 28px;
  border: none;
  border-radius: 7px;
  background: color-mix(in srgb, var(--grade-bad) 20%, transparent);
  padding: 0 9px;
  font-size: 12px;
  font-weight: 700;
  color: var(--grade-bad);
  cursor: pointer;
  animation: saved-confirm-in 160ms ease both;
}

@keyframes saved-confirm-in {
  from {
    opacity: 0;
    transform: scale(0.92);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* ── search and the tag filter ───────────────────────────────────────── */
.saved-tools {
  display: flex;
  flex-shrink: 0;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  padding: 14px 18px 10px;
}

.saved-search {
  display: flex;
  width: 320px;
  height: 34px;
  align-items: center;
  gap: 8px;
  border-radius: 8px;
  background: #262626;
  box-shadow: inset 0 0 0 1px var(--line);
  padding: 0 10px;
  color: var(--text-muted);
}

.saved-search:focus-within {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-brand) 60%, transparent);
}

.saved-search input {
  min-width: 0;
  flex: 1;
  border: none;
  background: transparent;
  font: inherit;
  font-size: 13px;
  color: var(--text-strong);
  outline: none;
}

.saved-search button {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border: none;
  border-radius: 50%;
  background: transparent;
  padding: 0;
  color: var(--text-muted);
  cursor: pointer;
}

.saved-search button:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.saved-filter {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-wrap: wrap;
  gap: 4px;
}

.saved-filter-option {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  border: none;
  border-radius: 999px;
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--line);
  padding: 0 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.saved-filter-option:hover {
  background: #333;
  color: var(--text-strong);
}

.saved-filter-option b {
  font-weight: 700;
  color: var(--text-muted);
}

.saved-filter-option i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--tone);
}

.saved-filter-option.is-selected {
  background: color-mix(in srgb, var(--accent-brand) 17%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-brand) 45%, transparent);
  color: var(--accent-brand);
}

.saved-error {
  flex-shrink: 0;
  margin: 0 18px 8px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--grade-bad) 14%, transparent);
  padding: 8px 12px;
  font-size: 12px;
  color: var(--grade-bad);
}

/* ── the table ───────────────────────────────────────────────────────── */
/* its own layer: the rank of a card (cards.css .playing-card-rank, z-index 10) stays under the add panel and its shade (owner
   2026-10-17: the board's ranks of a row showed through the panel) */
.saved-table {
  isolation: isolate;
  display: flex;
  min-height: 0;
  flex: 1;
  flex-direction: column;
  border-top: 1px solid var(--line);
  margin: 0 18px;
}

.saved-row {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) 124px minmax(0, 1.6fr) minmax(0, 1.25fr) minmax(0, 1fr) 70px 64px;
  align-items: center;
  gap: 12px;
  padding: 0 10px;
  text-align: left;
}

.saved-row.is-head {
  flex-shrink: 0;
  height: 34px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-muted);
}

.saved-sort {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.saved-sort:hover,
.saved-sort.is-active {
  color: var(--text-strong);
}

.saved-rows {
  min-height: 0;
  flex: 1;
  overflow-y: auto;
  padding-bottom: 14px;
}

.saved-rows > .saved-row {
  min-height: 38px;   /* owner 2026-10-17: lower rows, more of them in view (was 52, then 44) */
  padding-top: 2px;
  padding-bottom: 2px;
  margin-bottom: 3px;
  border-radius: 7px;
  background: #2a2a2a;
  font-size: 12px;
  color: var(--text-normal);
  cursor: pointer;
  outline: none;
  transition: background-color 150ms ease;
}

.saved-rows > .saved-row:hover,
.saved-rows > .saved-row:focus-visible {
  background: #383838;
}

/* the spot open in Study is lit as a picked row (frontend_rules 5a) */
.saved-rows > .saved-row.is-current {
  background: linear-gradient(90deg, rgba(255, 158, 69, 0.34), rgba(255, 158, 69, 0.14));
  box-shadow: inset 2px 0 0 var(--accent-brand);
  color: var(--text-strong);
}

.saved-cell-spot {             /* the label and the spot on one line */
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 6px;
}

.saved-cell-spot strong {
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
}

.saved-cell-spot .saved-spot-chip {
  flex: none;
}

.saved-spot-chip {
  border-radius: 4px;
  background: #3a3a3a;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--text-soft);
}

.saved-board {
  display: inline-flex;
  gap: 2px;
}

.playing-card--saved {             /* the board of a saved spot: the Recent list's flop cards (cards.css .playing-card--recent) */
  --card-width: 22px;
  --card-height: 30px;
}

.saved-cell-text {
  display: -webkit-box;
  min-width: 0;
  overflow: hidden;
  line-height: 1.4;
  color: var(--text-soft);
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.saved-cell-text.is-note {
  color: var(--text-normal);
}

.saved-cell-tags {
  display: flex;
  min-width: 0;
  flex-wrap: wrap;
  gap: 4px;
}

.saved-cell-time {
  font-size: 12px;
  color: var(--text-muted);
}

.saved-cell-actions {
  display: flex;
  justify-content: flex-end;
  gap: 2px;
  cursor: default;
}

.saved-muted {
  color: var(--text-muted);
}

/* a row being edited: a plate of its own with the note and the tags */
.saved-edit {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 4px;
  border-radius: 9px;
  background: #2f2f2f;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-brand) 40%, transparent);
  padding: 12px;
  animation: saved-edit-in 200ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes saved-edit-in {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.saved-edit-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text-strong);
}

.saved-edit-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* loading: plates with the site's sweeping light (the config card's) */
.saved-skeleton {
  display: grid;
  grid-template-columns: 1.2fr 0.5fr 1.6fr;
  align-items: center;
  gap: 18px;
  height: 38px;
  margin-bottom: 3px;
  border-radius: 7px;
  background: #262626;
  padding: 0 12px;
}

.saved-skeleton span {
  position: relative;
  height: 9px;
  overflow: hidden;
  border-radius: 3px;
  background: var(--surface-raised);
}

.saved-skeleton span::before {
  content: "";
  position: absolute;
  top: -4px;
  bottom: -4px;
  left: -65%;
  width: 60%;
  background: linear-gradient(90deg, transparent, var(--skeleton-sheen), transparent);
  animation: node-loading-row-sheen 900ms ease-in-out infinite;
}

.saved-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 48px 20px;
  text-align: center;
  font-size: 13px;
  color: var(--text-muted);
}

.saved-empty strong {
  font-size: 15px;
  color: var(--text-strong);
}

.saved-empty-icon {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  margin-bottom: 6px;
  border-radius: 14px;
  background: color-mix(in srgb, var(--accent-brand) 12%, transparent);
  color: var(--accent-brand);
}
/* The guided tours of Study and Practice (owner 2026-10-20: «Короткий тур при первом входе (матрица, узлы, Actions, Hands), демо-спот,
   понятные пустые экраны»; features/tour/Tour.tsx). The page is dimmed by four window-sized shades placed round the element by
   transform, so the cut-out slides from one element to the next; the outline and the card come in by opacity and a short rise. Only
   transform and opacity move (docs/frontend_rules.md 5b.3). Above every dialog and panel of the site, under the hover hints (1000). */

.tour {
  position: fixed;
  z-index: 950;
  inset: 0;
  pointer-events: none;
  animation: tour-in 220ms ease both;
}

.tour.is-closing { animation: tour-out 160ms ease both; }

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

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

/* each shade takes the clicks on its part of the page: the page waits under the tour */
.tour-shade {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.64);
  pointer-events: auto;
  transform-origin: 0 0;
  transition: transform 320ms cubic-bezier(0.2, 0, 0, 1);
  will-change: transform;
}

/* the cut-out's outline; it also covers the element, so a click there does not act on the page behind the tour */
.tour-ring {
  position: fixed;
  border-radius: 4px;
  box-shadow: 0 0 0 2px var(--accent-brand), 0 0 0 7px rgba(255, 158, 69, 0.18);
  pointer-events: auto;
  animation: tour-ring-in 260ms ease 200ms both;
}

@keyframes tour-ring-in {
  from { opacity: 0; }
}

.tour-card {
  position: fixed;
  top: 12px;
  left: 12px;
  width: 300px;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  background: var(--surface-panel);
  padding: 14px 16px 14px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
  color: var(--text-normal);
  pointer-events: auto;
  animation: tour-card-in 260ms cubic-bezier(0.2, 0, 0, 1) 120ms both;
}

/* the one layout pass in which the new step's card is measured before it is placed */
.tour-card.is-measuring {
  visibility: hidden;
  animation: none;
}

@keyframes tour-card-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

.tour-count {
  display: block;
  margin-bottom: 6px;
  color: var(--accent-brand);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.tour-title {
  margin: 0 0 6px;
  color: var(--text-strong);
  font-size: 15px;
  font-weight: 700;
  line-height: 1.3;
}

.tour-text {
  margin: 0;
  color: var(--text-soft);
  font-size: 13px;
  line-height: 1.5;
}

.tour-foot {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 14px;
}

.tour-dots {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-right: auto;
}

.tour-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--line-strong);
  transition: transform 200ms ease;
}

.tour-dot.is-active {
  background: var(--accent-brand);
  transform: scale(1.35);
}

.tour-skip,
.tour-back,
.tour-next {
  height: 30px;
  border: none;
  border-radius: 7px;
  padding: 0 12px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.tour-skip {
  background: transparent;
  padding: 0 8px;
  color: var(--text-muted);
}

.tour-skip:hover,
.tour-skip:focus-visible {
  color: var(--text-strong);
  outline: none;
}

.tour-back {
  background: var(--surface-raised);
  color: var(--text-normal);
}

.tour-back:hover,
.tour-back:focus-visible {
  background: var(--surface-active);
  color: var(--text-strong);
  outline: none;
}

.tour-next {
  min-width: 64px;
  background: var(--accent-brand);
  color: var(--text-on-brand);
}

.tour-next:hover { background: var(--accent-brand-hover); }

.tour-next:focus-visible {
  outline: 2px solid rgba(255, 158, 69, 0.45);
  outline-offset: 2px;
}

/* ── «Take the tour» in the sidebars' account row (AuthGate SidebarAccount) ─────────────────────────────────────────────────────────────
   The same quiet 32px icon as Sign out beside it. Its name: in the folded Study rail the rail's own label on the right (data-rail-label,
   study.css «narrow window»); elsewhere the same label above the button. */
.sidebar-account-help {
  position: relative;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.sidebar-account-help:hover,
.sidebar-account-help:focus-visible {
  background: var(--surface-hover);
  color: var(--text-strong);
  outline: none;
}

.study-page:not(.is-rail-collapsed) .sidebar-account-help::after,
.practice-page .sidebar-account-help::after {
  content: attr(data-rail-label);
  position: absolute;
  z-index: 40;
  bottom: calc(100% + 8px);
  left: 50%;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 6px 10px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  color: var(--text-soft);
  pointer-events: none;
  opacity: 0;
  transform: translateX(-50%);
  transition: opacity 120ms ease;
}

.study-page:not(.is-rail-collapsed) .sidebar-account-help:hover::after,
.practice-page .sidebar-account-help:hover::after { opacity: 1; }

/* ── the empty Recent card of the Study sidebar (RecentSpots.tsx): one quiet line until a spot is opened ─────────────────────────────── */
.recent-empty {
  margin: 0;
  padding: 2px 4px 4px;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.45;
}
/* The legal pages /terms, /privacy, /refunds, /cookies (owner 2026-10-20; pages/legal/LegalPage.tsx): the site's dark page with a bar
   (logo, the four documents, Back), the title with its date and lead, the contents in a sticky column beside a readable text column
   (720px, 15px at 1.7), and a footer with «adults only», the documents and «Cookie settings». The section in view is lit in the contents as the
   Study strip's rows are (frontend_rules 5a). Facts the owner still has to give are amber [PLACEHOLDERS]. They open without sign-in and
   on a phone: the desktop min-width of the body is lifted here as on the landing. Only transform and opacity move (5b.3). */

body:has(.legal-page) { min-width: 0; }

.legal-page {
  min-height: 100vh;
  background: var(--surface-page);
  color: var(--text-normal);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* ── the bar ─────────────────────────────────────────────────────────── */
.legal-bar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 24px;
  height: 64px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-sunken);
  padding: 0 max(24px, calc(50vw - 560px));
}

.legal-logo {
  display: flex;
  align-items: center;
  text-decoration: none;
}

.legal-logo-brand {
  display: flex;
  align-items: center;
  gap: 8px;
}

.legal-logo-brand .brand-logo-mark { height: 28px; }
.legal-logo-brand .brand-logo-word { height: 19px; }

.legal-tabs {
  display: flex;
  gap: 4px;
  margin: 0 auto;
}

.legal-tab {
  border-radius: 999px;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  color: var(--text-soft);
}

.legal-tab:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.legal-tab.is-active {
  background: color-mix(in srgb, var(--accent-brand) 16%, transparent);
  color: var(--accent-brand);
}

.legal-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  border: none;
  border-radius: 8px;
  background: var(--surface-raised);
  padding: 0 14px 0 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
}

.legal-back:hover { background: var(--line-strong); }
.legal-back svg { transition: transform 180ms cubic-bezier(0.2, 0, 0, 1); }
.legal-back:hover svg { transform: translateX(-3px); }

/* ── the title ───────────────────────────────────────────────────────── */
.legal-hero,
.legal-layout,
.legal-footer {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 24px;
}

.legal-hero {
  padding-top: 48px;
  padding-bottom: 36px;
  animation: legal-in 320ms cubic-bezier(0.2, 0, 0, 1) both;
}

.legal-layout {
  animation: legal-in 320ms 60ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes legal-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.legal-kicker {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--accent-brand);
}

.legal-hero h1 {
  margin: 10px 0 10px;
  font-size: 40px;
  font-weight: 800;
  letter-spacing: -0.6px;
  color: var(--text-strong);
}

.legal-meta {
  margin: 0;
  font-size: 13px;
  color: var(--text-muted);
}

.legal-lead {
  max-width: 720px;
  margin: 18px 0 0;
  font-size: 16px;
  line-height: 1.6;
  color: var(--text-dim);
}

/* ── contents and text ───────────────────────────────────────────────── */
.legal-layout {
  display: grid;
  grid-template-columns: 260px minmax(0, 720px);
  gap: 56px;
  align-items: start;
}

.legal-toc {
  position: sticky;
  top: 88px;
}

.legal-toc-box summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--text-muted);
  list-style: none;
  pointer-events: none;
}

.legal-toc-box summary::-webkit-details-marker { display: none; }
.legal-toc-box summary svg { display: none; }

.legal-toc ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

.legal-toc a {
  display: flex;
  gap: 10px;
  margin-inline: -12px;
  padding: 7px 12px;
  font-size: 13px;
  line-height: 1.35;
  text-decoration: none;
  color: var(--text-dim);
}

.legal-toc a:hover {
  background: #404040;
  color: var(--text-strong);
}

.legal-toc a.is-active {
  background: linear-gradient(90deg, rgba(255, 158, 69, 0.34), rgba(255, 158, 69, 0.14));
  box-shadow: inset 2px 0 0 var(--accent-brand);
  color: var(--text-strong);
}

.legal-toc-number {
  flex: none;
  width: 18px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

.legal-article {
  min-width: 0;
  padding-bottom: 40px;
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-soft);
}

.legal-section {
  scroll-margin-top: 88px;
  border-top: 1px solid var(--line);
  padding: 28px 0 8px;
}

.legal-section:first-child {
  border-top: none;
  padding-top: 0;
}

.legal-section h2 {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 14px;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--text-strong);
}

.legal-section-number {
  display: grid;
  flex: none;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent-brand) 14%, transparent);
  font-size: 13px;
  font-weight: 800;
  color: var(--accent-brand);
}

.legal-article p { margin: 0 0 14px; }
.legal-article strong { color: var(--text-strong); }

.legal-article a {
  color: var(--accent-brand);
  font-weight: 600;
  text-decoration: none;
}

.legal-article a:hover { text-decoration: underline; }

.legal-article ul {
  margin: 0 0 14px;
  padding: 0;
  list-style: none;
}

.legal-article li {
  position: relative;
  margin-bottom: 8px;
  padding-left: 20px;
}

.legal-article li::before {
  content: "";
  position: absolute;
  top: 10px;
  left: 4px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-brand);
}

.legal-article code {
  border-radius: 4px;
  background: var(--surface-raised);
  padding: 1px 6px;
  font-size: 13px;
  color: var(--text-strong);
}

.legal-table {
  width: 100%;
  margin: 4px 0 16px;
  border-collapse: collapse;
  font-size: 14px;
  line-height: 1.55;
}

.legal-table th {
  border-bottom: 1px solid var(--line-strong);
  padding: 8px 12px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.6px;
  text-align: left;
  text-transform: uppercase;
  color: var(--text-muted);
}

.legal-table td {
  border-bottom: 1px solid var(--line);
  padding: 10px 12px;
  vertical-align: top;
}

.legal-table td:first-child {
  font-weight: 600;
  color: var(--text-strong);
}

/* a fact the owner still has to fill in */
.legal-placeholder {
  border-radius: 4px;
  background: color-mix(in srgb, var(--accent-brand) 14%, transparent);
  padding: 1px 5px;
  font-weight: 700;
  color: var(--accent-brand);
}

/* ── footer ──────────────────────────────────────────────────────────── */
.legal-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 20px;
  border-top: 1px solid var(--line);
  padding-top: 24px;
  padding-bottom: 40px;
  font-size: 13px;
  color: var(--text-muted);
}

.legal-footer-note { flex: 1 1 240px; }

.legal-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
}

.legal-footer-links a {
  text-decoration: none;
  color: var(--text-soft);
}

.legal-footer-links a:hover { color: var(--text-strong); }

.legal-cookie-button {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: transparent;
  padding: 0 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
}

.legal-cookie-button:hover { background: var(--surface-hover); }

.legal-page a:focus-visible,
.legal-page button:focus-visible {
  outline: 2px solid var(--accent-brand);
  outline-offset: 2px;
}

/* ── phones ──────────────────────────────────────────────────────────── */
@media (max-width: 760px) {
  .legal-bar {
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 10px;
    height: auto;
    padding: 12px 16px 10px;
  }

  .legal-tabs {
    order: 3;
    width: 100%;
    margin: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .legal-tabs::-webkit-scrollbar { display: none; }

  .legal-tab {
    flex-shrink: 0;
    border: 1px solid var(--line-strong);
    padding: 7px 14px;
  }

  .legal-tab.is-active { border-color: var(--accent-brand); }

  .legal-hero,
  .legal-layout,
  .legal-footer {
    padding-right: 16px;
    padding-left: 16px;
  }

  .legal-hero { padding-top: 28px; padding-bottom: 24px; }
  .legal-hero h1 { font-size: 30px; }
  .legal-lead { font-size: 15px; }

  .legal-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }

  /* the contents fold into a box above the text */
  .legal-toc { position: static; }

  .legal-toc-box {
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--surface-panel);
    padding: 0 16px;
  }

  .legal-toc-box summary {
    min-height: 48px;
    margin: 0;
    font-size: 12px;
    pointer-events: auto;
    cursor: pointer;
  }

  .legal-toc-box summary svg {
    display: block;
    transition: transform 150ms ease;
  }

  .legal-toc-box[open] summary svg { transform: rotate(180deg); }
  .legal-toc-box ol { padding-bottom: 10px; }
  .legal-toc a { margin-inline: -16px; padding: 9px 16px; font-size: 14px; }

  .legal-section { scroll-margin-top: 112px; }
  .legal-section h2 { font-size: 18px; }
  .legal-article { font-size: 15px; }

  .legal-table { display: block; overflow-x: auto; }

  .legal-footer { flex-direction: column; align-items: flex-start; }
  .legal-footer-note { flex: none; }
}
/* The cookie banner (owner 2026-10-20; features/consent/CookieBanner.tsx): a dark card at the bottom of the screen that blocks nothing -
   the cookie mark in an amber tile, a short text with the Cookie Policy link, «Customize» (Necessary always on, Analytics on/off),
   «Necessary only» and the amber «Accept all». It stands below every dialog of the site (their backdrops start at 50). It comes up from
   below and leaves the same way; only transform and opacity move (frontend_rules 5b.3), always (5b.5). On a phone it is the full width
   less 12px either side, and an in-flow spacer of its measured height (set by the banner) lets the page's end scroll out from under it;
   the sign-in card stands at the top there, so the Google button and the 18+ line are never under the banner. */

.consent-banner {
  position: fixed;
  right: 0;
  bottom: 20px;
  left: 0;
  z-index: 45;
  width: 780px;
  max-width: calc(100vw - 32px);
  margin: 0 auto;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: #1d1d1d;
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.55);
  padding: 18px 20px 16px;
  color: var(--text-normal);
  animation: consent-in 320ms cubic-bezier(0.2, 0, 0, 1) both;
}

.consent-banner.is-leaving {
  animation: consent-out 200ms cubic-bezier(0.4, 0, 1, 1) both;   /* = LEAVE_MS in CookieBanner.tsx */
  pointer-events: none;
}

@keyframes consent-in {
  from {
    opacity: 0;
    transform: translateY(24px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes consent-out {
  from {
    opacity: 1;
    transform: translateY(0);
  }
  to {
    opacity: 0;
    transform: translateY(24px);
  }
}

.consent-main {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}

.consent-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--accent-brand) 15%, transparent);
  color: var(--accent-brand);
}

.consent-text h2 {
  margin: 0 0 4px;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.consent-text p {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-dim);
}

.consent-text a {
  color: var(--accent-brand);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.consent-text a:hover {
  text-decoration: underline;
}

/* ── Customize: the two kinds, each with its switch ─────────────────── */
.consent-options {
  display: grid;
  gap: 8px;
  margin: 14px 0 0 52px;
  animation: consent-options-in 200ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes consent-options-in {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.consent-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  border-radius: 10px;
  background: var(--surface-sunken);
  box-shadow: inset 0 0 0 1px var(--line);
  padding: 10px 12px 10px 14px;
}

.consent-option-text strong {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
}

.consent-option-text small {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
}

.consent-always {
  border-radius: 4px;
  background: color-mix(in srgb, var(--grade-good) 14%, transparent);
  padding: 2px 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--grade-good);
}

/* the switch: the amber fill is a layer of its own that fades in, the knob slides - nothing else moves */
.consent-switch {
  position: relative;
  flex: none;
  width: 42px;
  height: 24px;
  overflow: hidden;
  border: none;
  border-radius: 999px;
  background: var(--surface-raised);
  padding: 0;
  cursor: pointer;
}

.consent-switch::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: var(--accent-brand);
  opacity: 0;
  transition: opacity 160ms ease;
}

.consent-switch i {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--text-soft);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  transition: transform 220ms cubic-bezier(0.2, 0, 0, 1);
}

.consent-switch.is-on::before {
  opacity: 1;
}

.consent-switch.is-on i {
  background: var(--text-on-brand);
  transform: translateX(18px);
}

.consent-switch:disabled {
  opacity: 0.55;
  cursor: default;
}

/* ── the three choices ───────────────────────────────────────────────── */
.consent-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 14px;
}

.consent-button {
  height: 36px;
  border: none;
  border-radius: 8px;
  background: var(--surface-raised);
  padding: 0 16px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-strong);
  cursor: pointer;
}

.consent-button:hover {
  background: var(--line-strong);
}

.consent-button.is-quiet {
  margin-right: auto;
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--line-strong);
  color: var(--text-soft);
}

.consent-button.is-quiet:hover,
.consent-button.is-quiet.is-pressed {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.consent-button.is-primary {
  background: var(--accent-brand-deep);
  color: var(--text-on-brand);
}

.consent-button.is-primary:hover {
  background: var(--accent-brand);
}

.consent-button:focus-visible,
.consent-switch:focus-visible,
.consent-text a:focus-visible {
  outline: 2px solid var(--accent-brand);
  outline-offset: 2px;
}

.consent-spacer {
  display: none;
}

/* ── phones ──────────────────────────────────────────────────────────── */
@media (max-width: 700px) {
  .consent-banner {
    bottom: 12px;
    max-width: calc(100vw - 24px);
    padding: 14px 14px 12px;
  }

  .consent-icon {
    width: 32px;
    height: 32px;
  }

  .consent-text p {
    font-size: 12px;
  }

  .consent-options {
    margin-left: 0;
  }

  .consent-actions {
    flex-wrap: wrap;
  }

  .consent-button {
    flex: 1 1 auto;
    padding: 0 10px;
  }

  .consent-button.is-quiet {
    margin-right: 0;
  }

  /* the page's end can scroll out from under the banner (its height comes from the banner) */
  .consent-spacer {
    display: block;
  }

  /* the sign-in card stands at the top while the banner is up: its Google button and the 18+ line stay above it */
  html.has-consent-banner .auth-page {
    place-items: start center;
  }
}
/* The site admin (owner 2026-10-20; pages/admin): the sections on the left like Settings (the way back, the open section lit as the Study
   strip's rows, frontend_rules 5a), the open section on the right - figures, charts and lists on the panels of the site's dark look. Sizes
   are px; colours are the theme's tokens and their mixes (the charts' four: --chart-1..4, tokens.css); only transform and opacity move
   (frontend_rules 5b.3), and always (5b.5). Usable from a 1280px laptop up. */

.admin-page {
  display: grid;
  grid-template-columns: 264px minmax(0, 1fr);
  min-height: 100vh;
  background: var(--surface-page);
  color: var(--text-normal);
}

/* ── the left column ─────────────────────────────────────────────────── */
.admin-nav {
  position: sticky;
  top: 0;
  display: flex;
  height: 100vh;
  flex-direction: column;
  gap: 4px;
  border-right: 1px solid var(--line);
  background: var(--surface-sunken);
  padding: 24px 16px 16px;
}

.admin-back {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 8px;
  height: 34px;
  border: none;
  border-radius: 8px;
  background: var(--surface-raised);
  padding: 0 14px 0 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.admin-back svg {
  transition: transform 180ms cubic-bezier(0.2, 0, 0, 1);
}

.admin-back:hover {
  background: var(--line-strong);
}

.admin-back:hover svg {
  transform: translateX(-3px);
}

.admin-nav-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 28px 0 10px;
  font-size: 22px;
  font-weight: 800;
  color: var(--text-strong);
}

.admin-nav-title svg {
  color: var(--accent-brand);
}

.admin-nav-list {
  display: flex;
  flex-direction: column;
}

.admin-nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  border: none;
  background: transparent;
  margin-inline: -16px;
  padding: 10px 16px;
  text-align: left;
  color: var(--text-soft);
  cursor: pointer;
}

.admin-nav-item:hover {
  background: #404040;
}

.admin-nav-item.is-selected {
  background: linear-gradient(90deg, rgba(255, 158, 69, 0.34), rgba(255, 158, 69, 0.14));
  box-shadow: inset 2px 0 0 var(--accent-brand);
  color: var(--text-strong);
}

.admin-nav-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: var(--surface-raised);
  color: var(--text-soft);
}

.admin-nav-item.is-selected .admin-nav-icon {
  background: color-mix(in srgb, var(--accent-brand) 22%, transparent);
  color: var(--accent-brand);
}

.admin-nav-text {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.admin-nav-text strong {
  font-size: 14px;
  font-weight: 700;
}

.admin-nav-text small {
  font-size: 12px;
  color: var(--text-muted);
}

/* the open errors beside «Errors» */
.admin-nav-badge {
  flex: none;
  min-width: 22px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--grade-bad) 20%, transparent);
  padding: 2px 7px;
  text-align: center;
  font-size: 11px;
  font-weight: 800;
  color: var(--text-strong);
}

.admin-nav-run {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: auto;
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim);
  text-decoration: none;
  transition: background-color 120ms ease, color 120ms ease;
}

.admin-nav-run:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.admin-nav-user {
  display: flex;
  align-items: center;
  gap: 10px;
  border-top: 1px solid var(--line-strong);
  margin-top: 8px;
  padding: 18px 0 4px;
}

.admin-nav-user .admin-avatar {
  width: 36px;
  height: 36px;
}

.admin-nav-user-text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 3px;
}

.admin-nav-user-text strong,
.admin-nav-user-text small {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.admin-nav-user-text strong {
  font-size: 13px;
  color: var(--text-strong);
}

.admin-nav-user-text small {
  font-size: 11px;
  color: var(--text-muted);
}

.admin-avatar {
  display: grid;
  flex: none;
  place-items: center;
  width: 32px;
  height: 32px;
  overflow: hidden;
  border-radius: 50%;
  background: var(--surface-raised);
  font-size: 14px;
  font-weight: 700;
  color: var(--accent-brand);
}

.admin-avatar.is-large {
  width: 64px;
  height: 64px;
  font-size: 26px;
  box-shadow: 0 0 0 3px var(--surface-page), 0 0 0 4px color-mix(in srgb, var(--accent-brand) 45%, transparent);
}

.admin-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ── the open section ────────────────────────────────────────────────── */
.admin-main {
  min-width: 0;
  padding: 32px 36px 64px;
}

.admin-content {
  max-width: 1240px;
  animation: admin-in 260ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes admin-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

.admin-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 22px;
}

.admin-head h1 {
  margin: 0 0 6px;
  font-size: 28px;
  font-weight: 800;
  color: var(--text-strong);
}

.admin-head p {
  max-width: 640px;
  margin: 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-dim);
}

/* a segmented control: the period, the kind and the status of errors */
.admin-segments {
  display: inline-flex;
  flex: none;
  gap: 2px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--surface-sunken);
  padding: 3px;
}

.admin-segment {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  border: none;
  border-radius: 7px;
  background: transparent;
  padding: 0 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.admin-segment:hover {
  color: var(--text-strong);
}

.admin-segment.is-active {
  background: var(--surface-raised);
  color: var(--text-strong);
}

.admin-segment small {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-muted);
}

/* ── figures ─────────────────────────────────────────────────────────── */
.admin-stats {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}

.admin-stat {
  display: flex;
  min-height: 116px;
  flex-direction: column;
  gap: 4px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-panel);
  padding: 14px 16px 10px;
}

.admin-stat-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
}

.admin-stat-value {
  font-size: 28px;
  font-weight: 800;
  line-height: 1.15;
  color: var(--text-strong);
}

.admin-stat-note {
  font-size: 12px;
  color: var(--text-dim);
}

.admin-spark {
  display: block;
  width: 100%;
  height: 26px;
  margin-top: auto;
  padding-top: 6px;
}

.admin-spark-line {
  fill: none;
  stroke: var(--c);
  stroke-width: 1.5px;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* ── cards ───────────────────────────────────────────────────────────── */
.admin-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.admin-grid > .is-wide {
  grid-column: 1 / -1;
}

.admin-card {
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-panel);
  padding: 16px 18px 14px;
}

.admin-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.admin-card-head h2 {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-strong);
}

.admin-card-head p {
  margin: 3px 0 0;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-muted);
}

.admin-card-head:last-child {
  margin-bottom: 0;
}

.admin-empty {
  margin: 4px 0;
  font-size: 13px;
  color: var(--text-muted);
}

/* ── charts (pages/admin/charts.tsx) ─────────────────────────────────── */
.is-c1 { --c: var(--chart-1); }
.is-c2 { --c: var(--chart-2); }
.is-c3 { --c: var(--chart-3); }
.is-c4 { --c: var(--chart-4); }

.admin-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin: -4px 0 6px;
  font-size: 12px;
  color: var(--text-soft);
}

.admin-key {
  display: inline-block;
  width: 14px;
  height: 3px;
  margin-right: 6px;
  border-radius: 2px;
  background: var(--c);
  vertical-align: middle;
}

.admin-chart-plot {
  position: relative;
}

.admin-chart-plot svg {
  display: block;
  overflow: visible;
}

.admin-gridline {
  stroke: var(--chart-grid);
  stroke-width: 1px;
  shape-rendering: crispEdges;
}

.admin-axis {
  fill: var(--text-muted);
  font-size: 11px;
}

.admin-line {
  fill: none;
  stroke: var(--c);
  stroke-width: 2px;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.admin-area {
  fill: var(--c);
  fill-opacity: 0.1;
  stroke: none;
}

.admin-crosshair {
  stroke: var(--line-strong);
  stroke-width: 1px;
}

.admin-dot {
  fill: var(--c);
  stroke: var(--surface-panel);
  stroke-width: 2px;
}

.admin-chart-empty {
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  font-size: 12px;
  color: var(--text-muted);
}

/* the day under the pointer: the site's hint panel (ui.css .hover-hint), beside the crosshair */
.admin-tooltip {
  position: absolute;
  z-index: 5;
  display: flex;
  min-width: 150px;
  flex-direction: column;
  gap: 4px;
  pointer-events: none;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 8px 10px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
  font-size: 12px;
  color: var(--text-soft);
  transform: translateX(12px);
}

.admin-tooltip.is-left {
  transform: translateX(calc(-100% - 12px));
}

.admin-tooltip strong {
  color: var(--text-strong);
}

.admin-tooltip span {
  display: flex;
  align-items: center;
  white-space: nowrap;
}

.admin-tooltip b {
  margin-left: auto;
  padding-left: 14px;
  color: var(--text-strong);
}

/* a ranked list with bars */
.admin-bars {
  margin: 0;
  padding: 0;
  list-style: none;
}

.admin-bars li + li {
  margin-top: 10px;
}

.admin-bar-text {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
}

.admin-bar-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-normal);
}

.admin-bar-label small {
  margin-left: 8px;
  font-size: 11px;
  color: var(--text-muted);
}

.admin-bar-value {
  flex: none;
  font-weight: 700;
  color: var(--text-strong);
}

.admin-bar-value small {
  margin-left: 8px;
  font-size: 11px;
  font-weight: 400;
  color: var(--text-muted);
}

.admin-bar-track {
  height: 6px;
  margin-top: 5px;
  overflow: hidden;
  border-radius: 3px;
  background: var(--surface-sunken);
}

.admin-bar-fill {
  height: 100%;
  border-radius: 3px;
  background: var(--chart-1);
}

.admin-filter-key {
  border-radius: 4px;
  background: var(--surface-raised);
  padding: 1px 6px;
  font-size: 12px;
  color: var(--text-soft);
}

/* ── states and buttons ──────────────────────────────────────────────── */
.admin-loading {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 32px 0;
  font-size: 13px;
  color: var(--text-muted);
}

.admin-loading svg {
  animation: admin-breathe 1.2s ease-in-out infinite;
}

@keyframes admin-breathe {
  50% { opacity: 0.35; }
}

.admin-loadable {
  transition: opacity 160ms ease;
}

.admin-loadable.is-refreshing {
  opacity: 0.7;
}

.admin-problem {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--grade-bad) 12%, transparent);
  padding: 12px 14px;
  font-size: 13px;
  color: var(--text-strong);
}

.admin-calm {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px dashed var(--line-strong);
  border-radius: 12px;
  padding: 40px;
  font-size: 14px;
  color: var(--text-soft);
}

.admin-calm svg {
  color: var(--grade-good);
}

.admin-button {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  gap: 7px;
  height: 32px;
  border: none;
  border-radius: 8px;
  background: var(--surface-raised);
  padding: 0 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.admin-button:hover:not(:disabled) {
  background: var(--line-strong);
}

.admin-button:disabled {
  opacity: 0.4;
  cursor: default;
}

.admin-button.is-primary {
  background: var(--accent-brand);
  color: var(--text-on-brand);
}

.admin-button.is-primary:hover:not(:disabled) {
  background: var(--accent-brand-hover);
}

.admin-button.is-danger {
  background: color-mix(in srgb, var(--grade-bad) 16%, transparent);
  color: var(--text-strong);
}

.admin-button.is-danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--grade-bad) 28%, transparent);
}

.admin-button.is-icon {
  width: 32px;
  padding: 0;
}

.admin-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 12px;
}

.admin-error-text,
.admin-ok-text {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 auto 0 0;
  font-size: 12px;
}

.admin-error-text {
  color: var(--grade-bad);
}

.admin-ok-text {
  color: var(--grade-good);
}

/* a number field with its label (Limits, a user's limits) */
.admin-field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  border-top: 1px solid var(--line);
  padding: 12px 0;
}

.admin-card-head + .admin-field {
  border-top: none;
  padding-top: 2px;
}

.admin-field.is-compact {
  padding: 8px 0;
}

.admin-field-text {
  min-width: 0;
}

.admin-field-text strong {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-strong);
}

.admin-field-text small {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-muted);
}

.admin-field input {
  width: 110px;
  height: 34px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface-sunken);
  padding: 0 10px;
  text-align: right;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-strong);
  outline: none;
}

.admin-field input:focus {
  border-color: var(--accent-brand);
}

.admin-field input::placeholder {
  color: var(--text-muted);
  font-weight: 400;
}

/* ── users ───────────────────────────────────────────────────────────── */
.admin-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}

.admin-toolbar-note {
  margin-left: auto;
  font-size: 12px;
  color: var(--text-muted);
}

.admin-search {
  display: flex;
  width: 340px;
  height: 36px;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--surface-sunken);
  padding: 0 10px;
  color: var(--text-muted);
}

.admin-search:focus-within {
  border-color: color-mix(in srgb, var(--accent-brand) 55%, transparent);
}

.admin-search input {
  min-width: 0;
  flex: 1;
  border: none;
  background: transparent;
  font-size: 13px;
  color: var(--text-strong);
  outline: none;
}

.admin-search button {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.admin-search button:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.admin-table {
  display: flex;
  flex-direction: column;
}

.admin-user-row {
  display: grid;
  width: 100%;
  grid-template-columns: minmax(0, 2.4fr) 104px 104px 112px 72px 64px 92px;
  align-items: center;
  gap: 12px;
  border: none;
  background: transparent;
  padding: 0 12px;
  text-align: left;
  font: inherit;
  font-size: 13px;
  color: var(--text-normal);
}

.admin-user-row.is-head {
  height: 34px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-muted);
}

.admin-table > button.admin-user-row {
  min-height: 52px;
  margin-bottom: 4px;
  border-radius: 9px;
  background: #2a2a2a;
  cursor: pointer;
  transition: background-color 150ms ease, opacity 150ms ease;
}

.admin-table > button.admin-user-row:hover,
.admin-table > button.admin-user-row:focus-visible {
  background: #383838;
  outline: none;
}

.admin-table > button.admin-user-row.is-disabled {
  opacity: 0.6;
}

.admin-sort {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.admin-sort:hover,
.admin-sort.is-active {
  color: var(--text-strong);
}

.admin-user-cell {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 10px;
}

.admin-user-name {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}

.admin-user-name strong,
.admin-user-name small {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.admin-user-name strong {
  font-size: 13px;
  color: var(--text-strong);
}

.admin-user-name small {
  font-size: 12px;
  color: var(--text-muted);
}

.admin-today {
  display: flex;
  gap: 12px;
}

.admin-today span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--text-soft);
}

.admin-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border-radius: 999px;
  background: var(--surface-raised);
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-soft);
  white-space: nowrap;
}

.admin-badge.is-on {
  background: color-mix(in srgb, var(--grade-good) 16%, transparent);
  color: var(--text-strong);
}

.admin-badge.is-off {
  background: color-mix(in srgb, var(--grade-bad) 18%, transparent);
  color: var(--text-strong);
}

.admin-badge.is-admin {
  background: color-mix(in srgb, var(--accent-brand) 18%, transparent);
  color: var(--accent-brand);
}

.admin-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 12px;
  font-size: 12px;
  color: var(--text-muted);
}

/* ── a user's drawer ─────────────────────────────────────────────────── */
.admin-drawer-backdrop {
  position: fixed;
  z-index: 70;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  animation: admin-fade 200ms ease both;
}

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

.admin-drawer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 620px;
  max-width: calc(100vw - 48px);
  overflow-y: auto;
  border-left: 1px solid var(--line-strong);
  background: var(--surface-page);
  padding: 28px 28px 40px;
  box-shadow: -24px 0 60px rgba(0, 0, 0, 0.45);
  outline: none;
  animation: admin-drawer-in 280ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes admin-drawer-in {
  from {
    opacity: 0;
    transform: translateX(48px);
  }
}

.admin-drawer-close {
  position: absolute;
  top: 18px;
  right: 18px;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.admin-drawer-close:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.admin-detail .admin-card {
  margin-bottom: 12px;
}

.admin-detail-head {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 4px 40px 20px 4px;
}

.admin-detail-who {
  min-width: 0;
}

.admin-detail-who h2 {
  margin: 0;
  font-size: 20px;
  font-weight: 800;
  color: var(--text-strong);
}

.admin-detail-who > span {
  display: block;
  margin-top: 3px;
  font-size: 13px;
  color: var(--text-dim);
}

.admin-detail-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.admin-facts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin: 0 0 12px;
}

.admin-facts > div {
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-panel);
  padding: 10px 12px;
}

.admin-facts dt {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: capitalize;
}

.admin-facts dd {
  margin: 4px 0 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
  overflow-wrap: anywhere;
}

.admin-facts dd small {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  font-weight: 400;
  color: var(--text-muted);
}

.admin-facts.is-small {
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
}

.admin-facts.is-small > div {
  background: var(--surface-sunken);
}

.admin-facts.is-small dd {
  font-size: 12px;
  font-weight: 600;
}

.admin-feed {
  max-height: 420px;
  overflow-y: auto;
  margin: 0;
  padding: 0;
  list-style: none;
}

.admin-feed li {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  border-top: 1px solid var(--line);
  padding: 7px 0;
}

.admin-feed li:first-child {
  border-top: none;
}

.admin-feed-icon {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--surface-raised);
  color: var(--text-soft);
}

.admin-feed-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  color: var(--text-normal);
}

.admin-feed time {
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
}

.admin-logins {
  display: flex;
  flex-direction: column;
}

.admin-login-row {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.3fr) minmax(0, 0.9fr) minmax(0, 1.3fr);
  gap: 10px;
  border-top: 1px solid var(--line);
  padding: 8px 0;
  font-size: 12px;
  color: var(--text-soft);
}

.admin-login-row:first-child {
  border-top: none;
}

.admin-login-row > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.admin-login-event {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  font-weight: 600;
  color: var(--text-strong);
  text-transform: capitalize;
}

.admin-login-event small {
  flex-basis: 100%;
  font-weight: 400;
  color: var(--text-muted);
}

/* ── errors ──────────────────────────────────────────────────────────── */
.admin-errors {
  margin: 0;
  padding: 0;
  list-style: none;
}

.admin-error {
  margin-bottom: 6px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: #2a2a2a;
  transition: background-color 150ms ease;
}

.admin-error:hover {
  background: #313131;
}

.admin-error.is-open {
  border-color: var(--line);
  background: var(--surface-panel);
}

.admin-error-line {
  display: grid;
  width: 100%;
  grid-template-columns: 118px minmax(0, 1fr) 64px 64px 92px 16px;
  align-items: center;
  gap: 12px;
  border: none;
  background: transparent;
  padding: 10px 14px;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

/* the kind: a neutral pill with its colour as a dot (the colours follow the kinds, never the rank) */
.admin-kind {
  display: inline-flex;
  align-items: center;
  justify-self: start;
  gap: 6px;
  border-radius: 999px;
  background: var(--surface-raised);
  padding: 3px 9px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-soft);
  white-space: nowrap;
}

.admin-kind::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--c);
}

.admin-kind.is-js { --c: var(--chart-2); }
.admin-kind.is-auth { --c: var(--chart-1); }
.admin-kind.is-csp { --c: var(--chart-4); }
.admin-kind.is-node { --c: var(--chart-3); }

.admin-error-text-block {
  min-width: 0;
}

.admin-error-text-block strong,
.admin-error-text-block small {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.admin-error-text-block strong {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
}

.admin-error-text-block small {
  margin-top: 3px;
  font-size: 12px;
  color: var(--text-muted);
}

.admin-error.is-resolved .admin-error-text-block strong {
  color: var(--text-dim);
}

.admin-error-count {
  text-align: right;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-strong);
}

.admin-error-count small {
  display: block;
  font-size: 11px;
  font-weight: 400;
  color: var(--text-muted);
}

.admin-error-when {
  text-align: right;
  font-size: 12px;
  color: var(--text-muted);
}

.admin-error-chevron {
  color: var(--text-muted);
  transition: transform 180ms cubic-bezier(0.2, 0, 0, 1);
}

.admin-error.is-open .admin-error-chevron {
  transform: rotate(180deg);
}

.admin-error-detail {
  padding: 2px 14px 14px;
}

.admin-stack {
  max-height: 320px;
  overflow: auto;
  margin: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-sunken);
  padding: 10px 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-soft);
  white-space: pre;
}

/* a narrower laptop: one column of cards */
@media (max-width: 1180px) {
  .admin-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* The admin's Performance section (pages/admin/AdminPerf.tsx, owner 2026-10-20): the legend of the colours, the figures coloured good /
   needs improvement / poor, and the tables of pages, Study requests, page files, AI solves and site versions. The tiles, cards and charts
   are admin.css's. */

/* ── the legend ──────────────────────────────────────────────────────── */
.admin-perf-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin-bottom: 14px;
  font-size: 12px;
  color: var(--text-soft);
}

.admin-perf-legend p {
  flex: 1 1 360px;
  margin: 0;
  line-height: 1.45;
  color: var(--text-muted);
}

.admin-perf-key {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  white-space: nowrap;
}

.admin-perf-key::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--grade);
}

.admin-perf-key.is-good,
.admin-perf-value.is-good { --grade: var(--grade-good); }
.admin-perf-key.is-warn,
.admin-perf-value.is-warn { --grade: var(--grade-warn); }
.admin-perf-key.is-poor,
.admin-perf-value.is-poor { --grade: var(--grade-bad); }

/* ── the figures ─────────────────────────────────────────────────────── */
.admin-perf-value {
  color: var(--text-strong);
  white-space: nowrap;
}

.admin-perf-value.is-good,
.admin-perf-value.is-warn,
.admin-perf-value.is-poor {
  color: var(--grade);
}

.admin-perf-tile .admin-stat-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.admin-perf-tile .admin-stat-label small {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
}

.admin-perf-tile .admin-stat-value {
  font-size: 24px;
}

.admin-perf-tile-note {
  font-size: 11px;
  line-height: 1.35;
  color: var(--text-muted);
}

/* ── the tables ──────────────────────────────────────────────────────── */
.admin-perf-scroll {
  overflow-x: auto;
}

.admin-perf-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  color: var(--text-normal);
}

.admin-perf-table th {
  padding: 0 10px 8px;
  font-size: 11px;
  font-weight: 700;
  text-align: left;
  color: var(--text-muted);
  white-space: nowrap;
}

.admin-perf-table td {
  border-top: 1px solid var(--line);
  padding: 9px 10px;
  vertical-align: top;
}

.admin-perf-table th:first-child,
.admin-perf-table td:first-child {
  padding-left: 0;
}

.admin-perf-table th:last-child,
.admin-perf-table td:last-child {
  padding-right: 0;
}

.admin-perf-table .is-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.admin-perf-table code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  color: var(--text-soft);
}

.admin-perf-sub {
  display: block;
  font-size: 11px;
  color: var(--text-dim);
}

.admin-perf-foot {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--text-muted);
}
/* Daily limits and request rates (owner 2026-10-20; lib/usageLimits.ts, webapi/limits.py): the matrix card of a refused request
   (LimitCard in features/strategy/components/NodeErrorCard.tsx - the node error card's frame with an amber hourglass instead of the
   red mark), the AI Custom Solve dialog's note (features/limits/LimitNotice.tsx) and «Usage today» in Settings
   (features/limits/UsageToday.tsx). Colours are the theme's tokens and their mixes; only transform and opacity move (frontend_rules
   5b.3), and always (5b.5). */

/* ── the matrix card ─────────────────────────────────────────────────── */
.node-error-icon.is-limit {
  background: color-mix(in srgb, var(--accent-brand) 14%, transparent);
  color: var(--accent-brand);
}

.node-error-notice-dot.is-limit {
  background: var(--accent-brand);
}

.matrix-error.node-error.is-limit .node-error-card {
  animation: usage-limit-in 320ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes usage-limit-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ── the AI Custom Solve dialog's note ───────────────────────────────── */
.usage-limit-notice {
  display: flex;
  align-items: center;
  gap: 14px;
  border-top: 1px solid color-mix(in srgb, var(--accent-brand) 28%, transparent);
  background: linear-gradient(90deg, color-mix(in srgb, var(--accent-brand) 12%, transparent), color-mix(in srgb, var(--accent-brand) 3%, transparent));
  padding: 12px 22px;
  animation: usage-limit-in 320ms cubic-bezier(0.2, 0, 0, 1) both;
}

.usage-limit-notice-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent-brand) 16%, transparent);
  color: var(--accent-brand);
}

.usage-limit-notice-text {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.usage-limit-notice-text strong {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-strong);
}

.usage-limit-notice-text span {
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-muted);
}

.usage-limit-notice-text b {
  font-weight: 600;
  color: var(--text-strong);
}

.usage-limit-notice-link {
  flex: none;
}

/* ── Settings: Usage today ───────────────────────────────────────────── */
.usage-card .settings-card-head h2 {
  flex: 1;
}

.usage-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent-brand) 12%, transparent);
  padding: 3px 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--accent-brand);
}

.usage-row {
  border-top: 1px solid var(--line);
  padding: 14px 0 12px;
}

.settings-card-head + .usage-row {
  border-top: none;
  padding-top: 6px;
}

.usage-row-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
}

.usage-count {
  flex: none;
  padding-top: 1px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  white-space: nowrap;
}

.usage-count b {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.usage-row.is-full .usage-count b {
  color: var(--grade-warn);
}

/* the number's place while the day's usage loads: a short dim block with the loading light of the site's skeletons */
.usage-count-pending {
  position: relative;
  display: block;
  width: 56px;
  height: 14px;
  overflow: hidden;
  border-radius: 4px;
  background: var(--surface-raised);
}

.usage-count-pending::after,
.usage-card.is-loading .usage-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, var(--skeleton-sheen), transparent);
  transform: translateX(-100%);
  animation: usage-sheen 1100ms ease-in-out infinite;
}

@keyframes usage-sheen {
  to {
    transform: translateX(100%);
  }
}

/* a thin bar: the track is the full limit, the fill grows from the left (scaleX: only transform moves) */
.usage-bar {
  position: relative;
  display: block;
  height: 6px;
  margin-top: 12px;
  overflow: hidden;
  border-radius: 999px;
  background: var(--surface-sunken);
  box-shadow: inset 0 0 0 1px var(--line);
}

.usage-bar i {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-brand-deep), var(--accent-brand));
  transform-origin: left center;
  transition: transform 520ms cubic-bezier(0.2, 0, 0, 1);
}

.usage-row.is-full .usage-bar i {
  background: var(--grade-warn);
}

.usage-reset b {
  font-weight: 600;
  color: var(--text-soft);
}
/* The trainer's progress page (owner 2026-10-20; pages/practice/ProgressPage.tsx): the period's totals in tiles, a bar per day, the
   results by position, street, pot and table, the spots with the most mistakes and the latest hands. The look of Settings (settings.css):
   cards on the page surface, the brand colour for what is picked. Colours are the theme's tokens and their mixes; only transform and
   opacity move (frontend_rules 5b.3), and always (5b.5). */

.progress-page {
  min-height: 100vh;
  background: var(--surface-page);
  color: var(--text-normal);
}

.progress-content {
  max-width: 1120px;
  margin: 0 auto;
  padding: 32px 40px 64px;
  animation: progress-in 280ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes progress-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ── head ────────────────────────────────────────────────────────────── */
.progress-back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  border: none;
  border-radius: 8px;
  background: var(--surface-raised);
  padding: 0 14px 0 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
}

.progress-back svg {
  transition: transform 180ms cubic-bezier(0.2, 0, 0, 1);
}

.progress-back:hover {
  background: var(--line-strong);
}

.progress-back:hover svg {
  transform: translateX(-3px);
}

.progress-title {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin: 22px 0 20px;
}

.progress-title h1 {
  margin: 0 0 6px;
  font-size: 28px;
  font-weight: 800;
  color: var(--text-strong);
}

.progress-title p {
  margin: 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-dim);
}

/* the period and the chart's measure: segmented switches like the trainer's pause switch */
.progress-range,
.progress-segment {
  display: flex;
  gap: 2px;
  border-radius: 8px;
  background: var(--surface-sunken);
  padding: 3px;
}

.progress-range-option,
.progress-segment-option {
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
}

.progress-segment-option {
  padding: 5px 10px;
  font-size: 12px;
}

.progress-range-option:hover,
.progress-segment-option:hover {
  color: var(--text-strong);
}

.progress-range-option.is-selected,
.progress-segment-option.is-selected {
  background: var(--surface-active);
  color: var(--accent-brand);
}

/* ── tiles ───────────────────────────────────────────────────────────── */
.progress-tiles {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px;
}

.progress-tiles.is-loading {
  opacity: 0.6;
}

.progress-tile {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 4px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-panel);
  padding: 16px 18px;
}

.progress-tile.is-lead {
  border-color: color-mix(in srgb, var(--accent-brand) 35%, transparent);
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent-brand) 10%, var(--surface-panel)), var(--surface-panel));
}

.progress-tile-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
}

.progress-tile-value {
  font-size: 26px;
  font-weight: 800;
  line-height: 1.2;
  color: var(--text-strong);
}

.progress-tile.is-lead .progress-tile-value {
  color: var(--accent-brand);
}

/* Mistakes in red as Accuracy's tile, the result green won / red lost (owner 2026-10-21: «мистейк карточку тоже можно в таком же стиле
   только в красный цвет, а результат если + то зеленый, если минус то красный») */
.progress-tile.is-bad {
  border-color: color-mix(in srgb, var(--grade-bad) 35%, transparent);
  background: linear-gradient(180deg, color-mix(in srgb, var(--grade-bad) 10%, var(--surface-panel)), var(--surface-panel));
}
.progress-tile.is-bad .progress-tile-value {
  color: var(--grade-bad);
}
.progress-tile.is-good {
  border-color: color-mix(in srgb, var(--grade-good) 35%, transparent);
  background: linear-gradient(180deg, color-mix(in srgb, var(--grade-good) 10%, var(--surface-panel)), var(--surface-panel));
}
.progress-tile.is-good .progress-tile-value {
  color: var(--grade-good);
}

.progress-tile-sub {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  color: var(--text-dim);
}

.progress-note {
  margin: 10px 2px 16px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
}

/* ── cards ───────────────────────────────────────────────────────────── */
.progress-card {
  margin-bottom: 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-panel);
  padding: 18px 20px;
}

.progress-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}

.progress-card-head h2 {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.progress-card-icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent-brand) 14%, transparent);
  color: var(--accent-brand);
}

/* a breakdown card is never narrower than its table's five columns (~420px): narrower, the cards stack (owner 2026-10-21: «в прогрессе
   съехал текст в таблицах» - three 300px cards let the columns spill out) */
.progress-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
  gap: 16px;
}

.progress-grid .progress-card {
  margin-bottom: 0;
}

.progress-grid + .progress-card {
  margin-top: 16px;
}

.progress-none {
  padding: 10px 0;
  font-size: 13px;
  color: var(--text-muted);
}

.progress-message {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  font-size: 14px;
  color: var(--text-soft);
}

.progress-button {
  border: none;
  border-radius: 8px;
  background: var(--surface-raised);
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-strong);
  cursor: pointer;
}

.progress-button:hover {
  background: var(--line-strong);
}

.progress-button.is-brand {
  background: var(--accent-brand-deep);
  color: var(--text-on-brand);
}

.progress-button.is-brand:hover {
  background: var(--accent-brand);
}

.progress-button:disabled {
  opacity: 0.6;
  cursor: default;
}

.progress-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 48px 20px;
  text-align: center;
}

.progress-empty-icon {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 16px;
  background: color-mix(in srgb, var(--accent-brand) 14%, transparent);
  color: var(--accent-brand);
}

.progress-empty strong {
  font-size: 18px;
  color: var(--text-strong);
}

.progress-empty p {
  max-width: 420px;
  margin: 0 0 6px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-dim);
}

/* ── the bar per day ─────────────────────────────────────────────────── */
.progress-chart-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}

.progress-chart-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
}

.progress-chart-box {
  position: relative;
  overflow: hidden;
}

.progress-chart-box svg {
  display: block;
}

.progress-grid-line {
  stroke: var(--line);
  stroke-width: 1;
}

.progress-axis {
  fill: var(--text-muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.progress-bar {
  fill: var(--accent-brand);
  transition: opacity 120ms ease;
}

.progress-bar.is-dim {
  opacity: 0.45;
}

/* the hover target is the whole slot, taller and wider than the bar */
.progress-hit {
  fill: transparent;
}

.progress-tooltip {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  width: 180px;
  flex-direction: column;
  gap: 3px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface-raised);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  padding: 8px 10px;
  pointer-events: none;
  font-size: 12px;
  color: var(--text-normal);
}

.progress-tooltip strong {
  margin-bottom: 2px;
  color: var(--text-strong);
}

.progress-tooltip span {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-variant-numeric: tabular-nums;
}

.progress-tooltip i {
  font-style: normal;
  color: var(--text-muted);
}

/* ── breakdown tables ────────────────────────────────────────────────── */
.progress-table-scroll {
  overflow-x: auto;
}

.progress-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.progress-table th,
.progress-table td {
  border-top: 1px solid var(--line);
  padding: 8px 6px;
  text-align: right;
  white-space: nowrap;
}

.progress-table thead th {
  border-top: none;
  padding-top: 0;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
}

/* the accuracy column reads from the left: its header over its bar */
.progress-table .is-meter {
  text-align: left;
}

.progress-table th[scope="row"] {
  overflow: hidden;
  max-width: 220px;
  text-align: left;
  text-overflow: ellipsis;
  font-weight: 700;
  color: var(--text-strong);
}

.progress-meter {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.progress-meter-track {
  position: relative;
  display: block;
  width: 56px;
  height: 6px;
  overflow: hidden;
  border-radius: 3px;
  background: var(--surface-raised);
}

.progress-meter-fill {
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: 3px;
  background: var(--accent-brand);
}

/* ── spots to work on ────────────────────────────────────────────────── */
.progress-spots {
  margin: 0;
  padding: 0;
  list-style: none;
}

.progress-spot {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 14px;
  border-top: 1px solid var(--line);
  padding: 12px 0;
}

.progress-spot:first-child {
  border-top: none;
  padding-top: 2px;
}

.progress-spot-rank {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--surface-raised);
  font-size: 13px;
  font-weight: 800;
  color: var(--text-soft);
}

.progress-spot-main {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 4px;
}

.progress-spot-name {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}

.progress-spot-name strong {
  font-size: 14px;
  color: var(--text-strong);
}

.progress-spot-name small,
.progress-spot-line {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  color: var(--text-muted);
}

.progress-spot-moves {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  font-size: 13px;
}

.progress-move {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text-soft);
}

.progress-move.is-best {
  color: var(--text-strong);
}

.progress-spot-numbers {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  font-variant-numeric: tabular-nums;
}

.progress-spot-numbers strong {
  font-size: 14px;
  color: var(--text-strong);
}

.progress-spot-numbers small {
  font-size: 12px;
  color: var(--text-muted);
}

.progress-study {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: transparent;
  padding: 7px 10px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-soft);
  cursor: pointer;
}

.progress-study:hover:not(:disabled) {
  border-color: color-mix(in srgb, var(--accent-brand) 50%, transparent);
  color: var(--accent-brand);
}

.progress-study:disabled {
  opacity: 0.4;
  cursor: default;
}

.progress-study.is-small {
  padding: 5px 7px;
}

/* ── recent hands ────────────────────────────────────────────────────── */
.progress-hands {
  margin: 0;
  padding: 0;
  list-style: none;
}

.progress-hand {
  border-top: 1px solid var(--line);
}

.progress-hand:first-child {
  border-top: none;
}

.progress-hand-head {
  display: grid;
  grid-template-columns: 110px 18px 48px 112px minmax(0, 1fr) auto 76px 16px;
  align-items: center;
  gap: 10px;
  width: 100%;
  border: none;
  background: transparent;
  /* the row's light reaches the card's edges (frontend_rules 5a): the margin is the card's padding */
  margin-inline: -20px;
  padding: 9px 20px;
  text-align: left;
  font-size: 13px;
  color: var(--text-normal);
  cursor: pointer;
  box-sizing: content-box;
}

.progress-hand-head:hover {
  background: #404040;
}

.progress-hand.is-open .progress-hand-head {
  background: linear-gradient(90deg, rgba(255, 158, 69, 0.34), rgba(255, 158, 69, 0.14));
  box-shadow: inset 2px 0 0 var(--accent-brand);
  color: var(--text-strong);
}

.progress-hand-time {
  font-size: 12px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.progress-hand-nomark {
  width: 18px;
}

.progress-hand-cards,
.progress-hand-board {
  display: flex;
  gap: 2px;
}

.progress-playing-card {
  --card-width: 21px;
  --card-height: 28px;
  --card-radius: 3px;
}

.progress-hand-spot {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

.progress-hand-moves {
  font-size: 12px;
  color: var(--text-muted);
}

.progress-hand-result {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.progress-hand-result.is-win { color: var(--grade-good); }
.progress-hand-result.is-loss { color: var(--grade-bad); }

.progress-hand-chevron {
  color: var(--text-muted);
  transition: transform 180ms cubic-bezier(0.2, 0, 0, 1);
}

.progress-hand.is-open .progress-hand-chevron {
  transform: rotate(180deg);
}

.progress-hand-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px 0 12px 28px;
  animation: progress-in 220ms cubic-bezier(0.2, 0, 0, 1) both;
}

.progress-decision {
  display: grid;
  grid-template-columns: 18px 56px minmax(0, 1fr) 96px 56px 76px auto;
  align-items: center;
  gap: 10px;
  border-radius: 6px;
  padding: 6px 8px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  background: var(--surface-sunken);
}

.progress-decision-street {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-dim);
}

.progress-decision-text {
  display: flex;
  min-width: 0;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 6px;
  color: var(--text-soft);
}

.progress-decision-text strong {
  color: var(--text-strong);
}

.progress-decision-text small {
  overflow: hidden;
  width: 100%;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11px;
  color: var(--text-muted);
}

.progress-decision-grade {
  font-size: 12px;
  color: var(--text-dim);
}

.progress-decision-num {
  text-align: right;
  color: var(--text-soft);
}

.progress-hand-config {
  margin-top: 6px;
  font-size: 11px;
  color: var(--text-muted);
}

.progress-more {
  display: block;
  margin: 12px auto 0;
}

/* a narrow window: the tiles wrap, the hand rows drop the board */
/* ── drills (owner 2026-10-20 «Готовые тренировки в Practice»): which hands the page reads, the drill a hand was dealt for, a decision
   the clock ran out on ── */
.progress-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

/* a native select dressed as the period switch beside it: the browser's own list opens, the closed box is ours */
.progress-drill {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 38px;
  border-radius: 8px;
  background: var(--surface-sunken);
  color: var(--text-muted);
}

.progress-drill > svg:first-child {
  position: absolute;
  left: 11px;
  pointer-events: none;
}

.progress-drill select {
  appearance: none;
  height: 100%;
  border: none;
  border-radius: 8px;
  background: transparent;
  padding: 0 32px 0 32px;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-strong);
  cursor: pointer;
}

.progress-drill select:focus-visible {
  outline: 2px solid var(--accent-brand);
  outline-offset: 1px;
}

.progress-drill select option {
  background: #242424;
  color: var(--text-normal);
}

.progress-drill-chevron {
  position: absolute;
  right: 10px;
  pointer-events: none;
}

/* a drill's name in the By drill table opens that drill's hands */
.progress-pick {
  border: none;
  background: transparent;
  padding: 0;
  font: inherit;
  font-weight: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.progress-pick:hover {
  color: var(--accent-brand);
}

.progress-hand-drill {
  margin-left: 8px;
  border-radius: 5px;
  background: color-mix(in srgb, var(--accent-brand) 14%, transparent);
  padding: 1px 6px;
  font-size: 11px;
  font-weight: 700;
  color: var(--accent-brand);
}

.progress-time {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-left: 6px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--grade-bad) 16%, transparent);
  padding: 0 5px;
  font-size: 10px;
  font-weight: 800;
  line-height: 16px;
  color: var(--grade-bad);
  vertical-align: 1px;
}

@media (max-width: 900px) {
  .progress-content {
    padding: 20px 16px 48px;
  }

  .progress-tiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .progress-hand-head {
    grid-template-columns: 18px 48px minmax(0, 1fr) 76px 16px;
  }

  .progress-hand-time,
  .progress-hand-board,
  .progress-hand-moves {
    display: none;
  }

  .progress-spot {
    grid-template-columns: 28px minmax(0, 1fr);
  }

  .progress-decision {
    grid-template-columns: 18px 56px minmax(0, 1fr) 56px 76px auto;
  }

  .progress-decision-grade {
    display: none;
  }
}
/* ============================================================================
   Practice drills and the decision clock (owner 2026-10-20: «Готовые тренировки в Practice: «защита BB против BTN», «c-bet на флопе»,
   режим с таймером» - «реализуй красиво удобно»): the Drills entry in the sidebar, the drill picker, the drill bar over the table, the
   run's summary, the decision clock over the action buttons and the «Time» marks. Components: features/practice/components/
   DrillPicker.tsx, DrillBar.tsx, DrillSummary.tsx, DrillIcon.tsx, DecisionClock.tsx. Sizes are plain px; colours from tokens.css;
   motion is transform / opacity only (docs/frontend_rules.md 5b.3).
   ============================================================================ */

/* ── a drill's mark: one tile, tinted by the street the drill is played on ── */
.drill-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: color-mix(in srgb, var(--accent-brand) 15%, transparent);
  color: var(--accent-brand);
}

.drill-icon.is-flop {
  background: color-mix(in srgb, var(--action-passive) 15%, transparent);
  color: var(--action-passive);
}

.drill-icon.is-turn {
  background: color-mix(in srgb, var(--action-fold) 18%, transparent);
  color: var(--action-fold-hover);
}

.drill-icon.is-river {
  background: color-mix(in srgb, var(--ai-accent) 16%, transparent);
  color: var(--ai-accent);
}

/* ── the Drills entry at the top of the Practice sidebar ─────────────── */
.rail-drills {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-panel);
  padding: 10px 12px;
  text-align: left;
  color: var(--text-normal);
  cursor: pointer;
}

.rail-drills:hover {
  background: var(--surface-hover);
}

.rail-drills.is-active {
  border-color: color-mix(in srgb, var(--accent-brand) 38%, transparent);
  background: color-mix(in srgb, var(--accent-brand) 8%, var(--surface-panel));
}

.rail-drills .drill-icon {
  width: 30px;
  height: 30px;
  border-radius: 8px;
}

.rail-drills-mark {
  display: grid;
  flex: none;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent-brand) 15%, transparent);
  color: var(--accent-brand);
}

.rail-drills-text {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.rail-drills-text strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  font-weight: 800;
  color: var(--text-strong);
}

.rail-drills-text small {
  font-size: 12px;
  color: var(--text-muted);
}

.rail-drills-arrow {
  flex: none;
  color: var(--text-muted);
  transition: transform 180ms cubic-bezier(0.2, 0, 0, 1);
}

.rail-drills:hover .rail-drills-arrow {
  transform: translateX(3px);
}

/* ── the windows (picker, summary) over the site's .modal-backdrop ───── */
.drill-backdrop {
  z-index: 100;
}

.drill-picker,
.drill-summary {
  display: flex;
  max-width: 100%;
  max-height: calc(100vh - 64px);
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: #1d1d1d;
  box-shadow: 0 20px 80px rgba(0, 0, 0, 0.6);
  color: var(--text-normal);
  animation: drill-window-in 240ms cubic-bezier(0.2, 0, 0, 1) both;
}

.drill-picker {
  width: 1040px;
  height: 760px;
}

.drill-summary {
  width: 780px;
}

@keyframes drill-window-in {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.drill-picker-head,
.drill-summary-head {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid var(--line);
  background: #171717;
  padding: 12px 12px 12px 18px;
}

.drill-picker-mark {
  display: grid;
  flex: none;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: color-mix(in srgb, var(--accent-brand) 15%, transparent);
  color: var(--accent-brand);
}

.drill-picker-title,
.drill-summary-title {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.drill-picker-title h2,
.drill-summary-title h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 800;
  color: var(--text-strong);
}

.drill-picker-title small {
  font-size: 12px;
  color: var(--text-muted);
}

.drill-summary-title small {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--accent-brand);
}

/* ── the picker: filters ─────────────────────────────────────────────── */
.drill-picker-tools {
  display: flex;
  flex-shrink: 0;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 1px solid var(--line);
  padding: 12px 18px;
}

.drill-segment {
  display: flex;
  gap: 2px;
  border-radius: 8px;
  background: var(--surface-sunken);
  padding: 3px;
}

.drill-segment-option {
  border: none;
  border-radius: 6px;
  background: transparent;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
}

.drill-segment.is-small .drill-segment-option {
  padding: 6px 11px;
  font-size: 12px;
}

.drill-segment-option:hover {
  color: var(--text-strong);
}

.drill-segment-option.is-selected {
  background: var(--surface-active);
  color: var(--accent-brand);
}

.drill-timer {
  display: flex;
  align-items: center;
  gap: 10px;
}

.drill-timer-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
}

/* ── the picker: groups and cards ────────────────────────────────────── */
.drill-picker-body {
  display: flex;
  min-height: 0;
  flex: 1;
  flex-direction: column;
  gap: 18px;
  overflow-y: auto;
  padding: 16px 18px 20px;
}

.drill-group-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--text-dim);
}

.drill-group-count {
  border-radius: 999px;
  background: var(--surface-rail);
  padding: 1px 7px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0;
  color: var(--text-muted);
}

.drill-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 12px;
}

.drill-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-panel);
  padding: 14px;
  transition: transform 180ms cubic-bezier(0.2, 0, 0, 1);
}

.drill-card:hover {
  border-color: var(--line-strong);
  transform: translateY(-2px);
}

.drill-card.is-active {
  border-color: color-mix(in srgb, var(--accent-brand) 45%, transparent);
  background: color-mix(in srgb, var(--accent-brand) 6%, var(--surface-panel));
}

.drill-card-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.drill-card-name {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 6px;
}

.drill-card-name h4 {
  margin: 0;
  font-size: 15px;
  font-weight: 800;
  line-height: 20px;
  color: var(--text-strong);
}

.drill-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.drill-chip {
  border-radius: 5px;
  background: var(--surface-rail);
  padding: 1px 7px;
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  color: var(--text-soft);
}

.drill-card-text {
  flex: 1;
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-dim);
}

.drill-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  border-top: 1px solid var(--line);
  padding-top: 10px;
}

.drill-record {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 14px;
  font-size: 12px;
}

.drill-record.is-loading {
  opacity: 0.5;
}

.drill-record-item {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.drill-record-item i {
  font-size: 10px;
  font-style: normal;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-muted);
}

.drill-record-item strong {
  font-size: 15px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
}

.drill-record-new {
  color: var(--text-muted);
}

.drill-record-live {
  font-weight: 700;
  color: var(--accent-brand);
}

.drill-start {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 6px;
  height: 34px;
  border: none;
  border-radius: 8px;
  background: var(--accent-brand-deep);
  padding: 0 14px;
  font-size: 13px;
  font-weight: 800;
  color: var(--text-on-brand);
  cursor: pointer;
}

.drill-start:hover {
  background: var(--accent-brand);
}

.drill-start svg {
  transition: transform 180ms cubic-bezier(0.2, 0, 0, 1);
}

.drill-start:hover svg {
  transform: translateX(2px);
}

.drill-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin: 48px auto;
  max-width: 420px;
  text-align: center;
}

.drill-empty-mark {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 14px;
  background: var(--surface-rail);
  color: var(--text-muted);
}

.drill-empty strong {
  font-size: 16px;
  color: var(--text-strong);
}

.drill-empty p {
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-dim);
}

.drill-picker-foot {
  flex-shrink: 0;
  border-top: 1px solid var(--line);
  background: #171717;
  padding: 10px 18px;
  font-size: 12px;
  color: var(--text-muted);
}

/* buttons the windows share */
.drill-ghost,
.drill-secondary,
.drill-primary,
.drill-study {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 36px;
  border-radius: 8px;
  padding: 0 14px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.drill-ghost {
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--text-soft);
}

.drill-ghost:hover {
  color: var(--text-strong);
  background: var(--surface-hover);
}

.drill-secondary {
  border: none;
  background: var(--surface-rail);
  color: var(--text-strong);
}

.drill-secondary:hover {
  background: var(--surface-raised);
}

.drill-primary {
  border: none;
  background: var(--accent-brand-deep);
  font-weight: 800;
  color: var(--text-on-brand);
}

.drill-primary:hover {
  background: var(--accent-brand);
}

/* ── the drill bar over the table ────────────────────────────────────── */
.drill-bar {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 16px;
  border-bottom: 1px solid var(--line);
  background: #202020;
  padding: 8px 16px;
  animation: drill-bar-in 260ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes drill-bar-in {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.drill-bar-name {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 10px;
  border: none;
  border-radius: 8px;
  background: transparent;
  padding: 2px 8px 2px 2px;
  text-align: left;
  color: inherit;
  cursor: pointer;
}

.drill-bar-name:hover {
  background: var(--surface-hover);
}

.drill-bar-name .drill-icon {
  width: 30px;
  height: 30px;
  border-radius: 8px;
}

.drill-bar-text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 1px;
}

.drill-bar-text strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  font-weight: 800;
  color: var(--text-strong);
}

.drill-bar-text small {
  font-size: 12px;
  color: var(--text-muted);
}

.drill-bar-progress {
  display: flex;
  min-width: 120px;
  flex: 1;
  flex-direction: column;
  gap: 5px;
}

.drill-bar-count {
  font-size: 12px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.drill-bar-count strong {
  font-size: 13px;
  color: var(--text-strong);
}

.drill-bar-track {
  overflow: hidden;
  height: 5px;
  border-radius: 999px;
  background: var(--surface-rail);
}

/* grows into its new length: a hand finished is a step along the bar */
.drill-bar-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent-brand);
  transform-origin: left center;
  transition: transform 420ms cubic-bezier(0.2, 0, 0, 1);
}

.drill-bar-score {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: center;
  min-width: 64px;
}

.drill-bar-score strong {
  font-size: 18px;
  font-weight: 900;
  line-height: 20px;
  font-variant-numeric: tabular-nums;
}

.drill-bar-score small {
  font-size: 11px;
  color: var(--text-muted);
}

.drill-bar-score.is-idle strong { color: var(--text-muted); }
.drill-bar-score.is-good strong { color: var(--grade-good); }
.drill-bar-score.is-warn strong { color: var(--grade-warn); }
.drill-bar-score.is-bad strong { color: var(--grade-bad); }

.drill-bar-timer,
.drill-bar-end {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 6px;
  height: 32px;
  border-radius: 8px;
  padding: 0 12px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.drill-bar-timer {
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--text-muted);
}

.drill-bar-timer:hover {
  color: var(--text-strong);
}

.drill-bar-timer.is-on {
  border-color: color-mix(in srgb, var(--accent-brand) 40%, transparent);
  background: color-mix(in srgb, var(--accent-brand) 12%, transparent);
  color: var(--accent-brand);
}

.drill-bar-end {
  border: none;
  background: var(--surface-rail);
  color: var(--text-strong);
}

.drill-bar-end:hover {
  background: var(--surface-raised);
}

/* ── a drill's hand being dealt: the veil shows only after a moment (most are dealt before it could be read) ── */
.felt-preparing-veil.is-delayed .felt-preparing {
  animation-delay: 350ms;
}

/* ── the run's summary ───────────────────────────────────────────────── */
.drill-summary-score {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 22px;
  padding: 18px 20px 6px;
}

.drill-ring {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  width: 104px;
  height: 104px;
  animation: drill-ring-in 420ms cubic-bezier(0.2, 0, 0, 1) 120ms both;
}

@keyframes drill-ring-in {
  from {
    opacity: 0;
    transform: scale(0.86) rotate(-20deg);
  }
  to {
    opacity: 1;
    transform: scale(1) rotate(0deg);
  }
}

.drill-ring svg {
  position: absolute;
  inset: 0;
  width: 104px;
  height: 104px;
  transform: rotate(-90deg);
}

.drill-ring-track {
  fill: none;
  stroke: var(--surface-rail);
  stroke-width: 7;
}

.drill-ring-arc {
  fill: none;
  stroke: var(--text-muted);
  stroke-width: 7;
  stroke-linecap: round;
}

.drill-ring.is-good .drill-ring-arc { stroke: var(--grade-good); }
.drill-ring.is-warn .drill-ring-arc { stroke: var(--grade-warn); }
.drill-ring.is-bad .drill-ring-arc { stroke: var(--grade-bad); }

.drill-ring-value {
  font-size: 24px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
}

.drill-summary-facts {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 10px;
}

.drill-best {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--grade-warn) 18%, transparent);
  padding: 3px 10px;
  font-size: 12px;
  font-weight: 800;
  color: var(--grade-warn);
}

.drill-tiles {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}

.drill-tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-panel);
  padding: 10px 12px;
}

.drill-tile-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-muted);
}

.drill-tile-value {
  font-size: 18px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
}

.drill-tile-sub {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11px;
  color: var(--text-muted);
}

.drill-worst {
  display: flex;
  min-height: 0;
  flex: 1;
  flex-direction: column;
  overflow-y: auto;
  padding: 12px 20px 16px;
}

.drill-worst h3 {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--text-dim);
}

.drill-worst-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.drill-worst-row {
  display: grid;
  grid-template-columns: 16px auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-panel);
  padding: 8px 10px;
}

.drill-worst-cards {
  display: flex;
  align-items: center;
  gap: 2px;
}

.drill-worst-board {
  display: flex;
  gap: 2px;
  margin-left: 6px;
}

.drill-worst-card {
  --card-width: 21px;
  --card-height: 28px;
  --card-radius: 3px;
}

.drill-worst-text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}

.drill-worst-text strong {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-strong);
}

.drill-worst-text small {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  color: var(--text-muted);
}

.drill-worst-num {
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-soft);
}

.drill-study {
  height: 30px;
  border: 1px solid var(--line-strong);
  background: transparent;
  padding: 0 10px;
  font-size: 12px;
  color: var(--text-soft);
}

.drill-study:hover:not(:disabled) {
  color: var(--text-strong);
  background: var(--surface-hover);
}

.drill-study:disabled {
  opacity: 0.4;
  cursor: default;
}

.drill-worst-none {
  border: 1px dashed var(--line-strong);
  border-radius: 10px;
  padding: 16px;
  text-align: center;
  font-size: 13px;
  color: var(--text-dim);
}

.drill-summary-foot {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
  border-top: 1px solid var(--line);
  background: #171717;
  padding: 12px 18px;
}

.drill-summary-gap {
  flex: 1;
}

/* ── the decision clock: along the top edge of the action bar, whatever the bar holds ── */
.action-bar:has(> .decision-clock) {
  position: relative;
}

.decision-clock {
  pointer-events: none;
  position: absolute;
  top: -15px;
  right: 0;
  left: 0;
  display: flex;
  height: 12px;
  align-items: center;
  gap: 8px;
}

.decision-clock-track {
  overflow: hidden;
  height: 3px;
  flex: 1;
  border-radius: 999px;
  background: var(--surface-rail);
}

/* one run from full to empty over the decision's seconds (the duration is the setting, set on the element); held, it stands still */
.decision-clock-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent-brand);
  transform-origin: left center;
  animation-name: decision-clock-run;
  animation-timing-function: linear;
  animation-fill-mode: both;
  animation-play-state: paused;
}

@keyframes decision-clock-run {
  from { transform: scaleX(1); }
  to { transform: scaleX(0); }
}

.decision-clock.is-running .decision-clock-fill {
  animation-play-state: running;
}

/* over a finished hand or a past step there is no decision to time */
.action-bar.is-review > .decision-clock,
.action-bar.is-verdict > .decision-clock {
  opacity: 0;
}

.decision-clock.is-idle .decision-clock-fill {
  opacity: 0.3;
}

.decision-clock.is-held .decision-clock-fill {
  opacity: 0.55;
}

.decision-clock.is-low .decision-clock-fill {
  background: var(--grade-bad);
}

.decision-clock-time {
  display: inline-flex;
  min-width: 42px;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  font-size: 11px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

.decision-clock.is-running .decision-clock-time {
  color: var(--text-soft);
}

.decision-clock.is-low .decision-clock-time {
  color: var(--grade-bad);
  animation: decision-clock-beat 500ms ease-out infinite alternate;
}

@keyframes decision-clock-beat {
  from { transform: scale(1); }
  to { transform: scale(1.12); }
}

/* ── «Time»: a decision the clock ran out on ─────────────────────────── */
.hand-time-tag,
.drill-time-tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-left: 6px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--grade-bad) 16%, transparent);
  padding: 0 5px;
  font-size: 10px;
  font-weight: 800;
  line-height: 16px;
  letter-spacing: 0.3px;
  color: var(--grade-bad);
  vertical-align: 1px;
}

.strip-step-time {
  flex: none;
  color: var(--grade-bad);
}
/* ============================================================================
   The temporary page of loader animations, /loaders (owner 2026-10-21: «отдельную страницу, где я смогу протестировать 5 разных
   анимаций красивых при загрузке сайта логотипа ... Потом удалим эту страницу»; pages/loaderLab/LoaderLabPage.tsx).

   1 is the site's first loader (styles/boot.css until 2026-10-21), 5 is the one on the site since. All are drawn here, each in its own
   .ll-* names; each is the whole window in «Full screen» and the card's stage in a card. As the site's loader: only transform, opacity and filter move (frontend_rules 5b.3),
   one movement is one segment (5b.2), and where a thing moves and whether it shows are separate animations when they differ (5b.1).
   The leaving fade of each (.is-leaving) is the length LoaderLabPage.tsx VARIANTS gives it (leaveMs).
   ============================================================================ */

body:has(.loader-lab) { min-width: 0; }

.loader-lab {
  min-height: 100vh;
  padding: 32px 32px 64px;
  background: var(--surface-page);
  color: var(--text-normal);
}

.loader-lab-head {
  max-width: 1240px;
  margin: 0 auto 24px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.loader-lab-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 14px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-dim);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.loader-lab-back:hover { color: var(--text-strong); }
.loader-lab-title { margin: 0; font-size: 26px; font-weight: 700; color: var(--text-strong); }
.loader-lab-lead { margin: 6px 0 0; max-width: 640px; font-size: 14px; line-height: 20px; color: var(--text-dim); }
/* the numbers: a jump to each card */
.loader-lab-index { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.loader-lab-chip {
  width: 32px;
  height: 28px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface-panel);
  color: var(--text-soft);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
.loader-lab-chip:hover { background: var(--surface-hover); color: var(--accent-brand); }
.loader-lab-card { scroll-margin-top: 16px; }

.loader-lab-grid {
  max-width: 1240px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
}
.loader-lab-card {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface-panel);
}
.loader-lab-stage {
  position: relative;
  height: 340px;
  overflow: hidden;
  isolation: isolate;
  background: var(--surface-page);
}
/* a loader in a card stands in its stage instead of over the window */
.loader-lab-stage .ll-loader { position: absolute; z-index: 1; }

/* what the loader opens into: a page's outline */
.loader-lab-page {
  position: absolute;
  inset: 0;
  display: grid;
  align-content: start;
  gap: 12px;
  padding: 32px;
}
.loader-lab-page b,
.loader-lab-page i { display: block; height: 10px; border-radius: 5px; background: var(--surface-raised); }
.loader-lab-page b { width: 38%; height: 18px; margin-bottom: 10px; }
.loader-lab-page i:nth-of-type(1) { width: 92%; }
.loader-lab-page i:nth-of-type(2) { width: 78%; }
.loader-lab-page i:nth-of-type(3) { width: 64%; }

.loader-lab-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px 16px;
  flex-wrap: wrap;
  padding: 14px 16px 16px;
  border-top: 1px solid var(--line);
}
.loader-lab-text { flex: 1 1 260px; min-width: 0; }
.loader-lab-name { margin: 0; font-size: 16px; font-weight: 700; color: var(--text-strong); }
.loader-lab-number { margin-right: 8px; color: var(--accent-brand); }
.loader-lab-note { margin: 4px 0 0; font-size: 13px; line-height: 18px; color: var(--text-dim); }
.loader-lab-buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.loader-lab-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface-raised);
  color: var(--text-normal);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.loader-lab-button:hover:not(:disabled) { background: var(--surface-active); }
.loader-lab-button:disabled { opacity: 0.5; cursor: default; }
.loader-lab-button.is-primary { border-color: var(--accent-brand); background: var(--accent-brand); color: var(--text-on-accent); }
.loader-lab-button.is-primary:hover:not(:disabled) { background: var(--accent-brand-hover); }

/* «Full screen»: the loader over the whole window, the controls over it */
.loader-lab-full { position: fixed; inset: 0; z-index: 10000; }
.loader-lab-full-bar {
  position: fixed;
  z-index: 10001;
  left: 50%;
  bottom: 24px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  max-width: calc(100vw - 32px);
  padding: 8px 8px 8px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: rgba(20, 20, 20, 0.78);
  transform: translateX(-50%);
  transition: opacity 200ms ease-out;
}
.loader-lab-full.is-leaving .loader-lab-full-bar { opacity: 0; }
.loader-lab-full-name { margin-right: 8px; font-size: 14px; font-weight: 700; color: var(--text-strong); }

@media (max-width: 1080px) {
  .loader-lab-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .loader-lab { padding: 20px 16px 48px; }
  .loader-lab-stage { height: 280px; }
}

/* ── the loaders' common frame ───────────────────────────────────────────── */

.ll-loader {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: grid;
  place-items: center;
  overflow: hidden;
  color: var(--text-normal);
}
.ll-loader.is-leaving { opacity: 0; pointer-events: none; }
.ll-loader img { max-width: none; }

/* a layer cut to the logo's own shapes: a mask of the two pictures as a logo row draws them, the mark at the left and the lettering at
   the right (as .boot-shine in styles/boot.css); its box is the logo row's */
.ll-logo-mask {
  pointer-events: none;
  position: absolute;
  inset: 0;
  -webkit-mask-image: url("/assets/maxgto-mark-COQvd4oj.webp"), url("/assets/maxgto-word-B4gfxSmT.svg");
  mask-image: url("/assets/maxgto-mark-COQvd4oj.webp"), url("/assets/maxgto-word-B4gfxSmT.svg");
  -webkit-mask-position: left center, right center;
  mask-position: left center, right center;
  -webkit-mask-size: auto 60px, auto 42px;
  mask-size: auto 60px, auto 42px;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/* ── 1 · Glow: the site's first loader (styles/boot.css until 2026-10-21, when the owner put 5 · Aurora on the site) ─────── */

.ll-glow {
  background: radial-gradient(60% 55% at 50% 46%, #2b2b2b 0%, var(--surface-page) 100%);
  color: var(--text-normal);
  transition: opacity 420ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-glow.is-leaving { opacity: 0; pointer-events: none; }

.ll-glow-stage {
  display: grid;
  justify-items: center;
  gap: 30px;
  transition: transform 420ms cubic-bezier(0.4, 0, 0.2, 1), filter 420ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-glow.is-leaving .ll-glow-stage { transform: scale(1.04); filter: blur(2px); }

/* the mark (296 x 128) and the lettering (1790 x 309) side by side, as BrandLogo draws them */
.ll-glow-logo {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
}
.ll-glow-mark-box {
  position: relative;
  isolation: isolate;   /* the glow (z-index -1) stays behind the mark, inside this box */
  display: block;
  height: 60px;
  animation: ll-glow-mark-in 900ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
.ll-glow-mark { display: block; height: 60px; }
.ll-glow-word {
  display: block;
  height: 42px;
  animation: ll-glow-word-in 900ms cubic-bezier(0.16, 1, 0.3, 1) 160ms both;
}
@keyframes ll-glow-mark-in {
  from { opacity: 0; transform: translateY(10px) scale(0.92); filter: blur(6px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes ll-glow-word-in {
  from { opacity: 0; transform: translateX(-12px); filter: blur(4px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}

/* a warm light behind the mark, breathing slowly */
.ll-glow-glow {
  pointer-events: none;
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 50%;
  width: 260px;
  height: 260px;
  margin: -130px 0 0 -130px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 122, 40, 0.2) 0%, rgba(255, 122, 40, 0.07) 40%, rgba(255, 122, 40, 0) 68%);
  animation: ll-glow-glow 3200ms ease-in-out 900ms infinite alternate both;
}
@keyframes ll-glow-glow {
  from { opacity: 0.5; transform: scale(0.9); }
  to { opacity: 1; transform: scale(1.06); }
}

/* the light crossing the logo: a band moving under a mask of the two pictures, so it lights only the mark and the letters */
.ll-glow-sheen {
  pointer-events: none;
  position: absolute;
  inset: 0;
  overflow: hidden;
  -webkit-mask-image: url("/assets/maxgto-mark-COQvd4oj.webp"), url("/assets/maxgto-word-B4gfxSmT.svg");
  mask-image: url("/assets/maxgto-mark-COQvd4oj.webp"), url("/assets/maxgto-word-B4gfxSmT.svg");
  -webkit-mask-position: left center, right center;
  mask-position: left center, right center;
  -webkit-mask-size: auto 60px, auto 42px;
  mask-size: auto 60px, auto 42px;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.ll-glow-sheen::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 30%;
  background: linear-gradient(105deg, rgba(255, 255, 255, 0) 10%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0) 90%);
  transform: translateX(-110%);
  animation: ll-glow-sheen 3000ms 900ms infinite;
}
/* across in one segment, then still (outside the logo) until the next pass */
@keyframes ll-glow-sheen {
  0% { transform: translateX(-110%); animation-timing-function: cubic-bezier(0.45, 0, 0.2, 1); }
  55%, 100% { transform: translateX(345%); }
}

/* a light running along a thin line: shows a beat late, so a quick start sees only the logo */
.ll-glow-line {
  position: relative;
  display: block;
  overflow: hidden;
  width: 168px;
  height: 2px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.08);
}
.ll-glow-line { animation: ll-glow-fade-in 500ms ease-out 600ms both; }
.ll-glow-line i {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 40%;
  background: linear-gradient(90deg, rgba(255, 158, 69, 0), var(--accent-brand), rgba(255, 158, 69, 0));
  animation: ll-glow-run 1500ms cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes ll-glow-run {
  from { transform: translateX(-100%); }
  to { transform: translateX(250%); }
}
@keyframes ll-glow-fade-in {
  from { opacity: 0; }
}


@media (max-width: 520px) {
  .ll-glow-logo { gap: 12px; }
  .ll-glow-mark-box,
  .ll-glow-mark { height: 40px; }
  .ll-glow-word { height: 28px; }
  .ll-glow-sheen {
    -webkit-mask-size: auto 40px, auto 28px;
    mask-size: auto 40px, auto 28px;
  }
  .ll-glow-glow { width: 180px; height: 180px; margin: -90px 0 0 -90px; }
  .ll-glow-line { width: 120px; }
}

/* ── 2 · Ember ───────────────────────────────────────────────────────────── */

.ll-ember {
  background: radial-gradient(60% 60% at 50% 50%, #2e2520 0%, #1c1a19 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-ember-stage { transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1); }
.ll-ember.is-leaving .ll-ember-stage { transform: scale(1.08); filter: blur(4px); }

.ll-ember-logo { position: relative; display: flex; align-items: center; gap: 16px; }
.ll-ember-mark-box { position: relative; isolation: isolate; display: block; height: 60px; }
.ll-ember-mark {
  position: relative;
  display: block;
  height: 60px;
  animation:
    ll-ember-ignite 820ms cubic-bezier(0.22, 1.5, 0.36, 1) 240ms both,
    ll-show 260ms ease-out 240ms both,
    ll-ember-heat 1500ms cubic-bezier(0.16, 1, 0.3, 1) 240ms both;
}
@keyframes ll-ember-ignite {
  from { transform: scale(0.55); }
  to { transform: none; }
}
@keyframes ll-ember-heat {
  from { filter: brightness(2.4) saturate(1.5) blur(3px); }
  to { filter: brightness(1) saturate(1) blur(0); }
}
@keyframes ll-show {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* the heat behind the mark: comes up once, then flickers slowly */
.ll-ember-glow-box {
  pointer-events: none;
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 50%;
  width: 300px;
  height: 300px;
  margin: -150px 0 0 -150px;
  animation: ll-show 900ms ease-out 300ms both;
}
.ll-ember-glow {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 110, 30, 0.26) 0%, rgba(255, 110, 30, 0.08) 42%, rgba(255, 110, 30, 0) 68%);
  animation: ll-ember-flicker 1900ms ease-in-out 1100ms infinite alternate both;
}
@keyframes ll-ember-flicker {
  from { opacity: 0.6; transform: scale(0.94); }
  to { opacity: 1; transform: scale(1.05); }
}

/* the spark, then two waves out of it */
.ll-ember-spark {
  pointer-events: none;
  position: absolute;
  left: 50%;
  top: 50%;
  width: 24px;
  height: 24px;
  margin: -12px 0 0 -12px;
  border-radius: 50%;
  background: radial-gradient(circle, #fffaf0 0%, #ffd29e 30%, rgba(255, 158, 69, 0.5) 52%, rgba(255, 122, 40, 0) 72%);
  animation: ll-ember-spark-grow 700ms cubic-bezier(0.16, 1, 0.3, 1) both, ll-ember-spark-fade 700ms linear both;
}
@keyframes ll-ember-spark-grow {
  from { transform: scale(0.1); }
  to { transform: scale(4.5); }
}
@keyframes ll-ember-spark-fade {
  0% { opacity: 0; }
  18% { opacity: 1; }
  45% { opacity: 0.85; }
  100% { opacity: 0; }
}
.ll-ember-wave {
  pointer-events: none;
  position: absolute;
  left: 50%;
  top: 50%;
  width: 120px;
  height: 120px;
  margin: -60px 0 0 -60px;
  border: 2px solid rgba(255, 158, 69, 0.75);
  border-radius: 50%;
  animation: ll-ember-wave-grow 1200ms cubic-bezier(0.16, 1, 0.3, 1) 200ms both, ll-ember-wave-fade 1200ms ease-out 200ms both;
}
.ll-ember-wave.is-late { border-width: 1px; border-color: rgba(255, 214, 160, 0.6); animation-delay: 420ms; }
@keyframes ll-ember-wave-grow {
  from { transform: scale(0.15); }
  to { transform: scale(2.6); }
}
@keyframes ll-ember-wave-fade {
  0% { opacity: 0; }
  10% { opacity: 1; }
  100% { opacity: 0; }
}

/* the lettering uncovered from the left: the box slides right while the picture in it slides back by as much, so the picture stands
   still and only the box's edge - with a hot line on it - travels */
.ll-ember-word-clip {
  position: relative;
  display: block;
  overflow: hidden;
  animation: ll-ember-wipe 900ms cubic-bezier(0.65, 0, 0.35, 1) 640ms both;
}
.ll-ember-word-slide { display: block; animation: ll-ember-unwipe 900ms cubic-bezier(0.65, 0, 0.35, 1) 640ms both; }
.ll-ember-word { display: block; height: 42px; }
.ll-ember-word-clip::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: 4px;
  background: linear-gradient(180deg, rgba(255, 214, 160, 0) 0%, #ffe0b0 50%, rgba(255, 214, 160, 0) 100%);
  filter: blur(1px);
  animation: ll-ember-edge 900ms linear 640ms both;
}
@keyframes ll-ember-wipe {
  from { transform: translateX(-100%); }
  to { transform: none; }
}
@keyframes ll-ember-unwipe {
  from { transform: translateX(100%); }
  to { transform: none; }
}
@keyframes ll-ember-edge {
  0% { opacity: 0; }
  12% { opacity: 1; }
  78% { opacity: 1; }
  100% { opacity: 0; }
}

/* embers rising over the logo, each on its own beat */
.ll-ember-embers {
  pointer-events: none;
  position: absolute;
  left: -24px;
  right: -24px;
  top: 26px;
  height: 40px;
}
.ll-ember-embers i {
  position: absolute;
  bottom: 0;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff1d6 0%, #ffb15e 45%, rgba(255, 122, 40, 0) 75%);
  animation: ll-ember-rise 2600ms cubic-bezier(0.25, 0.6, 0.4, 1) 900ms infinite both, ll-ember-twinkle 2600ms linear 900ms infinite both;
}
.ll-ember-embers i:nth-child(even) { animation-name: ll-ember-rise-left, ll-ember-twinkle; }
.ll-ember-embers i:nth-child(1) { left: 4%; }
.ll-ember-embers i:nth-child(2) { left: 13%; width: 3px; height: 3px; animation-duration: 3000ms; animation-delay: 1500ms; }
.ll-ember-embers i:nth-child(3) { left: 23%; animation-duration: 2400ms; animation-delay: 1100ms; }
.ll-ember-embers i:nth-child(4) { left: 32%; width: 5px; height: 5px; animation-duration: 2900ms; animation-delay: 2100ms; }
.ll-ember-embers i:nth-child(5) { left: 42%; animation-duration: 2700ms; animation-delay: 1300ms; }
.ll-ember-embers i:nth-child(6) { left: 51%; width: 3px; height: 3px; animation-duration: 2500ms; animation-delay: 1800ms; }
.ll-ember-embers i:nth-child(7) { left: 61%; animation-duration: 3100ms; animation-delay: 1000ms; }
.ll-ember-embers i:nth-child(8) { left: 70%; width: 5px; height: 5px; animation-duration: 2600ms; animation-delay: 2300ms; }
.ll-ember-embers i:nth-child(9) { left: 80%; width: 3px; height: 3px; animation-duration: 2800ms; animation-delay: 1400ms; }
.ll-ember-embers i:nth-child(10) { left: 90%; animation-duration: 2400ms; animation-delay: 1900ms; }
@keyframes ll-ember-rise {
  from { transform: translate(0, 0) scale(1); }
  to { transform: translate(16px, -130px) scale(0.35); }
}
@keyframes ll-ember-rise-left {
  from { transform: translate(0, 0) scale(1); }
  to { transform: translate(-16px, -130px) scale(0.35); }
}
@keyframes ll-ember-twinkle {
  0% { opacity: 0; }
  14% { opacity: 1; }
  65% { opacity: 0.75; }
  100% { opacity: 0; }
}

/* ── 3 · Orbit ───────────────────────────────────────────────────────────── */

.ll-orbit {
  background: radial-gradient(60% 60% at 50% 46%, #2b2b2b 0%, var(--surface-page) 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-orbit-stage {
  display: grid;
  justify-items: center;
  gap: 22px;
  transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-orbit.is-leaving .ll-orbit-stage { transform: scale(0.97); filter: blur(3px); }

.ll-orbit-ring {
  position: relative;
  display: grid;
  place-items: center;
  width: 200px;
  height: 200px;
}
.ll-orbit-rings-leave {
  position: absolute;
  inset: 0;
  transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-orbit.is-leaving .ll-orbit-rings-leave { transform: scale(1.4); }
.ll-orbit-rings {
  position: absolute;
  inset: 0;
  animation: ll-orbit-rings-in 1000ms cubic-bezier(0.16, 1, 0.3, 1) both, ll-show 500ms ease-out both;
}
@keyframes ll-orbit-rings-in {
  from { transform: scale(0.7) rotate(-60deg); }
  to { transform: none; }
}
.ll-orbit-track {
  position: absolute;
  inset: 0;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 50%;
}
.ll-orbit-spin { position: absolute; inset: 0; animation: ll-orbit-spin 1500ms linear infinite; }
.ll-orbit-spin.is-slow { inset: 16px; opacity: 0.55; animation: ll-orbit-spin-back 3600ms linear infinite; }
.ll-orbit-arc {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(from 0deg, rgba(255, 158, 69, 0) 0deg, rgba(255, 158, 69, 0) 150deg, rgba(255, 158, 69, 0.85) 340deg,
    #ffe2bf 360deg);
  -webkit-mask: radial-gradient(farthest-side, rgba(0, 0, 0, 0) calc(100% - 3px), #000 calc(100% - 2px));
  mask: radial-gradient(farthest-side, rgba(0, 0, 0, 0) calc(100% - 3px), #000 calc(100% - 2px));
}
.ll-orbit-spin.is-slow .ll-orbit-arc {
  background: conic-gradient(from 180deg, rgba(255, 205, 140, 0) 0deg, rgba(255, 205, 140, 0) 200deg, rgba(255, 205, 140, 0.7) 360deg);
  -webkit-mask: radial-gradient(farthest-side, rgba(0, 0, 0, 0) calc(100% - 2px), #000 calc(100% - 1px));
  mask: radial-gradient(farthest-side, rgba(0, 0, 0, 0) calc(100% - 2px), #000 calc(100% - 1px));
}
/* the comet's head at the arc's bright end (the top of the turning box) */
.ll-orbit-head {
  position: absolute;
  top: -3px;
  left: 50%;
  width: 8px;
  height: 8px;
  margin-left: -4px;
  border-radius: 50%;
  background: #fff1dc;
  box-shadow: 0 0 10px 3px rgba(255, 158, 69, 0.75), 0 0 24px 8px rgba(255, 122, 40, 0.3);
}
@keyframes ll-orbit-spin {
  to { transform: rotate(360deg); }
}
@keyframes ll-orbit-spin-back {
  to { transform: rotate(-360deg); }
}

.ll-orbit-mark-box {
  position: relative;
  isolation: isolate;
  display: block;
  animation: ll-orbit-breathe 2400ms ease-in-out 1200ms infinite alternate both;
}
@keyframes ll-orbit-breathe {
  from { transform: scale(1); }
  to { transform: scale(1.04); }
}
.ll-orbit-halo {
  pointer-events: none;
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 50%;
  width: 220px;
  height: 220px;
  margin: -110px 0 0 -110px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 140, 50, 0.22) 0%, rgba(255, 140, 50, 0.06) 45%, rgba(255, 140, 50, 0) 70%);
  animation: ll-orbit-pulse 2400ms ease-in-out 1200ms infinite alternate both;
}
@keyframes ll-orbit-pulse {
  from { opacity: 0.45; }
  to { opacity: 1; }
}
.ll-orbit-mark { display: block; height: 60px; animation: ll-orbit-mark-in 900ms cubic-bezier(0.16, 1, 0.3, 1) 200ms both; }
@keyframes ll-orbit-mark-in {
  from { opacity: 0; transform: scale(0.84); filter: blur(6px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}
.ll-orbit-word { display: block; height: 42px; animation: ll-orbit-word-in 900ms cubic-bezier(0.16, 1, 0.3, 1) 480ms both; }
@keyframes ll-orbit-word-in {
  from { opacity: 0; transform: translateY(14px); filter: blur(4px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}

/* ── 4 · Card flip ───────────────────────────────────────────────────────── */

.ll-card {
  background: radial-gradient(60% 60% at 50% 48%, #2b2826 0%, #1d1c1b 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-card-stage { transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1); }
.ll-card.is-leaving .ll-card-stage { transform: scale(1.06) translateY(-4px); filter: blur(4px); }
.ll-card-row { display: flex; align-items: center; gap: 24px; }

/* the card above the lettering, which comes out from behind it */
.ll-card-float {
  position: relative;
  z-index: 1;
  animation: ll-card-float 2800ms ease-in-out 1700ms infinite alternate both;
}
@keyframes ll-card-float {
  from { transform: translateY(0) rotate(0deg); }
  to { transform: translateY(-6px) rotate(-1.5deg); }
}
.ll-card-deal {
  position: relative;
  width: 104px;
  height: 146px;
  perspective: 900px;
  animation: ll-card-deal 760ms cubic-bezier(0.16, 1, 0.3, 1) both, ll-show 260ms ease-out both;
}
@keyframes ll-card-deal {
  from { transform: translate(190px, -46px) rotate(32deg) scale(0.92); }
  to { transform: none; }
}
.ll-card-shadow {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: -8px;
  height: 30px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  filter: blur(12px);
}
.ll-card-flip {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  animation: ll-card-flip 820ms cubic-bezier(0.65, 0, 0.35, 1) 640ms both;
}
@keyframes ll-card-flip {
  from { transform: rotateY(180deg); }
  to { transform: rotateY(0deg); }
}
.ll-card-face {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: 10px;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.ll-card-face.is-back {
  transform: rotateY(180deg);
  border: 1px solid rgba(255, 158, 69, 0.55);
  background:
    repeating-linear-gradient(45deg, rgba(255, 158, 69, 0.14) 0 2px, rgba(255, 158, 69, 0) 2px 10px),
    repeating-linear-gradient(-45deg, rgba(255, 158, 69, 0.14) 0 2px, rgba(255, 158, 69, 0) 2px 10px),
    linear-gradient(160deg, #3a2a20 0%, #1d1918 100%);
}
.ll-card-face.is-back::after {
  content: "";
  position: absolute;
  inset: 7px;
  border: 1px solid rgba(255, 158, 69, 0.4);
  border-radius: 6px;
}
.ll-card-face.is-front {
  display: grid;
  place-items: center;
  border: 1px solid rgba(255, 196, 140, 0.55);
  background: radial-gradient(120% 90% at 30% 18%, #3a3532 0%, #211f1e 72%);
}
/* a light crossing the card face now and then */
.ll-card-face.is-front::after {
  content: "";
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: 0;
  width: 46%;
  background: linear-gradient(105deg, rgba(255, 255, 255, 0) 15%, rgba(255, 255, 255, 0.22) 50%, rgba(255, 255, 255, 0) 85%);
  transform: translateX(-130%);
  animation: ll-card-sheen 3200ms 1500ms infinite;
}
@keyframes ll-card-sheen {
  0% { transform: translateX(-130%); animation-timing-function: cubic-bezier(0.45, 0, 0.2, 1); }
  45%, 100% { transform: translateX(330%); }
}
.ll-card-mark { display: block; width: 76px; }
.ll-card-index {
  position: absolute;
  top: 8px;
  left: 10px;
  font-size: 16px;
  font-weight: 800;
  line-height: 1;
  color: #ffb468;
}
.ll-card-index.is-bottom { top: auto; left: auto; right: 10px; bottom: 8px; transform: rotate(180deg); }
.ll-card-word {
  position: relative;
  display: block;
  height: 42px;
  animation: ll-card-word-in 800ms cubic-bezier(0.16, 1, 0.3, 1) 1280ms both;
}
@keyframes ll-card-word-in {
  from { opacity: 0; transform: translateX(-60px); filter: blur(5px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}

/* ── 5 · Aurora ──────────────────────────────────────────────────────────── */

.ll-aurora {
  background: #171615;
  transition: opacity 520ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-aurora-sky {
  position: absolute;
  inset: 0;
  animation: ll-show 1400ms ease-out both;
  transition: transform 520ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-aurora.is-leaving .ll-aurora-sky { transform: scale(1.3); }
.ll-aurora-blob {
  position: absolute;
  left: 50%;
  top: 50%;
  border-radius: 50%;
  mix-blend-mode: screen;
}
.ll-aurora-blob.is-one {
  width: 560px;
  height: 560px;
  margin: -280px 0 0 -280px;
  background: radial-gradient(circle, rgba(255, 138, 48, 0.42) 0%, rgba(255, 138, 48, 0) 62%);
  animation: ll-aurora-one 9000ms ease-in-out infinite alternate both;
}
.ll-aurora-blob.is-two {
  width: 480px;
  height: 480px;
  margin: -240px 0 0 -240px;
  background: radial-gradient(circle, rgba(255, 70, 110, 0.26) 0%, rgba(255, 70, 110, 0) 62%);
  animation: ll-aurora-two 11000ms ease-in-out infinite alternate both;
}
.ll-aurora-blob.is-three {
  width: 440px;
  height: 440px;
  margin: -220px 0 0 -220px;
  background: radial-gradient(circle, rgba(255, 210, 120, 0.24) 0%, rgba(255, 210, 120, 0) 62%);
  animation: ll-aurora-three 13000ms ease-in-out infinite alternate both;
}
@keyframes ll-aurora-one {
  from { transform: translate(-190px, -70px) scale(1); }
  to { transform: translate(70px, 50px) scale(1.18); }
}
@keyframes ll-aurora-two {
  from { transform: translate(190px, 60px) scale(1.1); }
  to { transform: translate(-70px, -60px) scale(0.92); }
}
@keyframes ll-aurora-three {
  from { transform: translate(30px, 140px) scale(0.9); }
  to { transform: translate(-150px, -30px) scale(1.12); }
}
.ll-aurora-veil {
  pointer-events: none;
  position: absolute;
  inset: 0;
  background: radial-gradient(75% 75% at 50% 50%, rgba(23, 22, 21, 0) 35%, rgba(23, 22, 21, 0.85) 100%);
}
.ll-aurora-stage {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 36px;
  transition: transform 520ms cubic-bezier(0.4, 0, 0.2, 1), filter 520ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-aurora.is-leaving .ll-aurora-stage { transform: translateY(-10px); filter: blur(4px); }
.ll-aurora-focus { animation: ll-aurora-focus 1200ms cubic-bezier(0.16, 1, 0.3, 1) 150ms both; }
@keyframes ll-aurora-focus {
  from { opacity: 0; transform: scale(1.14); filter: blur(12px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}
.ll-aurora-logo {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  animation: ll-aurora-float 3200ms ease-in-out 1300ms infinite alternate both;
}
@keyframes ll-aurora-float {
  from { transform: translateY(0); }
  to { transform: translateY(-5px); }
}
.ll-aurora-mark { display: block; height: 60px; }
.ll-aurora-word { display: block; height: 42px; }
/* a warm light through the logo, cut to its shapes (.ll-logo-mask) */
.ll-aurora-shine { overflow: hidden; }
.ll-aurora-shine::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 34%;
  background: linear-gradient(105deg, rgba(255, 236, 210, 0) 10%, rgba(255, 236, 210, 0.55) 50%, rgba(255, 236, 210, 0) 90%);
  transform: translateX(-110%);
  animation: ll-aurora-shine 4200ms 1400ms infinite;
}
@keyframes ll-aurora-shine {
  0% { transform: translateX(-110%); animation-timing-function: cubic-bezier(0.45, 0, 0.2, 1); }
  40%, 100% { transform: translateX(310%); }
}
.ll-aurora-dots { display: flex; gap: 10px; animation: ll-show 600ms ease-out 1000ms both; }
.ll-aurora-dots i {
  display: block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #ffc58a;
  animation: ll-aurora-dot 700ms ease-in-out infinite alternate both;
}
.ll-aurora-dots i:nth-child(2) { animation-delay: 230ms; }
.ll-aurora-dots i:nth-child(3) { animation-delay: 460ms; }
@keyframes ll-aurora-dot {
  from { opacity: 0.25; transform: scale(0.7); }
  to { opacity: 1; transform: scale(1.1); }
}

/* ── a phone: the logo as small as the site's loader draws it there (styles/boot.css) ─────────────── */

@media (max-width: 520px) {
  .ll-ember-logo,
  .ll-aurora-logo { gap: 12px; }
  .ll-ember-mark-box,
  .ll-ember-mark,
  .ll-orbit-mark,
  .ll-aurora-mark { height: 40px; }
  .ll-ember-word,
  .ll-card-word,
  .ll-aurora-word { height: 28px; }
  .ll-orbit-word { height: 30px; }
  .ll-ember-glow-box { width: 200px; height: 200px; margin: -100px 0 0 -100px; }
  .ll-ember-wave { width: 80px; height: 80px; margin: -40px 0 0 -40px; }
  .ll-ember-embers { top: 16px; }
  .ll-orbit-ring { width: 150px; height: 150px; }
  .ll-orbit-spin.is-slow { inset: 12px; }
  .ll-orbit-halo { width: 170px; height: 170px; margin: -85px 0 0 -85px; }
  .ll-card-row { gap: 16px; }
  .ll-card-deal { width: 76px; height: 106px; }
  .ll-card-mark { width: 56px; }
  .ll-card-index { top: 6px; left: 7px; font-size: 12px; }
  .ll-card-index.is-bottom { top: auto; left: auto; right: 7px; bottom: 6px; }
  .ll-aurora-blob.is-one { width: 380px; height: 380px; margin: -190px 0 0 -190px; }
  .ll-aurora-blob.is-two { width: 320px; height: 320px; margin: -160px 0 0 -160px; }
  .ll-aurora-blob.is-three { width: 300px; height: 300px; margin: -150px 0 0 -150px; }
}

/* ── shared by 6-15 ──────────────────────────────────────────────────────── */

@keyframes ll-rise-in {
  from { opacity: 0; transform: translateY(12px); filter: blur(5px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}

/* ── 6 · Chips ───────────────────────────────────────────────────────────── */

.ll-chips {
  background: radial-gradient(60% 60% at 50% 46%, #2a2a2a 0%, #1c1c1c 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-chips-stage {
  display: grid;
  justify-items: center;
  gap: 34px;
  transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-chips.is-leaving .ll-chips-stage { transform: scale(1.06); filter: blur(4px); }
.ll-chips-logo { display: flex; align-items: center; gap: 16px; animation: ll-rise-in 900ms cubic-bezier(0.16, 1, 0.3, 1) 150ms both; }
.ll-chips-mark { display: block; height: 60px; }
.ll-chips-word { display: block; height: 42px; }

/* five chips, each a top seen at an angle (a circle squeezed flat) over its striped edge */
.ll-chips-stack { position: relative; width: 56px; height: 62px; }
.ll-chips-stack::before {
  content: "";
  position: absolute;
  left: -8px;
  right: -8px;
  bottom: -8px;
  height: 18px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.5);
  filter: blur(8px);
}
.ll-chip { position: absolute; left: 0; width: 56px; height: 27px; }
.ll-chip:nth-child(1) { bottom: 0; animation: ll-chip-drop-1 3600ms 500ms infinite both, ll-chip-show-1 3600ms linear 500ms infinite both; }
.ll-chip:nth-child(2) { bottom: 8px; animation: ll-chip-drop-2 3600ms 500ms infinite both, ll-chip-show-2 3600ms linear 500ms infinite both; }
.ll-chip:nth-child(3) { bottom: 16px; animation: ll-chip-drop-3 3600ms 500ms infinite both, ll-chip-show-3 3600ms linear 500ms infinite both; }
.ll-chip:nth-child(4) { bottom: 24px; animation: ll-chip-drop-4 3600ms 500ms infinite both, ll-chip-show-4 3600ms linear 500ms infinite both; }
.ll-chip:nth-child(5) { bottom: 32px; animation: ll-chip-drop-5 3600ms 500ms infinite both, ll-chip-show-5 3600ms linear 500ms infinite both; }
.ll-chip-side {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 17px;
  border-radius: 0 0 28px 28px / 0 0 10px 10px;
  background: repeating-linear-gradient(90deg, #c4621b 0 7px, #f6e7d8 7px 11px);
}
.ll-chip-top {
  position: absolute;
  left: 0;
  top: -18px;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: repeating-conic-gradient(#ff9e45 0deg 15deg, #fff1e2 15deg 30deg);
  transform: scaleY(0.36);
}
.ll-chip-top::after {
  content: "";
  position: absolute;
  inset: 7px;
  border: 2px dashed rgba(255, 255, 255, 0.55);
  border-radius: 50%;
  background: radial-gradient(circle, #ec8a36 0%, #cf6c21 72%);
}
.ll-chip:nth-child(even) .ll-chip-side { background: repeating-linear-gradient(90deg, #2c2c2c 0 7px, #e6e6e6 7px 11px); }
.ll-chip:nth-child(even) .ll-chip-top { background: repeating-conic-gradient(#3b3b3b 0deg 15deg, #ececec 15deg 30deg); }
.ll-chip:nth-child(even) .ll-chip-top::after { background: radial-gradient(circle, #3a3a3a 0%, #262626 72%); }
/* a round: each chip falls in its turn (gravity, a small bounce), the stack stands, then clears; one list of frames per chip, because
   each one's fall sits at its own place in the same round */
@keyframes ll-chip-drop-1 {
  0% { transform: translateY(-80px); animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  8% { transform: translateY(0); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  11% { transform: translateY(-6px); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  14%, 100% { transform: translateY(0); }
}
@keyframes ll-chip-drop-2 {
  0%, 9% { transform: translateY(-80px); animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  17% { transform: translateY(0); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  20% { transform: translateY(-6px); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  23%, 100% { transform: translateY(0); }
}
@keyframes ll-chip-drop-3 {
  0%, 18% { transform: translateY(-80px); animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  26% { transform: translateY(0); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  29% { transform: translateY(-6px); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  32%, 100% { transform: translateY(0); }
}
@keyframes ll-chip-drop-4 {
  0%, 27% { transform: translateY(-80px); animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  35% { transform: translateY(0); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  38% { transform: translateY(-6px); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  41%, 100% { transform: translateY(0); }
}
@keyframes ll-chip-drop-5 {
  0%, 36% { transform: translateY(-80px); animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  44% { transform: translateY(0); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  47% { transform: translateY(-6px); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  50%, 100% { transform: translateY(0); }
}
@keyframes ll-chip-show-1 { 0% { opacity: 0; } 2% { opacity: 1; } 78% { opacity: 1; } 88%, 100% { opacity: 0; } }
@keyframes ll-chip-show-2 { 0%, 9% { opacity: 0; } 11% { opacity: 1; } 78% { opacity: 1; } 88%, 100% { opacity: 0; } }
@keyframes ll-chip-show-3 { 0%, 18% { opacity: 0; } 20% { opacity: 1; } 78% { opacity: 1; } 88%, 100% { opacity: 0; } }
@keyframes ll-chip-show-4 { 0%, 27% { opacity: 0; } 29% { opacity: 1; } 78% { opacity: 1; } 88%, 100% { opacity: 0; } }
@keyframes ll-chip-show-5 { 0%, 36% { opacity: 0; } 38% { opacity: 1; } 78% { opacity: 1; } 88%, 100% { opacity: 0; } }

/* ── 7 · Suits ───────────────────────────────────────────────────────────── */

.ll-suits {
  background: radial-gradient(60% 60% at 50% 46%, #2a2726 0%, #1b1a19 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* four large faint suits drifting behind */
.ll-suits-bg { position: absolute; inset: 0; animation: ll-show 1400ms ease-out both; }
.ll-suits-ghost { position: absolute; width: 150px; height: 150px; fill: #ffffff; opacity: 0.04; }
.ll-suits-ghost:nth-child(1) { left: 4%; top: 4%; animation: ll-suits-drift-a 12000ms ease-in-out infinite alternate both; }
.ll-suits-ghost:nth-child(2) { right: 5%; top: 8%; animation: ll-suits-drift-b 14000ms ease-in-out infinite alternate both; }
.ll-suits-ghost:nth-child(3) { left: 10%; bottom: 2%; animation: ll-suits-drift-b 13000ms ease-in-out infinite alternate both; }
.ll-suits-ghost:nth-child(4) { right: 9%; bottom: 4%; animation: ll-suits-drift-a 15000ms ease-in-out infinite alternate both; }
@keyframes ll-suits-drift-a {
  from { transform: translate(0, 0) rotate(-14deg); }
  to { transform: translate(26px, 18px) rotate(-4deg); }
}
@keyframes ll-suits-drift-b {
  from { transform: translate(0, 0) rotate(12deg); }
  to { transform: translate(-24px, 16px) rotate(4deg); }
}
.ll-suits-stage {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 30px;
  transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-suits.is-leaving .ll-suits-stage { transform: scale(1.06); filter: blur(4px); }
.ll-suits-logo { display: flex; align-items: center; gap: 16px; animation: ll-rise-in 900ms cubic-bezier(0.16, 1, 0.3, 1) 150ms both; }
.ll-suits-mark { display: block; height: 60px; }
.ll-suits-word { display: block; height: 42px; }
.ll-suits-row { display: flex; gap: 22px; }
.ll-suits-slot { display: block; animation: ll-suits-in 600ms cubic-bezier(0.16, 1, 0.3, 1) both; }
.ll-suits-slot:nth-child(1) { animation-delay: 500ms; }
.ll-suits-slot:nth-child(2) { animation-delay: 580ms; }
.ll-suits-slot:nth-child(3) { animation-delay: 660ms; }
.ll-suits-slot:nth-child(4) { animation-delay: 740ms; }
@keyframes ll-suits-in {
  from { opacity: 0; transform: translateY(10px) scale(0.8); }
  to { opacity: 1; transform: none; }
}
/* each suit lights in its turn: up and bright, then back down and dim */
.ll-suits-icon { display: block; width: 20px; height: 20px; fill: #f2f2f2; animation: ll-suits-beat 2400ms 1100ms infinite both; }
.ll-suits-icon.is-red { fill: #ff8a3d; filter: drop-shadow(0 0 6px rgba(255, 138, 61, 0.55)); }
.ll-suits-slot:nth-child(2) .ll-suits-icon { animation-delay: 1400ms; }
.ll-suits-slot:nth-child(3) .ll-suits-icon { animation-delay: 1700ms; }
.ll-suits-slot:nth-child(4) .ll-suits-icon { animation-delay: 2000ms; }
@keyframes ll-suits-beat {
  0% { opacity: 0.25; transform: scale(0.86); animation-timing-function: cubic-bezier(0.2, 0.8, 0.3, 1); }
  16% { opacity: 1; transform: translateY(-5px) scale(1.18); animation-timing-function: cubic-bezier(0.5, 0, 0.5, 1); }
  42%, 100% { opacity: 0.25; transform: scale(0.86); }
}

/* ── 8 · Cascade ─────────────────────────────────────────────────────────── */

.ll-cascade {
  background: radial-gradient(60% 60% at 50% 46%, #2b2b2b 0%, var(--surface-page) 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-cascade-stage {
  position: relative;
  display: grid;
  place-items: center;
  transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-cascade.is-leaving .ll-cascade-stage { transform: translateY(-8px); filter: blur(4px); }
.ll-cascade-halo {
  pointer-events: none;
  position: absolute;
  left: 50%;
  top: 50%;
  width: 460px;
  height: 200px;
  margin: -100px 0 0 -230px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 140, 50, 0.16), rgba(255, 140, 50, 0));
  animation: ll-show 1200ms ease-out 300ms both;
}
.ll-cascade-logo { position: relative; display: flex; align-items: center; gap: 16px; }
.ll-cascade-mark {
  display: block;
  height: 60px;
  animation: ll-cascade-drop 900ms cubic-bezier(0.34, 1.56, 0.64, 1) 100ms both, ll-show 300ms ease-out 100ms both;
}
@keyframes ll-cascade-drop {
  from { transform: translateY(-34px) scale(0.9); }
  to { transform: none; }
}
/* 243.3px of lettering at 42px in seven slices of 34.757px; each slice's box is 1px wider so no seam shows between two */
.ll-cascade-word { display: flex; height: 42px; }
.ll-cascade-slot { display: block; width: 34.757px; animation: ll-cascade-fall 700ms cubic-bezier(0.22, 1.3, 0.4, 1) both, ll-cascade-focus 700ms ease-out both; }
.ll-cascade-strip { display: block; width: 35.757px; height: 42px; overflow: hidden; animation: ll-cascade-wave 3200ms infinite both; }
.ll-cascade-strip img { display: block; width: auto; height: 42px; }
.ll-cascade-slot:nth-child(1) { animation-delay: 420ms; }
.ll-cascade-slot:nth-child(2) { animation-delay: 490ms; }
.ll-cascade-slot:nth-child(3) { animation-delay: 560ms; }
.ll-cascade-slot:nth-child(4) { animation-delay: 630ms; }
.ll-cascade-slot:nth-child(5) { animation-delay: 700ms; }
.ll-cascade-slot:nth-child(6) { animation-delay: 770ms; }
.ll-cascade-slot:nth-child(7) { animation-delay: 840ms; }
.ll-cascade-slot:nth-child(1) .ll-cascade-strip { animation-delay: 1700ms; }
.ll-cascade-slot:nth-child(2) .ll-cascade-strip { animation-delay: 1770ms; }
.ll-cascade-slot:nth-child(3) .ll-cascade-strip { animation-delay: 1840ms; }
.ll-cascade-slot:nth-child(4) .ll-cascade-strip { animation-delay: 1910ms; }
.ll-cascade-slot:nth-child(5) .ll-cascade-strip { animation-delay: 1980ms; }
.ll-cascade-slot:nth-child(6) .ll-cascade-strip { animation-delay: 2050ms; }
.ll-cascade-slot:nth-child(7) .ll-cascade-strip { animation-delay: 2120ms; }
.ll-cascade-slot:nth-child(2) img { margin-left: -34.757px; }
.ll-cascade-slot:nth-child(3) img { margin-left: -69.514px; }
.ll-cascade-slot:nth-child(4) img { margin-left: -104.271px; }
.ll-cascade-slot:nth-child(5) img { margin-left: -139.028px; }
.ll-cascade-slot:nth-child(6) img { margin-left: -173.785px; }
.ll-cascade-slot:nth-child(7) img { margin-left: -208.542px; }
@keyframes ll-cascade-fall {
  from { transform: translateY(-30px) rotate(-10deg); }
  to { transform: none; }
}
@keyframes ll-cascade-focus {
  from { opacity: 0; filter: blur(6px); }
  to { opacity: 1; filter: blur(0); }
}
@keyframes ll-cascade-wave {
  0% { transform: none; animation-timing-function: cubic-bezier(0.3, 0, 0.3, 1); }
  7% { transform: translateY(-5px); animation-timing-function: cubic-bezier(0.5, 0, 0.6, 1); }
  15%, 100% { transform: none; }
}

/* ── 9 · Sonar ───────────────────────────────────────────────────────────── */

.ll-sonar {
  background: radial-gradient(60% 60% at 50% 50%, #262321 0%, #191817 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-sonar-stage {
  position: relative;
  display: grid;
  place-items: center;
  transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-sonar.is-leaving .ll-sonar-stage { transform: scale(1.06); filter: blur(4px); }
/* every ring and light is placed from the logo's middle */
.ll-sonar-field { pointer-events: none; position: absolute; left: 50%; top: 50%; width: 0; height: 0; }
.ll-sonar-core {
  position: absolute;
  left: -220px;
  top: -100px;
  width: 440px;
  height: 200px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 140, 50, 0.2), rgba(255, 140, 50, 0));
  animation: ll-sonar-beat 3000ms 500ms infinite both;
}
@keyframes ll-sonar-beat {
  0% { opacity: 1; transform: scale(1.06); animation-timing-function: cubic-bezier(0.2, 0.6, 0.35, 1); }
  35%, 100% { opacity: 0.5; transform: scale(0.96); }
}
.ll-sonar-ring {
  position: absolute;
  left: -210px;
  top: -78px;
  width: 420px;
  height: 156px;
  border: 1px solid rgba(255, 158, 69, 0.55);
  border-radius: 50%;
  animation: ll-sonar-grow 3000ms cubic-bezier(0.2, 0.6, 0.35, 1) 500ms infinite both, ll-sonar-fade 3000ms linear 500ms infinite both;
}
.ll-sonar-ring.is-two { animation-delay: 1500ms; }
.ll-sonar-ring.is-three { animation-delay: 2500ms; }
@keyframes ll-sonar-grow {
  from { transform: scale(0.35); }
  to { transform: scale(1.5); }
}
@keyframes ll-sonar-fade {
  0% { opacity: 0; }
  12% { opacity: 1; }
  100% { opacity: 0; }
}
.ll-sonar-blips i {
  position: absolute;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: #ffd29e;
  box-shadow: 0 0 8px 2px rgba(255, 158, 69, 0.6);
  animation: ll-sonar-blip 3000ms ease-out infinite both;
}
.ll-sonar-blips i:nth-child(1) { left: -190px; top: -46px; animation-delay: 1100ms; }
.ll-sonar-blips i:nth-child(2) { left: 168px; top: -60px; animation-delay: 1700ms; }
.ll-sonar-blips i:nth-child(3) { left: 214px; top: 40px; animation-delay: 2300ms; }
.ll-sonar-blips i:nth-child(4) { left: -150px; top: 64px; animation-delay: 2700ms; }
.ll-sonar-blips i:nth-child(5) { left: 30px; top: -96px; animation-delay: 3300ms; }
@keyframes ll-sonar-blip {
  0% { opacity: 0; transform: scale(0.4); }
  8% { opacity: 1; transform: scale(1); }
  40%, 100% { opacity: 0; transform: scale(0.6); }
}
.ll-sonar-logo {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  animation: ll-sonar-in 1000ms cubic-bezier(0.16, 1, 0.3, 1) 200ms both;
}
@keyframes ll-sonar-in {
  from { opacity: 0; transform: scale(0.94); filter: blur(6px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}
.ll-sonar-mark { display: block; height: 60px; }
.ll-sonar-word { display: block; height: 42px; }

/* ── 10 · Mirror ─────────────────────────────────────────────────────────── */

.ll-mirror {
  background: linear-gradient(180deg, #232120 0%, #1b1a19 52%, #141413 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-mirror-stage {
  display: grid;
  justify-items: center;
  transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-mirror.is-leaving .ll-mirror-stage { transform: translateY(-6px); filter: blur(4px); }
/* the logo comes down onto the floor; inside the upside-down copy the same motion brings the reflection up to it */
.ll-mirror-up {
  animation: ll-mirror-drop 1000ms cubic-bezier(0.34, 1.3, 0.64, 1) 150ms both, ll-mirror-focus 700ms ease-out 150ms both;
}
@keyframes ll-mirror-drop {
  from { transform: translateY(-28px); }
  to { transform: none; }
}
@keyframes ll-mirror-focus {
  from { opacity: 0; filter: blur(5px); }
  to { opacity: 1; filter: blur(0); }
}
.ll-mirror-logo { position: relative; display: flex; align-items: center; gap: 16px; }
.ll-mirror-mark { display: block; height: 60px; }
.ll-mirror-word { display: block; height: 42px; }
.ll-mirror-shine { overflow: hidden; }
.ll-mirror-shine::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 30%;
  background: linear-gradient(105deg, rgba(255, 255, 255, 0) 10%, rgba(255, 255, 255, 0.5) 50%, rgba(255, 255, 255, 0) 90%);
  transform: translateX(-110%);
  animation: ll-mirror-shine 3600ms 1300ms infinite;
}
@keyframes ll-mirror-shine {
  0% { transform: translateX(-110%); animation-timing-function: cubic-bezier(0.45, 0, 0.2, 1); }
  45%, 100% { transform: translateX(345%); }
}
.ll-mirror-horizon {
  display: block;
  width: 460px;
  height: 1px;
  margin: 10px 0 4px;
  background: linear-gradient(90deg, rgba(255, 158, 69, 0) 0%, rgba(255, 180, 110, 0.7) 50%, rgba(255, 158, 69, 0) 100%);
  animation: ll-mirror-line 900ms cubic-bezier(0.65, 0, 0.35, 1) 450ms both;
}
@keyframes ll-mirror-line {
  from { opacity: 0; transform: scaleX(0); }
  to { opacity: 1; transform: none; }
}
.ll-mirror-down {
  opacity: 0.26;
  transform: scaleY(-1);
  -webkit-mask-image: linear-gradient(0deg, #000 0%, rgba(0, 0, 0, 0) 78%);
  mask-image: linear-gradient(0deg, #000 0%, rgba(0, 0, 0, 0) 78%);
}
.ll-mirror-wave { transform-origin: 50% 100%; animation: ll-mirror-sway 3400ms ease-in-out 1200ms infinite alternate both; }
@keyframes ll-mirror-sway {
  from { transform: skewX(-2deg) scaleY(1); }
  to { transform: skewX(2deg) scaleY(0.97); }
}

/* ── 11 · Neon ───────────────────────────────────────────────────────────── */

.ll-neon {
  background: radial-gradient(70% 70% at 50% 50%, #1d1b1a 0%, #111010 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-neon-stage { transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1); }
.ll-neon.is-leaving .ll-neon-stage { transform: scale(1.05); filter: blur(4px); }
/* the sign switches on with a stutter; the frame follows; then the lettering hums now and then */
.ll-neon-sign { position: relative; isolation: isolate; padding: 24px 32px; animation: ll-neon-on 1500ms linear 250ms both; }
@keyframes ll-neon-on {
  0% { opacity: 0; }
  8% { opacity: 0.85; }
  11% { opacity: 0.1; }
  20% { opacity: 0.9; }
  23% { opacity: 0.25; }
  34% { opacity: 1; }
  38% { opacity: 0.55; }
  46%, 100% { opacity: 1; }
}
.ll-neon-wall {
  pointer-events: none;
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 50%;
  width: 600px;
  height: 320px;
  margin: -160px 0 0 -300px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 120, 40, 0.24), rgba(255, 120, 40, 0));
}
.ll-neon-frame {
  position: absolute;
  inset: 0;
  border: 2px solid rgba(255, 176, 110, 0.92);
  border-radius: 18px;
  box-shadow: 0 0 14px 2px rgba(255, 130, 50, 0.55), inset 0 0 14px 1px rgba(255, 130, 50, 0.35);
  animation: ll-neon-frame-on 1300ms linear 700ms both;
}
@keyframes ll-neon-frame-on {
  0% { opacity: 0; }
  10% { opacity: 1; }
  14% { opacity: 0.15; }
  26% { opacity: 0.9; }
  30% { opacity: 0.3; }
  42%, 100% { opacity: 1; }
}
.ll-neon-logo { display: flex; align-items: center; gap: 16px; animation: ll-neon-buzz 4300ms linear 2200ms infinite both; }
@keyframes ll-neon-buzz {
  0%, 60% { opacity: 1; }
  61% { opacity: 0.7; }
  62% { opacity: 1; }
  64% { opacity: 0.8; }
  65%, 100% { opacity: 1; }
}
.ll-neon-mark,
.ll-neon-word { filter: drop-shadow(0 0 4px rgba(255, 176, 110, 0.9)) drop-shadow(0 0 16px rgba(255, 120, 40, 0.55)); }
.ll-neon-mark { display: block; height: 60px; }
.ll-neon-word { display: block; height: 42px; }
.ll-neon-floor {
  pointer-events: none;
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: -62px;
  height: 40px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 130, 50, 0.22), rgba(255, 130, 50, 0));
}

/* ── 12 · Converge ───────────────────────────────────────────────────────── */

.ll-converge {
  background: radial-gradient(60% 60% at 50% 46%, #2b2b2b 0%, var(--surface-page) 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-converge-stage { transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1); }
.ll-converge.is-leaving .ll-converge-stage { transform: scale(1.06); filter: blur(4px); }
.ll-converge-logo { position: relative; display: flex; align-items: center; gap: 16px; }
.ll-converge-mark-box { position: relative; z-index: 1; display: block; height: 60px; }
/* twelve lights on twelve spokes rush into the mark's middle */
.ll-converge-rays { pointer-events: none; position: absolute; left: 50%; top: 50%; width: 0; height: 0; }
.ll-converge-ray { position: absolute; left: 0; top: 0; width: 0; height: 0; }
.ll-converge-ray:nth-child(1) { transform: rotate(0deg); }
.ll-converge-ray:nth-child(2) { transform: rotate(30deg); }
.ll-converge-ray:nth-child(3) { transform: rotate(60deg); }
.ll-converge-ray:nth-child(4) { transform: rotate(90deg); }
.ll-converge-ray:nth-child(5) { transform: rotate(120deg); }
.ll-converge-ray:nth-child(6) { transform: rotate(150deg); }
.ll-converge-ray:nth-child(7) { transform: rotate(180deg); }
.ll-converge-ray:nth-child(8) { transform: rotate(210deg); }
.ll-converge-ray:nth-child(9) { transform: rotate(240deg); }
.ll-converge-ray:nth-child(10) { transform: rotate(270deg); }
.ll-converge-ray:nth-child(11) { transform: rotate(300deg); }
.ll-converge-ray:nth-child(12) { transform: rotate(330deg); }
.ll-converge-ray i {
  position: absolute;
  left: -3px;
  top: -3px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #ffd29e;
  box-shadow: 0 0 6px 1px rgba(255, 158, 69, 0.7);
  animation: ll-converge-in 760ms cubic-bezier(0.6, 0, 0.9, 0.5) both, ll-converge-dot 760ms linear both;
}
.ll-converge-ray:nth-child(even) i { animation-name: ll-converge-in-near, ll-converge-dot; animation-delay: 80ms; }
@keyframes ll-converge-in {
  from { transform: translateX(170px) scale(1); }
  to { transform: translateX(0) scale(0.3); }
}
@keyframes ll-converge-in-near {
  from { transform: translateX(124px) scale(1); }
  to { transform: translateX(0) scale(0.3); }
}
@keyframes ll-converge-dot {
  0% { opacity: 0; }
  20% { opacity: 1; }
  85% { opacity: 1; }
  100% { opacity: 0; }
}
.ll-converge-flash {
  pointer-events: none;
  position: absolute;
  left: 50%;
  top: 50%;
  width: 30px;
  height: 30px;
  margin: -15px 0 0 -15px;
  border-radius: 50%;
  background: radial-gradient(circle, #fffaf0 0%, #ffd29e 32%, rgba(255, 158, 69, 0.4) 55%, rgba(255, 122, 40, 0) 72%);
  animation: ll-converge-burst 700ms cubic-bezier(0.16, 1, 0.3, 1) 760ms both, ll-converge-burst-fade 700ms linear 760ms both;
}
@keyframes ll-converge-burst {
  from { transform: scale(0.2); }
  to { transform: scale(5); }
}
@keyframes ll-converge-burst-fade {
  0% { opacity: 0; }
  14% { opacity: 1; }
  100% { opacity: 0; }
}
.ll-converge-mark {
  position: relative;
  display: block;
  height: 60px;
  animation: ll-converge-pop 800ms cubic-bezier(0.22, 1.5, 0.36, 1) 800ms both, ll-show 200ms ease-out 800ms both;
}
@keyframes ll-converge-pop {
  from { transform: scale(0.5); }
  to { transform: none; }
}
.ll-converge-word {
  display: block;
  height: 42px;
  animation: ll-converge-word 800ms cubic-bezier(0.16, 1, 0.3, 1) 1000ms both;
}
@keyframes ll-converge-word {
  from { opacity: 0; transform: translateX(-36px); filter: blur(5px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}
/* eight lights round the whole logo: each goes from side to side, and up and down a quarter of a turn later */
.ll-converge-orbit { pointer-events: none; position: absolute; left: 50%; top: 50%; width: 0; height: 0; animation: ll-show 900ms ease-out 1400ms both; }
.ll-converge-x { position: absolute; left: 0; top: 0; animation: ll-converge-across 2400ms cubic-bezier(0.37, 0, 0.63, 1) infinite alternate both; }
.ll-converge-x i {
  position: absolute;
  left: -2.5px;
  top: -2.5px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #ffe0b8;
  box-shadow: 0 0 6px 1px rgba(255, 158, 69, 0.6);
  opacity: 0.8;
  animation: ll-converge-updown 2400ms cubic-bezier(0.37, 0, 0.63, 1) infinite alternate both;
}
.ll-converge-x:nth-child(1) { animation-delay: 0ms; }
.ll-converge-x:nth-child(2) { animation-delay: -600ms; }
.ll-converge-x:nth-child(3) { animation-delay: -1200ms; }
.ll-converge-x:nth-child(4) { animation-delay: -1800ms; }
.ll-converge-x:nth-child(5) { animation-delay: -2400ms; }
.ll-converge-x:nth-child(6) { animation-delay: -3000ms; }
.ll-converge-x:nth-child(7) { animation-delay: -3600ms; }
.ll-converge-x:nth-child(8) { animation-delay: -4200ms; }
.ll-converge-x:nth-child(1) i { animation-delay: -1200ms; }
.ll-converge-x:nth-child(2) i { animation-delay: -1800ms; }
.ll-converge-x:nth-child(3) i { animation-delay: -2400ms; }
.ll-converge-x:nth-child(4) i { animation-delay: -3000ms; }
.ll-converge-x:nth-child(5) i { animation-delay: -3600ms; }
.ll-converge-x:nth-child(6) i { animation-delay: -4200ms; }
.ll-converge-x:nth-child(7) i { animation-delay: -4800ms; }
.ll-converge-x:nth-child(8) i { animation-delay: -5400ms; }
@keyframes ll-converge-across {
  from { transform: translateX(-240px); }
  to { transform: translateX(240px); }
}
@keyframes ll-converge-updown {
  from { transform: translateY(-58px); }
  to { transform: translateY(58px); }
}

/* ── 13 · Reveal ─────────────────────────────────────────────────────────── */

.ll-reveal {
  background: radial-gradient(60% 60% at 50% 46%, #2b2b2b 0%, var(--surface-page) 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-reveal-stage { transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1); }
.ll-reveal.is-leaving .ll-reveal-stage { transform: scale(1.06); filter: blur(4px); }
.ll-reveal-box { position: relative; padding: 16px; }
/* a seam of light, then the two doors slide apart onto the logo, which comes into focus behind them */
.ll-reveal-frame { position: relative; display: grid; place-items: center; width: 460px; height: 128px; overflow: hidden; }
.ll-reveal-logo { display: flex; align-items: center; gap: 16px; animation: ll-reveal-logo 1100ms cubic-bezier(0.16, 1, 0.3, 1) 420ms both; }
@keyframes ll-reveal-logo {
  from { transform: scale(1.08); filter: blur(6px) brightness(0.6); }
  to { transform: none; filter: blur(0) brightness(1); }
}
.ll-reveal-mark { display: block; height: 60px; }
.ll-reveal-word { display: block; height: 42px; }
.ll-reveal-door { position: absolute; top: 0; bottom: 0; width: 50%; }
.ll-reveal-door.is-left {
  left: 0;
  background: linear-gradient(90deg, #232323 0%, #2c2c2c 100%);
  box-shadow: inset -1px 0 0 rgba(255, 158, 69, 0.4);
  animation: ll-reveal-left 900ms cubic-bezier(0.76, 0, 0.24, 1) 420ms both;
}
.ll-reveal-door.is-right {
  right: 0;
  background: linear-gradient(270deg, #232323 0%, #2c2c2c 100%);
  box-shadow: inset 1px 0 0 rgba(255, 158, 69, 0.4);
  animation: ll-reveal-right 900ms cubic-bezier(0.76, 0, 0.24, 1) 420ms both;
}
@keyframes ll-reveal-left {
  from { transform: none; }
  to { transform: translateX(-101%); }
}
@keyframes ll-reveal-right {
  from { transform: none; }
  to { transform: translateX(101%); }
}
.ll-reveal-seam {
  position: absolute;
  z-index: 1;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 2px;
  margin-left: -1px;
  background: linear-gradient(180deg, rgba(255, 200, 140, 0) 0%, #ffd6a6 50%, rgba(255, 200, 140, 0) 100%);
  animation: ll-reveal-seam 420ms cubic-bezier(0.16, 1, 0.3, 1) both, ll-reveal-seam-fade 900ms linear both;
}
@keyframes ll-reveal-seam {
  from { transform: scaleY(0); }
  to { transform: none; }
}
@keyframes ll-reveal-seam-fade {
  0% { opacity: 0; }
  15% { opacity: 1; }
  55% { opacity: 1; }
  100% { opacity: 0; }
}
/* four focus corners come in from outside, then breathe */
.ll-reveal-corner {
  position: absolute;
  width: 20px;
  height: 20px;
  animation-duration: 700ms;
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
  animation-delay: 1150ms;
  animation-fill-mode: both;
}
.ll-reveal-corner i {
  position: absolute;
  inset: 0;
  border: 0 solid rgba(255, 158, 69, 0.85);
  animation-duration: 1800ms;
  animation-timing-function: ease-in-out;
  animation-delay: 1900ms;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-fill-mode: both;
}
.ll-reveal-corner.is-tl { left: 0; top: 0; animation-name: ll-reveal-tl; }
.ll-reveal-corner.is-tr { right: 0; top: 0; animation-name: ll-reveal-tr; }
.ll-reveal-corner.is-bl { left: 0; bottom: 0; animation-name: ll-reveal-bl; }
.ll-reveal-corner.is-br { right: 0; bottom: 0; animation-name: ll-reveal-br; }
.ll-reveal-corner.is-tl i { border-top-width: 2px; border-left-width: 2px; border-top-left-radius: 4px; animation-name: ll-reveal-tl-breathe; }
.ll-reveal-corner.is-tr i { border-top-width: 2px; border-right-width: 2px; border-top-right-radius: 4px; animation-name: ll-reveal-tr-breathe; }
.ll-reveal-corner.is-bl i { border-bottom-width: 2px; border-left-width: 2px; border-bottom-left-radius: 4px; animation-name: ll-reveal-bl-breathe; }
.ll-reveal-corner.is-br i { border-bottom-width: 2px; border-right-width: 2px; border-bottom-right-radius: 4px; animation-name: ll-reveal-br-breathe; }
@keyframes ll-reveal-tl { from { opacity: 0; transform: translate(-18px, -18px); } to { opacity: 1; transform: none; } }
@keyframes ll-reveal-tr { from { opacity: 0; transform: translate(18px, -18px); } to { opacity: 1; transform: none; } }
@keyframes ll-reveal-bl { from { opacity: 0; transform: translate(-18px, 18px); } to { opacity: 1; transform: none; } }
@keyframes ll-reveal-br { from { opacity: 0; transform: translate(18px, 18px); } to { opacity: 1; transform: none; } }
@keyframes ll-reveal-tl-breathe { from { transform: none; } to { transform: translate(-4px, -4px); } }
@keyframes ll-reveal-tr-breathe { from { transform: none; } to { transform: translate(4px, -4px); } }
@keyframes ll-reveal-bl-breathe { from { transform: none; } to { transform: translate(-4px, 4px); } }
@keyframes ll-reveal-br-breathe { from { transform: none; } to { transform: translate(4px, 4px); } }

/* ── 14 · Spotlight ──────────────────────────────────────────────────────── */

.ll-spot {
  background: #121110;
  transition: opacity 520ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ll-spot-stage { transition: transform 520ms cubic-bezier(0.4, 0, 0.2, 1), filter 520ms cubic-bezier(0.4, 0, 0.2, 1); }
.ll-spot.is-leaving .ll-spot-stage { transform: scale(1.05); filter: blur(4px); }
.ll-spot-logo { position: relative; display: flex; align-items: center; gap: 16px; }
/* the logo in the dark */
.ll-spot-logo > img { opacity: 0.16; filter: grayscale(1) brightness(1.4); animation: ll-spot-dim 900ms ease-out both; }
@keyframes ll-spot-dim {
  from { opacity: 0; }
  to { opacity: 0.16; }
}
.ll-spot-mark { display: block; height: 60px; }
.ll-spot-word { display: block; height: 42px; }
/* the light switches on with a blink, then swings from side to side */
.ll-spot-light { pointer-events: none; position: absolute; inset: 0; animation: ll-spot-on 700ms linear 350ms both; }
@keyframes ll-spot-on {
  0% { opacity: 0; }
  20% { opacity: 1; }
  32% { opacity: 0.2; }
  48%, 100% { opacity: 1; }
}
/* the beam hangs from a point 390px above the logo's middle; its angle follows the light's travel (atan(160 / 420) = 20.85deg) */
.ll-spot-pivot {
  position: absolute;
  left: 50%;
  top: -390px;
  width: 0;
  height: 0;
  filter: blur(6px);   /* on the beam's holder: the beam's own blur would come before its triangle cut, with hard edges */
  animation: ll-spot-aim 2800ms cubic-bezier(0.45, 0, 0.55, 1) 700ms infinite alternate both;
}
@keyframes ll-spot-aim {
  from { transform: rotate(20.85deg); }
  to { transform: rotate(-20.85deg); }
}
.ll-spot-cone {
  position: absolute;
  left: -120px;
  top: 0;
  width: 240px;
  height: 420px;
  background: linear-gradient(180deg, rgba(255, 220, 170, 0) 0%, rgba(255, 220, 170, 0.12) 100%);
  clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
}
.ll-spot-floor {
  position: absolute;
  left: 50%;
  top: 78px;
  width: 240px;
  height: 44px;
  margin-left: -120px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 210, 160, 0.2), rgba(255, 210, 160, 0));
  animation: ll-spot-swing 2800ms cubic-bezier(0.45, 0, 0.55, 1) 700ms infinite alternate both;
}
.ll-spot-window {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 190px;
  height: 190px;
  margin: -95px 0 0 -95px;
  overflow: hidden;
  border-radius: 50%;
  -webkit-mask-image: radial-gradient(circle, #000 50%, rgba(0, 0, 0, 0) 72%);
  mask-image: radial-gradient(circle, #000 50%, rgba(0, 0, 0, 0) 72%);
  animation: ll-spot-swing 2800ms cubic-bezier(0.45, 0, 0.55, 1) 700ms infinite alternate both;
}
.ll-spot-window::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle, rgba(255, 214, 160, 0.2) 0%, rgba(255, 214, 160, 0) 70%);
}
.ll-spot-counter {
  position: absolute;
  inset: 0;
  animation: ll-spot-counter 2800ms cubic-bezier(0.45, 0, 0.55, 1) 700ms infinite alternate both;
}
.ll-spot-lit {
  position: absolute;
  left: 50%;
  top: 50%;
  display: flex;
  align-items: center;
  gap: 16px;
  transform: translate(-50%, -50%);
}
.ll-spot-lit img { filter: brightness(1.15) drop-shadow(0 0 10px rgba(255, 170, 90, 0.45)); }
@keyframes ll-spot-swing {
  from { transform: translateX(-160px); }
  to { transform: translateX(160px); }
}
@keyframes ll-spot-counter {
  from { transform: translateX(160px); }
  to { transform: translateX(-160px); }
}

/* ── 15 · Glitch ─────────────────────────────────────────────────────────── */

.ll-glitch {
  background: radial-gradient(60% 60% at 50% 46%, #262626 0%, #171717 100%);
  transition: opacity 480ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* faint screen lines and a slow bright band passing down */
.ll-glitch-scan {
  pointer-events: none;
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: repeating-linear-gradient(180deg, rgba(255, 255, 255, 0.025) 0 1px, rgba(255, 255, 255, 0) 1px 3px);
}
.ll-glitch-scan::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 140px;
  background: linear-gradient(180deg, rgba(255, 158, 69, 0) 0%, rgba(255, 158, 69, 0.05) 50%, rgba(255, 158, 69, 0) 100%);
  animation: ll-glitch-band 4200ms linear infinite;
}
@keyframes ll-glitch-band {
  from { transform: translateY(-140px); }
  to { transform: translateY(1200px); }
}
.ll-glitch-stage { position: relative; transition: transform 480ms cubic-bezier(0.4, 0, 0.2, 1), filter 480ms cubic-bezier(0.4, 0, 0.2, 1); }
.ll-glitch.is-leaving .ll-glitch-stage { transform: scale(1.05); filter: blur(4px); }
.ll-glitch-logo { position: relative; }
.ll-glitch-mark { display: block; height: 60px; }
.ll-glitch-word { display: block; height: 42px; }
/* a glitch jumps on purpose: every step of these lists is a jump (steps), not a movement */
.ll-glitch-in { animation: ll-glitch-in 700ms steps(1, end) 200ms both; }
@keyframes ll-glitch-in {
  0% { opacity: 0; transform: translate(-8px, 0); }
  10% { opacity: 1; transform: translate(6px, -1px); }
  20% { opacity: 0.4; transform: translate(-4px, 1px); }
  30% { opacity: 1; transform: translate(3px, 0); }
  45% { transform: translate(-2px, 0); }
  60% { transform: translate(1px, 0); }
  75%, 100% { opacity: 1; transform: none; }
}
.ll-glitch-jolt { display: flex; align-items: center; gap: 16px; animation: ll-glitch-jolt 3600ms steps(1, end) 1400ms infinite; }
@keyframes ll-glitch-jolt {
  0% { transform: translate(3px, 0); }
  1.5% { transform: translate(-2px, 1px); }
  3% { transform: translate(1px, 0); }
  4.5%, 100% { transform: none; }
}
.ll-glitch-split { mix-blend-mode: screen; opacity: 0; }
.ll-glitch-split.is-a {
  background: #3ac8ff;
  animation: ll-glitch-a-in 700ms steps(1, end) 200ms both, ll-glitch-a 3600ms steps(1, end) 1400ms infinite;
}
.ll-glitch-split.is-b {
  background: #ff4a3d;
  animation: ll-glitch-b-in 700ms steps(1, end) 200ms both, ll-glitch-b 3600ms steps(1, end) 1400ms infinite;
}
@keyframes ll-glitch-a-in {
  0% { opacity: 0.9; transform: translate(-7px, 1px); }
  15% { transform: translate(5px, -1px); }
  30% { transform: translate(-4px, 0); }
  50% { opacity: 0.6; transform: translate(2px, 0); }
  75%, 100% { opacity: 0; transform: none; }
}
@keyframes ll-glitch-b-in {
  0% { opacity: 0.9; transform: translate(7px, -1px); }
  15% { transform: translate(-5px, 1px); }
  30% { transform: translate(4px, 0); }
  50% { opacity: 0.6; transform: translate(-2px, 0); }
  75%, 100% { opacity: 0; transform: none; }
}
@keyframes ll-glitch-a {
  0% { opacity: 0.75; transform: translate(-4px, 0); }
  2% { transform: translate(3px, 1px); }
  4% { opacity: 0.5; transform: translate(-2px, 0); }
  5.5%, 100% { opacity: 0; transform: none; }
}
@keyframes ll-glitch-b {
  0% { opacity: 0.75; transform: translate(4px, 0); }
  2% { transform: translate(-3px, -1px); }
  4% { opacity: 0.5; transform: translate(2px, 0); }
  5.5%, 100% { opacity: 0; transform: none; }
}
.ll-glitch-slice {
  pointer-events: none;
  position: absolute;
  left: 0;
  right: 0;
  top: 20px;
  height: 10px;
  overflow: hidden;
  opacity: 0;
  animation: ll-glitch-slice 3600ms steps(1, end) 1400ms infinite;
}
.ll-glitch-slice.is-low { top: 40px; height: 7px; animation-name: ll-glitch-slice-low; }
.ll-glitch-slice-row { position: absolute; left: 0; top: -20px; display: flex; align-items: center; gap: 16px; }
.ll-glitch-slice.is-low .ll-glitch-slice-row { top: -40px; }
@keyframes ll-glitch-slice {
  0% { opacity: 1; transform: translateX(12px); }
  2% { transform: translateX(-7px); }
  4% { opacity: 1; transform: translateX(4px); }
  5%, 100% { opacity: 0; transform: none; }
}
@keyframes ll-glitch-slice-low {
  0% { opacity: 1; transform: translateX(-9px); }
  1.5% { transform: translateX(6px); }
  3.5% { opacity: 1; transform: translateX(-3px); }
  5%, 100% { opacity: 0; transform: none; }
}

/* ── 6-15 on a phone: the logo as small as the site's loader draws it there ── */

@media (max-width: 520px) {
  .ll-logo-mask {
    -webkit-mask-size: auto 40px, auto 28px;
    mask-size: auto 40px, auto 28px;
  }
  .ll-chips-logo,
  .ll-suits-logo,
  .ll-cascade-logo,
  .ll-sonar-logo,
  .ll-mirror-logo,
  .ll-neon-logo,
  .ll-converge-logo,
  .ll-reveal-logo,
  .ll-spot-logo,
  .ll-spot-lit,
  .ll-glitch-jolt,
  .ll-glitch-slice-row { gap: 12px; }
  .ll-chips-mark,
  .ll-suits-mark,
  .ll-cascade-mark,
  .ll-sonar-mark,
  .ll-mirror-mark,
  .ll-neon-mark,
  .ll-converge-mark-box,
  .ll-converge-mark,
  .ll-reveal-mark,
  .ll-spot-mark,
  .ll-glitch-mark { height: 40px; }
  .ll-chips-word,
  .ll-suits-word,
  .ll-sonar-word,
  .ll-mirror-word,
  .ll-neon-word,
  .ll-converge-word,
  .ll-reveal-word,
  .ll-spot-word,
  .ll-glitch-word { height: 28px; }
  /* the lettering at 28px is 162.2px: seven slices of 23.171px */
  .ll-cascade-word,
  .ll-cascade-strip,
  .ll-cascade-strip img { height: 28px; }
  .ll-cascade-slot { width: 23.171px; }
  .ll-cascade-strip { width: 24.171px; }
  .ll-cascade-slot:nth-child(2) img { margin-left: -23.171px; }
  .ll-cascade-slot:nth-child(3) img { margin-left: -46.342px; }
  .ll-cascade-slot:nth-child(4) img { margin-left: -69.513px; }
  .ll-cascade-slot:nth-child(5) img { margin-left: -92.684px; }
  .ll-cascade-slot:nth-child(6) img { margin-left: -115.855px; }
  .ll-cascade-slot:nth-child(7) img { margin-left: -139.026px; }
  .ll-cascade-halo { width: 320px; height: 150px; margin: -75px 0 0 -160px; }
  .ll-suits-ghost { width: 100px; height: 100px; }
  .ll-sonar-ring { left: -150px; top: -56px; width: 300px; height: 112px; }
  .ll-sonar-core { left: -160px; top: -74px; width: 320px; height: 148px; }
  .ll-sonar-blips i:nth-child(1) { left: -130px; top: -36px; }
  .ll-sonar-blips i:nth-child(2) { left: 118px; top: -44px; }
  .ll-sonar-blips i:nth-child(3) { left: 146px; top: 30px; }
  .ll-sonar-blips i:nth-child(4) { left: -104px; top: 46px; }
  .ll-sonar-blips i:nth-child(5) { left: 20px; top: -68px; }
  .ll-mirror-horizon { width: 300px; }
  .ll-neon-sign { padding: 16px 20px; }
  .ll-neon-wall { width: 400px; height: 220px; margin: -110px 0 0 -200px; }
  .ll-converge-ray i { animation-name: ll-converge-in-sm, ll-converge-dot; }
  .ll-converge-ray:nth-child(even) i { animation-name: ll-converge-in-near-sm, ll-converge-dot; }
  .ll-converge-x { animation-name: ll-converge-across-sm; }
  .ll-converge-x i { animation-name: ll-converge-updown-sm; }
  .ll-reveal-frame { width: 310px; height: 92px; }
  .ll-reveal-box { padding: 12px; }
  .ll-spot-pivot { top: -262px; animation-name: ll-spot-aim-sm; }
  .ll-spot-cone { left: -84px; width: 168px; height: 282px; }
  .ll-spot-floor { top: 54px; width: 170px; margin-left: -85px; animation-name: ll-spot-swing-sm; }
  .ll-spot-window { width: 130px; height: 130px; margin: -65px 0 0 -65px; animation-name: ll-spot-swing-sm; }
  .ll-spot-counter { animation-name: ll-spot-counter-sm; }
  .ll-glitch-slice { top: 13px; height: 7px; }
  .ll-glitch-slice-row { top: -13px; }
  .ll-glitch-slice.is-low { top: 27px; height: 5px; }
  .ll-glitch-slice.is-low .ll-glitch-slice-row { top: -27px; }
}
@keyframes ll-converge-in-sm {
  from { transform: translateX(120px) scale(1); }
  to { transform: translateX(0) scale(0.3); }
}
@keyframes ll-converge-in-near-sm {
  from { transform: translateX(88px) scale(1); }
  to { transform: translateX(0) scale(0.3); }
}
@keyframes ll-converge-across-sm {
  from { transform: translateX(-160px); }
  to { transform: translateX(160px); }
}
@keyframes ll-converge-updown-sm {
  from { transform: translateY(-40px); }
  to { transform: translateY(40px); }
}
/* the phone's beam: 262px above the middle, travel 100px (atan(100 / 282) = 19.53deg) */
@keyframes ll-spot-aim-sm {
  from { transform: rotate(19.53deg); }
  to { transform: rotate(-19.53deg); }
}
@keyframes ll-spot-swing-sm {
  from { transform: translateX(-100px); }
  to { transform: translateX(100px); }
}
@keyframes ll-spot-counter-sm {
  from { transform: translateX(100px); }
  to { transform: translateX(-100px); }
}
/* What's new, the site banner and the Announcements tab (owner 2026-10-20; features/notices, pages/admin/AdminNotices.tsx, AdminBeta.tsx).
   The banner is a slim bar at the top of every signed-in page, part of the layout: while it stands the html element has
   `has-site-banner` and the one-screen pages below give it its 36px (the list at «the page makes room»), so nothing is covered and the
   Study page still fits the window. What's new is a window in the site's modal look (the dark card of Delete account / Saved spots) with
   an amber glow in its head. Sizes are px; colours are the theme's tokens and their mixes; only transform and opacity move
   (frontend_rules 5b.3), always (5b.5). */

/* ── the banner ──────────────────────────────────────────────────────── */
.site-banner {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 36px;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  background: var(--surface-sunken);
  padding: 0 44px;
  font-size: 13px;
  color: var(--text-normal);
  animation: site-banner-in 260ms cubic-bezier(0.2, 0, 0, 1) both;
}

/* a soft light of the tone in the middle of the bar */
.site-banner::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(90deg, transparent 8%, color-mix(in srgb, var(--accent-brand) 11%, transparent) 50%, transparent 92%);
}

.site-banner.is-warning {
  border-bottom-color: color-mix(in srgb, var(--grade-warn) 28%, transparent);
  background: color-mix(in srgb, var(--grade-warn) 9%, var(--surface-sunken));
}

.site-banner.is-warning::before {
  background: linear-gradient(90deg, transparent 8%, color-mix(in srgb, var(--grade-warn) 12%, transparent) 50%, transparent 92%);
}

.site-banner.is-maintenance {
  border-bottom-color: color-mix(in srgb, var(--grade-bad) 30%, transparent);
  background: color-mix(in srgb, var(--grade-bad) 10%, var(--surface-sunken));
}

.site-banner.is-maintenance::before {
  background: linear-gradient(90deg, transparent 8%, color-mix(in srgb, var(--grade-bad) 13%, transparent) 50%, transparent 92%);
}

.site-banner.is-leaving {
  animation: site-banner-out 180ms cubic-bezier(0.4, 0, 1, 1) both;   /* = LEAVE_MS in NoticesHost.tsx */
  pointer-events: none;
}

@keyframes site-banner-in {
  from {
    opacity: 0;
    transform: translateY(-100%);
  }
}

@keyframes site-banner-out {
  to {
    opacity: 0;
    transform: translateY(-100%);
  }
}

.site-banner-inner {
  position: relative;
  display: flex;
  min-width: 0;
  max-width: 1200px;
  align-items: center;
  gap: 10px;
}

.site-banner-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 7px;
  background: color-mix(in srgb, var(--accent-brand) 16%, transparent);
  color: var(--accent-brand);
}

.site-banner.is-warning .site-banner-icon {
  background: color-mix(in srgb, var(--grade-warn) 18%, transparent);
  color: var(--grade-warn);
}

.site-banner.is-maintenance .site-banner-icon {
  background: color-mix(in srgb, var(--grade-bad) 18%, transparent);
  color: var(--grade-bad);
}

/* one line: a longer text is cut, and the site's hint shows all of it (SiteBanner) */
.site-banner-text {
  min-width: 0;
  overflow: hidden;
  font-weight: 500;
  color: var(--text-strong);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.site-banner-link {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 4px;
  font-weight: 700;
  color: var(--accent-brand);
  text-decoration: none;
}

.site-banner-link:hover {
  text-decoration: underline;
}

.site-banner-close {
  position: absolute;
  top: 5px;
  right: 8px;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.site-banner-close:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

/* the admin's preview: the same bar inside the preview frame */
.site-banner.is-preview {
  position: relative;
  z-index: auto;
}

/* on a phone (the landing and the legal pages) the text may take two lines */
@media (max-width: 700px) {
  .site-banner {
    height: auto;
    min-height: 36px;
    justify-content: flex-start;
    padding: 7px 42px 7px 14px;
  }

  .site-banner-inner {
    flex-wrap: wrap;
    row-gap: 2px;
  }

  .site-banner-text {
    flex: 1 1 200px;
    white-space: normal;
  }
}

/* ── the page makes room for the bar ─────────────────────────────────── */
/* Every page that is one window tall, or sticks a column to the top, gives the bar its 36px; the others are just 36px longer. */
html.has-site-banner .study-page {
  min-height: calc(100vh - 36px);
}

html.has-site-banner .study-rail {
  top: 36px;
  height: calc(100vh - 36px);
  min-height: calc(100vh - 36px);
}

@media (min-height: 700px) {
  html.has-site-banner .study-page:not(.is-ranges) {
    height: calc(100vh - 36px);
  }
}

html.has-site-banner .practice-page,
html.has-site-banner .rail {
  height: calc(100vh - 36px);
}

html.has-site-banner .settings-nav,
html.has-site-banner .admin-nav {
  top: 36px;
  height: calc(100vh - 36px);
}

html.has-site-banner .settings-page,
html.has-site-banner .admin-page,
html.has-site-banner .progress-page,
html.has-site-banner .landing-page,
html.has-site-banner .legal-page,
html.has-site-banner .run-page,
html.has-site-banner .page-fallback,
html.has-site-banner .not-found-page,
html.has-site-banner .auth-page {
  min-height: calc(100vh - 36px);
}

html.has-site-banner .legal-bar {
  top: 36px;
}

html.has-site-banner .legal-toc {
  top: 124px;
}

/* ── the banner on the sign-in card ──────────────────────────────────── */
.signin-notice {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 16px 0 4px;
  border: 1px solid color-mix(in srgb, var(--accent-brand) 26%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, var(--accent-brand) 8%, var(--surface-sunken));
  padding: 10px 12px;
  text-align: left;
  animation: whatsnew-fade 240ms ease-out both;
}

.signin-notice.is-warning {
  border-color: color-mix(in srgb, var(--grade-warn) 30%, transparent);
  background: color-mix(in srgb, var(--grade-warn) 8%, var(--surface-sunken));
}

.signin-notice.is-maintenance {
  border-color: color-mix(in srgb, var(--grade-bad) 32%, transparent);
  background: color-mix(in srgb, var(--grade-bad) 9%, var(--surface-sunken));
}

.signin-notice-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  background: color-mix(in srgb, var(--accent-brand) 16%, transparent);
  color: var(--accent-brand);
}

.signin-notice.is-warning .signin-notice-icon {
  background: color-mix(in srgb, var(--grade-warn) 18%, transparent);
  color: var(--grade-warn);
}

.signin-notice.is-maintenance .signin-notice-icon {
  background: color-mix(in srgb, var(--grade-bad) 18%, transparent);
  color: var(--grade-bad);
}

.signin-notice p {
  margin: 2px 0 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-normal);
}

.signin-notice a {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-weight: 700;
  color: var(--accent-brand);
  text-decoration: none;
}

/* ── What's new ──────────────────────────────────────────────────────── */
/* above every page and below nothing it waits for: it opens only when no other window is up */
.whatsnew-backdrop {
  z-index: 90;
  padding: 24px;
  animation: whatsnew-fade 200ms ease-out both;
}

.whatsnew-backdrop.is-leaving {
  animation: whatsnew-fade-out 180ms ease-in both;   /* = LEAVE_MS in WhatsNew.tsx */
  pointer-events: none;
}

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

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

.whatsnew {
  position: relative;
  display: flex;
  width: 520px;
  max-width: 100%;
  max-height: calc(100vh - 48px);
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  background: #1d1d1d;
  box-shadow: 0 24px 90px rgba(0, 0, 0, 0.6);
  color: var(--text-normal);
  animation: whatsnew-in 340ms cubic-bezier(0.2, 0, 0, 1) both;
}

.whatsnew-backdrop.is-leaving .whatsnew {
  animation: whatsnew-out 180ms cubic-bezier(0.4, 0, 1, 1) both;
}

@keyframes whatsnew-in {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }
}

@keyframes whatsnew-out {
  to {
    opacity: 0;
    transform: translateY(10px) scale(0.985);
  }
}

.whatsnew-hero {
  position: relative;
  display: flex;
  flex: none;
  align-items: center;
  gap: 12px;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  background: #171717;
  padding: 16px 14px 16px 20px;
}

/* the amber light drifting slowly behind the mark */
.whatsnew-glow {
  position: absolute;
  top: -90px;
  left: -60px;
  width: 300px;
  height: 200px;
  border-radius: 50%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--accent-brand) 30%, transparent), transparent);
  pointer-events: none;
  animation: whatsnew-glow 4200ms ease-in-out infinite alternate;
}

@keyframes whatsnew-glow {
  from {
    opacity: 0.55;
    transform: translateX(0) scale(1);
  }
  to {
    opacity: 0.9;
    transform: translateX(46px) scale(1.12);
  }
}

.whatsnew-mark {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 11px;
  background: color-mix(in srgb, var(--accent-brand) 18%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-brand) 30%, transparent);
  color: var(--accent-brand);
}

.whatsnew-heading {
  position: relative;
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.whatsnew-heading span {
  font-size: 15px;
  font-weight: 800;
  color: var(--text-strong);
}

.whatsnew-heading small {
  font-size: 12px;
  color: var(--text-muted);
}

.whatsnew-close {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.whatsnew-close:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.whatsnew-body {
  min-height: 0;
  overflow-y: auto;
  padding: 20px 22px 6px;
  animation: whatsnew-fade 220ms ease-out both;
}

.whatsnew-body.is-list {
  padding: 14px 14px 6px;
}

.whatsnew-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
  font-size: 12px;
  color: var(--text-muted);
}

.whatsnew-version {
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent-brand) 16%, transparent);
  padding: 2px 9px;
  font-weight: 700;
  color: var(--accent-brand);
}

.whatsnew-title {
  margin: 0 0 16px;
  font-size: 20px;
  font-weight: 800;
  line-height: 1.3;
  color: var(--text-strong);
}

.whatsnew-items {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0 0 18px;
  padding: 0;
  list-style: none;
}

/* the lines come in one after another (--i: the line's place, WhatsNew.tsx) */
.whatsnew-item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  animation: whatsnew-item-in 380ms cubic-bezier(0.2, 0, 0, 1) both;
  animation-delay: calc(120ms + var(--i, 0) * 50ms);
}

@keyframes whatsnew-item-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

.whatsnew-item-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: var(--surface-raised);
  color: var(--accent-brand);
}

.whatsnew-item-text {
  padding-top: 5px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-normal);
}

.whatsnew-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 16px;
  font-size: 13px;
  font-weight: 700;
  color: var(--accent-brand);
  text-decoration: none;
}

.whatsnew-link:hover {
  text-decoration: underline;
}

.whatsnew-foot {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-top: 1px solid var(--line);
  padding: 12px 16px 12px 14px;
}

.whatsnew-earlier {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 32px;
  border: none;
  border-radius: 8px;
  background: transparent;
  padding: 0 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
}

.whatsnew-earlier:hover {
  background: var(--surface-hover);
  color: var(--text-strong);
}

.whatsnew-count,
.whatsnew-new {
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent-brand) 18%, transparent);
  padding: 1px 7px;
  font-size: 11px;
  font-weight: 800;
  color: var(--accent-brand);
  white-space: nowrap;
}

.whatsnew-count {
  margin-left: 2px;
}

.whatsnew-done {
  height: 34px;
  border: none;
  border-radius: 8px;
  background: var(--accent-brand);
  padding: 0 22px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-on-brand);
  cursor: pointer;
}

.whatsnew-done:hover {
  background: var(--accent-brand-hover);
}

/* the earlier updates: a row each, opened in place */
.whatsnew-history {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0 0 8px;
  list-style: none;
}

.whatsnew-history-row {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-panel);
}

.whatsnew-history-head {
  display: flex;
  width: 100%;
  align-items: center;
  gap: 10px;
  border: none;
  background: transparent;
  padding: 10px 12px 10px 14px;
  text-align: left;
  color: inherit;
  cursor: pointer;
}

.whatsnew-history-head:hover {
  background: var(--surface-hover);
}

.whatsnew-history-text {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.whatsnew-history-text strong {
  overflow: hidden;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-strong);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.whatsnew-history-text small {
  font-size: 12px;
  color: var(--text-muted);
}

.whatsnew-chevron {
  flex: none;
  color: var(--text-muted);
  transition: transform 200ms cubic-bezier(0.2, 0, 0, 1);
}

.whatsnew-history-row.is-open .whatsnew-chevron {
  transform: rotate(180deg);
}

.whatsnew-history-body {
  border-top: 1px solid var(--line);
  padding: 14px 14px 0;
  animation: whatsnew-item-in 260ms cubic-bezier(0.2, 0, 0, 1) both;
}

.whatsnew-history-body .whatsnew-meta {
  display: none;
}

.whatsnew-history-body .whatsnew-title {
  margin-bottom: 12px;
  font-size: 16px;
}

.whatsnew-history-body .whatsnew-items {
  gap: 10px;
  margin-bottom: 14px;
}

.whatsnew-empty {
  margin: 22px 0 18px;
  text-align: center;
  font-size: 13px;
  color: var(--text-muted);
}

/* the admin's preview: the card as it stands, in the column beside the form */
.whatsnew.is-preview {
  width: 100%;
  max-height: none;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
}

.whatsnew.is-preview .whatsnew-close,
.whatsnew.is-preview .whatsnew-done,
.whatsnew.is-preview .whatsnew-link {
  pointer-events: none;
}

/* ── the Announcements tab (pages/admin/AdminNotices.tsx) ────────────── */
.announce {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.announce-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: start;
  gap: 24px;
}

.announce-form {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 12px;
}

.announce-field {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 6px;
}

.announce-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-dim);
}

.announce-label small {
  margin-left: auto;
  font-weight: 600;
  color: var(--text-muted);
}

.announce-field input,
.announce-field textarea,
.announce-line input,
.announce-icon-pick select {
  width: 100%;
  height: 34px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface-sunken);
  padding: 0 10px;
  font: inherit;
  font-size: 13px;
  color: var(--text-strong);
  outline: none;
  color-scheme: dark;
}

.announce-field textarea {
  height: 58px;
  resize: none;
  padding: 8px 10px;
  line-height: 1.45;
}

.announce-field input:focus,
.announce-field textarea:focus,
.announce-line input:focus,
.announce-icon-pick select:focus {
  border-color: var(--accent-brand);
}

.announce-field input::placeholder,
.announce-field textarea::placeholder,
.announce-line input::placeholder {
  color: var(--text-muted);
}

.announce-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 12px;
}

.announce-pair.is-narrow-first {
  grid-template-columns: 170px minmax(0, 1fr);
}

.announce-hint {
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
}

.announce-field .admin-segments {
  align-self: flex-start;
}

.announce-switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  border-top: 1px solid var(--line);
  padding-top: 12px;
}

.announce-switch-text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}

.announce-switch-text strong {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
}

.announce-switch-text small {
  font-size: 12px;
  color: var(--text-muted);
}

/* the lines of an update: icon, text, remove */
.announce-lines {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.announce-line {
  display: grid;
  grid-template-columns: 136px minmax(0, 1fr) 32px;
  align-items: center;
  gap: 8px;
}

.announce-icon-pick {
  position: relative;
  display: block;
}

.announce-icon-tile {
  position: absolute;
  top: 6px;
  left: 6px;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: var(--surface-raised);
  color: var(--accent-brand);
  pointer-events: none;
}

.announce-icon-pick select {
  padding-left: 34px;
  cursor: pointer;
}

.announce-add {
  align-self: flex-start;
}

/* the previews */
.announce-preview {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 12px;
}

.announce-preview-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* a page in miniature under the bar: the rail, the node strip, the matrix and the panels */
.announce-preview-page {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-page);
}

.announce-preview-shell {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) 92px;
  grid-template-rows: 22px 120px;
  gap: 8px;
  padding: 0 10px 10px 0;
}

.announce-preview-shell i {
  border-radius: 6px;
  background: var(--surface-panel);
}

.announce-preview-shell .is-rail {
  grid-row: 1 / 3;
  border-radius: 0;
  background: var(--surface-rail);
}

.announce-preview-shell .is-strip {
  grid-column: 2 / 4;
  margin-top: 8px;
}

.announce-preview-shell .is-matrix {
  background: linear-gradient(135deg, color-mix(in srgb, var(--action-aggressive) 30%, var(--surface-panel)),
    color-mix(in srgb, var(--action-passive) 26%, var(--surface-panel)) 55%, color-mix(in srgb, var(--action-fold) 30%, var(--surface-panel)));
  opacity: 0.8;
}

.announce-preview-signin {
  display: flex;
  flex-direction: column;
  align-items: center;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  background: var(--surface-panel);
  padding: 18px 20px 16px;
  text-align: center;
}

.announce-preview-signin strong {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}

.announce-preview-signin .signin-notice {
  align-self: stretch;
  margin: 12px 0;
}

.announce-preview-google {
  display: block;
  width: 100%;
  border-radius: 8px;
  background: var(--text-strong);
  padding: 8px 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--surface-page);
}

/* the list of updates */
.announce-editor {
  margin-bottom: 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-sunken);
  padding: 16px;
  animation: whatsnew-item-in 240ms cubic-bezier(0.2, 0, 0, 1) both;
}

.announce-releases {
  display: flex;
  flex-direction: column;
}

.announce-release {
  display: grid;
  grid-template-columns: 82px minmax(0, 1fr) auto 32px auto;
  align-items: center;
  gap: 12px;
  border-top: 1px solid var(--line);
  padding: 10px 0;
}

.announce-release:first-child {
  border-top: none;
}

.announce-release.is-editing {
  opacity: 0.5;
}

.announce-release .admin-badge {
  justify-self: start;
}

.announce-release-text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}

.announce-release-text strong {
  display: flex;
  align-items: center;
  gap: 8px;
  overflow: hidden;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-strong);
  white-space: nowrap;
}

.announce-release-text small {
  overflow: hidden;
  font-size: 12px;
  color: var(--text-muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.announce-newest {
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent-brand) 16%, transparent);
  padding: 1px 7px;
  font-size: 11px;
  font-style: normal;
  font-weight: 800;
  color: var(--accent-brand);
}

.announce-release-time {
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
}

.announce-release .admin-button.is-danger {
  min-width: 32px;
  padding: 0 10px;
}

/* ── Beta features in a user's drawer (pages/admin/AdminBeta.tsx) ─────── */
.beta-features {
  display: flex;
  flex-direction: column;
}

.beta-feature {
  display: flex;
  align-items: center;
  gap: 12px;
  border-top: 1px solid var(--line);
  padding: 10px 0;
}

.beta-feature:first-child {
  border-top: none;
  padding-top: 2px;
}

.beta-feature-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--ai-accent) 16%, transparent);
  color: var(--ai-accent);
}

.beta-feature-text {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.beta-feature-text strong {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
}

.beta-feature-text small {
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-muted);
}

@media (max-width: 1100px) {
  .announce-split {
    grid-template-columns: minmax(0, 1fr);
  }
}
