/* Poker Table - fast opponent tagging.
   Visual language follows the PurePoker client: deep navy, glossy plates,
   gold for anything that represents money, blue felt with a lit centre. */

:root {
  --bg-0:      #050912;
  --bg-1:      #0a1120;
  --panel:     #111a2b;
  --panel-2:   #16202f;
  --plate-hi:  #333941;
  --plate-lo:  #1a1e24;
  --line:      #223047;
  --line-soft: #1a2537;

  --text:      #eaf1fa;
  --text-dim:  #7d8ea5;
  --gold:      #f2c74a;
  --accent:    #3b82f6;

  --felt-hi:   #1f5490;
  --felt-mid:  #17406f;
  --felt-lo:   #0f2a4c;
  --rail:      #080b12;

  /* Global motion scale. Every duration in the motion section at the foot of
     this file is calc()'d off it, so 0 kills all of it from one line. */
  --motion:    1;

  --station:   #2ea043;
  --spew:      #e2a53c;
  --trap:      #d64545;
  --nit:       #3b82f6;
  --reg:       #a371f7;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  color: var(--text);
  background: radial-gradient(ellipse 120% 80% at 50% -10%, #12203a 0%, var(--bg-1) 45%, var(--bg-0) 100%);
  font: 14px/1.45 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* ----------------------------------------------------------- topbar --- */

.topbar {
  display: flex;
  align-items: center;
  gap: 20px;
  height: 60px;
  padding: 0 18px;
  background: linear-gradient(180deg, rgba(22,32,47,.92), rgba(10,17,32,.92));
  border-bottom: 1px solid var(--line-soft);
  backdrop-filter: blur(20px);
  position: relative;
  z-index: 20;
}
.topbar::after {
  content: '';
  position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.07), transparent);
}



.controls { display: flex; align-items: center; gap: 13px; margin-left: auto; }
.ctl { display: flex; align-items: center; gap: 7px; font-size: 11px; color: var(--text-dim);
       text-transform: uppercase; letter-spacing: .07em; font-weight: 600; }

.ctl select, .ctl input {
  background: linear-gradient(180deg, #0d1421, #121b2b);
  border: 1px solid var(--line);
  color: var(--text);
  border-radius: 9px;
  padding: 7px 10px;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0;
  text-transform: none;
  box-shadow: inset 0 1px 3px rgba(0,0,0,.4);
}
.ctl input { width: 70px; }
.ctl select:focus, .ctl input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(59,130,246,.18); }

.btn {
  background: linear-gradient(180deg, #4f92ff, #2f6fd6);
  border: 1px solid #5b9bff;
  color: #fff;
  border-radius: 10px;
  padding: 8px 15px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(59,130,246,.32), inset 0 1px 0 rgba(255,255,255,.26);
  transition: filter .15s;
}
.btn:hover { filter: brightness(1.12); }
.btn:active { transform: translateY(1px); }
.btn.ghost {
  background: linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.02));
  border-color: var(--line);
  color: var(--text-dim);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
}
.btn.ghost:hover { color: var(--text); border-color: #2e405c; }

.status { font-size: 11.5px; color: var(--text-dim); white-space: nowrap; letter-spacing: .02em; }
.status.warn { color: var(--gold); }

/* ------------------------------------------------------------ layout --- */

.layout { display: flex; height: calc(100% - 60px); }

.tablewrap {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Seats hang outside the felt by a few percent plus half their own height,
     so this padding is the headroom that keeps the top and bottom players on
     screen. Shrink it and they get clipped. */
  padding: 86px 90px;
  min-width: 0;
  min-height: 0;
}

/* The felt: upright stadium, matching the PurePoker client - black rail,
   hairline inner ring, lit centre. Sized off available height so the
   portrait shape always fits. */
.felt {
  position: relative;
  /* 90%, not 100% - the table sits 10% smaller than the space allows, which
     buys breathing room around the seats and frees width for the chart column.
     Seat radii are percentages of the felt so they shrink with it; the chips
     and blind markers are measured at render time, so they follow. */
  height: 90%;
  aspect-ratio: 62 / 100;
  max-width: 100%;
  border-radius: 999px;
  background:
    radial-gradient(ellipse 86% 62% at 50% 40%, var(--felt-hi) 0%, var(--felt-mid) 54%, var(--felt-lo) 100%);
  border: 12px solid var(--rail);
  box-shadow:
    0 30px 70px rgba(0,0,0,.72),
    0 0 0 1px rgba(120,170,255,.10),
    inset 0 0 90px rgba(0,0,0,.42),
    inset 0 3px 22px rgba(150,200,255,.10);
}
/* inner hairline ring, like the client */
.felt::before {
  content: '';
  position: absolute; inset: 14px;
  border-radius: 999px;
  border: 1px solid rgba(160,200,255,.14);
  pointer-events: none;
}

.felt-center {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  pointer-events: none;
  user-select: none;
  width: 92%;
}
/* the house wordmark, etched into the felt rather than sitting on top of it */
.felt-center .logo {
  font-size: clamp(30px, 4.4vw, 62px);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1;
  text-shadow: 0 2px 0 rgba(0,0,0,.32), 0 0 34px rgba(120,180,255,.13);
}
.felt-center .logo .z { color: rgba(242,199,74,.82); }
.felt-center .logo .k { color: rgba(214,233,255,.72); }

.felt-center .suitrow {
  margin-top: 7px;
  display: flex; justify-content: center; gap: 11px;
  font-size: clamp(11px, 1.2vw, 16px);
  font-style: normal;
}
.felt-center .suitrow i { font-style: normal; }
.felt-center .suitrow .s { color: rgba(190,215,255,.3); }
.felt-center .suitrow .r { color: rgba(226,110,110,.42); }

.felt-center .stake {
  margin-top: 16px;
  font-size: 12.5px;
  color: rgba(160,195,240,.44);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: capitalize;
}
.felt-center .stake .pot {
  display: block;
  margin-top: 4px;
  color: var(--gold);
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -.01em;
  text-transform: none;
}
.felt-center .stake .pot.dim {
  color: rgba(150,185,230,.34);
  font-size: 12px;
  font-weight: 600;
}

/* -------------------------------------------------------------- seats --- */

.seat {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 124px;
  cursor: pointer;
  text-align: center;
  user-select: none;
  /* Opacity is here so folding fades - see the motion section at the foot. */
  transition: transform .14s cubic-bezier(.2,.8,.3,1),
              opacity calc(var(--motion) * 260ms) ease-out;
}
.seat:hover { transform: translate(-50%, -50%) scale(1.055); z-index: 6; }
.seat.selected { z-index: 7; }

/* avatar disc */
.seat .av {
  width: 58px; height: 58px;
  margin: 0 auto -14px;
  border-radius: 50%;
  background: linear-gradient(160deg, #2c3a52, #16202f);
  border: 2px solid #3a4a63;
  box-shadow: 0 5px 16px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.14);
  display: flex; align-items: center; justify-content: center;
  font-size: 21px; font-weight: 700; color: #93a8c4;
  position: relative; z-index: 2;
  overflow: hidden;
}
.seat .av::after {   /* gloss highlight */
  content: '';
  position: absolute; inset: 0 0 52% 0;
  background: linear-gradient(180deg, rgba(255,255,255,.16), transparent);
  border-radius: 50% 50% 42% 42% / 60% 60% 40% 40%;
}

/* dark nameplate */
.seat .plate {
  position: relative;
  padding: 15px 9px 5px;
  border-radius: 8px;
  background: linear-gradient(180deg, var(--plate-hi), var(--plate-lo));
  border: 1px solid rgba(255,255,255,.13);
  box-shadow: 0 5px 16px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.13);
}
.seat .alias {
  font-size: 12.5px; font-weight: 600; color: #f0f4fa;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-shadow: 0 1px 2px rgba(0,0,0,.6);
}
/* gold line, where the client puts the stack */
.seat .sub {
  margin-top: 3px;
  padding-top: 4px;
  border-top: 1px solid rgba(255,255,255,.09);
  font-size: 11.5px; font-weight: 700; color: var(--gold);
  letter-spacing: .02em;
}
.seat .sub .vp { color: #6f7f96; font-weight: 600; font-size: 10.5px; margin-left: 6px; }
.seat .sub .vp.dim { color: #5b6a80; font-weight: 500; }
.seat .sub.dim { color: #6f7f96; font-weight: 500; }

/* the stack, double-click to edit */
.seat .stk { color: var(--gold); font-weight: 800; cursor: text; }
.seat .stkedit {
  width: 62px;
  background: #0b1220;
  border: 1px solid var(--accent);
  border-radius: 5px;
  color: var(--text);
  font-size: 11.5px;
  font-weight: 800;
  line-height: 1.3;
  text-align: center;
  padding: 1px 3px;
}
.seat .stkedit:focus { outline: none; }
.seat.hero .heroline { display: flex; align-items: center; justify-content: center; gap: 7px; margin-top: 4px; }
.seat.hero .heroline .stk { font-size: 11.5px; }

/* Tag chip sits under the plate, and only exists once there's a tag. An
   "untagged" label on every unknown player is noise on a full table - the
   absence of a chip says the same thing without taking up room. */
.seat .tagchip {
  display: inline-block;
  padding: 3px 11px;
  border-radius: 6px;
  font-size: 9.5px; font-weight: 800; letter-spacing: .1em;
  color: #fff;
  box-shadow: 0 3px 10px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,255,255,.28);
}

/* empty seat - no nameplate at all, just a small quiet disc, the way an
   empty chair reads at a real table */
.seat.empty .av {
  width: 43.5px; height: 43.5px;
  margin: 0 auto;
  background: rgba(6,14,26,.4);
  border: 1px solid rgba(150,190,240,.26);
  box-shadow: none;
  color: rgba(150,190,240,.4);
  font-size: 16.5px; font-weight: 300;
}
.seat.empty .av::after { display: none; }
.seat.empty:hover .av {
  border-color: rgba(150,190,240,.55);
  color: rgba(190,215,245,.75);
}
.seat.empty.selected .av {
  border-color: #5b9bff;
  box-shadow: 0 0 0 3px rgba(59,130,246,.26);
}

/* Hero's position. Lives inside the nameplate rather than under it - hero
   sits at the bottom of the felt, and anything below the plate pushes off
   the edge of the screen. Kept very light: it's orientation, not something
   you read every hand. */
/* Position chip - one per seated player, hero included, all identical. Tucked
   into the top-right corner of the plate rather than onto the stack/VPIP line,
   which already has two items and wraps on the longer labels like UTG+1.
   Top-left is where the hole cards sit, so top-right it is. */
.seat .poschip {
  position: absolute;
  top: -8px; right: 7px;
  padding: 1px 7px;
  border-radius: 6px;
  background: linear-gradient(180deg, #273649, #1a2534);
  border: 1px solid rgba(255,255,255,.15);
  color: rgba(198,212,232,.74);
  font-size: 9px; font-weight: 700; letter-spacing: .08em;
  box-shadow: 0 2px 7px rgba(0,0,0,.5);
  z-index: 3;
}
/* Folded seats dim as a whole, and the chip should go with them. */
.seat.folded .poschip { opacity: .4; }

/* hero */
.seat.hero .plate {
  border-color: rgba(163,113,247,.72);
  box-shadow: 0 5px 20px rgba(120,70,220,.34), inset 0 1px 0 rgba(255,255,255,.14);
}
.seat.hero .av { border-color: rgba(163,113,247,.66); color: #c9b0f7; }

/* selection ring */
.seat.selected .plate {
  border-color: #5b9bff;
  box-shadow: 0 0 0 3px rgba(59,130,246,.26), 0 6px 20px rgba(59,130,246,.32), inset 0 1px 0 rgba(255,255,255,.16);
}
.seat.selected .av { border-color: #5b9bff; }

/* tag-coloured avatar ring */
.seat.t-STATION .av { border-color: var(--station); box-shadow: 0 0 14px rgba(46,160,67,.42), inset 0 1px 0 rgba(255,255,255,.14); }
.seat.t-SPEW    .av { border-color: var(--spew);    box-shadow: 0 0 14px rgba(226,165,60,.42), inset 0 1px 0 rgba(255,255,255,.14); }
.seat.t-TRAP    .av { border-color: var(--trap);    box-shadow: 0 0 14px rgba(214,69,69,.42),  inset 0 1px 0 rgba(255,255,255,.14); }
.seat.t-NIT     .av { border-color: var(--nit);     box-shadow: 0 0 14px rgba(59,130,246,.42), inset 0 1px 0 rgba(255,255,255,.14); }
.seat.t-REG     .av { border-color: var(--reg);     box-shadow: 0 0 14px rgba(163,113,247,.42),inset 0 1px 0 rgba(255,255,255,.14); }

.tag-STATION { background: linear-gradient(180deg, #38c455, #1f8a36); }
.tag-SPEW    { background: linear-gradient(180deg, #f0b855, #c8892a); }
.tag-TRAP    { background: linear-gradient(180deg, #e85c5c, #b83333); }
.tag-NIT     { background: linear-gradient(180deg, #5b9bff, #2f6fd6); }
.tag-REG     { background: linear-gradient(180deg, #b78bff, #8b5cf0); }

/* position badges (BB / SB / D) */
.posbadge {
  position: absolute;
  width: 25px; height: 25px;
  border-radius: 50%;
  font-size: 9.5px; font-weight: 800; line-height: 25px; text-align: center;
  transform: translate(-50%, -50%);
  z-index: 4;
  box-shadow: 0 3px 9px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.35);
  pointer-events: none;
}
.posbadge.d  { background: linear-gradient(180deg, #fdfdfd, #c9d2dd); color: #16202f; }
.posbadge.sb { background: linear-gradient(180deg, #6fa8ff, #3b7fe0); color: #fff; }
.posbadge.bb { background: linear-gradient(180deg, #6fa8ff, #3b7fe0); color: #fff; }

/* ------------------------------------------------------------ sidebar --- */

/* ------------------------------------------------ hero range column --- */

/* Sits between the felt and the tag sidebar. Shows the chart for whatever
   position hero is in, recomputed from the button on every felt render. */
/* Deliberately a floating card rather than a flush panel - it sits on its
   own border with dark space either side so it doesn't read as part of the
   tag sidebar next to it. */
/* Hand on the left, chart on the right, side by side between the felt and
   the tag sidebar. */
.rightstack {
  flex-shrink: 0;
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 14px;
  margin: 18px 16px 18px 0;
  max-height: calc(100% - 36px);
  min-height: 0;
}

/* Wide enough for a hand-history line. At 232px the replay list truncated
   every player name to "Tmo..." and the text panel showed about half a line;
   340 fits a name, and fits most of a hand-history line without scrolling. */
.leftstack {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: 340px;
  flex-shrink: 0;
  min-height: 0;
}

.rangecol, .dealcol, .actioncol, .replaycol {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 18px 16px;
  flex-shrink: 0;
}
/* The 13x13 grid is sized off this column, so the column width IS the chart
   size - widening it is the only way to grow the chart, and the surrounding
   text was shrunk below to pay for it.
   322 -> 402 (+25% cells) -> 456 (+15% again). Cells are now ~31.5px. */
.rangecol { width: 456px; overflow-y: auto; max-height: 100%; }
.dealcol, .actioncol, .replaycol { width: 100%; }

/* ------------------------------------------------------------- roller --- */

/* Standalone 1-100 die, sat to the left of "Your hand". Deliberately dumb:
   it knows nothing about charts or frequencies, it just gives you a number.
   The chart-aware roll lives inside the hand module and settles itself. */
/* The die and the Next button. No panel, no captions - each button carries its
   own border and its tooltip says what it does. Sized to its contents so it
   takes no more width than it needs. */
.rollcol {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

/* Ends the hand and moves the button one seat - the between-hands action, so
   it sits right where your cursor already is after rolling. */
.nextbtn {
  width: 72px;
  padding: 8px 0;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(255,255,255,.055), rgba(255,255,255,.012));
  color: var(--text-dim);
  cursor: pointer;
  font-size: 10px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: .1em;
  text-transform: uppercase;
  transition: color .15s, border-color .15s, background .15s;
}
.nextbtn:hover {
  color: var(--text);
  border-color: var(--accent);
  background: rgba(59,130,246,.15);
}
.nextbtn:active { transform: translateY(1px); }
.rolldie {
  width: 72px;
  height: 72px;
  display: grid;
  place-items: center;
  padding: 0;
  cursor: pointer;
  border: 1px solid #2e405c;
  border-radius: 18px;
  background: linear-gradient(160deg, var(--plate-hi), var(--plate-lo));
  box-shadow: 0 6px 16px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,255,255,.14);
  transition: border-color .15s ease;
}
.rolldie:hover { border-color: var(--accent); }
.rolldie:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(59,130,246,.28); }
.rollnum {
  font: 700 27px/1 ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.rollnum.idle { color: var(--text-dim); }

/* Tumble while it's in the air, one bounce as it lands. */
.rolldie.tumbling { animation: dietumble .3s linear infinite; }
.rolldie.tumbling .rollnum { color: var(--gold); }
@keyframes dietumble {
  0%   { transform: rotate(0deg)  scale(1);    }
  25%  { transform: rotate(-8deg) scale(1.06); }
  50%  { transform: rotate(0deg)  scale(.96);  }
  75%  { transform: rotate(8deg)  scale(1.06); }
  100% { transform: rotate(0deg)  scale(1);    }
}
.rolldie.settled { animation: diesettle .4s cubic-bezier(.18,.9,.3,1.5); }
@keyframes diesettle {
  0%   { transform: scale(1.2); }
  55%  { transform: scale(.95); }
  100% { transform: scale(1);   }
}
@media (prefers-reduced-motion: reduce) {
  .rolldie.tumbling, .rolldie.settled { animation: none; }
}

.rangecol .cell { font-size: 13px; }
.rangecol::-webkit-scrollbar { width: 8px; }
.rangecol::-webkit-scrollbar-thumb { background: #23324a; border-radius: 4px; }

.rzhead { display: flex; align-items: center; justify-content: space-between; margin-bottom: 2px; }
.rzpos { font-size: 16px; font-weight: 800; letter-spacing: -.02em; color: var(--text); }
.rznode { font-size: 9.5px; color: var(--text-dim); text-transform: uppercase; letter-spacing: .08em; }

.rznav { display: flex; gap: 6px; }
.rzarrow {
  width: 21px; height: 21px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.045);
  color: var(--text-dim);
  cursor: pointer;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.rzarrow:hover { background: rgba(255,255,255,.1); color: var(--text); border-color: var(--accent); }
.rzarrow:active { transform: translateY(1px); }
.rzsub { color: var(--text-dim); font-size: 10px; line-height: 1.45; margin-bottom: 9px; }

.rzpct { color: var(--station); font-weight: 800; }
.rzpct.raise { color: #e0736f; }
.rzsize { color: var(--gold); font-weight: 800; }

.rzflag {
  margin-top: 8px;
  padding: 6px 8px;
  border-radius: 7px;
  border: 1px solid rgba(226,165,60,.28);
  background: rgba(226,165,60,.08);
  color: #d9bd83;
  font-size: 9.5px;
  line-height: 1.5;
}

/* someone has re-raised and the chart on screen is the wrong node */
.rzflag.warn {
  border-color: rgba(214,69,69,.42);
  background: rgba(214,69,69,.11);
  color: #edA0a0;
  margin: 11px 0;
}
.rzflag.warn em { color: #fff; font-style: normal; font-weight: 800; }
.dlverdict.warn {
  background: rgba(214,69,69,.13); border: 1px solid rgba(214,69,69,.4);
  color: #edA0a0; margin-bottom: 8px;
}

/* a real chart is no longer a warning, just a note */
.rzflag.ok {
  border-color: rgba(46,160,67,.26);
  background: rgba(46,160,67,.07);
  color: #93b79c;
}

/* mixed frequency - partially filled from the bottom */
.cell.rz-mix { color: #cfe6d6; font-weight: 700; }

.rzempty { color: var(--text-dim); font-size: 12.5px; line-height: 1.7; }

/* --------------------------------------------------- chips and cards --- */

/* one universal chip, the amount sits beside it */
.chip {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex; align-items: center; gap: 5px;
  z-index: 5;
  pointer-events: none;
}
.chip i {
  width: 17px; height: 17px; border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, #f4f7fb 0%, #cfd8e6 42%, #93a1b5 100%);
  border: 2px solid #6d7a8d;
  box-shadow: 0 2px 6px rgba(0,0,0,.6);
  display: block;
}
.chip b {
  font-size: 11.5px; font-weight: 800; color: var(--gold);
  text-shadow: 0 1px 3px rgba(0,0,0,.9);
}
.chip b .u { font-size: 8.5px; font-weight: 700; opacity: .72; margin-left: 1px; }

/* Hole cards tuck into the top-left of the nameplate, beside the avatar, so
   they read as part of the player card. Overlapped slightly and tilted, the
   way cards actually sit on a table. */
.seat .holecards {
  position: absolute;
  left: 0; top: 10px;
  display: flex; align-items: flex-start;
  z-index: 3;
  pointer-events: none;
}
/* Fanned from the left, so the card underneath keeps its whole left edge.
   The two are tilted in opposite directions and the back one sits a touch
   lower, which is what makes a pair of cards read as a fan rather than as one
   card with a smudge behind it. */
.seat .holecards > * { transform-origin: bottom left; }
.seat .holecards > *:first-child {
  transform: rotate(-9deg) translateY(2px);
  margin-right: -12px;
}
.seat .holecards > *:last-child { transform: rotate(6deg); }

.cardback {
  width: 26px; height: 36px; border-radius: 5px;
  background:
    repeating-linear-gradient(45deg, #2b3f66 0 3px, #223354 3px 6px);
  border: 1px solid #4d5f85;
  box-shadow: 0 2px 7px rgba(0,0,0,.55);
}

/* The card face on the felt is NOT the centred one from the deal panel.
   Overlapped cards only show the leading edge of the card underneath, so the
   rank has to live in the top-left corner the way a real index does -- centred
   pips vanish the moment anything covers them. */
.seat .holecards .dlcard {
  width: 26px; height: 36px;
  border-radius: 5px;
  align-items: flex-start; justify-content: flex-start;
  padding: 2px 0 0 3px;
  gap: 0;
  border: 1px solid rgba(255,255,255,.28);
  font-size: 12.5px;
  font-weight: 800;
  line-height: 1;
  box-shadow: 0 2px 7px rgba(0,0,0,.55);
}
.seat .holecards .dlcard .su {
  font-size: 11px;
  margin: -1px 0 0 -1px;
  line-height: 1;
}
/* The top card lifts clear of the one behind it. */
.seat .holecards > *:last-child { box-shadow: -2px 3px 9px rgba(0,0,0,.6); }
.seat.folded { opacity: .34; }
.seat.toact .plate { border-color: #5b9bff; box-shadow: 0 0 0 3px rgba(59,130,246,.3); }

/* -------------------------------------------------------- action bar --- */

.abar { display: flex; flex-direction: column; gap: 8px; }
.ahead { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.areset {
  padding: 4px 9px;
  border-radius: 7px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.areset:hover { color: #e08b8b; border-color: rgba(214,69,69,.45); background: rgba(214,69,69,.08); }
.abrow { display: flex; gap: 7px; }
.abrow .abtn { flex: 1; }
/* Where the Deal button used to be. Dealing moved to Enter in the hand box,
   so this panel points at it rather than offering a second way to do it. */
.abhint { margin-top: 9px; font-size: 11px; color: var(--text-dim); line-height: 1.5; }
.abhint kbd {
  display: inline-block;
  padding: 1px 6px; margin: 0 1px;
  border: 1px solid var(--line); border-bottom-width: 2px;
  border-radius: 5px;
  background: rgba(255,255,255,.06);
  color: var(--text);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
}
.abar .who { font-size: 14px; font-weight: 800; color: var(--text); }
.abar .meta { font-size: 11px; color: var(--text-dim); line-height: 1.5; }
.abtn {
  padding: 9px 15px; border-radius: 9px;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.05);
  color: var(--text); cursor: pointer;
  font-size: 12.5px;
  font-weight: 800;
  line-height: 1;
}
.abtn:hover { background: rgba(255,255,255,.11); border-color: var(--accent); }
.abtn.fold  { border-color: rgba(214,69,69,.4);  color: #e08b8b; }
.abtn.check { border-color: rgba(46,160,67,.4);  color: #7fd08e; }
.abtn.raise { border-color: rgba(242,199,74,.42); color: var(--gold); }
.abtn.go    { background: var(--accent); border-color: var(--accent); color: #fff; }
.abar input {
  flex: 1; min-width: 0;
  background: #0b1220; border: 1px solid var(--line);
  border-radius: 8px; color: var(--text); padding: 8px 9px;
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1; text-align: center;
}
.abar input.wide { letter-spacing: .06em; }
.abar input:focus { outline: none; border-color: var(--accent); }
.abar .err { color: #e08b8b; font-size: 11.5px; font-weight: 700; }

/* ------------------------------------------------------ deal a hand --- */

.dlrow { display: flex; gap: 8px; align-items: center; }
.dlinput {
  flex: 1; min-width: 0;
  background: linear-gradient(180deg, #0b1220, #101a29);
  border: 1px solid var(--line);
  border-radius: 9px;
  color: var(--text);
  padding: 9px 11px;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: .06em;
}
.dlinput:focus { outline: none; border-color: var(--accent); }
.dlinput::placeholder { color: #4d5c72; letter-spacing: .02em; font-weight: 400; }

.dlbtn {
  padding: 9px 13px;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.05);
  color: var(--text);
  cursor: pointer;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
}
.dlbtn:hover { background: rgba(255,255,255,.1); border-color: var(--accent); }
/* Enter starts a hand, so it reads as the primary action rather than a
   neutral one - it's the button you press every single hand. */
.dlbtn.go {
  background: linear-gradient(180deg, #38c455, #1f8a36);
  border-color: #45d267; color: #04170a;
  box-shadow: 0 2px 10px rgba(46,160,67,.3), inset 0 1px 0 rgba(255,255,255,.26);
}
.dlbtn.go:hover { filter: brightness(1.1); background: linear-gradient(180deg, #38c455, #1f8a36); }
.dlbtn.go:active { transform: translateY(1px); }

.dlcards { display: flex; gap: 6px; align-items: center; margin: 13px 0 10px; }
/* Four-colour deck, matching the client these hands are read from: the face
   carries the suit and the index is white on top of it. Four ranks on four
   identical white cards is the slowest thing to read on a felt; colour tells
   you the suit before you have focused on the pip. */
.dlcard {
  width: 34px; height: 46px;
  border-radius: 6px;
  background: var(--suit, #3a4761);
  color: #fff;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  font-size: 15px;
  font-weight: 800;
  line-height: 1;
  box-shadow: 0 3px 10px rgba(0,0,0,.5);
  text-shadow: 0 1px 2px rgba(0,0,0,.35);
}
.dlcard.sc { --suit: linear-gradient(158deg, #35ad57, #1f7d3b); }
.dlcard.sh { --suit: linear-gradient(158deg, #cf3049, #98172e); }
.dlcard.sd { --suit: linear-gradient(158deg, #3585db, #1c5aa8); }
.dlcard.ss { --suit: linear-gradient(158deg, #2b3352, #141829); }
/* `.red` no longer colours anything -- the face does. Kept because other rules
   still key off it. */
.dlcard.red { color: #fff; }
.dlcard .su { font-size: 13px; margin-top: 1px; opacity: .96; }
.dllabel { margin-left: 6px; font-size: 17px; font-weight: 800; color: var(--text); }

.dlverdict {
  padding: 10px 12px;
  border-radius: 9px;
  font-size: 13px; font-weight: 700;
  line-height: 1.5;
}
.dlverdict.open { background: rgba(46,160,67,.13); border: 1px solid rgba(46,160,67,.34); color: #7fd08e; }
.dlverdict.fold { background: rgba(214,69,69,.1);  border: 1px solid rgba(214,69,69,.28); color: #e08b8b; }
.dlverdict.mix  { background: rgba(226,165,60,.1); border: 1px solid rgba(226,165,60,.3);  color: #e0bd7e; }
.dlverdict small { display: block; font-weight: 500; font-size: 11.5px; margin-top: 3px; opacity: .82; }

.dlroll { display: flex; gap: 8px; align-items: center; margin-top: 9px; }
.dlrolled { font-size: 11.5px; color: var(--text-dim); }
.dlrolled b { color: var(--text); }

.dlhint { color: var(--text-dim); font-size: 11.5px; line-height: 1.6; margin-top: 10px; }

.sidebar {
  width: 352px;
  flex-shrink: 0;
  background: linear-gradient(180deg, rgba(17,26,43,.96), rgba(8,14,26,.96));
  border-left: 1px solid var(--line-soft);
  padding: 22px;
  overflow-y: auto;
  backdrop-filter: blur(20px);
  transition: width .18s cubic-bezier(.2,.8,.3,1),
              padding .18s cubic-bezier(.2,.8,.3,1);
}

/* Collapsed: the panel goes to nothing and the felt takes the space. Width
   rather than display:none so it animates, and the content is clipped rather
   than reflowed - a 352px panel reflowing to 0 makes the grids jump. */
body.side-collapsed .sidebar {
  width: 0;
  padding-left: 0; padding-right: 0;
  border-left: none;
  overflow: hidden;
}

/* The handle. A sibling of the panel, not inside it, so it survives the
   sidebar's innerHTML being replaced on every render. */
.sidetoggle {
  flex-shrink: 0;
  width: 15px;
  border: none;
  border-left: 1px solid var(--line-soft);
  background: linear-gradient(180deg, rgba(22,32,47,.9), rgba(10,17,32,.9));
  color: var(--text-dim);
  cursor: pointer;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  padding: 0;
  display: flex; align-items: center; justify-content: center;
  transition: color .15s, background .15s;
}
.sidetoggle:hover { color: var(--text); background: rgba(59,130,246,.16); }
.sidetoggle::before { content: '\203A'; font-size: 15px; }          /* > */
body.side-collapsed .sidetoggle::before { content: '\2039'; }        /* < */
.sidebar::-webkit-scrollbar { width: 8px; }
.sidebar::-webkit-scrollbar-thumb { background: #23324a; border-radius: 4px; }

.sidebar h2 { margin: 0 0 5px; font-size: 19px; font-weight: 700; letter-spacing: -.01em; }
.sidebar .sub { color: var(--text-dim); font-size: 11.5px; margin-bottom: 18px; }

.hint { color: #a6b6cc; font-size: 13px; line-height: 1.7; }
.hint b { color: var(--text); }

.taggrid { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; margin: 6px 0 10px; }

.tagbtn {
  padding: 13px 8px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(255,255,255,.055), rgba(255,255,255,.012));
  color: var(--text);
  cursor: pointer;
  font-size: 13px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: .06em;
  text-align: center;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
  transition: all .15s ease;
}
.tagbtn small { display: block; font-weight: 500; font-size: 10px; color: var(--text-dim); margin-top: 4px; letter-spacing: 0; }
.tagbtn:hover { border-color: #33455f; transform: translateY(-1px); }
.tagbtn:active { transform: translateY(0); }
.tagbtn.wide { grid-column: 1 / -1; }

.tagbtn.on { color: #fff; border-color: transparent; box-shadow: inset 0 1px 0 rgba(255,255,255,.3); }
.tagbtn.on.b-STATION { background: linear-gradient(180deg, #38c455, #1f8a36); box-shadow: 0 4px 16px rgba(46,160,67,.36), inset 0 1px 0 rgba(255,255,255,.3); }
.tagbtn.on.b-SPEW    { background: linear-gradient(180deg, #f0b855, #c8892a); color: #241a04; box-shadow: 0 4px 16px rgba(226,165,60,.36), inset 0 1px 0 rgba(255,255,255,.4); }
.tagbtn.on.b-TRAP    { background: linear-gradient(180deg, #e85c5c, #b83333); box-shadow: 0 4px 16px rgba(214,69,69,.36), inset 0 1px 0 rgba(255,255,255,.3); }
.tagbtn.on.b-NIT     { background: linear-gradient(180deg, #5b9bff, #2f6fd6); box-shadow: 0 4px 16px rgba(59,130,246,.36), inset 0 1px 0 rgba(255,255,255,.3); }
.tagbtn.on.b-REG     { background: linear-gradient(180deg, #b78bff, #8b5cf0); box-shadow: 0 4px 16px rgba(163,113,247,.36), inset 0 1px 0 rgba(255,255,255,.3); }
.tagbtn.on small { color: rgba(255,255,255,.8); }
.tagbtn.on.b-SPEW small { color: rgba(0,0,0,.55); }

.exploit {
  background: linear-gradient(180deg, rgba(255,255,255,.045), rgba(255,255,255,.012));
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 11px;
  padding: 12px 14px;
  font-size: 12.5px;
  line-height: 1.6;
  margin: 12px 0 18px;
  color: #c3d2e4;
}
.exploit.none { border-left-color: #2c3b52; color: var(--text-dim); }

.field { margin-bottom: 13px; }
.field label { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .1em;
               color: var(--text-dim); margin-bottom: 6px; font-weight: 700; }

.field input, .field textarea {
  width: 100%;
  background: linear-gradient(180deg, #0b1220, #101a29);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  padding: 9px 11px;
  font-size: 13px;
  font-weight: 400;
  line-height: 1.5;
  resize: vertical;
  box-shadow: inset 0 1px 4px rgba(0,0,0,.42);
}
.field input:focus, .field textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(59,130,246,.16), inset 0 1px 4px rgba(0,0,0,.42); }
.field input::placeholder, .field textarea::placeholder { color: #536479; }

.row { display: flex; gap: 10px; }
.row .field { flex: 1; }


.legend { margin-top: 20px; border-top: 1px solid var(--line-soft); padding-top: 16px; }
.legend .li { display: flex; gap: 11px; align-items: flex-start; margin-bottom: 14px; font-size: 12px; }
.legend .sw { width: 12px; height: 12px; border-radius: 4px; flex-shrink: 0; margin-top: 3px;
              box-shadow: inset 0 1px 0 rgba(255,255,255,.3); }
.legend b { display: block; font-size: 11.5px; letter-spacing: .07em; margin-bottom: 2px; }
.legend span { color: var(--text-dim); line-height: 1.55; }

/* ------------------------------------------------------------- picker --- */

.picker {
  position: fixed;
  z-index: 40;
  width: 300px;
  background: linear-gradient(180deg, rgba(20,30,48,.99), rgba(10,17,30,.99));
  border: 1px solid #26364e;
  border-radius: 15px;
  box-shadow: 0 22px 60px rgba(0,0,0,.78), inset 0 1px 0 rgba(255,255,255,.08);
  overflow: hidden;
  backdrop-filter: blur(24px);
}
.picker input {
  width: 100%;
  border: none;
  border-bottom: 1px solid var(--line-soft);
  background: rgba(0,0,0,.28);
  color: var(--text);
  padding: 13px 15px;
  font-size: 14px;
  font-weight: 400;
  line-height: 1;
}
.picker input:focus { outline: none; }
.picker input::placeholder { color: #536479; }

.picker-list { max-height: 296px; overflow-y: auto; }
.picker-list::-webkit-scrollbar { width: 7px; }
.picker-list::-webkit-scrollbar-thumb { background: #23324a; border-radius: 4px; }

.pick {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 15px;
  cursor: pointer;
  border-bottom: 1px solid rgba(26,37,55,.55);
}
.pick:hover, .pick.cursor { background: rgba(59,130,246,.13); }
.pick .nm { flex: 1; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick .tg { font-size: 8.5px; font-weight: 800; padding: 3px 7px; border-radius: 5px; color: #fff; letter-spacing: .08em;
            box-shadow: inset 0 1px 0 rgba(255,255,255,.28); }
.pick .hl { font-size: 10.5px; color: #5d6f86; min-width: 14px; text-align: right; }
.pick.seated { opacity: .32; }

.picker-foot { display: flex; gap: 9px; padding: 11px 13px; border-top: 1px solid var(--line-soft); background: rgba(0,0,0,.2); }
.picker-foot .btn { flex: 1; }

/* ------------------------------------------------------------- toasts --- */

.toast-stack { position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%);
               z-index: 60; display: flex; flex-direction: column; gap: 8px; align-items: center; }

.toast {
  background: linear-gradient(180deg, rgba(24,34,52,.98), rgba(12,20,34,.98));
  border: 1px solid #2a3a54;
  border-left: 3px solid var(--station);
  padding: 11px 20px;
  border-radius: 12px;
  font-size: 13px; font-weight: 500;
  box-shadow: 0 12px 34px rgba(0,0,0,.66), inset 0 1px 0 rgba(255,255,255,.07);
  backdrop-filter: blur(18px);
  animation: rise .22s cubic-bezier(.2,.9,.3,1);
}
.toast.err { border-left-color: var(--trap); }
@keyframes rise { from { opacity: 0; transform: translateY(12px) scale(.96); } }

@media (max-width: 1240px) {
  .sidebar { width: 312px; }
  .tablewrap { padding: 70px 74px; }
  .seat { width: 106px; }
}
@media (max-height: 820px) {
  .tablewrap { padding: 66px 92px; }
  .seat { width: 106px; }
  .seat .av { width: 46px; height: 46px; font-size: 17px; margin-bottom: -12px; }
  .seat .plate { padding: 13px 8px 5px; }
  .felt-center .logo { font-size: 30px; }
  .felt-center .stake { margin-top: 10px; }
}

/* ------------------------------------------------------ sticky flags --- */

.flagbox { margin-bottom: 12px; }
.flagrow { display: flex; gap: 8px; }

/* The collapsed limp+call chip keeps this class, so this rule outlives the
   flag itself. */
.ff.f-limp_call { color: var(--spew); }

.flagbtn {
  flex: 1;
  padding: 11px 6px;
  border-radius: 11px;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.012));
  color: #93a5bc;
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: .04em;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
  /* No transition on background - it is a gradient, and gradients cannot
     interpolate. Animating them alongside box-shadow makes the lit state
     arrive in two visible stages. On/off snaps; only hover eases. */
  transition: border-color .12s ease, color .12s ease;
}
.flagbtn:hover { border-color: #3b5170; color: var(--text); }
.flagbtn:active { transform: scale(.97); }

.flagbtn.on {
  color: #fff;
  border-color: transparent;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.3);
  transition: none;
}
.flagbtn.on.f-limp     { background: linear-gradient(180deg, #38c455, #1f8a36); box-shadow: 0 3px 14px rgba(46,160,67,.36), inset 0 1px 0 rgba(255,255,255,.3); }
.flagbtn.on.f-call     { background: linear-gradient(180deg, #f0b855, #c8892a); color: #241a04; box-shadow: 0 3px 14px rgba(226,165,60,.36), inset 0 1px 0 rgba(255,255,255,.4); }
/* Two range shapes needing opposite responses, so they read as different
   colours: red for linear (all value - believe him), purple for polarized
   (there are bluffs in there - fight back). */
/* Folds too much: blue, the same colour NIT carries, because the response is
   the same - apply pressure and they surrender. */
.flagbtn.on.f-fold_cbet { background: linear-gradient(180deg, #5b9bff, #2f6fd6); box-shadow: 0 3px 14px rgba(59,130,246,.36), inset 0 1px 0 rgba(255,255,255,.3); }
.flagbtn.on.f-threebet_linear { background: linear-gradient(180deg, #e85c5c, #b83333); box-shadow: 0 3px 14px rgba(214,69,69,.36), inset 0 1px 0 rgba(255,255,255,.3); }
.flagbtn.on.f-threebet_polar  { background: linear-gradient(180deg, #b78bff, #8b5cf0); box-shadow: 0 3px 14px rgba(163,113,247,.36), inset 0 1px 0 rgba(255,255,255,.3); }

/* flag pips on the seat plate */
/* Chip row under the plate - the tag chip first, then any flags. This is where
   the old "untagged" label used to sit, so a recorded read now appears exactly
   where you're already looking for one.

   Flags are labelled rather than colour-coded bars: a 4px stripe is not a read
   you can act on at speed, and the colour alone never said which flag it was.
   Colour rides on currentColor, so each flag needs one declaration below. */
.seat .chiprow {
  display: flex; flex-wrap: wrap; gap: 4px;
  justify-content: center; margin-top: 5px;
}
.seat .ff {
  display: inline-block;
  padding: 3px 9px;
  border-radius: 6px;
  background: rgba(4,10,20,.72);
  border: 1px solid currentColor;
  font-size: 9.5px; font-weight: 800; letter-spacing: .06em;
  line-height: 1;
  font-style: normal;
  white-space: nowrap;
  box-shadow: 0 3px 10px rgba(0,0,0,.4);
}
.ff.f-limp     { color: var(--station); }
.ff.f-call     { color: var(--spew); }
.ff.f-fold_cbet { color: var(--nit); }
.ff.f-threebet_linear { color: var(--trap); }
.ff.f-threebet_polar  { color: var(--reg); }

.sugg {
  display: flex; align-items: center; gap: 10px;
  background: linear-gradient(180deg, rgba(59,130,246,.11), rgba(59,130,246,.03));
  border: 1px solid rgba(59,130,246,.3);
  border-radius: 11px;
  padding: 10px 12px;
  margin-bottom: 14px;
  font-size: 12px;
}
.sugg.ok { background: linear-gradient(180deg, rgba(46,160,67,.12), rgba(46,160,67,.03)); border-color: rgba(46,160,67,.32); }
.sugg > div { flex: 1; }
.sugg b { display: block; font-size: 12.5px; letter-spacing: .06em; margin-bottom: 2px; }
.sugg span { color: var(--text-dim); line-height: 1.5; }
.sugg .apply { padding: 6px 13px; font-size: 11px; flex-shrink: 0; }

/* ------------------------------------------------------- range grid --- */

.rangebox { margin: 16px 0 4px; border-top: 1px solid var(--line-soft); padding-top: 14px; }

.rangehead { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 9px; }
.rangehead h3 { font-size: 10px; text-transform: uppercase; letter-spacing: .1em;
                color: var(--text-dim); margin: 0; font-weight: 700; }
.rangehint { font-size: 9.5px; color: #566a82; }

.grid13 {
  display: grid;
  grid-template-columns: repeat(13, 1fr);
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line);
  border-radius: 7px;
  overflow: hidden;
  padding: 1px;
}

.cell {
  aspect-ratio: 1;
  display: flex; align-items: center; justify-content: center;
  font-size: 7.5px; font-weight: 600;
  cursor: pointer;
  user-select: none;
  color: #5c6d84;
  background: #0e1522;
  transition: none;
}
.cell.pair    { background: #131d2e; }
.cell.suited  { background: #101828; }
.cell.offsuit { background: #0d1420; }
.cell:hover { outline: 1px solid var(--accent); outline-offset: -1px; z-index: 2; color: #fff; }

/* flat on/off - either the hand is in this slice or it isn't */
.cell.hit, .cell.hit.pair {
  background: var(--gold);
  color: #1a1405;
  font-weight: 800;
}

/* hero's own chart - green means open, distinct from the gold used on the
   opponent grid so the two never read as the same claim */
.cell.rz-on, .cell.rz-on.pair, .cell.rz-on.suited, .cell.rz-on.offsuit {
  background: var(--station);
  color: #04170a;
  font-weight: 800;
}

/* ruled out - you've confirmed they DON'T do this with the hand, which is a
   different claim from a blank cell meaning you haven't seen it yet */
.cell.no, .cell.no.pair, .cell.no.suited, .cell.no.offsuit {
  background: #05070c;
  color: #2b3446;
  font-weight: 600;
}


/* ---------------------------------------------------- villain range --- */

.rzmode { display: flex; gap: 4px; margin: 7px 0 6px; }
.modetab {
  flex: 1;
  padding: 5px 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: linear-gradient(180deg, rgba(255,255,255,.045), rgba(255,255,255,.01));
  color: var(--text-dim);
  font-size: 9px;
  font-weight: 700;
  line-height: 1.3; letter-spacing: .03em;
  cursor: pointer;
}
.modetab:hover { color: var(--text); border-color: #2e405c; }
.modetab.on {
  background: linear-gradient(180deg, #4f92ff, #2f6fd6);
  border-color: #5b9bff; color: #fff;
  box-shadow: 0 2px 9px rgba(59,130,246,.32), inset 0 1px 0 rgba(255,255,255,.24);
}

.vrslide { display: flex; align-items: center; gap: 7px; margin: 2px 0 7px; }
.vrslide label { display: flex; align-items: center; gap: 8px; flex: 1;
                 font-size: 9.5px; text-transform: uppercase; letter-spacing: .08em;
                 color: var(--text-dim); font-weight: 700; }
.vrslide input[type=range] { flex: 1; accent-color: var(--gold); min-width: 0; }
.vrslide b { color: var(--gold); font-size: 12px; min-width: 34px; text-align: right; }

/* Solver range and the widening are different claims and must never read as
   the same one: green is solved, gold is modelled. */
.cell.vr-core, .cell.vr-core.pair, .cell.vr-core.suited, .cell.vr-core.offsuit {
  background: var(--station); color: #04170a; font-weight: 800;
}
.cell.vr-extra, .cell.vr-extra.pair, .cell.vr-extra.suited, .cell.vr-extra.offsuit {
  background: var(--gold); color: #1a1405; font-weight: 800;
}
/* Observations ride on top as a ring, so they compose with either fill
   instead of replacing it - what you've seen and what the model says are
   independent facts about the same cell. */
.cell.vr-seen { box-shadow: inset 0 0 0 2px #fff; }
.cell.vr-out  { box-shadow: inset 0 0 0 2px var(--trap); opacity: .55; }

.vrlegend {
  display: flex; flex-wrap: wrap; gap: 4px 12px;
  margin-top: 7px; font-size: 9px; color: var(--text-dim);
}
.vrlegend span { display: flex; align-items: center; gap: 5px; }
.vrlegend .sw { width: 10px; height: 10px; border-radius: 3px; display: block;
                background: #16202f; border: 1px solid var(--line); }
.vrlegend .sw.vr-core  { background: var(--station); border-color: var(--station); }
.vrlegend .sw.vr-extra { background: var(--gold); border-color: var(--gold); }
.vrlegend .sw.vr-seen  { background: #16202f; border-color: #fff; }
.vrlegend .sw.vr-out   { background: #16202f; border-color: var(--trap); }
.warn-inline { color: var(--spew); font-weight: 700; }

/* ------------------------------------------------------- chart zoom --- */

/* Cells render at 7.5px, which is enough to answer "is my hand in here" at a
   glance and useless for studying a chart. Clicking one opens a read-only copy
   at whatever size the window allows. */

.zoom {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  padding: 22px;
  background: rgba(3,7,14,.8);
  backdrop-filter: blur(7px);
}
.zoom[hidden] { display: none; }

.zoomcard {
  background: linear-gradient(180deg, var(--panel), var(--bg-1));
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: 0 40px 90px rgba(0,0,0,.72);
  padding: 18px 18px 20px;
  max-width: 100%; max-height: 100%;
  display: flex; flex-direction: column; gap: 13px;
  overflow: auto;
}
.zoomhead { display: flex; align-items: flex-start; justify-content: space-between; gap: 28px; }
.zoomhead h3 {
  margin: 0; font-size: 15.5px; font-weight: 700;
  letter-spacing: .01em; color: var(--text);
}
.zoomhead .btn small { font-size: 9px; opacity: .6; font-weight: 500; }
.zoomsub {
  margin-top: 5px; max-width: 62ch;
  font-size: 12px; line-height: 1.55; color: var(--text-dim);
}
.zoomsub .rzpct { color: var(--gold); font-weight: 800; }
.zoomsub .rzpct.raise { color: var(--trap); }
.zoomsub .rzsize { color: var(--gold); font-weight: 700; }

.zoombody { display: flex; justify-content: center; }
/* Square, and as large as the shorter side of the window allows - the header
   above it is roughly 130px, hence the subtraction. */
.zoombody .grid13 {
  width: min(84vw, calc(100vh - 200px));
  gap: 2px;
  border-radius: 11px;
}
.zoombody .cell {
  font-size: clamp(9px, 1.55vh, 18px);
  font-weight: 700;
  cursor: default;               /* the copy is for reading, not editing */
}
.zoombody .cell.rz-on, .zoombody .cell.hit { font-weight: 800; }
.zoombody .cell:hover { outline-width: 2px; }

/* The affordance on the panels themselves. */
.rzzoom, .rangezoom {
  background: none; border: 1px solid var(--line);
  color: var(--text-dim);
  border-radius: 6px; padding: 2px 7px;
  font-size: 9px;
  font-weight: 700;
  line-height: 1.5; letter-spacing: .08em; text-transform: uppercase;
  cursor: pointer;
}
.rzzoom:hover, .rangezoom:hover { color: var(--text); border-color: #2e405c; }
.rangecol .grid13 { cursor: zoom-in; }

/* --------------------------------------------------- coaching prompt --- */

.exploit.coach {
  border-left-color: var(--gold);
  background: linear-gradient(180deg, rgba(242,199,74,.09), rgba(242,199,74,.02));
  border-color: rgba(242,199,74,.24);
}

.coachstep {
  font-size: 10px; font-weight: 800; letter-spacing: .11em; text-transform: uppercase;
  color: var(--gold); margin-bottom: 5px;
}
.exploit:not(.coach) .coachstep { color: var(--accent); }
.coachtext { color: #c9d7e8; line-height: 1.6; }

/* ------------------------------------------------- pool assumption --- */

.pool {
  background: linear-gradient(180deg, rgba(163,113,247,.11), rgba(163,113,247,.025));
  border: 1px solid rgba(163,113,247,.28);
  border-radius: 12px;
  padding: 12px 14px;
  margin-bottom: 16px;
}
.poolhead {
  font-size: 10px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: #c4a5ff; margin-bottom: 7px;
}
.poolbody { font-size: 12px; line-height: 1.6; color: #bccbdd; }
.poolbody ul { margin: 8px 0 0; padding-left: 15px; }
.poolbody li { margin-bottom: 7px; }
.poolbody li:last-child { margin-bottom: 0; }
.poolbody b { color: #e9f0f9; }

/* second prompt box - the standing 3-bet assumption */
.exploit.pool3b {
  border-left-color: var(--reg);
  background: linear-gradient(180deg, rgba(163,113,247,.10), rgba(163,113,247,.025));
  border-color: rgba(163,113,247,.26);
  margin-top: -6px;
}
.exploit.pool3b .coachstep { color: #c4a5ff; }
.exploit.pool3b.contested {
  border-left-color: var(--trap);
  background: linear-gradient(180deg, rgba(214,69,69,.11), rgba(214,69,69,.025));
  border-color: rgba(214,69,69,.3);
}
.exploit.pool3b.contested .coachstep { color: #ff8f8f; }


/* range grid position tabs */
.postabs { display: flex; gap: 5px; margin-bottom: 8px; }
.postab {
  flex: 1;
  padding: 7px 4px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.012));
  color: #8fa2ba;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: .05em;
  cursor: pointer;
}
.postab:hover { color: var(--text); border-color: #3b5170; }
.postab.on {
  background: linear-gradient(180deg, #4f92ff, #2f6fd6);
  border-color: #5b9bff; color: #fff;
  box-shadow: 0 2px 10px rgba(59,130,246,.34), inset 0 1px 0 rgba(255,255,255,.26);
  transition: none;
}
.postab .n { margin-left: 5px; opacity: .75; font-weight: 500; }
.rangefoot { margin-top: 7px; font-size: 10px; color: #566a82; }

.postabs.acttabs { margin-top: -3px; }
.postab.act { font-size: 10px; padding: 6px 3px; }
.postab.act.on {
  background: linear-gradient(180deg, #b78bff, #8b5cf0);
  border-color: #b78bff;
  box-shadow: 0 2px 10px rgba(163,113,247,.34), inset 0 1px 0 rgba(255,255,255,.26);
}

/* ---------------------------------------------- panel section heads --- */

.sechead {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #7d92ad;
  margin: 18px 0 9px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line-soft);
}
.sechead:first-of-type { margin-top: 4px; }

.pending {
  padding: 13px 14px;
  border: 1px dashed rgba(150,190,240,.24);
  border-radius: 11px;
  background: rgba(4,10,20,.34);
  color: #5f7189;
  font-size: 11.5px;
  line-height: 1.5;
  margin-bottom: 4px;
}

/* ------------------------------------------------- preflop bet sizing --- */


/* ==================================================== motion ============
   Motion policy, stated so it survives the next edit:

     animate state CHANGES and navigation; never animate input feedback.

   The three `transition: none` rules earlier in this file (.flagbtn.on,
   .cell, .postab.on) are the hot path - the controls clicked fast and
   repeatedly while a hand is live - and they stay instant deliberately. Do
   not "fix" them by adding a transition.

   Everything below animates transform and opacity only, so it stays on the
   compositor and never triggers layout. That matters with two tables open.
   Durations are calc()'d off --motion; set it to 0 to kill the lot.
   ---------------------------------------------------------------------- */

/* The seat on the clock. A ring that breathes outward rather than a static
   outline - slow enough to read as ambient, so it registers peripherally
   without pulling your eye off the cards. The static ring underneath stays,
   so the seat is still marked when motion is off. */
.seat.toact .plate::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 10px;
  border: 2px solid rgba(91,155,255,.6);
  pointer-events: none;
  animation: toactring calc(var(--motion) * 1800ms) cubic-bezier(.25,.6,.35,1) infinite;
}
@keyframes toactring {
  0%   { opacity: .9; transform: scale(1); }
  65%  { opacity: 0;  transform: scale(1.11); }
  100% { opacity: 0;  transform: scale(1.11); }
}

/* Chips arriving in front of a seat. They scale up from the plate rather
   than appearing, which reads as the bet coming off the stack. */
.chip.isnew {
  animation: chipin calc(var(--motion) * 200ms) cubic-bezier(.2,.9,.3,1.35);
}
@keyframes chipin {
  from { opacity: 0; transform: translate(-50%, -50%) scale(.55); }
}

/* Bets going to the pot at the end of a street. Eased slow-then-fast so the
   chips look drawn in rather than thrown, and the amount fades early -- the
   number has already been counted into the pot by then, and two copies of it
   on screen at once reads as double. */
.chip.chipfly {
  z-index: 4;
  animation: chipfly calc(var(--motion) * 460ms) cubic-bezier(.55,.06,.68,.9) forwards;
}
.chip.chipfly b { animation: chipflyfade calc(var(--motion) * 200ms) forwards; }
@keyframes chipfly {
  to {
    transform: translate(-50%, -50%)
               translate(var(--dx, 0), var(--dy, 0)) scale(.42);
    opacity: 0;
  }
}
@keyframes chipflyfade { to { opacity: 0; } }

/* Who won. Sits where that seat's chips would be, so it reads as belonging to
   the player rather than floating over the felt. Rises in behind the chips
   flying out, and stays put -- this is the thing you are looking for when you
   stop stepping. */
.winbanner {
  position: absolute;
  transform: translate(-50%, -50%);
  z-index: 6;
  display: flex; align-items: center; gap: 7px;
  padding: 5px 11px;
  white-space: nowrap;
  border-radius: 999px;
  border: 1px solid rgba(120, 220, 160, .55);
  background: linear-gradient(180deg, rgba(22, 62, 42, .97), rgba(12, 40, 27, .97));
  box-shadow: 0 6px 18px rgba(0, 0, 0, .5), 0 0 0 3px rgba(98, 201, 138, .10);
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  /* Visible in its own right, with the animation only adding movement. Filling
     `both` off a delayed animation would have meant the banner is invisible
     until the animation runs -- and it does not always run: a throttled tab, a
     reduced-motion setting, or anything else that stops compositing would have
     hidden the one thing you are looking for at the end of a hand. */
  opacity: 1;
  animation: winbanner calc(var(--motion) * 520ms) cubic-bezier(.2,.85,.3,1.15);
}
.winbanner .who {
  color: #eaf6ee;
  max-width: 150px; overflow: hidden; text-overflow: ellipsis;
}
.winbanner .amt { color: #7fe0a4; font-variant-numeric: tabular-nums; }
/* Transform only, deliberately: nothing here touches opacity, so the banner is
   visible whatever state the animation is in. An animation that is active but
   not progressing -- a throttled or occluded tab -- holds its first keyframe,
   so animating opacity from 0 means the banner can sit invisible indefinitely.
   Movement is decoration; being readable is not. */
@keyframes winbanner {
  from { transform: translate(-50%, -34%) scale(.92); }
  to   { transform: translate(-50%, -50%) scale(1); }
}

/* The pot going out to the winner. Slower and easing OUT rather than in --
   chips leaving are a bet being made, chips arriving are a pot being won, and
   the second deserves to be watched rather than snatched away. */
.chip.chipwin {
  z-index: 5;
  animation: chipwin calc(var(--motion) * 700ms) cubic-bezier(.22,.68,.3,1) forwards;
}
@keyframes chipwin {
  0%   { transform: translate(-50%, -50%) scale(.5); opacity: 0; }
  18%  { transform: translate(-50%, -50%) scale(1);  opacity: 1; }
  100% {
    transform: translate(-50%, -50%)
               translate(var(--dx, 0), var(--dy, 0)) scale(.92);
    opacity: 0;
  }
}

/* The pot, when it grows. A single firm bump - the number is the thing that
   matters, so this draws the eye to it and gets out of the way. */
.felt-center .stake .pot.bumped {
  animation: potbump calc(var(--motion) * 420ms) cubic-bezier(.2,.85,.3,1.3);
}
@keyframes potbump {
  0%   { transform: scale(1);    }
  32%  { transform: scale(1.13); }
  100% { transform: scale(1);    }
}

/* The board, as real cards on the felt rather than text in the stake line.
   Sized between the hole cards and the deal-panel cards - big enough to read
   across the table at a glance, small enough to leave the centre uncrowded. */
.feltboard {
  display: flex;
  gap: 5px;
  justify-content: center;
  margin-top: 10px;
}
.feltboard .dlcard {
  width: 30px; height: 41px;
  border-radius: 5px;
  font-size: 13.5px;
  box-shadow: 0 4px 12px rgba(0,0,0,.6);
}
.feltboard .dlcard .su { font-size: 11px; }

/* Board cards landing. --i is set per card in app.js, so the flop arrives as
   three cards in sequence rather than one block. */
.feltboard .dlcard.isnew {
  animation: cardin calc(var(--motion) * 260ms) cubic-bezier(.2,.85,.3,1.15) backwards;
  animation-delay: calc(var(--i, 0) * var(--motion) * 70ms);
}
@keyframes cardin {
  from { opacity: 0; transform: translateY(-9px) scale(.9); }
}

/* One switch for all of it. Extends the existing die-roll guard to cover
   everything added here. */
@media (prefers-reduced-motion: reduce) {
  .seat.toact .plate::after,
  .chip,
  .chip.chipfly,
  .chip.chipwin,
  .winbanner,
  .felt-center .stake .pot.bumped,
  .feltboard .dlcard.isnew { animation: none; }
  .seat { transition: transform .14s cubic-bezier(.2,.8,.3,1); }
}

/* ---------------------------------------------------------- replay --- */

.rprow { display: flex; gap: 8px; margin: 10px 0 0; }
.rpsel {
  flex: 1; min-width: 0;
  background: linear-gradient(180deg, #0b1220, #101a29);
  border: 1px solid var(--line);
  border-radius: 9px;
  color: var(--text);
  padding: 8px 10px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.2;
}
.rpsel:focus { outline: none; border-color: var(--accent); }
.abtn.wide { width: 100%; }

/* The hand list. Every hand in the session, in order, so you can see where you
   are in a run rather than hunting through a dropdown one at a time.
   Capped and scrollable because a session is hundreds of hands and the
   transport controls below it must stay reachable. */
.rplist {
  margin-top: 10px;
  max-height: 232px;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: rgba(4,10,20,.42);
}
.rplist::-webkit-scrollbar { width: 8px; }
.rplist::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,.14); border-radius: 8px;
}
.rpitem {
  display: flex; align-items: center; gap: 8px;
  width: 100%;
  padding: 6px 9px;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line-soft);
  color: var(--text-dim);
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  text-align: left;
  transition: none;             /* hot path, same reasoning as .rpbtn */
}
.rpitem:last-child { border-bottom: 0; }
.rpitem:hover { background: rgba(255,255,255,.06); color: var(--text); }
.rpitem.on {
  background: rgba(90,160,255,.14);
  color: var(--text);
  box-shadow: inset 2px 0 0 var(--accent);
}
.rpn {
  min-width: 22px;
  color: #5f7189;
  font-variant-numeric: tabular-nums;
}
.rpitem.on .rpn { color: var(--accent); }
.rpmid { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.rpwho {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 700;
}
.rpmeta { font-size: 10.5px;
 font-weight: 500;
 line-height: 1.2; color: #5f7189; }
.rpnet { font-variant-numeric: tabular-nums; min-width: 40px; text-align: right; }
.rpnet.up { color: #62c98a; }
.rpnet.dn { color: #ff7b86; }
.rpcards { display: flex; gap: 3px; }

/* Remote. Play steps the hand on a timer so you can watch it rather than
   click through it; the arrows either side move one action, the triangles
   move a whole hand. */
.rpbtn.play { flex: 1.3; color: var(--accent); }
.rpbtn.play.on { background: rgba(90,160,255,.2); border-color: var(--accent); }
.rpspeedrow {
  display: flex; align-items: center; gap: 8px;
  margin-top: 8px;
}
.rpspeed {
  flex: 1; min-width: 0;
  accent-color: var(--accent);
  height: 3px;
}
.rpspeedv {
  min-width: 30px; text-align: right;
  font-size: 11px;
  font-weight: 600;
  line-height: 1; color: #5f7189;
  font-variant-numeric: tabular-nums;
}
.rpc {
  padding: 1px 4px;
  border-radius: 4px;
  background: rgba(255,255,255,.07);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: .02em;
}
/* Four-colour deck, matching the felt. */
.rpc.ss { color: #cfd9e6; }
.rpc.sh { color: #ff7b86; }
.rpc.sd { color: #6fb2ff; }
.rpc.sc { color: #62c98a; }
.rppot { font-variant-numeric: tabular-nums; color: #8fa4bd; }
.rpbad { color: #ffb454; font-weight: 800; }

.rphint {
  margin-top: 10px;
  font-size: 11.5px; line-height: 1.5;
  color: #5f7189;
}

/* ------------------------------------------------- range builder --- */

/* Moving between the two pages. */
.pagenav { display: flex; gap: 4px; }
.pagenav a {
  padding: 6px 14px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--text-dim);
  /* Longhand, not `font: 700 12.5px/1 inherit`. `inherit` is not a valid
     family inside the shorthand, so the browser threw the whole declaration
     away and these rendered at the default 16px -- which is what pushed the
     fifth tab off the edge of a phone. */
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
}
.pagenav a:hover { background: rgba(255,255,255,.07); color: var(--text); }
.pagenav a.on { background: rgba(90,160,255,.18); color: var(--text); }

/* The builder has a page to itself. A 13x13 grid you paint by dragging wants
   room -- squeezed into the table's 340px column the cells are 24px and the
   labels are unreadable. */
/* Scrolls itself rather than the page. `html, body` are locked to the viewport
   for the table, which is a fixed layout by design -- the felt fills the screen
   and nothing must move. The builder is taller than the viewport, so it needs a
   scroll of its own instead of unlocking the whole document and changing how
   the other page behaves. */
.buildpage {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 16px;
  padding: 18px;
  height: calc(100% - 60px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.buildside {
  position: relative;                 /* the frequency popup anchors to this */
  width: min(860px, 100%);
}
/* Three charts side by side need the room, so the answers page is allowed to
   run wider than the builder. */
body.rangepage .buildside:has(.pcharts) {
  width: min(1480px, 100%);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 20px 22px 24px;
}

/* The frequencies for one hand, in view mode. Numbers rather than a shape:
   the cell already shows you the shape, this is for when you want the value. */
.bpop {
  position: absolute;
  z-index: 20;
  min-width: 132px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: rgba(10, 17, 28, .97);
  box-shadow: 0 10px 26px rgba(0,0,0,.55);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  pointer-events: none;               /* never swallows the next click */
}
.bpophand {
  font-size: 13.5px; font-weight: 800; color: var(--text);
  margin-bottom: 4px;
}
.bpoprow {
  display: flex; justify-content: space-between; gap: 14px;
  text-transform: capitalize;
  font-variant-numeric: tabular-nums;
}
.bpoprow.raise span { color: #ff9b96; }
.bpoprow.call  span { color: #8fdc9a; }
.bpoprow.fold  span { color: #9dc6ef; }
.bpoprow b { color: var(--text); font-weight: 700; }
.bpoprow b i { color: #7f92a8; font-style: normal; font-weight: 600; }
.bpopnote {
  margin-top: 5px; padding-top: 5px;
  border-top: 1px solid var(--line);
  color: #93a4ba; font-weight: 600; font-size: 11px;
}

/* ------------------------------------------------- practice --- */

/* The answers grid is coloured by MISTAKE, not by action. What you want from
   a marked chart is where you were wrong; the right answer is a click away. */
.cell.mark-ok     { background: var(--m-ok); }
.cell.mark-missed { background: var(--m-missed); }  /* folded a hand it plays */
.cell.mark-extra  { background: var(--m-extra); }   /* played one it does not */
.cell.mark-wrong  { background: var(--m-wrong); }   /* right hand, wrong action */

.pscore { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.pstat {
  padding: 5px 9px; border-radius: 7px;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  background: rgba(255,255,255,.05); color: #93a4ba;
}
.pstat.ok     { background: rgba(47,109,67,.35);  color: #b7e8c4; }
.pstat.near   { background: rgba(63,132,198,.20); color: #bcd9f4; }
.pstat.missed { background: rgba(47,95,146,.40);  color: #bcd9f4; }
.pstat.extra  { background: rgba(138,80,36,.40);  color: #f0c69b; }
.pstat.wrong  { background: rgba(140,59,110,.40); color: #f3bcdf; }

.pworst { margin-top: 12px; }
.pworsthead {
  font-size: 12px;
  font-weight: 700;
  line-height: 1; color: var(--text-dim);
  margin-bottom: 6px;
}
.pworstrow {
  display: flex; align-items: center; gap: 10px;
  padding: 5px 8px;
  border-radius: 7px;
  background: rgba(4,10,20,.42);
  margin-bottom: 3px;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.3;
}
.pw-hand { min-width: 42px; font-weight: 800; color: var(--text); }
.pw-you  { flex: 1; color: #f0c69b; }
.pw-want { flex: 1; color: #b7e8c4; }
/* Saved ranges, same furniture as the replayer's hand list. */
.buildlist {
  width: 296px;
  flex-shrink: 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 18px 16px 20px;
}
.buildlist .rplist { max-height: min(70vh, 620px); }
.buildlist .rpitem { position: relative; padding-right: 22px; }
.bdel {
  position: absolute; right: 6px; top: 50%;
  transform: translateY(-50%);
  width: 16px; height: 16px; line-height: 15px; text-align: center;
  border-radius: 4px;
  color: #5f7189; font-size: 14px;
}
.bdel:hover { background: rgba(255,120,130,.18); color: #ff9aa2; }
.bsaverow { gap: 8px; }
.bname {
  flex: 1; min-width: 0;
  background: linear-gradient(180deg, #0b1220, #101a29);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--text);
  padding: 8px 10px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.2;
}
.bname::placeholder { color: #566780; }
.bname:focus { outline: none; border-color: var(--accent); }
.rpmini.bsave {
  flex: 0 0 auto; padding: 8px 16px;
  background: rgba(90,160,255,.18); border-color: var(--accent);
  color: var(--text);
}
.rpmini.bsave:hover { background: rgba(90,160,255,.30); }
.rangepage .bgrid .cell { font-size: clamp(9px, 1.15vw, 15px); }
.rangepage .brow { margin-top: 14px; }
.rangepage .bact { padding: 10px 0; font-size: 13px; }
.rangepage .btot { padding: 8px 0; font-size: 12.5px; }

/* Solver colours, because that is what the eye is already trained on: raise
   red, call green, fold blue. Fold is a real colour rather than the dark of
   the felt -- a hand you have decided to fold and a hand you have not looked
   at yet should not look the same, and in a solver grid they never do. */
:root {
  --b-raise: #e0433c;
  --b-call:  #43a94e;
  --b-fold:  #3d84c6;
  /* Marking colours for the difference chart. Deliberately not the action
     colours: that grid answers "where was I wrong", not "what does this hand
     do", and reusing red/green/blue there would read as a third range. */
  --m-ok:     #2f6d43;
  --m-missed: #2f5f92;
  --m-extra:  #8a5024;
  --m-wrong:  #8c3b6e;
}
.brow { display: flex; gap: 6px; margin-top: 10px; align-items: center; }
.bact {
  flex: 1;
  padding: 7px 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(255,255,255,.04);
  color: var(--text-dim);
  cursor: pointer;
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1;
  text-transform: capitalize;
}
.bact:hover { background: rgba(255,255,255,.09); }
.bact.on.raise { background: rgba(224,67,60,.30); border-color: var(--b-raise); color: #ffd9d7; }
.bact.on.call  { background: rgba(67,169,78,.30);  border-color: var(--b-call);  color: #d6f5da; }
.bact.on.fold  { background: rgba(61,132,198,.30); border-color: var(--b-fold);  color: #d7e8fa; }
.bpct { flex: 1; min-width: 0; accent-color: var(--accent); height: 3px; }
.bpctv {
  min-width: 38px; text-align: right;
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1; color: var(--text);
  font-variant-numeric: tabular-nums;
}
/* `pinch-zoom`, not `none`. None stopped a one-finger drag from scrolling the
   page, which is what makes drag-to-paint work -- but it also switched off
   pinch, and at 23px a cell on a phone the grid is unreadable without it. This
   value keeps the pan blocked and lets the zoom through. */
.bgrid { margin-top: 10px; touch-action: pinch-zoom; }
/* Wider than tall, like every solver grid: the cell is read left to right, so
   the extra width is where the mix actually lives. */
.bgrid .cell {
  aspect-ratio: 1.32;
  color: #dbe6f2;
  text-shadow: 0 1px 2px rgba(0,0,0,.85);
  justify-content: flex-start;
  padding-left: 4px;
}
.bview .cell { cursor: pointer; }

.bfoot { display: flex; gap: 8px; margin-top: 8px; }
.btot {
  flex: 1; text-align: center;
  padding: 5px 0; border-radius: 7px;
  font-size: 11px;
  font-weight: 700;
  line-height: 1; text-transform: capitalize;
  font-variant-numeric: tabular-nums;
}
.btot.raise { background: rgba(224,67,60,.22); color: #ffc9c6; }
.btot.call  { background: rgba(67,169,78,.22);  color: #b7ecbc; }
.btot.fold  { background: rgba(61,132,198,.22); color: #c3ddf6; }

/* The original text behind the replay. Worth having in reach: it is what a
   tracker or a forum post wants, and seeing it is how you check the replay
   against the source when a hand looks wrong. */
.rptools { display: flex; gap: 6px; margin-top: 10px; }
.rpmini {
  flex: 1;
  padding: 6px 4px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(255,255,255,.05);
  color: var(--text);
  cursor: pointer;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
}
.rpmini:hover { background: rgba(255,255,255,.1); }
/* Beside the list it is about, not stretched across it: .rpmini is `flex: 1`
   because it belongs to a row of equal buttons, which is the wrong shape for
   one link sitting next to a heading. */
.bsettings {
  flex: none;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(255,255,255,.05);
  color: var(--text-dim);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
}
.bsettings:hover {
  background: rgba(90,160,255,.18);
  border-color: var(--accent);
  color: var(--text);
}
.rpmini.on { background: rgba(90,160,255,.2); border-color: var(--accent); }
.rptext {
  margin: 8px 0 0;
  max-height: 260px;
  overflow: auto;
  padding: 9px 10px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: rgba(4,10,20,.42);
  color: #a9bdd6;
  font: 500 11px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* Wrap rather than scroll sideways. The header line alone is 80 characters,
     so no sensible column width fits it -- and a line you have to scroll to
     read is a line you will not check. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  user-select: text;
}
.rptext::-webkit-scrollbar { width: 8px; height: 8px; }
.rptext::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,.14); border-radius: 8px;
}

/* Transport. Sized for repeated clicking, and deliberately NOT animated -
   stepping a hand is the hot path here, the same reasoning as .flagbtn.on. */
.rptransport {
  display: flex; align-items: center; gap: 6px;
  margin-top: 12px;
}
.rpbtn {
  flex: 1;
  padding: 7px 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(255,255,255,.05);
  color: var(--text);
  cursor: pointer;
  font-size: 15px;
  font-weight: 700;
  line-height: 1;
  transition: none;
}
.rpbtn:hover { background: rgba(255,255,255,.1); border-color: var(--accent); }
.rpbtn:active { transform: translateY(1px); }
.rpstep {
  min-width: 58px; text-align: center;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.rplast {
  margin-top: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(4,10,20,.42);
  border: 1px solid var(--line-soft);
  font-size: 12px; font-weight: 600;
  color: #b9cbe2;
  text-transform: capitalize;
}
.rpwon {
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(46,160,67,.13);
  border: 1px solid rgba(46,160,67,.34);
  color: #7fd08e;
  font-size: 11.5px; font-weight: 700;
}
/* A disagreement between the history and the engine. Loud on purpose: it
   means one of the two is wrong, and quietly rendering the hand anyway is how
   you end up trusting a replay that skipped a bet. */
.rpwarn {
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(214,69,69,.1);
  border: 1px solid rgba(214,69,69,.28);
  color: #e08b8b;
  font-size: 11px; font-weight: 600; line-height: 1.45;
}

/* Boot failure, shown on the felt. It moved here when the sidebar was removed
   - the old reporter wrote into that panel, so once it was gone the error
   handler threw and hid the failure it existed to report. */
.bootfail {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: min(520px, 86%);
  padding: 22px 24px;
  border-radius: 14px;
  background: var(--panel);
  border: 1px solid rgba(214,69,69,.4);
  box-shadow: 0 18px 50px rgba(0,0,0,.6);
}
.bootfail h2 { margin: 0 0 10px; font-size: 17px; color: #e08b8b; }
.bootfail .hint {
  font-size: 12.5px; line-height: 1.55; color: var(--text-dim);
  margin-top: 8px;
}
.bootfail code {
  display: block;
  padding: 8px 10px; margin-top: 4px;
  border-radius: 7px;
  background: #0b1220;
  color: #d8e4f4;
  font: 500 11.5px/1.5 ui-monospace, "SF Mono", Consolas, monospace;
  white-space: pre-wrap; word-break: break-word;
}

/* ------------------------------------------- practice: the answers page --- */

/* Three grids across, so "yours" and "the range" can be compared directly
   rather than held in your head one after the other. */
.pcharts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-top: 14px;
}
.pchart {
  background: rgba(4, 10, 20, .40);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 13px 14px;
  min-width: 0;
}
.pcharttitle { font-size: 12.5px;
 font-weight: 700;
 line-height: 1; color: var(--text); }
.pcharttitle b { color: var(--accent); margin-right: 5px; }
.pchartnote {
  font-size: 11px; line-height: 1.45; color: var(--text-dim);
  margin: 4px 0 8px; min-height: 32px;
}
.pchart .bgrid { margin-top: 0; }
.pchart .cell { font-size: 7px; padding-left: 2px; }
.pchart .bfoot { margin-top: 8px; }
.pchart .btot { font-size: 10px; padding: 4px 0; }
.plegend {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-top: 8px; font-size: 10.5px; color: var(--text-dim);
}
.plegend i {
  display: inline-block; width: 9px; height: 9px;
  border-radius: 3px; margin-right: 4px; vertical-align: -1px;
}

/* The score, said once and said large. */
.phead {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  background: rgba(4, 10, 20, .40);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 14px 16px;
  margin-top: 12px;
}
.pbig {
  font-size: 36px;
  font-weight: 800;
  line-height: 1; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.pbig small { font-size: 15px; color: var(--text-dim); margin-left: 3px; }
.pbigsub { font-size: 10.5px; color: var(--text-dim); margin-top: 3px; }
.pverdict { flex: 1; min-width: 220px; font-size: 12px; color: var(--text-dim); }
.pverdict b { color: var(--text); }

/* Misses, ranked by what they actually cost. */
.pmisses { margin-top: 14px; }
.pmisshead { font-size: 12.5px;
 font-weight: 700;
 line-height: 1; color: var(--text-dim); margin-bottom: 8px; }
.pmisstable { width: 100%; border-collapse: collapse; font-size: 12px; }
.pmisstable th {
  text-align: left; padding: 0 8px 6px;
  font-size: 10px;
  font-weight: 700;
  line-height: 1; letter-spacing: .4px;
  text-transform: uppercase; color: #5f7189;
}
.pmisstable td {
  padding: 6px 8px; border-top: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
}
.pmh { font-weight: 800; width: 48px; }
.pcost { text-align: right; width: 78px; color: var(--text-dim); }
.pbar {
  height: 4px; border-radius: 3px; background: var(--line);
  overflow: hidden; margin-top: 3px;
}
.pbar i { display: block; height: 100%; background: linear-gradient(90deg, #8c3b6e, #e0433c); }
.ppill {
  display: inline-block; padding: 2px 8px; border-radius: 20px;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1.5;
}
.ppill.missed { background: rgba(47,95,146,.40);  color: #bcd9f4; }
.ppill.extra  { background: rgba(138,80,36,.40);  color: #f0c69b; }
.ppill.wrong  { background: rgba(140,59,110,.40); color: #f3bcdf; }
.pmix { font-weight: 700; }
.pmix .r { color: #ff9b96; }
.pmix .c { color: #8fdc9a; }
.pmix .f { color: #9dc6ef; }

/* Attempt history. */
.phist-wrap { margin-top: 16px; }
.phisthead {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 8px;
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1; color: var(--text-dim);
}
.phist td { font-size: 11.5px; }
.pwhen { color: var(--text-dim); width: 108px; }
.phist b.good { color: #7fe0a4; }
.phist b.mid  { color: #ffd76a; }
.phist b.poor { color: #ff8f96; }
.pbest {
  font-size: 9.5px;
  font-weight: 700;
  line-height: 1; letter-spacing: .3px;
  padding: 2px 5px; border-radius: 4px; margin-left: 4px;
  background: rgba(127,224,164,.18); color: #7fe0a4;
}
.pdelcell { width: 22px; text-align: right; }
.pdelcell .bdel { position: static; transform: none; cursor: pointer; }
.phist tr.popenable { cursor: pointer; }
.phist tr.popenable:hover td { background: rgba(255,255,255,.05); }

/* Folders in the saved-range list. Real directories under Ranges/, so the
   grouping you see here is the grouping on disk. */
.rpfolder {
  display: flex; align-items: center; gap: 7px;
  width: 100%;
  padding: 7px 9px;
  background: none; border: 0; border-top: 1px solid var(--line);
  color: var(--text-dim);
  cursor: pointer;
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1.2;
  text-align: left;
}
.rplist > .rpfolder:first-child { border-top: 0; }
.rpfolder:hover { background: rgba(255,255,255,.05); color: var(--text); }
.rpcaret { width: 9px; font-size: 9px; color: #5f7189; }
.rpfoldername {
  flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rpcount {
  font-size: 10px;
  font-weight: 700;
  line-height: 1; color: #5f7189;
  background: rgba(255,255,255,.06); border-radius: 20px; padding: 3px 6px;
}
.rpitem.nested { padding-left: 25px; }
.rpitem.nested.deep { padding-left: 38px; }
.rpfolder.deep { padding-left: 22px; }
.bmove {
  width: 16px; height: 16px; line-height: 15px; text-align: center;
  border-radius: 4px; color: #5f7189; font-size: 11px; flex-shrink: 0;
}
.rpitem .bmove { position: absolute; right: 24px; top: 50%; transform: translateY(-50%); }
.bmove:hover { background: rgba(120,190,255,.18); color: #9dc6ef; }
.rpitem { padding-right: 44px; }

/* ------------------------------------- folders: make, fill, empty out --- */

/* Two buttons in the sidebar head, where there was one -- both smaller, so
   the heading still fits on one line beside them. */
.bheadacts { display: flex; align-items: center; gap: 5px; flex: none; }
.buildlist .rzhead { gap: 8px; }
.buildlist .rzpos { flex: none; white-space: nowrap; }
.buildlist .bsettings { padding: 4px 9px; font-size: 10.5px; }
button.bsettings { cursor: pointer; font-family: inherit; }

/* Duplicate, beside the pencil and the cross.

   Three buttons is more than a 276px row can carry next to a name and a date,
   so the date and the buttons take turns: the date is what you want while you
   are reading the list, the buttons are what you want once you have picked a
   row out, and you are never after both at the same moment. */
.buildlist .rpitem { padding-right: 62px; }
.buildlist .rpitem .bcopy,
.buildlist .rpitem .bmove,
.buildlist .rpitem .bdel { opacity: 0; }
.buildlist .rpitem:hover .rpmeta,
.buildlist .rpitem.on .rpmeta { opacity: 0; }
.buildlist .rpitem:hover .bcopy, .buildlist .rpitem.on .bcopy,
.buildlist .rpitem:hover .bmove, .buildlist .rpitem.on .bmove,
.buildlist .rpitem:hover .bdel,  .buildlist .rpitem.on .bdel { opacity: 1; }
.bcopy {
  position: absolute; right: 42px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; line-height: 15px; text-align: center;
  border-radius: 4px; color: #5f7189; font-size: 12px; flex-shrink: 0;
}
.bcopy:hover { background: rgba(120,190,255,.18); color: #9dc6ef; }

/* A date is a date: it should not push the name it belongs to off the row. */
.buildlist .rpwho {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.buildlist .rpmeta { flex: none; white-space: nowrap; }

/* The cross on a folder row sits in the flow -- .rpfolder is a flex row, not
   a positioned one, and an absolute cross there would land somewhere else
   entirely. */
.rpfolder .bdel {
  position: static; transform: none;
  width: 16px; height: 16px; line-height: 15px; flex-shrink: 0;
}
.buildlist .rpfolder .bmove,
.buildlist .rpfolder .bdel { opacity: 0; }
.buildlist .rpfolder:hover .bmove,
.buildlist .rpfolder:hover .bdel { opacity: 1; }

/* Dragging. The row you picked up fades; anything it can land on lights up.
   Only one of the two is a change of state, so only the target gets a border
   -- a list where five rows glow is a list you cannot read. */
.rpitem[data-drag], .rpfolder[data-drag] { cursor: grab; }
/* The rows are dragged, so a slow press must not start selecting their text. */
.rpitem[data-drag], .rpfolder[data-drag] { user-select: none; -webkit-user-select: none; }
body.bdragcursor, body.bdragcursor * { cursor: grabbing !important; }

/* What is in your hand. A row that only goes translucent tells you something
   started but not what you are carrying or where it is. */
.bghost {
  position: fixed; left: 0; top: 0; z-index: 500;
  pointer-events: none;
  padding: 6px 12px;
  border-radius: var(--r-sm);
  background: var(--surface-3);
  border: 1px solid var(--line-hi);
  box-shadow: var(--shadow-3);
  color: var(--text);
  font-size: var(--t-sm);
  font-weight: 700;
  line-height: 1.2;
  max-width: 220px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bdrag { opacity: .4; }
.dropon {
  background: rgba(90,160,255,.22) !important;
  box-shadow: inset 0 0 0 1px var(--accent);
  color: var(--text);
}
/* The row you are dragging is still under the cursor, so it must not look
   like somewhere you could drop it. */
.bdrag.dropon { background: none !important; box-shadow: none; }

/* "Top level": how a chart comes back OUT of a folder. There is no row to
   drop it on for that -- loose charts are just the ones with no folder above
   them -- so the target only exists while something is in the air. */
/* The way a chart comes back out of a folder. Only there while something is
   in the air, and laid OVER the foot of the list rather than inside it -- a
   target that appears in the flow shoves every row down at the instant the
   drag starts, which moves whatever you were aiming at. */
#bList { position: relative; }
.rproot {
  display: none;
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 4;
  padding: 11px 9px;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1.2; letter-spacing: .05em;
  text-transform: uppercase;
  color: #8ab4e8;
  background: rgba(12,20,34,.94);
  border: 1px dashed var(--line-hi);
  border-radius: var(--r-sm);
  text-align: center;
  backdrop-filter: blur(3px);
}
.rplist.bcanunfile ~ .rproot { display: block; }
.rproot.dropon { color: #fff; border-style: solid; }

/* ---------------------------------------------------- practice: hints --- */

/* Wide enough to actually read. Thirteen columns in a 300px column gave 19px
   cells with the labels squashed to nothing -- a chart you cannot read is not
   a hint. */
.phintcol {
  /* Beside the grid, never under it: the peek lasts ten seconds, and a
     panel that wraps below costs most of that in scrolling. It gives up
     width with the grid instead of dropping. */
  flex: 0 1 560px;
  min-width: 330px;
}
.phintbtn {
  display: block; width: 100%;
  margin-top: 10px; padding: 14px 12px;
  border: 1px solid var(--line); border-radius: 11px;
  background: linear-gradient(180deg, rgba(90,160,255,.14), rgba(90,160,255,.06));
  color: var(--text); cursor: pointer; text-align: left;
}
.phintbtn:hover { border-color: var(--accent); background: rgba(90,160,255,.20); }
.phintbig { display: block; font-size: 13.5px;
 font-weight: 700;
 line-height: 1.2; }
.phintsub { display: block; margin-top: 3px; font-size: 11px;
 font-weight: 600;
 line-height: 1.3; color: var(--text-dim); }
.phintclock {
  font-variant-numeric: tabular-nums;
  background: rgba(255,215,106,.18); color: #ffd76a;
  padding: 3px 8px; border-radius: 20px; font-weight: 700;
}
.phintgrid { margin-top: 10px; }
/* Nearly square, unlike the grid you are working on. That one is wide because
   the cell IS the mix and the mix is read left to right; this one is a picture
   to memorise, and squat cells make it harder to see the shape of the range. */
/* Selector carries .bgrid too: `.rangepage .bgrid .cell` above sets the font
   size for the working grid and out-specifies a plain `.phintgrid .cell`, so
   without it the hint cells were drawn at the working grid's 15px inside a
   30px box. */
.rangepage .bgrid.phintgrid .cell {
  aspect-ratio: 1.06;
  font-size: clamp(9px, 0.8vw, 13px);
  padding-left: 0;
  justify-content: center;
  /* A grid item will not shrink below its own content by default, so at this
     width the labels held the columns apart and the last two ran off the edge
     of the panel. */
  min-width: 0;
  overflow: hidden;
}
.pstat.hint { background: rgba(255,215,106,.20); color: #ffd76a; }
.phints {
  font-size: 9.5px;
  font-weight: 700;
  line-height: 1; padding: 2px 5px; border-radius: 4px;
  margin-left: 4px; background: rgba(255,215,106,.16); color: #ffd76a;
}


/* ------------------------------------------------------ chart info --- */

/* A backfill screen, not a form. The job is to review a hundred guesses, so
   the row is wide and flat and every control is one click from the last. */
.metapage {
  height: calc(100% - 60px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 20px 24px 60px;
}
.metahead {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 24px; max-width: 1500px;
}
.metatitle { margin: 0; font-size: 21px;
 font-weight: 700;
 line-height: 1.2; }
.metaback {
  color: var(--accent); text-decoration: none; font-weight: 700;
  margin-right: 4px; white-space: nowrap;
}
.metaback:hover { text-decoration: underline; }
.metasub {
  margin-top: 6px; max-width: 720px;
  font-size: 12.5px; line-height: 1.55; color: var(--text-dim);
}
.metacount {
  flex: none; padding: 8px 14px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--panel);
  font-size: 12.5px; color: var(--text-dim);
}
.metacount b { font-size: 17px; color: var(--text); }
.metacount.ok { border-color: #2f6d43; }
.metacount.ok b { color: #6fd08c; }

.metabar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 9px;
  margin: 16px 0 10px; padding: 11px 14px;
  border: 1px solid var(--line); border-radius: 11px; background: var(--panel);
  max-width: 1500px;
}
.metabarlab { font-size: 12px; color: var(--text-dim); }
.metatoggle {
  margin-left: auto; display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--text-dim); cursor: pointer;
}
.cfill {
  padding: 7px 13px; border-radius: 8px; cursor: pointer;
  border: 1px solid var(--accent); background: rgba(90,160,255,.18);
  color: var(--text); font-size: 12px;
 font-weight: 700;
 line-height: 1;
}
.cfill:hover { background: rgba(90,160,255,.30); }

.metatable {
  width: 100%; max-width: 1500px; border-collapse: collapse; margin-top: 4px;
}
.metatable th {
  text-align: left; padding: 7px 10px; white-space: nowrap;
  font-size: 10px;
  font-weight: 700;
  line-height: 1; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-dim); border-bottom: 1px solid var(--line);
}
.metatable td { padding: 7px 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.crow:hover td { background: rgba(255,255,255,.025); }
.cname { font-size: 13px; white-space: nowrap; }
.cfolder { color: var(--text-dim); font-size: 11.5px; }
/* Amber until a chart can actually be used, green once it can. The count in
   the corner is the same fact; the dot is where you are already looking. */
.cdot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  margin-right: 8px; background: #d8a13a;
}
.cdot.ok { background: #4fae6a; }
.csaved {
  margin-left: 8px; padding: 2px 6px; border-radius: 4px;
  font-size: 9.5px;
  font-weight: 700;
  line-height: 1; background: rgba(79,174,106,.16); color: #6fd08c;
}
.csuggest {
  margin-left: 8px; padding: 3px 8px; border-radius: 20px; cursor: pointer;
  border: 1px dashed var(--line); background: none;
  color: var(--text-dim); font-size: 10.5px;
 font-weight: 600;
 line-height: 1.3;
}
.csuggest:hover { border-color: var(--accent); color: var(--text); border-style: solid; }

.cinput {
  padding: 5px 7px; border-radius: 7px; font-size: 12px;
 font-weight: 600;
 line-height: 1.2;
  border: 1px solid var(--line); background: #0e1522; color: var(--text);
}
.cinput:focus { outline: none; border-color: var(--accent); }
/* Nothing chosen yet reads as a hole to fill, not as a value. */
.cinput[data-empty] { color: var(--text-dim); border-style: dashed; }
.cnum { width: 62px; }
.csize { width: 66px; }

.cvs { min-width: 300px; }
.cvslabel {
  display: block; margin-bottom: 3px;
  font-size: 9.5px;
  font-weight: 600;
  line-height: 1; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-dim);
}
.cchips { display: inline-flex; flex-wrap: wrap; gap: 3px; }
.cchip {
  padding: 4px 7px; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--line); background: #0e1522;
  color: var(--text-dim); font-size: 10.5px;
 font-weight: 700;
 line-height: 1;
}
.cchip:hover { border-color: var(--accent); color: var(--text); }
.cchip.on {
  background: rgba(90,160,255,.24); border-color: var(--accent); color: #fff;
}
.cnone { font-size: 11.5px; color: var(--text-dim); font-style: italic; }

.cactions { white-space: nowrap; text-align: right; }
.cmini {
  display: inline-block; margin-left: 5px; padding: 4px 8px;
  border: 1px solid var(--line); border-radius: 6px; background: none;
  color: var(--text-dim); font-size: 10.5px;
 font-weight: 600;
 line-height: 1.2;
  cursor: pointer; text-decoration: none;
}
.cmini:hover { border-color: var(--accent); color: var(--text); }
.metafoot { max-width: 1500px; margin-top: 14px; }
.metafoot code {
  padding: 1px 5px; border-radius: 4px;
  background: rgba(255,255,255,.06); font-size: 11px;
}


/* =======================================================================
   Refresh: a token layer, and the furniture every page shares.

   The felt is left alone -- deep navy, gold for money, a lit blue table is
   what this app looks like, and it is the part that already works. What
   dated it was everything AROUND the felt: a dozen one-off type sizes, six
   different corner radii, and a solid navy 1px border drawn round every box
   whether or not it sat on the same surface.

   So the change is structural rather than decorative. Depth now comes from
   surfaces that get lighter as they rise, the way a modern dark theme does
   it, and borders went from a drawn line to a translucent hairline that
   reads correctly over the panel, over the felt and over a popover without
   being three different colours. Sizes and spacing come off a scale, so the
   next thing built here inherits the decisions instead of re-making them.
   ======================================================================= */

:root {
  /* Type. Seven steps, because the old file had fourteen sizes between 9.5
     and 15px and no two of them meant anything different. */
  --t-2xs: 10px;
  --t-xs:  11px;
  --t-sm:  12px;
  --t-md:  13px;
  --t-lg:  15px;
  --t-xl:  18px;
  --t-2xl: 23px;

  /* Space, on a 4px rhythm. */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 20px; --s-6: 28px; --s-7: 40px;

  /* Radius. Bigger than before across the board -- a 6px corner on a 200px
     panel is the tell of a 2015 admin theme. */
  --r-xs: 6px;  --r-sm: 9px;  --r-md: 12px;
  --r-lg: 16px; --r-xl: 22px; --r-full: 999px;

  /* Elevation by surface, not by shadow: each level is a little lighter than
     the one it sits on, so a popover over a card over the page reads as three
     planes even where nothing casts a shadow. */
  --surface-1: #0d1524;
  --surface-2: #121c2e;
  --surface-3: #182338;
  --raise-1: rgba(255,255,255,.04);
  --raise-2: rgba(255,255,255,.07);

  /* Hairlines. Translucent, so one value is correct over the panel, over the
     felt and over a popover -- which a solid navy line never was. */
  --line:      rgba(255,255,255,.09);
  --line-soft: rgba(255,255,255,.05);
  --line-hi:   rgba(255,255,255,.16);

  --shadow-1: 0 1px 2px rgba(0,0,0,.45);
  --shadow-2: 0 10px 30px -12px rgba(0,0,0,.7), 0 2px 6px rgba(0,0,0,.35);
  --shadow-3: 0 24px 60px -18px rgba(0,0,0,.8), 0 4px 12px rgba(0,0,0,.4);
  --ring: 0 0 0 3px rgba(59,130,246,.34);
}

body {
  /* Numbers line up in a column wherever they appear -- stacks, pot sizes,
     percentages, scores. This app is mostly numbers. */
  font-feature-settings: "tnum" 1, "cv05" 1;
  letter-spacing: -.005em;
}

/* One focus ring, everywhere, and only for the keyboard. The app had exactly
   one element that showed focus at all. */
:where(a, button, select, input, textarea, [tabindex]):focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-radius: var(--r-xs);
  position: relative;
  z-index: 3;
}

::selection { background: rgba(59,130,246,.34); color: #fff; }

/* Scrollbars were styled four times with three different colours. */
* { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.16) transparent; }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,.13);
  border: 2px solid transparent;
  background-clip: content-box;
  border-radius: var(--r-full);
}
::-webkit-scrollbar-thumb:hover { background-clip: content-box; background-color: rgba(255,255,255,.24); }

/* ------------------------------------------------------------ chrome --- */

.topbar {
  gap: var(--s-5);
  padding: 0 var(--s-5);
  background: linear-gradient(180deg, rgba(20,30,48,.86), rgba(9,15,28,.92));
  border-bottom: 1px solid var(--line-soft);
}

/* A segmented control on a recessed track, rather than three loose words.
   It says "these are the places you can be" in a way a row of links does not. */
.pagenav {
  gap: 2px;
  padding: 4px;
  border-radius: var(--r-full);
  background: rgba(0,0,0,.3);
  border: 1px solid var(--line-soft);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.4);
}
.pagenav a {
  padding: 7px 16px;
  border-radius: var(--r-full);
  font-size: var(--t-sm);
  font-weight: 700;
  line-height: 1;
  letter-spacing: .01em;
  transition: color calc(.14s * var(--motion)), background calc(.14s * var(--motion));
}
.pagenav a:hover { background: var(--raise-1); }
.pagenav a.on {
  background: linear-gradient(180deg, #3f83e8, #2a63c4);
  color: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.22);
}

/* ----------------------------------------------------------- buttons --- */

/* Five classes invented five button shapes. They keep their own names -- each
   is used in a different place for a different reason -- but they now agree
   about corner, weight, hairline and what pressing one feels like. */
.btn, .rpmini, .cfill, .bsettings, .cmini, .bact, .phintbtn, .csuggest {
  transition: background calc(.14s * var(--motion)),
              border-color calc(.14s * var(--motion)),
              transform calc(.08s * var(--motion));
}
.btn:active, .rpmini:active, .cfill:active,
.bsettings:active, .cmini:active { transform: translateY(1px); }

.btn {
  border-radius: var(--r-md);
  padding: 9px 16px;
  font-size: var(--t-md);
  font-weight: 650;
  line-height: 1;
  background: linear-gradient(180deg, #4a8dfb, #2b66cf);
  border-color: rgba(255,255,255,.18);
  box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,.24);
}
.btn.ghost {
  background: var(--surface-2);
  border-color: var(--line);
  box-shadow: var(--shadow-1);
}
.btn.ghost:hover { background: var(--surface-3); border-color: var(--line-hi); }

.rpmini, .cmini, .bsettings, .bact {
  border-radius: var(--r-sm);
  background: var(--raise-1);
  border: 1px solid var(--line);
}
.rpmini:hover, .cmini:hover, .bsettings:hover, .bact:hover {
  background: var(--raise-2);
  border-color: var(--line-hi);
}
.cfill {
  border-radius: var(--r-sm);
  padding: 8px 15px;
  box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,.14);
}

/* ---------------------------------------------------------- surfaces --- */

.buildlist, .metabar, .metacount, .rangecol, .picker, .zoombody {
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-1);
  box-shadow: var(--shadow-2);
}

/* The builder and the practice pages were content floating on the page
   background with nothing behind it, which is why they read as unfinished
   next to the table. Same panel the answers page already used. */
body.rangepage .buildside {
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-2);
  padding: var(--s-5);
}
body.rangepage .buildside:has(.pcharts) { padding: var(--s-5); }

.rplist {
  border-radius: var(--r-md);
  border-color: var(--line-soft);
  background: rgba(0,0,0,.24);
}
.rpitem { border-bottom-color: var(--line-soft); }

/* The hint chart is a popover over the page, so it sits a plane higher. */
.phintcol {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-3);
  padding: var(--s-4);
}

/* ------------------------------------------------------ chart settings -- */

.metapage { padding: var(--s-6) var(--s-6) var(--s-7); }
.metatitle { font-size: var(--t-2xl);
 font-weight: 750;
 line-height: 1.15; letter-spacing: -.02em; }
.metasub { font-size: var(--t-md); }
.metacount { border-radius: var(--r-md); padding: var(--s-2) var(--s-4); }
.metabar { border-radius: var(--r-md); padding: var(--s-3) var(--s-4); }
.metatable th { font-size: var(--t-2xs); }
.metatable td { border-bottom-color: var(--line-soft); }
.cinput { border-radius: var(--r-xs); border-color: var(--line); background: var(--surface-2); }
.cchip  { border-radius: var(--r-xs); border-color: var(--line); background: var(--surface-2); }
.csuggest { border-radius: var(--r-full); }

/* ------------------------------------------------------------ motion --- */

/* The file already scales its animations off --motion. Nothing here needs to
   know that individually if the token is turned off at the source. */
@media (prefers-reduced-motion: reduce) {
  :root { --motion: 0; }
  * { animation-duration: 1ms !important; transition-duration: 1ms !important; }
}


/* ------------------------------------------------ refresh, second pass --- */

/* .rpmini is `flex: 1` because it normally belongs to a row of equal buttons.
   Beside a heading it stretched into a full-width slab, which read as the
   most important thing on the page rather than the least. */
.phisthead .rpmini,
.metabar .cfill { flex: 0 0 auto; padding: 6px 12px; }
.phisthead { font-size: var(--t-md); }

/* Headings. Everything on these pages was 12-15px and bold, so nothing looked
   like a title and the eye had nowhere to land first. */
.rangepage .rzpos { letter-spacing: -.015em; }
.buildside > .rzhead:first-child .rzpos { font-size: var(--t-xl) !important; }
.buildside > .rzhead:first-child { margin-bottom: var(--s-3); }

/* The panel now draws the edge, so the list inside does not need to draw one
   too -- two hairlines 16px apart is the look of a box inside a box. */
.buildlist .rplist, .buildside .rplist {
  border: 0;
  background: transparent;
  margin-top: var(--s-2);
}
.buildlist .rpitem, .buildside .rpitem {
  border-radius: var(--r-xs);
  border-bottom: 0;
  padding: 8px 10px;
}
.buildlist .rpitem { padding-right: 44px; }
.buildside .rpitem + .rpitem { margin-top: 2px; }

/* The action row: raise, call, fold. These are the three most-clicked
   controls in the app and they looked like form furniture. */
.bact { padding: 10px 0; font-size: var(--t-sm); letter-spacing: .02em; }
.btot { border-radius: var(--r-sm); }
.brow { gap: var(--s-2); }

/* Money and percentages read as numbers, not as words. */
.bpctv, .rpnet, .pcost, .metacount b, .cnum { font-variant-numeric: tabular-nums; }


/* --------------------------------------- refresh, the replay column --- */

/* The busiest panel in the app and the one that looked most like a form: six
   identical grey slabs stacked down the right-hand side. They keep their
   sizes -- the transport is a hot path and the targets are already tuned --
   and gain the same hairline, corner and surface as everything else.

   No transitions here: .rpbtn and .rpitem are clicked in fast runs while
   stepping a hand, and a 140ms fade on the pressed state makes a fast run
   feel like it is lagging behind the click. */
.rpbtn {
  border-radius: var(--r-sm);
  background: var(--raise-1);
  border-color: var(--line);
  box-shadow: var(--shadow-1);
}
.rpbtn:hover { background: var(--raise-2); border-color: var(--line-hi); }
.rpbtn.play.on {
  background: linear-gradient(180deg, rgba(90,160,255,.34), rgba(90,160,255,.18));
  border-color: var(--accent);
  color: #fff;
}
.rplast { border-radius: var(--r-sm); }

/* The sidebar is a plane above the felt, so it says so with a surface rather
   than only a border. */
.sidebar {
  background: linear-gradient(180deg, rgba(18,28,46,.97), rgba(8,13,24,.97));
  border-left: 1px solid var(--line-soft);
}

/* The panel headings on the felt side: same reason as the builder's, the page
   had no first thing to look at. */
.rzhead .rzpos { letter-spacing: -.015em; }


/* ------------------------------------------ refresh, last details --- */

/* The foot of the answers page had it backwards: "Try again" was a small
   chip and "Pick another" stretched across the width, so the secondary
   action was the loudest thing on the page. Both are now their own size,
   the primary one first. */
.rprow:has(#pAgain) { justify-content: flex-start; }
.rprow:has(#pAgain) .rpmini { flex: 0 0 auto; padding: 9px 20px; font-size: var(--t-md); }

/* The answer chart is already inside a panel; a second border 16px in is a
   box drawn inside a box. */
.phintcol .phintgrid { border-radius: var(--r-sm); overflow: hidden; }

/* Toasts sit above everything, so they get the top surface and the deepest
   shadow rather than the same flat plate as a list row. */
.toast {
  border-radius: var(--r-md);
  background: var(--surface-3);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-3);
}


/* --------------------------------------------------- the row menu --- */

/* The row is a list entry again: a name, and nothing competing with it. */
.buildlist .rpitem, .buildside .rpitem { padding-right: 30px; }
.rpitem { padding-right: 30px; }

/* Visible on hover, on keyboard focus, and while its own menu is open --
   otherwise the row is just the name. */
.rpdots {
  position: absolute; right: 6px; top: 50%;
  transform: translateY(-50%);
  width: 20px; height: 20px; line-height: 17px; text-align: center;
  border-radius: var(--r-xs);
  color: var(--text-dim); font-size: 15px; letter-spacing: 0;
  opacity: 0; flex-shrink: 0;
}
/* The count is the last thing in the row's flow and the ellipsis is pinned to
   the right edge, so without this they sit on top of each other -- and the
   count is exactly what you want to read while hovering a folder. */
.rpfolder { position: relative; padding-right: 32px; }
.rpitem:hover .rpdots, .rpfolder:hover .rpdots,
.rpitem:focus-within .rpdots, .rpfolder:focus-within .rpdots { opacity: 1; }
.rpdots:hover { background: var(--raise-2); color: var(--text); }

.ctxmenu {
  position: fixed; z-index: 400;
  min-width: 178px; padding: 5px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface-3);
  box-shadow: var(--shadow-3);
  animation: ctxin calc(.11s * var(--motion)) ease-out;
}
@keyframes ctxin {
  from { opacity: 0; transform: translateY(-4px) scale(.98); }
  to   { opacity: 1; transform: none; }
}
.ctxhead {
  padding: 5px 9px 7px;
  font-size: var(--t-2xs);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ctxitem {
  display: block; width: 100%;
  padding: 7px 9px;
  border: 0; border-radius: var(--r-xs);
  background: none; color: var(--text);
  font-size: var(--t-sm);
  font-weight: 600;
  line-height: 1.2;
  text-align: left; cursor: pointer;
}
.ctxitem:hover { background: var(--raise-2); }
.ctxitem.danger { color: #ff9aa2; }
.ctxitem.danger:hover { background: rgba(255,120,130,.16); }
.ctxsep { height: 1px; margin: 5px 4px; background: var(--line); }


/* ------------------------------------------------- the folder tree --- */

/* A folder was drawn dimmer and smaller than the charts inside it, with a
   rule above and nothing below, so it read as a divider between charts rather
   than as the thing containing them -- and once open there was no sign of
   where its contents stopped.

   Now it is a header: brighter than its contents, on a band of its own, with
   a rail down the left of everything filed under it. Same shape a file tree
   has had for thirty years, because it is the shape that reads. */

.rpfolder {
  margin: 8px 0 2px;
  padding: 8px 32px 8px 8px;
  border-top: 0;
  border-radius: var(--r-xs);
  /* No plate behind it. The name being brighter and larger than the charts
     under it is already enough to say "this is the heading" -- a grey band as
     well just puts a box round every folder. Hover still lights up, because
     that is a different question: what am I about to click. */
  background: none;
  color: #fff;
  font-size: var(--t-md);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.005em;
}
.rplist > .rpfolder:first-child { margin-top: 0; }
.rpfolder:hover { background: var(--raise-2); }
.rpfolder.dropon { background: rgba(90,160,255,.22) !important; }

/* One glyph that turns, rather than two that swap: the rotation is the thing
   that says open and shut. */
.rpcaret {
  width: 16px; font-size: 15px; line-height: 1;
  color: #9fb3cc;
  transition: transform calc(.14s * var(--motion)) ease;
}
.rpfolder:not(.shut) .rpcaret { transform: rotate(90deg); }

/* A count, not a badge. The grey pill it used to sit in was the loudest thing
   in the row and it is the least important. */
.rpcount {
  background: none; padding: 0;
  font-size: var(--t-2xs);
  font-weight: 700;
  line-height: 1;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

/* Indent alone. A rail down the left was drawn here for a while; with the
   folder header already sitting above its charts and nothing else competing
   for that column, it was one more line on screen doing a job the indent had
   already done. */
/* Past the folder's name, not just past its arrow. At 22px a chart started
   LEFT of the folder text above it -- the caret and its gap put that text at
   about 31px -- so the one thing carrying the nesting was reading backwards. */
.rpitem.nested { padding-left: 52px; position: relative; }
.rpitem.deep { padding-left: 74px; }

.rpunfiled {
  margin: 14px 0 3px;
  padding: 0 8px;
  font-size: var(--t-2xs);
  font-weight: 700;
  line-height: 1;
  letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-dim);
  opacity: .75;
}


/* ------------------------------------------------ the insertion line --- */

/* Where it will land. A row that lights up says "into here"; a line on one
   edge says "between these two", which is a different promise and has to look
   different or the two drops are indistinguishable until you let go. */
.rpitem.dropbefore::after, .rpitem.dropafter::after {
  content: '';
  position: absolute; left: 6px; right: 6px; height: 2px;
  border-radius: 2px; z-index: 3;
  background: var(--accent);
  box-shadow: 0 0 6px rgba(59,130,246,.75);
}
.rpitem.dropbefore::after { top: -1px; }
.rpitem.dropafter::after { bottom: -1px; }


/* --------------------------------------------- the saved ranges column --- */

/* Same height as the chart beside it. `.buildpage` aligns to flex-start, so
   the column was as tall as its contents and stopped halfway down a full
   grid, which read as the page having been cut off rather than as a list that
   happened to be short.

   Scoped to this column by name: `.buildlist` is also worn by the practice
   page's hint panel, which is a popover and has no business being as tall as
   whatever is next to it. */
/* Grid, not flex, and only on the page that has this column. A flex line in a
   container with a definite height cannot grow past that height, so
   `align-self: stretch` stopped the column at the bottom of the window while
   the chart carried on past it. A grid row sizes to its tallest item and both
   cells stretch to match, which is the thing actually being asked for. */
.buildpage:has(> .savedcol) {
  display: grid;
  /* `auto` rather than a number, so the track follows .buildlist's width
     instead of having to be kept in step with it by hand. */
  grid-template-columns: minmax(0, 860px) auto;
  align-items: stretch;
}
.savedcol {
  display: flex;
  flex-direction: column;
}
.savedcol #bList {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
}
/* The list takes the room that is left and scrolls inside it, so the panel
   itself never grows past the chart. */
.savedcol .rplist {
  flex: 1; min-height: 0;
  max-height: none;
  overflow-y: auto;
}


/* ------------------------------------------------------ the chart title --- */

.rztitle { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* Where it is filed, in the type that context goes in. */
.rzcrumb {
  font-size: var(--t-2xs);
  font-weight: 700;
  line-height: 1;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* What it is called. */
.rzname {
  font-size: var(--t-xl);
  font-weight: 750;
  line-height: 1.15;
  letter-spacing: -.02em;
  color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The head is a row of two things; only the title should give up width. */
.rzhead:has(.rztitle) { align-items: flex-start; gap: 16px; }
.rzhead:has(.rztitle) .rznode { flex: none; margin-top: 4px; }


/* --------------------------------------------------- the lucky button --- */

/* Beside the heading, and deliberately the brightest thing on the pick
   screen: the whole point is that it is easier to press than it is to scroll
   the list and talk yourself into the chart you already know. */
/* Beside the title, not pinned to the far side of the panel. `.rzhead` is
   space-between because it usually holds a heading and a status on opposite
   edges; here the button belongs TO the heading. */
.pickhead { justify-content: flex-start; gap: 14px; }

.plucky {
  flex: none;
  padding: 8px 16px;
  border-radius: var(--r-full);
  border: 1px solid var(--accent);
  background: linear-gradient(180deg, rgba(90,160,255,.26), rgba(90,160,255,.12));
  color: var(--text);
  font-size: var(--t-sm);
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,.16);
  transition: background calc(.14s * var(--motion)),
              transform calc(.08s * var(--motion));
}
.plucky:hover { background: rgba(90,160,255,.36); }
.plucky:active { transform: translateY(1px); }
.plucky:disabled {
  opacity: .4; cursor: default;
  border-color: var(--line); background: var(--raise-1);
}


/* -------------------------------------------------------- the mix panel --- */

/* One hand's three frequencies, over the square they belong to. */
.bmix {
  position: fixed; z-index: 420;
  width: 232px; padding: 10px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface-3);
  box-shadow: var(--shadow-3);
  animation: ctxin calc(.11s * var(--motion)) ease-out;
}
.bmixhead {
  padding: 2px 2px 8px;
  font-size: var(--t-md);
  font-weight: 800;
  line-height: 1;
  color: var(--text);
}
.bmixrow { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
.bmixstep {
  flex: none; width: 24px; height: 26px;
  border: 1px solid var(--line); border-radius: var(--r-xs);
  background: var(--raise-1); color: var(--text-dim);
  font-size: 13px;
  font-weight: 700;
  line-height: 1; cursor: pointer;
}
.bmixstep:hover { background: var(--raise-2); color: var(--text); }

/* The bubble is the number and the level at once: it fills to whatever it is
   set to, so the panel can be read without reading it. */
.bmixbub {
  flex: 1; min-width: 0; height: 26px;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 9px;
  border-radius: var(--r-full);
  border: 1px solid var(--line);
  color: #eef4fb;
  font-size: var(--t-xs);
  font-weight: 700;
  line-height: 1;
  text-transform: capitalize;
  cursor: ew-resize;
  touch-action: none;
  user-select: none; -webkit-user-select: none;
  text-shadow: 0 1px 2px rgba(0,0,0,.7);
}
.bmixbub b { font-variant-numeric: tabular-nums; }
.bmixbub.raise { background: linear-gradient(to right, var(--b-raise) 0 var(--fill), rgba(224,67,60,.14) var(--fill) 100%); }
.bmixbub.call  { background: linear-gradient(to right, var(--b-call)  0 var(--fill), rgba(67,169,78,.14) var(--fill) 100%); }
.bmixbub.fold  { background: linear-gradient(to right, var(--b-fold)  0 var(--fill), rgba(61,132,198,.14) var(--fill) 100%); }
.bmixhint {
  margin-top: 8px;
  font-size: var(--t-2xs);
  font-weight: 600;
  line-height: 1.4;
  color: var(--text-dim);
}


/* The total, and the one thing standing between an unbalanced mix and the
   rest of the app. Quiet when it is right, amber when it is not -- a warning,
   not an alarm: nothing has gone wrong, there is just a number still to
   place. */
.bmixtot {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 9px; padding: 6px 9px;
  border-radius: var(--r-xs);
  border: 1px solid var(--line);
  font-size: var(--t-xs);
  font-weight: 700;
  line-height: 1;
  color: var(--text-dim);
}
.bmixtot b { font-variant-numeric: tabular-nums; color: var(--text); }
.bmixtot.bad {
  border-color: rgba(255,199,74,.5);
  background: rgba(255,199,74,.12);
  color: var(--gold);
}
.bmixtot.bad b { color: var(--gold); }

/* Tried to leave while it does not add up. */
.bmix.bmixnag { animation: bmixnag calc(.4s * var(--motion)) ease; }
@keyframes bmixnag {
  0%, 100% { transform: translateX(0); }
  15% { transform: translateX(-5px); }
  35% { transform: translateX(5px); }
  55% { transform: translateX(-3px); }
  75% { transform: translateX(3px); }
}


/* ==================================================== the spot trainer --- */

.mockflag {
  margin-left: auto;
  padding: 4px 10px;
  border-radius: var(--r-full);
  border: 1px dashed rgba(255,215,106,.45);
  background: rgba(255,215,106,.10);
  color: var(--gold);
  font-size: var(--t-2xs);
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: .04em;
}

.trainerpage {
  display: grid;
  /* The felt wants room. It is the thing you are reading. */
  grid-template-columns: minmax(0, 1000px) 300px;
  /* One row, the height of the page rather than of its contents, so the felt
     can be handed whatever is left over after the header and the buttons. */
  grid-template-rows: minmax(0, 1fr);
  align-items: stretch;
  justify-content: center;
  gap: 16px;
  padding: 18px;
  height: calc(100% - 60px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.tmain, .tside {
  background: var(--surface-1);
  min-height: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-2);
  padding: var(--s-5);
}
.tside { display: flex; flex-direction: column; }
.tmain { display: flex; flex-direction: column; }

/* ------------------------------------------------------------ the felt --- */

/* The table app's own felt, embedded. Everything that draws it -- .felt,
   .seat, .plate, .dlcard, .chip, .posbadge -- is the table page's CSS,
   untouched; all that is needed here is a box for it to sit in and a smaller
   pad, since this panel is 660px rather than a whole window. */
/* The box the table is allowed to occupy, and the fixed-size stage that gets
   scaled down into it. Every number here is the table app's own: 373x601 of
   felt, and the overhang of the seats that hang off its edges. */
/* Takes whatever height is left after the header, the question and the
   buttons, and the table is scaled to fit it. */
.tfeltbox { position: relative; flex: 1; min-height: 240px; }
.tfeltstage {
  position: absolute; left: 50%; top: 50%;
  width: 946px; height: 686px;
  transform: translate(-50%, -50%) scale(var(--tscale, 1));
  transform-origin: center;
}
.tfeltwrap {
  width: 946px; height: 686px;
  padding: 42px 286px;
}
.tfeltwrap .felt { height: 601px; }
/* A seat that has thrown its hand away is still at the table. */
.tfeltwrap .seat.folded { opacity: .38; }
.tfeltwrap .seat.folded .plate { filter: grayscale(.5); }
/* Nobody has a real name in a made-up spot, so the plate says the seat. */
.tfeltwrap .alias { color: var(--text-dim); }
.tfeltwrap .seat.hero .alias { color: var(--text); }

/* ------------------------------------------------------------ the story --- */

/* Your hand, twice: small on the felt where it really sits, and big beside
   the question because reading it is the question. Same .dlcard the replayer
   uses, so it is the app's card and not a second kind. */
.thand {
  display: flex; align-items: center; gap: var(--s-4);
  margin-top: var(--s-4);
}
.thand .dlcards { margin: 0; flex: none; }

.tstory { font-size: var(--t-md); line-height: 1.5; color: var(--text); }
.tstory b { color: #fff; }
.tprice {
  display: block; margin-top: 4px;
  font-size: var(--t-xs);
  font-weight: 600;
  line-height: 1.3; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

/* ----------------------------------------------------------- the choice --- */

/* Everything under the hand, in a box that is the same height whether you
   have answered or not.

   The felt above it is the only flexible item in a fixed-height column, so it
   absorbs every pixel this block gains or loses -- answering grew this side by
   113px and the table shrank by 113px to pay for it, then grew back on the
   next spot. The table was resizing twice per spot.

   Bottom-aligned so the buttons land in the same place in both states too. */
.tbottom {
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: 248px;
}
.tchoices { display: flex; gap: var(--s-2); margin-top: var(--s-5); }

/* Fetching the next spot with the last one still on screen. Nothing moves;
   the buttons just stop taking presses. */
.tbusy .tchoice { pointer-events: none; opacity: .55; }
.tchoice {
  flex: 1;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 15px 0;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--raise-1);
  color: var(--text);
  cursor: pointer;
  font-size: var(--t-lg);
  font-weight: 800;
  line-height: 1;
  text-transform: capitalize;
  transition: background calc(.12s * var(--motion)),
              border-color calc(.12s * var(--motion)),
              transform calc(.08s * var(--motion));
}
.tchoice:active { transform: translateY(1px); }
.tchoice.raise:hover { background: rgba(224,67,60,.30); border-color: var(--b-raise); }
.tchoice.call:hover  { background: rgba(67,169,78,.30);  border-color: var(--b-call); }
.tchoice.fold:hover  { background: rgba(61,132,198,.30); border-color: var(--b-fold); }
.tchoice.next {
  background: linear-gradient(180deg, #4a8dfb, #2b66cf);
  border-color: rgba(255,255,255,.2);
  box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,.24);
}
/* The key that does the same thing, so the mouse becomes optional. */
.tchoicekey {
  font-size: var(--t-2xs);
  font-weight: 700;
  line-height: 1;
  padding: 3px 6px; border-radius: var(--r-xs);
  background: rgba(0,0,0,.32); color: var(--text-dim);
}

/* ---------------------------------------------------------- the verdict --- */

.tverdict {
  margin-top: var(--s-5);
  padding: 12px 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--raise-1);
}
.tverdicttop {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.tverdicttop b { font-size: var(--t-lg);
 font-weight: 800;
 line-height: 1; }
.tverdicttop span {
  font-size: var(--t-2xs);
  font-weight: 700;
  line-height: 1; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-dim);
}
.tverdictnote { margin-top: 5px; font-size: var(--t-sm); color: var(--text-dim); line-height: 1.5; }
.tverdict.ok   { border-color: rgba(79,174,106,.45); background: rgba(79,174,106,.12); }
.tverdict.ok b { color: #7fe0a4; }
/* Amber, not red: a hand in the small half of a mix is a hand you play, just
   less often than the other one. Marking it wrong would teach the wrong thing. */
.tverdict.part   { border-color: rgba(255,199,74,.45); background: rgba(255,199,74,.12); }
.tverdict.part b { color: var(--gold); }
.tverdict.bad   { border-color: rgba(214,69,69,.5); background: rgba(214,69,69,.14); }
.tverdict.bad b { color: #ff9aa2; }

.tmix { margin-top: var(--s-4); }
.tmixlabel {
  display: flex; justify-content: space-between; gap: 10px;
  margin-bottom: 6px;
  font-size: var(--t-2xs);
  font-weight: 700;
  line-height: 1; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-dim);
}
.tmixlabel span { text-transform: none; letter-spacing: 0; color: #9dc6ef; }
.tbar {
  display: flex; height: 30px; border-radius: var(--r-xs);
  overflow: hidden; border: 1px solid var(--line);
}
.tbarpart {
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-2xs);
  font-weight: 700;
  line-height: 1; color: #fff;
  text-transform: capitalize;
  text-shadow: 0 1px 2px rgba(0,0,0,.7);
  overflow: hidden; white-space: nowrap;
}
.tbarpart.raise { background: var(--b-raise); }
.tbarpart.call  { background: var(--b-call); }
.tbarpart.fold  { background: var(--b-fold); }

/* ---------------------------------------------------------- the session --- */

.tscore {
  margin-top: var(--s-3);
  padding: var(--s-4) 0;
  text-align: center;
  border-radius: var(--r-md);
  background: var(--raise-1);
  border: 1px solid var(--line);
}
.tscorebig {
  font-size: 30px;
  font-weight: 800;
  line-height: 1; letter-spacing: -.03em; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.tscoresub {
  margin-top: 4px; font-size: var(--t-2xs);
 font-weight: 600;
 line-height: 1;
  letter-spacing: .08em; text-transform: uppercase; color: var(--text-dim);
}

.tlog { margin-top: var(--s-3); overflow-y: auto; flex: 1; min-height: 0; }
.tlogrow {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 8px;
  border-radius: var(--r-xs);
  font-size: var(--t-xs);
  font-weight: 600;
  line-height: 1.2;
  color: var(--text-dim);
  border-left: 2px solid transparent;
}
.tlogrow:hover { background: var(--raise-1); }
.tlogrow.ok   { border-left-color: #4fae6a; }
.tlogrow.part { border-left-color: var(--gold); }
.tlogrow.bad  { border-left-color: #d64545; }
.tlogcards { font-weight: 800; color: var(--text); min-width: 42px; }
.tlogspot { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tlogpick { text-transform: capitalize; }
.tlogpct { font-variant-numeric: tabular-nums; min-width: 34px; text-align: right; color: var(--text); }

.tmocknote {
  margin-top: auto; padding-top: var(--s-4);
  border-top: 1px solid var(--line-soft);
}


/* ------------------------------------------------------- the randomizer --- */

/* A die, sitting with the hand, because that is what it is: the number you
   are playing this hand to. It used to be a full-width scale with both ends
   labelled -- which explained itself well and took more of the screen than
   the table did, to say one number.

   It is a readout, not a control. Rolling again was possible for a while and
   should not have been: a number you can re-roll is not a number you have to
   play, and the whole reason for having one is that you do not get to choose
   it. One roll, one spot. */
.tdie {
  position: relative;
  flex: none;
  /* Beside the sentence that sets the spot up, not shoved to the far edge of
     the panel. You read the hand, then what happened, then your number -- and
     things read in one breath should not have a gap in the middle. */
  width: 62px; height: 62px;
  border-radius: 15px;
  border: 1px solid rgba(0,0,0,.35);
  background: linear-gradient(158deg, #fbfdff 0%, #e4ebf4 55%, #cdd7e4 100%);
  box-shadow: 0 6px 14px -4px rgba(0,0,0,.65),
              inset 0 -3px 0 rgba(0,0,0,.10),
              inset 0 2px 0 rgba(255,255,255,.9);
  display: flex; align-items: center; justify-content: center;
}
.tdienum {
  font-size: 25px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.04em;
  color: #16202f;
  font-variant-numeric: tabular-nums;
}
.tdie.rolling { animation: tdieroll calc(.46s * var(--motion)) ease-out; }
@keyframes tdieroll {
  0%   { transform: rotate(0) scale(1); }
  25%  { transform: rotate(-16deg) scale(1.14); }
  55%  { transform: rotate(13deg) scale(1.09); }
  80%  { transform: rotate(-5deg) scale(1.02); }
  100% { transform: rotate(0) scale(1); }
}

/* The same number again, on the chart's own bar: this is where it landed, and
   therefore why the answer is what it is. */
.tbarwrap { position: relative; }
.tbarpin {
  position: absolute; top: 50%; height: 40px;
  width: 3px; margin-left: -1.5px;
  transform: translateY(-50%);
  border-radius: 2px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0,0,0,.55), 0 2px 6px rgba(0,0,0,.5);
}
.tbarpin b {
  position: absolute; left: 50%; top: -20px;
  transform: translateX(-50%);
  padding: 2px 6px; border-radius: var(--r-xs);
  background: #fff; color: #16202f;
  font-size: var(--t-2xs);
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.tmix { margin-top: var(--s-6); }

.tlogroll {
  font-variant-numeric: tabular-nums;
  min-width: 26px; text-align: right;
  color: var(--gold);
  font-weight: 800;
}
.tlogpick i { font-style: normal; color: var(--text); }


/* ------------------------------------------------- trainer: coverage --- */

/* How much of the library you have been asked, on live squares only. Counting
   the hands every chart always folds would read ninety-something on day one
   and mean nothing. */
.tcover { margin-top: auto; padding-top: var(--s-4); border-top: 1px solid var(--line-soft); }
.tcoverbar {
  height: 6px; border-radius: var(--r-full);
  background: rgba(255,255,255,.07);
  overflow: hidden; margin-bottom: 10px;
}
.tcoverbar span { display: block; height: 100%; background: var(--accent); border-radius: inherit; }
.tcoverrow {
  display: flex; justify-content: space-between; align-items: baseline; gap: 8px;
  font-size: var(--t-xs);
  font-weight: 600;
  line-height: 1.5; color: var(--text-dim);
}
.tcoverrow b { color: var(--text); font-variant-numeric: tabular-nums; }
.tcoverrow i { font-style: normal; opacity: .6; }
.tcoverrow.stale, .tcoverrow.stale b { color: var(--gold); }

/* Nothing to ask yet, because no chart says where you are sitting. */
.tempty { justify-content: center; }
.tmissing {
  margin: 10px 0 0; padding-left: 18px;
  font-size: var(--t-sm);
  font-weight: 600;
  line-height: 1.7; color: var(--gold);
}


/* -------------------------------------------------- trainer: studying --- */

/* What the session is allowed to draw from. At the top of the panel because it
   is the first decision of a session, not a preference buried in a menu. */
.tstudy { margin-bottom: var(--s-5); }
.tstudysel { width: 100%; margin-top: 7px; padding: 8px 9px; font-size: var(--t-sm); }
.tstudyall {
  padding: 3px 9px; border-radius: var(--r-full);
  border: 1px solid var(--line); background: none;
  color: var(--text-dim); font-size: var(--t-2xs);
 font-weight: 700;
 line-height: 1.4;
  cursor: pointer;
}
.tstudyall:hover { border-color: var(--accent); color: var(--text); }
.tstudycount { margin-top: 8px; }

/* ------------------------------------------------------------------ home -- */

/* The front door of the study edition. One column, generous margins: this is
   the one screen in the app that is read rather than worked in, so it gets
   reading measure instead of the edge-to-edge density everything else wants. */
.homepage {
  max-width: 860px;
  margin: 0 auto;
  padding: var(--s-7) var(--s-5) var(--s-7);
  display: flex; flex-direction: column; gap: var(--s-6);
}

/* Numbers, on their own recessed strip. Four at most -- the fourth only
   appears when something actually needs attention. */
.homestats {
  display: grid; gap: var(--s-2);
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.homestat {
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--s-3) var(--s-4);
  background: var(--surface-1);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
}
.homestat.warn { border-color: rgba(226,165,60,.4); }
.homestat.go {
  text-decoration: none;
  transition: background calc(.16s * var(--motion)),
              border-color calc(.16s * var(--motion));
}
.homestat.go:hover { background: var(--surface-2); }
.homestat.warn.go:hover { border-color: rgba(226,165,60,.75); }
.homestat.warn .homestatsub { color: var(--spew); font-weight: 700; }
.homestatnum {
  font-weight: 800;
  font-size: var(--t-2xl);
  line-height: 1;
  letter-spacing: -.03em;
  color: var(--text);
}
.homestat.warn .homestatnum { color: var(--spew); }
.homestatlabel {
  font-weight: 700;
  font-size: var(--t-sm);
  line-height: 1.2;
  color: var(--text);
}
.homestatsub {
  font-weight: 500;
  font-size: var(--t-xs);
  line-height: 1.3;
  color: var(--text-dim);
}


.homeh2 {
  margin: 0 0 var(--s-3);
  font-weight: 800;
  font-size: var(--t-lg);
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--text);
}
@media (max-width: 560px) {
  .homepage { padding: var(--s-5) var(--s-4); gap: var(--s-5); }
}

/* ------------------------------------------------------------------ auth -- */

/* Who you are, pushed to the far end of the bar. Present only when there is
   an account to be signed out of -- run this locally and there is nothing
   here, because there is nobody to be. */
.authwho {
  margin-left: auto;
  display: flex; align-items: center; gap: var(--s-3);
  /* Usernames are stored lowercase because they become folder names; a name
     is a name, so it is shown the way one is written. */
  text-transform: capitalize;
  font-weight: 700;
  font-size: var(--t-xs);
  line-height: 1;
  color: var(--text-dim);
}
.authwho a {
  color: var(--text-dim); text-decoration: none;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-full);
}
.authwho a:hover { color: var(--text); border-color: var(--line-hi); }

/* The sign-in screen. One card, centred, nothing else on the page: it is the
   only screen with a single thing to do on it. */
.authpage { display: flex; min-height: 100%; }
.authwrap {
  margin: auto;
  width: 100%; max-width: 380px;
  padding: var(--s-5);
}
.authcard {
  display: flex; flex-direction: column; gap: var(--s-3);
  padding: var(--s-6);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-3);
}
.authcard h1 {
  margin: 0;
  font-weight: 800;
  font-size: var(--t-2xl);
  line-height: 1.15;
  letter-spacing: -.03em; color: var(--text);
}
.authsub {
  margin: 0 0 var(--s-2);
  font-size: var(--t-sm);
  font-weight: 500;
  line-height: 1.5; color: var(--text-dim);
}
.autherr {
  padding: var(--s-3);
  border-radius: var(--r-sm);
  background: rgba(214,69,69,.14);
  border: 1px solid rgba(214,69,69,.4);
  color: #ffb3b3;
  font-weight: 600;
  font-size: var(--t-sm);
  line-height: 1.4;
}
.authfield { display: flex; flex-direction: column; gap: var(--s-1); }
.authfield > span {
  font-weight: 700;
  font-size: var(--t-xs);
  line-height: 1;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-dim);
}
.authfield small { color: var(--text-dim); font-size: var(--t-xs);
 font-weight: 500;
 line-height: 1.4; }
.authfield input {
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--text);
  padding: 10px 12px;
  font-weight: 600;
  font-size: var(--t-md);
  line-height: 1.2;
}
.authfield input:focus { outline: none; border-color: var(--accent); }
.authgo {
  margin-top: var(--s-2);
  padding: 11px 16px;
  border-radius: var(--r-sm);
  border: 1px solid var(--accent);
  background: rgba(90,160,255,.22);
  color: var(--text);
  font-weight: 800;
  font-size: var(--t-md);
  line-height: 1;
  cursor: pointer;
}
.authgo:hover { background: rgba(90,160,255,.34); }
.authalt {
  text-align: center;
  font-size: var(--t-sm);
  font-weight: 500;
  line-height: 1.4; color: var(--text-dim);
}
.authalt a { color: var(--accent); text-decoration: none; font-weight: 700; }


/* --------------------------------------------- trainer: the whole chart --- */

.tchartwrap {
  position: fixed; inset: 0; z-index: 500;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(4,8,16,.72);
  backdrop-filter: blur(3px);
  animation: tchartin calc(.13s * var(--motion)) ease-out;
}
@keyframes tchartin { from { opacity: 0; } to { opacity: 1; } }
.tchartpanel {
  width: min(820px, 100%);
  max-height: 100%;
  overflow-y: auto;
  padding: var(--s-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-2);
  box-shadow: var(--shadow-3);
}
.tchartsub { margin-top: 6px; }
.tchartgrid { margin-top: var(--s-3); }
/* The hand you were just asked, so the answer you saw has a place in the
   shape rather than being a fact on its own. */
.tchartgrid .cell.hot {
  outline: 2px solid #fff;
  outline-offset: -2px;
  z-index: 2;
  font-weight: 800;
  box-shadow: 0 0 12px rgba(255,255,255,.55);
}
.tchoice.see { flex: 0 0 auto; padding-left: 22px; padding-right: 22px; }
/* .rpmini is `flex: 1` because it usually belongs to a row of equal buttons.
   Next to a heading it stretches across the panel -- third time this has
   caught me, so it is worth saying out loud. */
.tchartpanel .rzhead .rpmini { flex: 0 0 auto; padding: 6px 14px; }

/* ------------------------------------------------------ home: mastery -- */

.homeknowhead {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin-bottom: var(--s-2);
}
.homeknowhead .homeh2 { margin: 0; }
.knowoverall {
  margin-left: auto;
  font-weight: 800;
  font-size: var(--t-xl);
  line-height: 1;
  letter-spacing: -.02em;
}
.knownote {
  margin: 0 0 var(--s-3);
  max-width: 62ch;
  font-weight: 500;
  font-size: var(--t-xs);
  line-height: 1.5;
  color: var(--text-dim);
}
.knowrows {
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface-1);
}
.knowrow {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-4);
  border-top: 1px solid var(--line-soft);
  text-decoration: none;
  color: var(--text-dim);
}
.knowrow:first-child { border-top: 0; }
.knowrow:hover { background: var(--raise-1); }
/* Seat names are short and want to line up, so the column is fixed rather
   than sized to the longest one that happens to be present. */
.knowpos {
  flex: 0 0 46px;
  font-weight: 800;
  font-size: var(--t-sm);
  line-height: 1;
  color: var(--text);
}
.knowbar {
  flex: 1; min-width: 0; height: 7px;
  border-radius: var(--r-full);
  background: rgba(255,255,255,.07);
  overflow: hidden;
}
.knowbar i {
  display: block; height: 100%;
  border-radius: var(--r-full);
  transition: width calc(.4s * var(--motion));
}
.knowbar i.good { background: var(--station); }
.knowbar i.ok   { background: var(--spew); }
.knowbar i.poor { background: var(--trap); }
.knowpct {
  flex: 0 0 40px; text-align: right;
  font-weight: 800;
  font-size: var(--t-sm);
  line-height: 1;
}
.knowpct.good, .knowoverall.good { color: var(--station); }
.knowpct.ok,   .knowoverall.ok   { color: var(--spew); }
.knowpct.poor, .knowoverall.poor { color: var(--trap); }

/* --------------------------------------------------------- centred nav -- */

/* The tabs sit in the middle of the bar rather than at its left edge.

   Whatever shares the bar with them -- your name on the study pages, the
   database status on the table -- comes out of the flow to do it. Left in,
   the tabs would be centred in the space *left over*, which means they shift
   sideways when the name beside them is longer, and sit in a different place
   on the table page than on the others. Centred on the window, they land in
   the same spot on every page. */
.topbar { justify-content: center; }
.topbar .authwho,
.topbar .status {
  position: absolute;
  right: var(--s-5);
  top: 50%;
  transform: translateY(-50%);
  margin-left: 0;
}

/* Narrow screens are handled in one place, at the end of this file. Letting
   the bar wrap here was the old answer and it had two faults: your name took a
   whole row to itself, and on the widths where it did NOT wrap the tabs were
   centred on the leftover space instead of the window -- so the pill moved
   sideways depending on how long your name is. */

/* ------------------------------------------------------------- the seat -- */

.seatpage {
  max-width: 980px;
  margin: 0 auto;
  padding: var(--s-6) var(--s-5) var(--s-7);
  display: flex; flex-direction: column; gap: var(--s-5);
}

.seathead {
  display: flex; align-items: center; gap: var(--s-3);
  flex-wrap: wrap;
}
.seatback {
  flex: 0 0 100%;
  text-decoration: none; color: var(--text-dim);
  font-weight: 700;
  font-size: var(--t-xs);
  line-height: 1;
  margin-bottom: var(--s-1);
}
.seatback:hover { color: var(--text); }
.seathead h1 {
  margin: 0;
  font-weight: 800;
  font-size: clamp(24px, 3vw, 32px);
  line-height: 1.1;
  letter-spacing: -.03em;
  color: var(--text);
}
.seatscore {
  font-weight: 800;
  font-size: var(--t-2xl);
  line-height: 1;
  letter-spacing: -.02em;
}
.seatscore.good, .seatchartscore.good, .swpct.good { color: var(--station); }
.seatscore.ok,   .seatchartscore.ok,   .swpct.ok   { color: var(--spew); }
.seatscore.poor, .seatchartscore.poor, .swpct.poor { color: var(--trap); }
.seatdrill {
  margin-left: auto;
  padding: 9px 16px;
  border-radius: var(--r-full);
  border: 1px solid var(--accent);
  background: rgba(90,160,255,.2);
  color: var(--text);
  text-decoration: none;
  font-weight: 800;
  font-size: var(--t-sm);
  line-height: 1;
}
.seatdrill:hover { background: rgba(90,160,255,.34); }

.seatnote {
  margin: 0; max-width: 68ch;
  font-weight: 500;
  font-size: var(--t-xs);
  line-height: 1.55;
  color: var(--text-dim);
}

/* One chart, with its grid. */
.seatchart {
  padding: var(--s-4);
  background: var(--surface-1);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
}
.seatcharthead {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin-bottom: var(--s-3);
  flex-wrap: wrap;
}
.seatchartname {
  font-weight: 800;
  font-size: var(--t-md);
  line-height: 1.2;
  color: var(--text);
}
.seatchartsub {
  font-weight: 500;
  font-size: var(--t-xs);
  line-height: 1.2;
  color: var(--text-dim);
}
.seatchartscore {
  margin-left: auto;
  font-weight: 800;
  font-size: var(--t-lg);
  line-height: 1;
}
.seatchartopen {
  flex: 0 0 auto;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  color: var(--text-dim);
  text-decoration: none;
  font-weight: 700;
  font-size: var(--t-xs);
  line-height: 1;
}
.seatchartopen:hover { color: var(--text); border-color: var(--line-hi); }

/* The heatmap. Same 13x13 as everywhere else in the app, wider than tall,
   because that is the shape a range is read in. */
.seatgrid {
  display: grid;
  grid-template-columns: repeat(13, 1fr);
  gap: 2px;
}
.seatcell {
  display: flex; align-items: center; padding-left: 3px;
  aspect-ratio: 1.32;
  border-radius: 3px;
  font-weight: 700;
  font-size: clamp(7px, .95vw, 11px);
  line-height: 1;
  letter-spacing: -.02em;
  text-shadow: 0 1px 2px rgba(0,0,0,.8);
  overflow: hidden;
  cursor: default;
}
/* Answered, but against a mix the chart no longer has. Hatched rather than
   recoloured, so it reads as "this number is suspect" instead of as a
   different score. */
.seatcell.stale {
  outline: 1px dashed rgba(255,255,255,.45);
  outline-offset: -2px;
}

/* Weakest hands. */
.seatweakrows {
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface-1);
  margin-top: var(--s-3);
}
.seatweakrow {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-4);
  border-top: 1px solid var(--line-soft);
  font-weight: 600;
  font-size: var(--t-sm);
  line-height: 1.2;
  color: var(--text-dim);
}
.seatweakrow:first-child { border-top: 0; }
.swhand { flex: 0 0 48px; font-weight: 800; color: var(--text); }
.swmix  { flex: 0 0 74px; font-weight: 500; font-size: var(--t-xs); }
.swchart {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 500;
}
.swrec  { flex: 0 0 44px; text-align: right; font-weight: 500; }
.swpct  { flex: 0 0 44px; text-align: right; font-weight: 800; }
.swlast { flex: 0 0 78px; text-align: right; font-weight: 500; font-size: var(--t-xs); }

@media (max-width: 620px) {
  .seatpage { padding: var(--s-5) var(--s-3); }
  .swmix, .swlast { display: none; }
  .seatdrill { margin-left: 0; }
}

/* ------------------------------------------------- the pages that scroll -- */

/* html and body are locked to the viewport with overflow hidden, because the
   table is a fixed-viewport app. Long pages therefore have to scroll an inner
   container, or their bottom half is simply unreachable.

   The existing pages do that with height: calc(100% - 60px), which hard-codes
   the topbar. That number stopped being true the moment the bar was allowed
   to wrap on a phone. These two use flexbox instead: the bar takes what it
   takes, the page gets the rest, and nothing has to know how tall the bar is.

   Scoped with :has() so only the pages that opt in become flex columns --
   .buildpage and .metapage keep the layout they already work with. */
body.rangepage:has(> .homepage),
body.rangepage:has(> .seatpage) {
  display: flex;
  flex-direction: column;
}
body.rangepage > .topbar { flex: 0 0 auto; }
.homepage, .seatpage {
  flex: 1 1 auto;
  min-height: 0;
  /* Explicit, because these centre themselves with auto side margins and an
     auto margin in the cross axis switches off the stretch a flex item would
     otherwise get -- leaving the page sized to its widest sentence. */
  width: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* --------------------------------------------------------- the clock -- */

/* A dialog over a blurred room. The blur is doing real work: the felt behind
   is busy and colourful, and a flat scrim over it still reads as a table you
   could go back to. Blurred, it reads as put aside. */
.ckmodal {
  position: fixed; inset: 0; z-index: 400;
  display: flex; align-items: center; justify-content: center;
  padding: var(--s-5);
  background: rgba(4, 9, 18, .62);
  backdrop-filter: blur(14px) saturate(.7);
  -webkit-backdrop-filter: blur(14px) saturate(.7);
  animation: ckfade calc(.22s * var(--motion)) ease-out;
}
@keyframes ckfade { from { opacity: 0 } to { opacity: 1 } }

.ckcard {
  width: 100%; max-width: 420px;
  padding: var(--s-6);
  background: var(--surface-2);
  border: 1px solid var(--line-hi);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-3);
  text-align: center;
}
.ckcard h2 {
  margin: 0 0 var(--s-2);
  font-weight: 800;
  font-size: var(--t-2xl);
  line-height: 1.15;
  letter-spacing: -.03em;
  color: var(--text);
}
.ckcard p {
  margin: 0 0 var(--s-5);
  font-weight: 500;
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--text-dim);
}

.ckpresets {
  display: grid; gap: var(--s-2);
  grid-template-columns: repeat(3, 1fr);
  margin-bottom: var(--s-4);
}
.ckpreset {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: var(--s-3) 0;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-1);
  color: var(--text);
  cursor: pointer;
  font-weight: 800;
  font-size: var(--t-lg);
  line-height: 1;
}
.ckpreset span {
  font-weight: 600;
  font-size: var(--t-2xs, 10px);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.ckpreset:hover { border-color: var(--accent); background: rgba(90,160,255,.16); }

.ckcustom {
  display: flex; align-items: center; justify-content: center; gap: var(--s-2);
  margin-bottom: var(--s-4);
  font-weight: 600;
  font-size: var(--t-sm);
  color: var(--text-dim);
}
.ckcustom input {
  width: 74px;
  padding: 9px 10px;
  text-align: center;
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--text);
  font-weight: 800;
  font-size: var(--t-md);
  font-family: inherit;
}
.ckcustom input:focus { outline: none; border-color: var(--accent); }
.ckgo {
  padding: 9px 16px;
  border-radius: var(--r-sm);
  border: 1px solid var(--accent);
  background: rgba(90,160,255,.22);
  color: var(--text);
  cursor: pointer;
  font-weight: 800;
  font-size: var(--t-sm);
  font-family: inherit;
}
.ckgo:hover { background: rgba(90,160,255,.36); }

.cknone {
  border: 0; background: none;
  color: var(--text-dim);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  font-weight: 600;
  font-size: var(--t-xs);
  font-family: inherit;
}
.cknone:hover { color: var(--text); }

.ckstats {
  display: flex; justify-content: center; gap: var(--s-5);
  margin-bottom: var(--s-5);
}
.ckstat {
  display: flex; flex-direction: column; gap: 2px;
  font-weight: 600;
  font-size: var(--t-xs);
  color: var(--text-dim);
}
.ckstat b {
  font-weight: 800;
  font-size: var(--t-2xl);
  line-height: 1;
  letter-spacing: -.03em;
  color: var(--text);
}

/* ---- the card in the corner ---- */

/* Face down by default. Sized and shaped like the hole cards on the felt, so
   that turning one over to look is the gesture the app has already taught. */
/* The spot counter and the clock, stacked at the right of the header. */
.rznodecol {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: var(--s-2);
  flex: 0 0 auto;
}
.ckslot { display: block; line-height: 0; }

.ckcardface {
  display: block;
  width: 46px; height: 64px;
  padding: 0; border: 0; background: none;
  cursor: pointer;
  perspective: 700px;
}
.ckflip {
  position: relative;
  display: block; width: 100%; height: 100%;
  transform-style: preserve-3d;
}
.ckback, .ckfront {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px;
}

/* The peel. The back is a flap hinged on its bottom-left corner and lifted
   away by --peel, which the drag writes straight into. Rotating about the
   diagonal is what makes it read as a corner coming up off the felt rather
   than a lid opening.

   No transition while you are dragging -- the card has to be under your
   finger, not chasing it. The class goes on for the snap back or the release
   into open, which are the only moments it should animate itself. */
.ckback {
  transform-origin: left bottom;
  transform: rotate3d(-1, 1, 0, calc(var(--peel, 0) * 168deg));
  box-shadow: 0 6px 16px rgba(0,0,0,.55);
  transition: transform calc(.42s * var(--motion)) cubic-bezier(.2, .85, .25, 1);
}
.ckcardface.ckdrag .ckback { transition: none; }
/* Past halfway the flap is edge-on and then facing away; hiding its back face
   stops the crosshatch reappearing mirrored over the time underneath. */
.ckback { backface-visibility: hidden; -webkit-backface-visibility: hidden; }

/* What is underneath darkens under the flap and lifts as it comes away, so
   the two read as stacked rather than as one image swapping for another. */
.ckfront {
  filter: brightness(calc(.55 + var(--peel, 0) * .45));
  transition: filter calc(.42s * var(--motion)) ease-out;
}
.ckcardface.ckdrag .ckfront { transition: none; }
/* The back: the same navy as a spade card, with the crosshatch a card back
   has, so it reads as face down rather than as an empty button. */
.ckback {
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,.05) 0 3px, transparent 3px 6px),
    linear-gradient(158deg, #2b3352, #141829);
  border: 1px solid rgba(255,255,255,.14);
  color: #8ea6c8;
}
.ckpip { font-size: 20px; opacity: .8; }
.ckfront {
  background: linear-gradient(158deg, #1f5490, #0f2a4c);
  border: 1px solid rgba(255,255,255,.2);
  color: #fff;
}
.cktime {
  font-weight: 800;
  font-size: 15px;
  letter-spacing: -.02em;
  text-shadow: 0 1px 2px rgba(0,0,0,.5);
}
.ckcardface { touch-action: none; }        /* a drag peels, it does not scroll */

/* The last minute. It breathes rather than showing a number -- you learn that
   the end is near without being handed a clock to watch. Stops under the
   pointer: if you are looking at it, it has nothing left to tell you. */
.ckcardface.soon .ckback {
  animation: cksoon calc(1.6s * var(--motion)) ease-in-out infinite;
}
.ckcardface:hover .ckback { animation: none; }
@keyframes cksoon {
  0%, 100% { box-shadow: 0 0 0 0 rgba(242,199,74,0); }
  50%      { box-shadow: 0 0 0 4px rgba(242,199,74,.28); }
}

@media (max-width: 620px) {
  .ckcardface { width: 40px; height: 56px; }
  .cktime { font-size: 13px; }
}


/* --------------------------------------------------- pasting ranges in --- */

.bpastewrap {
  position: fixed; inset: 0; z-index: 500;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(4,8,16,.72);
  backdrop-filter: blur(3px);
}
.bpastebox {
  width: min(620px, 100%); max-height: 100%; overflow-y: auto;
  padding: var(--s-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-2);
  box-shadow: var(--shadow-3);
}
.bpastebox .rzhead .rpmini { flex: 0 0 auto; padding: 6px 14px; }
.bpastelab {
  display: block; margin: var(--s-4) 0 5px;
  font-size: var(--t-2xs);
  font-weight: 800;
  line-height: 1;
  letter-spacing: .08em; text-transform: uppercase;
}
.bpastelab.raise { color: var(--b-raise); }
.bpastelab.call  { color: var(--b-call); }
.bpastein {
  width: 100%; height: 84px; resize: vertical;
  padding: 10px 11px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: #0e1522; color: var(--text);
  font: 500 12px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.bpastein:focus { outline: none; border-color: var(--accent); }
.bpastefoot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); margin-top: var(--s-4);
}
.bpastefoot .rphint { margin: 0; }
.bpastefoot .rpmini { flex: 0 0 auto; padding: 8px 18px; }
.bpastefoot .rpmini:disabled { opacity: .45; cursor: default; }


/* --------------------------------------------------------------- brand -- */

/* The wordmark. Uppercase with positive tracking rather than the tight
   negative tracking every other heading uses -- a title wants to be read fast
   and a logo wants to be read as a shape, and they are not the same job.

   ZUL takes the accent so the mark has an anchor that survives being shrunk
   into a login card or a favicon. */
.brandmark {
  /* Tight to the tagline: the two are one lockup, and the air goes underneath
     them rather than between them. */
  margin: 0 0 7px;
  font-size: clamp(32px, 4.6vw, 54px);
  font-weight: 900;
  line-height: 1;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text);
}
.brandz { color: var(--accent); }

.brandtag {
  margin: 0 0 var(--s-6);
  font-size: clamp(12px, 1.25vw, 15px);
  font-weight: 800;
  line-height: 1.3;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text);
}

/* Four beats, one per thing you actually do here, in the order you do them.
   Sized up from body text and given a wider measure -- it is read as a rhythm
   rather than a paragraph, and a line that wraps mid-beat loses the rhythm. */
.brandsub {
  margin: 0; max-width: 64ch;
  color: var(--text-dim);
  font-weight: 600;
  font-size: clamp(14px, 1.5vw, 18px);
  line-height: 1.5;
  letter-spacing: .005em;
}
/* The payoff beat, lifted out of the grey. Unbreakable, because a beat split
   across two lines stops being a beat. */
.brandlast { color: var(--accent); white-space: nowrap; }

/* On the login card the mark is the heading, so it comes down to heading size
   and the tagline loses its bottom margin -- the form is right underneath. */
.brandmark.small { font-size: clamp(24px, 3vw, 32px); margin-bottom: 6px; }
.brandtag.small { margin-bottom: var(--s-4); font-size: 11px; }

/* ------------------------------------------------------------ sessions -- */

/* Timed sittings at the trainer. The record is pinned above the list rather
   than sorted into it, because "the most I have ever done" and "have I been
   turning up lately" are two questions and one ordering cannot answer both. */
.homesess {
  padding: var(--s-5);
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--surface-1);
}
.sesshead {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-4); margin-bottom: var(--s-4);
}
.sesstot {
  font-size: 12px;
  font-weight: 600;
  line-height: 1; letter-spacing: .04em;
  color: var(--text-dim); white-space: nowrap;
}
/* The empty state is a label for a space, not a sentence -- so it is centred
   and set the way a placeholder is, rather than reading as prose the eye has
   to start on every time the page loads. */
.sessempty {
  display: flex; align-items: center; justify-content: center;
  min-height: 76px;
  color: var(--text-dim);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .04em;
}
.sessempty a { color: var(--accent); }

/* The record. Bigger type and a warmer ground than the rows, so it reads as a
   different kind of thing at a glance rather than as row zero. */
.sessbest {
  display: grid; align-items: center; gap: 3px var(--s-4);
  grid-template-columns: auto 1fr auto;
  grid-template-areas: "badge  badge  date"
                       "big    meta   meta";
  padding: var(--s-4) var(--s-5);
  border-radius: 12px;
  border: 1px solid rgba(59,130,246,.35);
  background: rgba(59,130,246,.08);
}
.sessbadge {
  grid-area: badge;
  font-size: 10px;
  font-weight: 800;
  line-height: 1; letter-spacing: .16em; text-transform: uppercase;
  color: var(--accent);
}
.sessbig {
  grid-area: big;
  font-size: clamp(22px, 2.6vw, 30px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.02em; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.sessmeta { grid-area: meta; color: var(--text-dim); font-size: var(--t-sm); }
.sessmeta b { color: var(--text); font-weight: 700; }
.sessbest .sessdate { grid-area: date; }

/* The rest, newest first. One grid so every column lines up down the list --
   ragged numbers are the thing that makes a log look like a dump. */
.sesslist {
  margin-top: var(--s-3);
  max-height: 268px; overflow-y: auto;
}
.sessrow {
  display: grid; align-items: center; gap: var(--s-4);
  grid-template-columns: 68px 76px 1fr 44px 58px;
  padding: 9px var(--s-3);
  border-radius: 8px;
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
}
.sessrow:hover { background: rgba(255,255,255,.035); }
.sessmins { color: var(--text); font-weight: 700; }
.sessspots, .sessdate { color: var(--text-dim); }
.sessdate { text-align: right; white-space: nowrap; }
.sesspct { color: var(--text); font-weight: 600; text-align: right; }

/* Accuracy drawn as well as written: a column of percentages is read one at a
   time, a column of bars is read as a shape. */
.sessbar {
  height: 5px; border-radius: 3px;
  background: rgba(255,255,255,.07);
  overflow: hidden;
}
.sessbar i { display: block; height: 100%; background: var(--accent); }

@media (max-width: 620px) {
  .sessrow { grid-template-columns: 62px 1fr 44px; }
  .sessspots, .sessbar { display: none; }
}

/* The train button. Same footprint as the stat tiles beside it so the strip
   stays a strip, but it is the only one you can press -- accent ground and a
   name instead of a number, because a number here would read as another thing
   to look at rather than the thing to do. */
.homestat.train {
  display: flex; flex-direction: column; justify-content: center; gap: 5px;
  border-color: rgba(59,130,246,.45);
  background: rgba(59,130,246,.11);
  text-decoration: none;
  transition: background calc(.12s * var(--motion)) ease,
              border-color calc(.12s * var(--motion)) ease;
}
.homestat.train:hover {
  background: rgba(59,130,246,.19);
  border-color: var(--accent);
}
.hometrainname {
  font-size: clamp(20px, 2.3vw, 26px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--text);
}
.hometrainsub { font-size: var(--t-sm); color: var(--accent); font-weight: 600; }

/* --------------------------------------------------- the shared set --- */

/* Which charts everyone drills. Only the owner sees this column -- for anyone
   else the shared set is a fact about the app, not a control, and a disabled
   checkbox would only invite them to wonder why. */
.cshared { width: 62px; text-align: center; }
.cshare { display: inline-flex; cursor: pointer; }
.cshare input { position: absolute; opacity: 0; width: 0; height: 0; }
.cshare span {
  display: block; width: 18px; height: 18px;
  border-radius: 5px;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.04);
  transition: background calc(.12s * var(--motion)) ease,
              border-color calc(.12s * var(--motion)) ease;
}
.cshare input:checked + span {
  background: var(--accent);
  border-color: var(--accent);
  /* The tick is drawn rather than typed: a glyph would sit differently in
     every font stack the browser might fall back to. */
  background-image: linear-gradient(45deg, transparent 42%, #fff 42%, #fff 55%, transparent 55%),
                    linear-gradient(-45deg, transparent 58%, #fff 58%, #fff 71%, transparent 71%);
  background-size: 100% 100%;
}
.cshare input:focus-visible + span {
  outline: none; box-shadow: 0 0 0 3px rgba(59,130,246,.3);
}
.cshare input:disabled + span { opacity: .3; cursor: default; }
.cshare:has(input:disabled) { cursor: default; }

/* ------------------------------------------------------ on a phone --- */

/* The trainer and the range builder are the two pages that were built as
   side-by-side columns and stayed that way at every width. On a 375px screen
   that meant the second column pushed the first off the left edge: the felt
   half off-screen with the answer buttons hidden behind the panel, and the
   13x13 grid squeezed into a sliver under the saved-ranges list.
   
   Both become one column here, in reading order -- the thing you are looking
   at, then the thing you press, then everything else. */
@media (max-width: 720px) {

  /* The same flex-column trick .homepage uses. html and body are locked to
     the viewport, so a page has to scroll an inner container; doing it with
     `height: calc(100% - 60px)` hard-codes a topbar height that stopped being
     true the moment the nav learned to scroll. */
  body.rangepage:has(> .trainerpage),
  body.rangepage:has(> .buildpage) {
    display: flex;
    flex-direction: column;
  }
  .trainerpage,
  .buildpage,
  .buildpage:has(> .savedcol) {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    height: auto;
    min-height: 0;
    gap: 12px;
    padding: 12px;
    /* The desktop rule centres these, which is right when the content fits and
       wrong the moment it does not: a centred flex item taller than its box
       overflows BOTH ends, and the end above the scroll origin cannot be
       scrolled to. Measured on a phone, .tmain sat at offsetTop -427 -- the
       felt and the question were off the top of a page that would not scroll
       up to them. It also drifts: every row the session log adds makes the
       content taller, so the centring lifts everything another notch, which is
       the page walking upward as you answer spots. */
    justify-content: flex-start;
    align-items: stretch;
  }

  /* ---- the spot trainer ---- */

  /* The felt gets a share of the screen rather than whatever is left, so the
     answer buttons are always in the same place and always reachable with a
     thumb. tFitFelt() scales the 946x686 stage down to fit whatever this
     works out to, so there is no second number to keep in step. */
  /* Each panel takes the height its contents need and the PAGE scrolls. As
     flex children they were being squeezed to fit instead, which pushed the
     hand, the question and the answer buttons out of the panel and under the
     one below it. */
  .tmain, .tside { flex: 0 0 auto; padding: var(--s-4); }
  .tfeltbox { height: 38vh; min-height: 200px; flex: none; }

  /* Fold, call, raise. Big enough to hit without looking, which is the point
     of a trainer you use one-handed on a couch. */
  .tchoices { gap: 8px; margin-top: var(--s-4); }

  /* The reservation applies here too. The felt has its own height on a phone
     so it is not what pays, but the PAGE is: answering makes this block 113px
     taller and the next spot takes it away again, so everything under the hand
     -- the answer buttons included -- walks up the screen between the tap that
     answers and the tap that moves on. Bottom-aligned, so the buttons still
     sit at the end of the page; the reserved room opens above them. */
  .tchoice { padding: 16px 8px; }
  .tchoicename { font-size: 15px; }
  /* The keyboard hint is a lie on a phone. */
  .tchoicekey { display: none; }

  /* ---- the range builder ---- */

  /* Full width and squarer cells: 13 across 375px is 27px a side, and the
     flatter desktop cell would leave 20px of height to hit. */
  .savedcol { max-height: 60vh; }
  .rangepage .bgrid .cell { aspect-ratio: 1.12; font-size: 10px; padding-left: 2px; }
  .brow { flex-wrap: wrap; }
  .bact { min-width: 84px; }
}

/* ------------------------------------------------------------ the bar --- */

/* Who you are, as an object rather than as stray text.

   It used to be a bare grey word floating beside a glossy pill, which read as
   something left over rather than something placed. A quiet chip gives it an
   edge of its own without competing with the tabs -- it is the least important
   thing in the bar and should look it, but it should still look deliberate. */


/* The name truncates; the link does not. They used to be one text node inside
   the chip, so constraining the chip cut whichever came last -- which on a
   phone with a long username meant Sign out disappeared off the edge and there
   was no way to sign out at all. */
.authname { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.authwho a { flex: 0 0 auto; }

/* One row at every width. The tabs never wrap and never shrink; when there is
   not enough room they scroll sideways, which keeps every tab reachable and
   at a size you can hit. The name holds its ground on the right. */
@media (max-width: 700px) {
  .topbar {
    flex-wrap: nowrap;
    height: 52px;
    gap: 8px;
    padding: 0 10px;
    /* The BAR must not scroll -- only the tabs inside it. */
    overflow: hidden;
    /* Back to a plain row: with the name in the flow again there is no
       leftover space to centre the tabs in, so they simply take what is left
       and the name takes what it needs. */
    justify-content: flex-start;
  }
  .topbar .authwho,
  .topbar .status {
    position: static;
    transform: none;
    flex: 0 0 auto;
    margin-left: auto;
    font-size: 11px;
    padding: 5px 9px;
  }
  /* All four tabs, fixed, sharing the width equally. They used to scroll
     sideways, which meant the tab you wanted could be off the edge and you
     had to discover that by swiping a bar that did not look swipeable. */
  .pagenav {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
  }
  .pagenav a {
    flex: 1 1 0;
    min-width: 0;
    padding: 8px 4px;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .authwho a { padding: 4px 8px; }
}

/* Past this the tabs alone fill the bar, so the name is what gives way: it
   truncates rather than pushing the tabs off. Truncating and not hiding,
   because with two accounts the point of showing it at all is telling you
   which one you are in -- and Sign out has to stay reachable regardless. */
@media (max-width: 430px) {
  .authwho { max-width: 46vw; padding: 5px 8px; gap: 6px; }
  .authname { max-width: 62px; }
  .authwho a { font-size: 10.5px; padding: 3px 7px; }
}

/* ---------------------------------------------------------- account --- */

/* The avatar sits where the username used to. A name told you who you were
   and offered nothing to do about it; this is the same information as a
   control, which is what the corner of a bar is for. */
.acct { position: relative; display: flex; align-items: center; }

.acctbtn {
  display: grid; place-items: center;
  width: 34px; height: 34px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.04);
  color: var(--text-dim);
  cursor: pointer;
  transition: border-color calc(.12s * var(--motion)) ease,
              color calc(.12s * var(--motion)) ease,
              background calc(.12s * var(--motion)) ease;
}
.acctbtn:hover, .acctbtn[aria-expanded="true"] {
  color: var(--text);
  border-color: var(--accent);
  background: rgba(59,130,246,.14);
}
.acctbtn:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(59,130,246,.3); }

/* Drawn rather than a glyph: a font character would sit differently in every
   fallback stack, and this has to be centred in a 34px circle. */
.acctav svg {
  width: 19px; height: 19px;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
}
.acctav.big svg { width: 26px; height: 26px; }

.acctmenu {
  position: absolute; top: calc(100% + 9px); right: 0;
  z-index: 60;
  width: 288px;
  padding: var(--s-4);
  border-radius: 13px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  box-shadow: var(--shadow-3);
  animation: acctin calc(.12s * var(--motion)) ease-out;
}
@keyframes acctin {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

.accthead { display: flex; align-items: center; gap: 11px; }
.accthead .acctav {
  display: grid; place-items: center;
  width: 42px; height: 42px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.04);
  color: var(--text-dim);
  flex: 0 0 auto;
}
.acctwho { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.acctwho b {
  font-size: 15px; font-weight: 700; color: var(--text);
  text-transform: capitalize;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acctwho i { font-style: normal; font-size: 11.5px; color: var(--text-dim); }

.acctstats {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  margin-top: var(--s-4);
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 9px;
  overflow: hidden;
}
.acctstats span {
  display: flex; flex-direction: column; gap: 2px;
  padding: 9px 6px;
  background: var(--surface-1);
  text-align: center;
  font-size: 10.5px; color: var(--text-dim);
  letter-spacing: .03em;
}
.acctstats b {
  font-size: 16px; font-weight: 700; color: var(--text);
  font-variant-numeric: tabular-nums;
}

.acctsep { height: 1px; background: var(--line); margin: var(--s-4) 0; }

.acctitem {
  display: flex; align-items: baseline; gap: 8px;
  width: 100%;
  padding: 9px 10px;
  border: 0; border-radius: 8px;
  background: none;
  color: var(--text);
  text-align: left; text-decoration: none;
  font-size: 13.5px; font-weight: 600;
  cursor: pointer;
}
.acctitem i { font-style: normal; font-size: 11.5px; color: var(--text-dim); }
.acctitem:hover { background: rgba(255,255,255,.06); }

.acctrow.dim { padding: 10px; font-size: 13px; color: var(--text-dim); }

/* Arming the reset. It looks different from the rest of the menu on purpose:
   everything above is information, and this is the one thing that removes
   something. */
.acctdanger {
  padding: var(--s-3);
  border-radius: 9px;
  border: 1px solid rgba(226,114,107,.4);
  background: rgba(226,114,107,.08);
}
.acctdanger p {
  margin: 0 0 9px;
  font-size: 12.5px; line-height: 1.55; color: var(--text-dim);
}
.acctdanger p b { color: var(--text); }
.acctdanger label {
  display: block; margin-bottom: 5px;
  font-size: 11px; color: var(--text-dim);
}
.acctdanger label b { color: var(--text); text-transform: none; }
.acctdanger input {
  width: 100%;
  padding: 8px 10px;
  border-radius: 7px;
  border: 1px solid var(--line);
  background: #0e1522;
  color: var(--text);
  font-size: 13px;
}
.acctdanger input:focus { outline: none; border-color: var(--accent); }

.acctrowbtns { display: flex; gap: 7px; margin-top: 9px; }
.acctbtn2 {
  flex: 1;
  padding: 8px 10px;
  border-radius: 7px;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.04);
  color: var(--text-dim);
  font-size: 12.5px; font-weight: 700;
  cursor: pointer;
}
.acctbtn2:hover { color: var(--text); border-color: var(--line-hi); }
.acctbtn2.go {
  border-color: rgba(226,114,107,.55);
  background: rgba(226,114,107,.16);
  color: #f0a49e;
}
.acctbtn2.go:hover { background: rgba(226,114,107,.26); color: #fff; }

@media (max-width: 430px) {
  .acctbtn { width: 30px; height: 30px; }
  .acctav svg { width: 17px; height: 17px; }
  /* Anchored to the bar rather than the button, so a 288px panel cannot hang
     off the edge of a 375px screen. */
  .acctmenu { position: fixed; top: 58px; right: 8px; left: 8px; width: auto; }
}

/* -------------------------------------------------------- leaderboard --- */

/* A module on the front page, sized to sit between the stat strip above it
   and the sessions card below -- so it reads as one of the things you glance
   at on the way to training, not as a destination. */
.homeboard {
  padding: var(--s-5);
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--surface-1);
}
.lbhead {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-4); flex-wrap: wrap; margin-bottom: var(--s-4);
}
.lbscope { font-size: 12px; font-weight: 600; color: var(--text-dim); }
.lbempty {
  margin: 0; font-size: var(--t-sm); line-height: 1.6; color: var(--text-dim);
}
.lbempty a { color: var(--accent); }

.lbrows { display: flex; flex-direction: column; gap: 2px; }

/* One grid for every row so the tiers and the numbers line up down the
   column. Ragged columns are what make a board read as a dump of numbers
   rather than a ranking. */
.lbrow {
  display: grid;
  grid-template-columns: 24px minmax(70px, 1fr) auto 68px;
  align-items: center;
  gap: var(--s-3);
  padding: 11px var(--s-3);
  border-radius: 9px;
  font-variant-numeric: tabular-nums;
}
.lbrow.you { background: rgba(59,130,246,.1); }
.lbrow:hover { background: rgba(255,255,255,.035); }
.lbrow.you:hover { background: rgba(59,130,246,.14); }

.lbrank {
  display: inline-flex; align-items: center; justify-content: center;
  width: 21px; height: 21px; border-radius: 50%;
  font-size: 11px; font-weight: 800;
  color: var(--text-dim); background: rgba(255,255,255,.05);
}
.lbrank.m1 { color: #1b1405; background: #e3b341; }
.lbrank.m2 { color: #16181c; background: #c2c9d1; }
.lbrank.m3 { color: #1d1109; background: #c88a52; }

.lbwho {
  font-size: 14.5px; font-weight: 700; color: var(--text);
  text-transform: capitalize;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lbwho i {
  margin-left: 6px; font-style: normal;
  font-size: 10px; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent);
}




@media (max-width: 520px) {
  .lbrow { grid-template-columns: 22px minmax(50px, 1fr) auto 54px; }
  /* The row is already tinted when it is yours, so the badge is saying it
     twice -- and at this width it was being ellipsised to "Anthony Y…",
     which reads as a bug rather than as emphasis. */
  .lbwho i { display: none; }
}

/* ------------------------------------------------------------- tiers --- */

/* Iron through Zulpion. A band you are in says more at a glance than a
   percentage does, because it is a thing you can be rather than a number you
   have to compare against something. */
.lbtier {
  justify-self: end;
  padding: 4px 10px;
  border-radius: var(--r-full);
  border: 1px solid currentColor;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .07em;
  text-transform: uppercase;
  white-space: nowrap;
}
.lbtier.t-iron    { color: #8b8983; background: rgba(139,137,131,.12); }
.lbtier.t-bronze  { color: #c07840; background: rgba(192,120,64,.13); }
.lbtier.t-silver  { color: #b9c4d2; background: rgba(185,196,210,.13); }
.lbtier.t-gold    { color: #e3b341; background: rgba(227,179,65,.14); }
.lbtier.t-plat    { color: #4fd0c0; background: rgba(79,208,192,.13); }
.lbtier.t-diamond { color: #74a9ff; background: rgba(116,169,255,.15); }
/* The top band gets the only glow on the page. It is meant to be the thing
   you notice somebody else having. */
.lbtier.t-zulpion {
  color: #d79bff;
  background: rgba(199,125,255,.18);
  border-color: #c77dff;
  box-shadow: 0 0 14px rgba(199,125,255,.35);
}

.lbpts {
  text-align: right;
  font-size: 17px;
  font-weight: 800;
  color: var(--text);
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 430px) {
  .lbtier { padding: 3px 7px; font-size: 10px; letter-spacing: .04em; }
  .lbpts { font-size: 15px; }
}

/* A seat's bet, drawn as part of the seat rather than as a free chip on the
   felt. Owning it makes "whose money is that" a fact of the markup instead of
   something the reader has to work out from where it landed. */
.chip.tbet {
  position: absolute;
  transform: translate(-50%, -50%);
  white-space: nowrap;
}

/* -------------------------------------------------------------- locks --- */

/* The lock sits in the top-right corner of a square and is the only part of
   that square that is not the brush. Its hit area is deliberately bigger than
   the drawing -- the cell is 23px on a phone, and a target you have to aim at
   is one you will miss and paint instead. */
.cell { position: relative; }
.cell .lk {
  position: absolute;
  top: 0; right: 0;
  width: 46%; height: 52%;
  min-width: 13px; min-height: 12px;
  cursor: pointer;
  opacity: 0;
  transition: opacity calc(.1s * var(--motion)) ease;
}
/* The body of the padlock, drawn rather than typed: a glyph would sit
   differently in every fallback stack and this has to land in a corner. */
.cell .lk::after {
  content: '';
  position: absolute; top: 5px; right: 2px;
  width: 8px; height: 6px;
  border-radius: 1.5px;
  background: currentColor;
}
/* and its shackle */
.cell .lk::before {
  content: '';
  position: absolute; top: 1px; right: 4px;
  width: 4px; height: 4px;
  border: 1.5px solid currentColor;
  border-bottom: 0;
  border-radius: 3px 3px 0 0;
}
.cell:hover .lk { opacity: .45; }
.cell .lk:hover { opacity: .9; }

/* A locked square says so all the time -- if you had to hover to find out,
   you would only discover it by trying to paint over it and failing. */
.cell.locked .lk { opacity: 1; color: #ffd76b; }
.cell.locked {
  outline: 1px solid rgba(255,215,107,.5);
  outline-offset: -1px;
}
.cell.locked:hover { cursor: not-allowed; }

/* Fingers have no hover, so the corner is always faintly there on touch. */
@media (hover: none) {
  .cell .lk { opacity: .22; }
}

/* The rank tile. Same furniture as the counts beside it, but the number is a
   place rather than a quantity, so "of 4" rides along with it -- #3 means
   nothing without knowing what it is out of. */
/* Two things on the top line: where you are, and how far to the next band.
   The gap goes hard right so it reads as a destination rather than as another
   fact about now -- and it is the only accent on the strip, because it is the
   line meant to make somebody press Train. */
.homestat.rank {
  display: grid;
  grid-template-columns: auto 1fr;
  /* The climb rides on the LABEL row, not beside the number. Next to the
     number the two together were wider than the tile -- "236 to Bronze" can
     not wrap and neither can "64 IRON", so the column overflowed its own
     padding by 9px. Beside the short label there is always room. */
  grid-template-areas: "num   num"
                       "label climb";
  align-items: baseline;
  column-gap: var(--s-3);
}
.homestat.rank .homestatnum {
  grid-area: num;
  display: flex; align-items: baseline; gap: 6px;
}
.homestat.rank .homestatnum i { font-style: normal; letter-spacing: .07em; }
.homestat.rank .homestatlabel { grid-area: label; }

.rankclimb {
  grid-area: climb;
  justify-self: end;
  display: flex; align-items: center; gap: 4px;
  white-space: nowrap;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--accent);
}
.rankclimb b { font-size: 14px; font-weight: 800; font-variant-numeric: tabular-nums; }
.rankclimb i { font-style: normal; color: var(--text-dim); }
.rankarrow { font-size: 13px; opacity: .75; }
.ranktier {
  padding: 2px 7px;
  border-radius: var(--r-full);
  border: 1px solid currentColor;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .07em;
  text-transform: uppercase;
}
.ranktier.t-iron    { color: #8b8983; background: rgba(139,137,131,.12); }
.ranktier.t-bronze  { color: #c07840; background: rgba(192,120,64,.13); }
.ranktier.t-silver  { color: #b9c4d2; background: rgba(185,196,210,.13); }
.ranktier.t-gold    { color: #e3b341; background: rgba(227,179,65,.14); }
.ranktier.t-plat    { color: #4fd0c0; background: rgba(79,208,192,.13); }
.ranktier.t-diamond { color: #74a9ff; background: rgba(116,169,255,.15); }
.ranktier.t-zulpion {
  color: #d79bff; background: rgba(199,125,255,.18); border-color: #c77dff;
  box-shadow: 0 0 10px rgba(199,125,255,.3);
}

/* ------------------------------------------------- how ranking works --- */

.lbinfo {
  width: 21px; height: 21px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.04);
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 800;
  font-style: italic;
  line-height: 1;
  cursor: pointer;
  flex: 0 0 auto;
}
.lbinfo:hover { color: var(--text); border-color: var(--accent); }
.lbinfo:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(59,130,246,.3); }
.lbhead { align-items: center; }

.lbinfowrap {
  position: fixed; inset: 0; z-index: 600;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  background: rgba(4,8,16,.74);
  backdrop-filter: blur(3px);
}
.lbinfobox {
  width: min(440px, 100%);
  max-height: 100%; overflow-y: auto;
  padding: var(--s-5);
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  box-shadow: var(--shadow-3);
}
.lbinfohead {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-4); margin-bottom: var(--s-4);
}
.lbinfohead h2 {
  margin: 0;
  font-size: 17px; font-weight: 700; color: var(--text);
}
.lbinfox {
  padding: 6px 12px;
  border-radius: var(--r-full);
  border: 1px solid var(--line);
  background: none;
  color: var(--text-dim);
  font-size: 12px; font-weight: 700;
  cursor: pointer;
  flex: 0 0 auto;
}
.lbinfox:hover { color: var(--text); border-color: var(--line-hi); }

.lbinfobox p {
  margin: 0 0 var(--s-4);
  font-size: 13.5px; line-height: 1.62; color: var(--text-dim);
}
.lbinfobox p b { color: var(--text); font-weight: 600; }
.lbinfobox p:last-child { margin-bottom: 0; }

/* The ladder, highest first -- it is a thing you climb, so it reads upward. */
.lbtiers {
  display: flex; flex-direction: column; gap: 1px;
  margin: 0 0 var(--s-4);
  padding: var(--s-3);
  border-radius: 10px;
  background: var(--surface-1);
  border: 1px solid var(--line);
}
.lbtrow {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 5px 4px;
  border-radius: 6px;
}
.lbtrow.here { background: rgba(59,130,246,.12); }
.lbtrow .lbtier { justify-self: start; min-width: 84px; text-align: center; }
.lbtrange {
  margin-left: auto;
  font-size: 12px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.lbthere {
  font-size: 9.5px; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent);
}
