/*
! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com
*/

/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/

*,
::before,
::after {
  box-sizing: border-box;
  /* 1 */
  border-width: 0;
  /* 2 */
  border-style: solid;
  /* 2 */
  border-color: #e5e7eb;
  /* 2 */
}

::before,
::after {
  --tw-content: '';
}

/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
*/

html {
  line-height: 1.5;
  /* 1 */
  -webkit-text-size-adjust: 100%;
  /* 2 */
  -moz-tab-size: 4;
  /* 3 */
  -o-tab-size: 4;
     tab-size: 4;
  /* 3 */
  font-family: var(--font-ui);
  /* 4 */
  font-feature-settings: normal;
  /* 5 */
  font-variation-settings: normal;
  /* 6 */
}

/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/

body {
  margin: 0;
  /* 1 */
  line-height: inherit;
  /* 2 */
}

/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/

hr {
  height: 0;
  /* 1 */
  color: inherit;
  /* 2 */
  border-top-width: 1px;
  /* 3 */
}

/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/

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

/*
Remove the default font size and weight for headings.
*/

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

/*
Reset links to optimize for opt-in styling instead of opt-out.
*/

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

/*
Add the correct font weight in Edge and Safari.
*/

b,
strong {
  font-weight: bolder;
}

/*
1. Use the user's configured `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
*/

code,
kbd,
samp,
pre {
  font-family: var(--font-data);
  /* 1 */
  font-size: 1em;
  /* 2 */
}

/*
Add the correct font size in all browsers.
*/

small {
  font-size: 80%;
}

/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/

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

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/

table {
  text-indent: 0;
  /* 1 */
  border-color: inherit;
  /* 2 */
  border-collapse: collapse;
  /* 3 */
}

/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/

button,
input,
optgroup,
select,
textarea {
  font-family: inherit;
  /* 1 */
  font-feature-settings: inherit;
  /* 1 */
  font-variation-settings: inherit;
  /* 1 */
  font-size: 100%;
  /* 1 */
  font-weight: inherit;
  /* 1 */
  line-height: inherit;
  /* 1 */
  color: inherit;
  /* 1 */
  margin: 0;
  /* 2 */
  padding: 0;
  /* 3 */
}

/*
Remove the inheritance of text transform in Edge and Firefox.
*/

button,
select {
  text-transform: none;
}

/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/

button,
[type='button'],
[type='reset'],
[type='submit'] {
  -webkit-appearance: button;
  /* 1 */
  background-color: transparent;
  /* 2 */
  background-image: none;
  /* 2 */
}

/*
Use the modern Firefox focus style for all focusable elements.
*/

:-moz-focusring {
  outline: auto;
}

/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/

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

/*
Add the correct vertical alignment in Chrome and Firefox.
*/

progress {
  vertical-align: baseline;
}

/*
Correct the cursor style of increment and decrement buttons in Safari.
*/

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

/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/

[type='search'] {
  -webkit-appearance: textfield;
  /* 1 */
  outline-offset: -2px;
  /* 2 */
}

/*
Remove the inner padding in Chrome and Safari on macOS.
*/

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

/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/

::-webkit-file-upload-button {
  -webkit-appearance: button;
  /* 1 */
  font: inherit;
  /* 2 */
}

/*
Add the correct display in Chrome and Safari.
*/

summary {
  display: list-item;
}

/*
Removes the default spacing and border for appropriate elements.
*/

blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
  margin: 0;
}

fieldset {
  margin: 0;
  padding: 0;
}

legend {
  padding: 0;
}

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

/*
Reset default styling for dialogs.
*/

dialog {
  padding: 0;
}

/*
Prevent resizing textareas horizontally by default.
*/

textarea {
  resize: vertical;
}

/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/

input::-moz-placeholder, textarea::-moz-placeholder {
  opacity: 1;
  /* 1 */
  color: #9ca3af;
  /* 2 */
}

input::placeholder,
textarea::placeholder {
  opacity: 1;
  /* 1 */
  color: #9ca3af;
  /* 2 */
}

/*
Set the default cursor for buttons.
*/

button,
[role="button"] {
  cursor: pointer;
}

/*
Make sure disabled buttons don't get the pointer cursor.
*/

:disabled {
  cursor: default;
}

/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
   This can trigger a poorly considered lint error in some tools but is included by design.
*/

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

/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/

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

/* Make elements with the HTML hidden attribute stay hidden by default */

[hidden] {
  display: none;
}

body {
  font-family: var(--font-text);
  color: var(--tm-fg);
  background: var(--tm-bg);
  -webkit-font-smoothing: antialiased;
}

:focus-visible {
  outline: 2px solid var(--tm-accent);
  outline-offset: 3px;
}

::-moz-selection {
  background: var(--tm-accent);
  color: var(--tm-inverse);
}

::selection {
  background: var(--tm-accent);
  color: var(--tm-inverse);
}

button, a, input, summary {
  transition:
            background-color 200ms,
            border-color 200ms,
            color 200ms,
            fill 200ms,
            stroke 200ms,
            box-shadow 200ms;
}

:root {
  /* ───────────────────────────────────────────────────────────────
         * SEMANTIC FONT ROLES — the single source of truth for typography.
         * Every Tailwind `font-*` class and every CSS `font-family` rule
         * resolves through one of these four variables. To flip a role
         * across the entire app (e.g. "all serif back to mono"), change
         * the right-hand side here. One line, whole app updates.
         *
         *   data    — tabular content: numbers, percentages, EV/N, bet
         *             sizes, abbreviations (BTN/SB), keychords, card
         *             ranks. Anything you scan or align in columns.
         *   text    — names + prose: panel titles, section labels,
         *             action words (Fold/Call/Shove), button labels,
         *             body prose, empty-state messages. Anything you
         *             read or recognize.
         *   ui      — site-nav chrome: TopNav links, breadcrumbs, mono
         *             caps idiom for navigation.
         *   display — hero wordmark only. The bitmap brand mark.
         * ─────────────────────────────────────────────────────────────── */
  --font-data: "IBM Plex Mono", monospace;
  --font-text: "Barlow", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-ui: var(--font-text);
  --font-display: var(--font-text);
  /* ───────────────────────────────────────────────────────────────
         * SHADOW + LIFT SCALE — depth tokens. Same offset-shadow idiom
         * across every elevated surface; one scale, four steps.
         * `--lift` is the displacement a surface moves on hover/press
         * (mirrors the delta between adjacent shadow steps).
         *
         *   pressed  — depressed state (button :active)
         *   sm       — default tactile (chips, buttons, small cards)
         *   md       — panels + surface cards resting
         *   lg       — hover-lifted surfaces, modals, drawers
         * ─────────────────────────────────────────────────────────────── */
  /* Flat by default. Surfaces separate by value and a hairline, not
           by a drop shadow — a simulated light source is what makes flat
           data chrome read as a decade-old phone. The two large steps
           survive for things that genuinely float above the page (modals,
           drawers, the tour spotlight), where the shadow is doing
           occlusion rather than decoration. */
  --shadow-pressed: none;
  --shadow-sm: none;
  --shadow-md: 0 8px 24px var(--tm-shadow);
  --shadow-lg: 0 20px 56px var(--tm-shadow);
  --lift: 1px;
  /* ───────────────────────────────────────────────────────────────
         * TYPE SCALE — display + heading + body sizes. Smaller sizes
         * (10-16px) are handled by Tailwind utilities (text-xxs..base);
         * this scale owns the larger headline + body sizes that recur
         * across input.css.
         * ─────────────────────────────────────────────────────────────── */
  --text-hero: 96px;
  --text-h1: 48px;
  --text-h2: 32px;
  --text-h3: 28px;
  --text-h4: 24px;
  --text-lead: 22px;
  --text-body: 18px;
  --text-md: 15px;
  /* ───────────────────────────────────────────────────────────────
         * SPACING SCALE — semantic gaps for the analysis/play rhythm.
         * Tweaking these reshapes panel density app-wide in one line.
         * ─────────────────────────────────────────────────────────────── */
  --space-panel: 16px;
  --space-section: 32px;
  /* Terminal Modernist core - light mode values (high contrast) */
  --tm-bg: #eeebe4;
  --tm-fg: #16181a;
  --tm-accent: #1f6f63;
  --tm-muted: #6d6961;
  --tm-hover: #f5f3ee;
  --tm-border: #d6d2c8;
  --tm-surface: #faf9f6;
  --tm-inverse: #faf9f6;
  --tm-shadow: rgba(38, 32, 22, 0.16);
  /* Felt. On paper it is the one large saturated block on the page, so
           it moves off the screen-cyan green onto a warmer printed one that
           sits with the ground instead of vibrating against it. Dark mode
           keeps the original below. */
  --felt: #2f5a4b;
  --felt-light: #3b6c5a;
  --felt-edge: #1f3f35;
  --range-color: #1f6f63;
  --lattice-cell: 28px;
  /* Preflop (private) street background — neutral grey vs the felt board */
  --street-private: #e9e6de;
  /* Settlement band — the terminal boundary. Warm parchment: the
           quiet tint of --action-terminal, so the column reads as the same
           family as the terminal amber without shouting over the felt. */
  --street-settle: #efe2c4;
  /* Card colors */
  --card-white: #ffffff;
  --card-black: #000000;
  --card-red: #dc2626;
  --card-back: #e8e4db;
  /* The card back's field, and the stake marker's. Both live on the
           felt, so both are keyed to it rather than to the page. */
  --card-back-ink: #a8322c;
  --chip-field: #111815;
  --chip-rim: rgba(255, 255, 255, 0.38);
  /* Paper - warm off-white for tactile elements */
  --paper: #f9fbfc;
  /* Paper fixed - stays warm white even in dark mode (for felt surfaces) */
  --paper-felt: #faf9f6;
  /* ───────────────────────────────────────────────────────────────
         * INKS. On paper the only saturated things on the page should be
         * the ones carrying meaning, and they should look laid down rather
         * than lit up — screen-bright primaries on a warm ground read as
         * stickers. These sit a tier deeper and a tier duller than their
         * dark-mode counterparts, which keeps white knockout type legible
         * on every one of them and keeps the page quiet between readings.
         * Semantics are unchanged: grey=fold, green=check, blue=call,
         * ochre=raise, red=all-in, teal=chance, gold=terminal.
         * ─────────────────────────────────────────────────────────────── */
  --action-fold: #6f6a63;
  --action-check: #2f6b4f;
  --action-call: #2a5d8f;
  --action-raise: #b4601f;
  --action-allin: #a8322c;
  --action-chance: #1d6e7a;
  --action-terminal: #946512;
  /* Accent palette */
  --accent-gold: #946512;
  /* Histogram colors */
  --hist-obs-stroke: #a8322c;
  --hist-abs-stroke: #946512;
  /* Game-tree lane stripes — subtle alternating column tints */
  --tree-lane-a: rgba(22, 24, 26, 0.035);
  --tree-lane-b: transparent;
  /* P&L backgrounds */
  --pnl-positive-bg: rgba(47, 107, 79, 0.14);
  --pnl-negative-bg: rgba(168, 50, 44, 0.14);
  --pnl-positive-fill: rgba(47, 107, 79, 0.32);
  --pnl-negative-fill: rgba(168, 50, 44, 0.32);
  /* ───────────────────────────────────────────────────────────────
         * INSTRUMENT RIG — the physical layer. Every surface in the app is
         * one of four things and picks its tokens from here:
         *
         *   chassis — the machined ground the modules are bolted to
         *   bezel   — a module's raised face
         *   well    — a recess a readout is sunk into
         *   key     — a control you can press
         *
         * `edge-hi` / `edge-lo` are the catch-light and the shadow of a
         * milled edge; `groove` is a cut line; `cast` is what a raised
         * thing throws onto what is under it. Light from directly above,
         * always — a second light source is what makes a rendered UI look
         * like clip art.
         * ─────────────────────────────────────────────────────────────── */
  --rig-chassis: #eeebe4;
  --rig-bezel: #faf9f6;
  --rig-well: #f3f1ea;
  --rig-key: #f5f3ee;
  --rig-etch: #6d6961;
  --rig-line: #d6d2c8;
  --rig-reticle: rgba(22, 24, 26, 0.055);
  --rig-lamp-off: rgba(22, 24, 26, 0.14);
  /* Stroke widths for SVG elements */
  --stroke-hairline: 0.5;
  --stroke-thin: 1;
  --stroke-sm: 1.5;
  --stroke-md: 2;
  /* Dash patterns for SVG elements */
  --dash-sm: 3 2;
  --dash-md: 4 2;
}

.\!dark {
  /* Terminal Modernist core - high contrast dark */
  --tm-bg: #0c0d0f !important;
  --tm-fg: #e9eaec !important;
  --tm-accent: #72d5c3 !important;
  --tm-muted: #8b929b !important;
  --tm-hover: #1c1f23 !important;
  --tm-border: #2a2e34 !important;
  --tm-surface: #141619 !important;
  --tm-inverse: #0c0d0f !important;
  --tm-shadow: rgba(0, 0, 0, 0.5) !important;
  /* Preflop (private) street background — neutral grey, lighter than bg */
  --street-private: #24242c !important;
  /* Settlement band — warm charcoal, the dark twin of the parchment. */
  --street-settle: #3a2c0e !important;
  /* Paper - slightly lighter surface for tactile elements in dark */
  --paper: #17232f !important;
  /* ───────────────────────────────────────────────────────────────
         * SEMANTIC PALETTE — single-loud, calibrated-quiet. Brand orange
         * (--action-raise / --tm-accent) is the only fully-saturated
         * color in dark mode. Every other semantic accent sits in the
         * Tailwind 400-tier so they share lightness + chroma register
         * and read as one supporting family rather than five competing
         * primaries. Preserves semantics: green=check, blue=call,
         * red=allin/loss, cyan=chance, amber=terminal/gold.
         * ─────────────────────────────────────────────────────────────── */
  --action-check: #34d399 !important;
  --action-call: #60a5fa !important;
  --action-raise: #fb923c !important;
  --action-allin: #f87171 !important;
  --action-chance: #22d3ee !important;
  --action-terminal: #fbbf24 !important;
  /* Gold and abstraction-stroke fold into the terminal amber so
           there are no two competing oranges (brand vs gold) on screen. */
  --accent-gold: #fbbf24 !important;
  /* P&L backgrounds - brighter for dark bg */
  --pnl-positive-bg: rgba(34, 197, 94, 0.15) !important;
  --pnl-negative-bg: rgba(239, 68, 68, 0.15) !important;
  --pnl-positive-fill: rgba(34, 197, 94, 0.35) !important;
  --pnl-negative-fill: rgba(239, 68, 68, 0.35) !important;
  /* Histogram colors - track the calibrated semantic palette */
  --hist-obs-stroke: #f87171 !important;
  --hist-abs-stroke: #fbbf24 !important;
  /* Game-tree lane stripes for dark mode */
  --tree-lane-a: rgba(255, 255, 255, 0.04) !important;
  --tree-lane-b: transparent !important;
  --felt: #164e51 !important;
  --felt-light: #216969 !important;
  --felt-edge: #0f3039 !important;
  --rig-chassis: #0c0d0f !important;
  --rig-bezel: #141619 !important;
  --rig-well: #08090a !important;
  --rig-key: #1c1f23 !important;
  --rig-etch: #8b929b !important;
  --rig-line: #2a2e34 !important;
  --rig-reticle: rgba(190, 200, 212, 0.07) !important;
  --rig-lamp-off: rgba(190, 200, 212, 0.13) !important;
}

.dark {
  /* Terminal Modernist core - high contrast dark */
  --tm-bg: #0c0d0f;
  --tm-fg: #e9eaec;
  --tm-accent: #72d5c3;
  --tm-muted: #8b929b;
  --tm-hover: #1c1f23;
  --tm-border: #2a2e34;
  --tm-surface: #141619;
  --tm-inverse: #0c0d0f;
  --tm-shadow: rgba(0, 0, 0, 0.5);
  /* Preflop (private) street background — neutral grey, lighter than bg */
  --street-private: #24242c;
  /* Settlement band — warm charcoal, the dark twin of the parchment. */
  --street-settle: #3a2c0e;
  /* Paper - slightly lighter surface for tactile elements in dark */
  --paper: #17232f;
  /* ───────────────────────────────────────────────────────────────
         * SEMANTIC PALETTE — single-loud, calibrated-quiet. Brand orange
         * (--action-raise / --tm-accent) is the only fully-saturated
         * color in dark mode. Every other semantic accent sits in the
         * Tailwind 400-tier so they share lightness + chroma register
         * and read as one supporting family rather than five competing
         * primaries. Preserves semantics: green=check, blue=call,
         * red=allin/loss, cyan=chance, amber=terminal/gold.
         * ─────────────────────────────────────────────────────────────── */
  --action-check: #34d399;
  --action-call: #60a5fa;
  --action-raise: #fb923c;
  --action-allin: #f87171;
  --action-chance: #22d3ee;
  --action-terminal: #fbbf24;
  /* Gold and abstraction-stroke fold into the terminal amber so
           there are no two competing oranges (brand vs gold) on screen. */
  --accent-gold: #fbbf24;
  /* P&L backgrounds - brighter for dark bg */
  --pnl-positive-bg: rgba(34, 197, 94, 0.15);
  --pnl-negative-bg: rgba(239, 68, 68, 0.15);
  --pnl-positive-fill: rgba(34, 197, 94, 0.35);
  --pnl-negative-fill: rgba(239, 68, 68, 0.35);
  /* Histogram colors - track the calibrated semantic palette */
  --hist-obs-stroke: #f87171;
  --hist-abs-stroke: #fbbf24;
  /* Game-tree lane stripes for dark mode */
  --tree-lane-a: rgba(255, 255, 255, 0.04);
  --tree-lane-b: transparent;
  --felt: #164e51;
  --felt-light: #216969;
  --felt-edge: #0f3039;
  --rig-chassis: #0c0d0f;
  --rig-bezel: #141619;
  --rig-well: #08090a;
  --rig-key: #1c1f23;
  --rig-etch: #8b929b;
  --rig-line: #2a2e34;
  --rig-reticle: rgba(190, 200, 212, 0.07);
  --rig-lamp-off: rgba(190, 200, 212, 0.13);
}

*, ::before, ::after {
  --tw-border-spacing-x: 0;
  --tw-border-spacing-y: 0;
  --tw-translate-x: 0;
  --tw-translate-y: 0;
  --tw-rotate: 0;
  --tw-skew-x: 0;
  --tw-skew-y: 0;
  --tw-scale-x: 1;
  --tw-scale-y: 1;
  --tw-pan-x:  ;
  --tw-pan-y:  ;
  --tw-pinch-zoom:  ;
  --tw-scroll-snap-strictness: proximity;
  --tw-gradient-from-position:  ;
  --tw-gradient-via-position:  ;
  --tw-gradient-to-position:  ;
  --tw-ordinal:  ;
  --tw-slashed-zero:  ;
  --tw-numeric-figure:  ;
  --tw-numeric-spacing:  ;
  --tw-numeric-fraction:  ;
  --tw-ring-inset:  ;
  --tw-ring-offset-width: 0px;
  --tw-ring-offset-color: #fff;
  --tw-ring-color: rgb(59 130 246 / 0.5);
  --tw-ring-offset-shadow: 0 0 #0000;
  --tw-ring-shadow: 0 0 #0000;
  --tw-shadow: 0 0 #0000;
  --tw-shadow-colored: 0 0 #0000;
  --tw-blur:  ;
  --tw-brightness:  ;
  --tw-contrast:  ;
  --tw-grayscale:  ;
  --tw-hue-rotate:  ;
  --tw-invert:  ;
  --tw-saturate:  ;
  --tw-sepia:  ;
  --tw-drop-shadow:  ;
  --tw-backdrop-blur:  ;
  --tw-backdrop-brightness:  ;
  --tw-backdrop-contrast:  ;
  --tw-backdrop-grayscale:  ;
  --tw-backdrop-hue-rotate:  ;
  --tw-backdrop-invert:  ;
  --tw-backdrop-opacity:  ;
  --tw-backdrop-saturate:  ;
  --tw-backdrop-sepia:  ;
}

::backdrop {
  --tw-border-spacing-x: 0;
  --tw-border-spacing-y: 0;
  --tw-translate-x: 0;
  --tw-translate-y: 0;
  --tw-rotate: 0;
  --tw-skew-x: 0;
  --tw-skew-y: 0;
  --tw-scale-x: 1;
  --tw-scale-y: 1;
  --tw-pan-x:  ;
  --tw-pan-y:  ;
  --tw-pinch-zoom:  ;
  --tw-scroll-snap-strictness: proximity;
  --tw-gradient-from-position:  ;
  --tw-gradient-via-position:  ;
  --tw-gradient-to-position:  ;
  --tw-ordinal:  ;
  --tw-slashed-zero:  ;
  --tw-numeric-figure:  ;
  --tw-numeric-spacing:  ;
  --tw-numeric-fraction:  ;
  --tw-ring-inset:  ;
  --tw-ring-offset-width: 0px;
  --tw-ring-offset-color: #fff;
  --tw-ring-color: rgb(59 130 246 / 0.5);
  --tw-ring-offset-shadow: 0 0 #0000;
  --tw-ring-shadow: 0 0 #0000;
  --tw-shadow: 0 0 #0000;
  --tw-shadow-colored: 0 0 #0000;
  --tw-blur:  ;
  --tw-brightness:  ;
  --tw-contrast:  ;
  --tw-grayscale:  ;
  --tw-hue-rotate:  ;
  --tw-invert:  ;
  --tw-saturate:  ;
  --tw-sepia:  ;
  --tw-drop-shadow:  ;
  --tw-backdrop-blur:  ;
  --tw-backdrop-brightness:  ;
  --tw-backdrop-contrast:  ;
  --tw-backdrop-grayscale:  ;
  --tw-backdrop-hue-rotate:  ;
  --tw-backdrop-invert:  ;
  --tw-backdrop-opacity:  ;
  --tw-backdrop-saturate:  ;
  --tw-backdrop-sepia:  ;
}

.container {
  width: 100%;
}

@media (min-width: 640px) {
  .container {
    max-width: 640px;
  }
}

@media (min-width: 768px) {
  .container {
    max-width: 768px;
  }
}

@media (min-width: 1024px) {
  .container {
    max-width: 1024px;
  }
}

@media (min-width: 1280px) {
  .container {
    max-width: 1280px;
  }
}

@media (min-width: 1536px) {
  .container {
    max-width: 1536px;
  }
}

.tm-workspace {
  width: 100%;
  max-width: 1680px;
  margin-inline: auto;
  padding: 28px 32px 20px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* Masthead. A rule under the title is the oldest device in print for
       "the page starts here", and it does the job that a heavier background
       or a boxed header would otherwise be asked to do. */

.tm-workspace-heading {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--rig-line);
}

.tm-workspace-heading h1 {
  font-size: 32px;
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.1;
}

.tm-workspace-heading p, .tm-rail-heading p {
  font-size: 14px;
  color: var(--tm-muted);
  margin-top: 6px;
}

.tm-rail-heading h2 {
  font-size: 16px;
  font-weight: 600;
  white-space: nowrap;
}

/* Engraved, not typeset. Small caps on a wide track, filled a shade
       brighter than the face and cut with a one-pixel shadow underneath —
       the legend stamped into an instrument's housing. It is a name, so it
       stays quiet: the readout beside it is what you are meant to read. */

.tm-panel-title {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--tm-fg);
}

.tm-spot-tools {
  position: relative;
  z-index: 20;
}

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

.tm-workspace-focus .tm-analysis-spot {
  display: none;
}

.tm-spot-tools summary, .tm-session-badge {
  --face: var(--rig-key);
  position: relative;
  cursor: pointer;
  background: var(--face);
  border: 1px solid color-mix(in srgb, var(--face) 72%, var(--rig-line));
  border-radius: 2px;
  transition:
            transform 50ms linear,
            filter 90ms linear;
}

.tm-spot-tools summary:hover:not(:disabled), .tm-session-badge:hover:not(:disabled) {
  filter: brightness(1.14);
}

.tm-spot-tools summary:active:not(:disabled), .tm-session-badge:active:not(:disabled) {
  transform: translateY(1px);
  filter: brightness(0.86);
}

.tm-spot-tools summary:disabled, .tm-session-badge:disabled {
  cursor: not-allowed;
  filter: saturate(0.15);
  opacity: 0.4;
  transform: none;
}

.tm-spot-tools summary:focus-visible, .tm-session-badge:focus-visible {
  outline: 2px solid var(--tm-accent);
  outline-offset: 2px;
}

.tm-spot-tools summary, .tm-session-badge {
  padding: 9px 14px;
  color: var(--tm-muted);
  font-size: 13px;
  list-style: none;
}

.tm-spot-tools summary::-webkit-details-marker {
  display: none;
}

.tm-spot-tools[open] summary {
  color: var(--tm-accent);
}

.tm-tools-popover {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  padding: 18px;
  width: -moz-max-content;
  width: max-content;
  max-width: calc(100vw - 32px);
  border: 1px solid var(--tm-border);
  border-radius: 10px;
  background: var(--tm-surface);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.tm-tool-label {
  color: var(--tm-muted);
  font-size: 12px;
}

.tm-analysis-spot {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(360px, 1.1fr) minmax(0, 1fr);
  gap: 20px;
  align-items: stretch;
}

.tm-analysis-spot > .tm-panel {
  min-height: 450px;
}

.tm-analysis-spot > .tm-panel:last-child {
  grid-column: span 2;
}

.tm-analysis-ranges {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(360px, 1.1fr) minmax(0, 1fr);
  gap: 20px;
}

.tm-analysis-insights {
  display: grid;
  grid-template-rows: minmax(320px, 1fr) 210px;
  gap: 20px;
  min-width: 0;
}

.tm-analysis-insights .tm-panel-header {
  padding-inline: 12px;
  gap: 4px;
}

.tm-analysis-insights .tm-panel-header > div {
  gap: 4px;
}

.tm-analysis-insights .tm-panel-header .tm-btn-sm {
  padding-inline: 5px;
  font-size: 12px;
}

/* Shared header readout — the Equity legend and the Strategy stats are
       the same object: two rows of (label, value, optional reading) that have
       to line up on one column grid. Rows are emitted as bare cells, not
       wrapped, because a per-row wrapper would let each row size its own
       columns and the two would drift apart — which is exactly what they did.
       Fixed line-height and `nowrap` throughout: the panel header cannot grow
       (see `.tm-panel-header`). */

.tm-readout {
  display: grid;
  grid-template-columns: max-content max-content minmax(0, 1fr);
  align-items: center;
  -moz-column-gap: 10px;
       column-gap: 10px;
  row-gap: 1px;
  min-width: 0;
  padding-left: 12px;
  border-left: 1px solid var(--rig-line);
  font-family: var(--font-text);
  font-size: 12px;
  line-height: 15px;
  color: var(--tm-muted);
}

.tm-readout-tight {
  grid-template-columns: max-content max-content;
}

.tm-readout-key {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  white-space: nowrap;
}

button.tm-readout-key {
  cursor: pointer;
}

.tm-readout-swatch {
  width: 9px;
  height: 9px;
  border: 2px solid currentColor;
  flex-shrink: 0;
}

.tm-readout-val {
  text-align: right;
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tm-readout-note {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  cursor: help;
}

.tm-readout-note:not(:empty)::before {
  content: "\00b7";
  padding-right: 6px;
}

.tm-policy-content {
  height: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  grid-template-rows: auto minmax(140px, 1fr);
  gap: 12px;
  position: relative;
}

.tm-policy-tools {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

/* The edge strip takes the slack and scrolls inside it, so a long line
       runs off to the right instead of wrapping and stealing a row from the
       chart below. */

.tm-policy-tools > :last-child {
  flex: 1;
  min-width: 0;
}

.tm-policy-tools .tm-btn-sm {
  font-size: 12px;
  padding: 4px 6px;
}

.tm-policy-chart {
  min-height: 0;
  min-width: 0;
  overflow: hidden;
}

.tm-policy-choices {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

/* Seven rows, always — the widest frontier NLHE's bet grid can offer
       (fold, check/call, five raise sizes). Reserving all seven unconditionally
       is what keeps the panel one height: sized to the choice count, a
       three-way spot and a seven-way spot would push the whole ranges row to
       two different heights as you walk the line. Empty rows cost nothing but
       the space the tall case needs anyway. */

.tm-policy-choices > div {
  grid-template-columns: 1fr;
  grid-template-rows: repeat(7, 26px);
  overflow: hidden;
  grid-auto-flow: row;
  align-self: center;
  align-content: center;
}

.tm-analysis-spot > .tm-panel:first-child,
    .tm-analysis-ranges > .tm-panel {
  container-type: inline-size;
}

.tm-workspace .tm-card-grid, .tm-workspace .tm-range-grid, .tm-workspace .tm-felt-rail {
  --lattice-cell: calc((100cqw - 56px) / 13);
}

.tm-workspace .tm-card-grid .w-7,
    .tm-workspace .tm-felt-rail .w-7,
    .tm-workspace .tm-range-grid .w-7 {
  width: var(--lattice-cell);
  height: var(--lattice-cell);
}

.tm-workspace .tm-card-grid .text-xl {
  font-size: clamp(12px, 4cqw, 20px);
}

.tm-spot-content {
  min-height: 380px;
}

/* Decision surface in the Spot panel: eight tiles — seven legal edges
       plus a free-form raise field — over a nav strip. Four columns, because
       four is what the felt's 13-column lattice divides into without leaving
       a stub, and two rows because seven edges is the frontier's ceiling. */

.tm-decisions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  flex-shrink: 0;
  padding-top: 10px;
}

.tm-decision-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: 38px;
  gap: 6px;
}

/* The cap face is the edge's own colour, handed in as `--face` so the
       key rules can derive the light fall and the skirt from it. */

.tm-decision {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  color: var(--tm-inverse);
  font-family: var(--font-text);
  font-size: 12px;
  font-weight: 700;
  line-height: 1.05;
  overflow: hidden;
}

.tm-decision-sub {
  font-family: var(--font-data);
  font-size: 10px;
  font-weight: 500;
  opacity: 0.88;
}

/* A slot with no key in it — the blanking plate over an unpopulated
       position, sunk like the well it is cut into. Reserving the space is
       what keeps the block one height as the frontier narrows. */

.tm-decision-void {
  border-radius: 2px;
  background: var(--rig-well);
  border: 1px solid var(--rig-line);
}

/* Chance node: nothing to choose, so the one thing that can happen
       takes the whole block rather than sitting in a corner of it. */

.tm-decision-fill {
  grid-column: 1 / -1;
  grid-row: 1 / span 2;
}

/* The eighth tile. A raise the grid does not carry, typed: `12`, `40bb`,
       `0.5p`, `75%`, `2/3`. Same footprint as a preset so the row stays even. */

.tm-decision-input {
  background: var(--rig-well);
  border: 1px solid var(--rig-line);
  border-radius: 2px;
  width: 100%;
  height: 100%;
  padding-inline: 6px;
  border: 0;
  color: var(--tm-fg);
  font-family: var(--font-data);
  font-size: 11px;
  text-align: center;
}

.tm-decision-input:focus {
  outline: 2px solid var(--tm-accent);
  outline-offset: -1px;
}

/* Armed: what you typed parses AND is legal here. The border is the
       only affordance — the field must not resize as you type. */

.tm-decision-nav {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 6px;
}

.tm-decision-nav button {
  height: 24px;
  color: var(--tm-fg);
  font-family: var(--font-ui);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.tm-workspace .tm-range-grid {
  width: 100%;
}

/* The deck sits in a recess; the range grid does not. Padding plus an
       equal negative margin keeps a grid's content box where it was, but it
       still grows the border box — and the range grid is the one surface
       measured off its own container width (`--lattice-cell` divides
       `100cqw` by 13), so the extra 10px pushed its right-hand column past
       the edge it was supposed to line up with. The deck is `max-content`
       and immune, so it keeps the recess. */

.tm-deck-well {
  background: var(--rig-well);
  border: 1px solid var(--rig-line);
  border-radius: 2px;
  padding: 5px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: -moz-max-content;
  width: max-content;
}

.tm-range-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 2px;
  background: color-mix(in srgb, var(--range-color) var(--weight), var(--tm-bg));
  color: var(--card-black);
  font-family: var(--font-text);
  font-size: clamp(10px, 3.1cqw, 14px);
  font-weight: 600;
  cursor: pointer;
  position: relative;
}

.\!dark .tm-range-cell {
  color: var(--card-white) !important;
}

.dark .tm-range-cell {
  color: var(--card-white);
}

.\!dark .tm-range-cell[data-bright="true"] {
  color: var(--card-black) !important;
}

.dark .tm-range-cell[data-bright="true"] {
  color: var(--card-black);
}

.tm-range-cell:hover, .tm-range-cell:focus-visible {
  z-index: 1;
  outline: 2px solid var(--tm-fg);
  outline-offset: 0;
}

.tm-range-suffix {
  font-size: 0.7em;
  opacity: 0.75;
  align-self: baseline;
  margin-top: 0.65em;
}

/* Caption under the range grid. Three columns — hand | separator |
       weight — so the middle dot sits on the grid's centre line no matter
       how wide either reading gets, and the numbers never shuffle sideways
       between cells. Height is fixed; nothing here may resize the grid. */

.tm-range-caption {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  width: 100%;
  /* Reserved height, with the room the readout was missing: the label
           sat jammed against the grid's last row. Still fixed — it may not
           resize, or the grid moves out from under the cursor reading it. */
  height: 26px;
  margin-top: 2px;
  line-height: 26px;
  font-family: var(--font-data);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--tm-muted);
}

.tm-range-caption-hand {
  text-align: right;
  color: var(--tm-fg);
}

.tm-range-caption-sep {
  padding-inline: 6px;
}

.tm-range-caption-weight {
  text-align: left;
}

.tm-range-caption-hint {
  grid-column: 1 / -1;
  grid-row: 1;
  text-align: center;
}

.tm-workspace-guide {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  font-size: 12px;
  color: var(--tm-muted);
}

/* Miniature keycaps — same light, same skirt, one size down. */

.tm-workspace-guide kbd, .tm-topnav kbd {
  --face: var(--rig-key);
  position: relative;
  cursor: pointer;
  background: var(--face);
  border: 1px solid color-mix(in srgb, var(--face) 72%, var(--rig-line));
  border-radius: 2px;
  transition:
            transform 50ms linear,
            filter 90ms linear;
}

.tm-workspace-guide kbd:hover:not(:disabled), .tm-topnav kbd:hover:not(:disabled) {
  filter: brightness(1.14);
}

.tm-workspace-guide kbd:active:not(:disabled), .tm-topnav kbd:active:not(:disabled) {
  transform: translateY(1px);
  filter: brightness(0.86);
}

.tm-workspace-guide kbd:disabled, .tm-topnav kbd:disabled {
  cursor: not-allowed;
  filter: saturate(0.15);
  opacity: 0.4;
  transform: none;
}

.tm-workspace-guide kbd:focus-visible, .tm-topnav kbd:focus-visible {
  outline: 2px solid var(--tm-accent);
  outline-offset: 2px;
}

.tm-workspace-guide kbd, .tm-topnav kbd {
  display: inline-block;
  padding: 0 5px;
  font-family: var(--font-data);
  font-size: 11px;
  line-height: 16px;
  cursor: default;
}

.tm-play-stage {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr) 230px;
  gap: 28px;
  align-items: center;
  min-height: 500px;
}

.tm-opponent-settings, .tm-play-actions {
  background: var(--tm-surface);
  border: 1px solid var(--tm-border);
  border-radius: 12px;
  padding: 16px;
}

.tm-rail-heading {
  padding-bottom: 12px;
}

.tm-game-control {
  width: 100%;
}

.tm-table-stage {
  position: relative;
  height: 480px;
}

.tm-table-stage .tm-box {
  max-width: 100%;
}

.tm-table-stage .tm-felt {
  border-radius: 46%;
  border: 10px solid var(--felt-edge);
  background: radial-gradient(ellipse at 50% 40%, var(--felt-light), var(--felt));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--card-white) 16%, transparent), inset 0 0 60px var(--felt-edge), 0 16px 40px var(--tm-shadow);
  padding: 8px;
}

.tm-table-seats {
  position: relative;
  z-index: 1;
}

.tm-player-seat {
  --tm-muted: #526b7c;
  --tm-accent: #18796f;
  padding: 12px 14px 4px;
  border-radius: 12px;
  border-color: var(--tm-border);
  box-shadow: 0 8px 24px var(--tm-shadow);
}

.tm-seat-head, .tm-seat-body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.tm-seat-head {
  height: 24px;
  margin-bottom: 8px;
  color: var(--card-black);
}

.tm-seat-name {
  font-size: 14px;
  font-weight: 600;
}

.tm-seat-dealer {
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--card-black);
  color: var(--card-white);
  width: 20px;
  height: 20px;
  font-size: 11px;
  font-weight: 700;
}

.tm-seat-stack {
  display: flex;
  flex-direction: column;
  color: var(--card-black);
}

.tm-seat-stack span {
  font-size: 11px;
  color: var(--tm-muted);
}

.tm-seat-stack strong {
  font-size: 22px;
  line-height: 1.1;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.tm-seat-stake {
  font-size: 11px;
  color: var(--tm-muted);
  margin-top: 4px;
}

.tm-seat-cards {
  display: flex;
  gap: 4px;
}

.tm-seat-cards > div, .tm-seat-cards .tm-card, .tm-seat-cards .tm-card-back {
  width: 36px;
  height: 46px;
}

.tm-seat-cards > div > div {
  width: 36px;
  height: 46px;
  border-radius: 4px;
}

.tm-player-seat > div:last-child {
  height: 20px;
}

.tm-board-center {
  color: var(--card-white);
}

.tm-pot-value {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 26px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.tm-pot-label {
  font-size: 12px;
  font-weight: 400;
  opacity: 0.7;
}

.tm-table-wordmark {
  font-size: 26px;
  letter-spacing: -0.05em;
  font-weight: 800;
  opacity: 0.25;
}

.tm-play-log {
  height: 280px;
}

.tm-play-log .tm-panel-body-flush {
  overflow: auto;
}

.tm-play-actions .tm-btn-active {
  padding-block: 12px;
}

.tm-play-actions .tm-input {
  min-width: 0;
}

@media (max-width: 1200px) {
  .tm-analysis-ranges {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .tm-analysis-insights {
    grid-column: 1 / -1;
    grid-row: 2;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 320px;
  }

  .tm-analysis-spot {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .tm-analysis-spot > .tm-panel:last-child {
    grid-column: auto;
  }

  .tm-play-stage {
    grid-template-columns: 170px minmax(0, 1fr) 190px;
    gap: 16px;
  }

  .tm-opponent-settings, .tm-play-actions {
    padding: 10px;
  }
}

@media (max-width: 900px) {
  .tm-workspace {
    padding: 24px 16px;
  }

  .tm-play-stage {
    grid-template-columns: 1fr 1fr;
  }

  .tm-play-table {
    grid-column: 1 / -1;
    grid-row: 1;
  }

  .tm-table-stage {
    max-width: 700px;
    margin: auto;
    height: 420px;
  }

  .tm-opponent-settings, .tm-play-actions {
    height: 100%;
  }

  .tm-play-stage .tm-rail-heading {
    text-align: center;
  }

  .tm-workspace-guide {
    flex-wrap: wrap;
  }
}

@media (max-width: 640px) {
  :root .tm-topnav {
    flex-wrap: wrap;
    gap: 8px;
    padding: 12px 16px;
  }

  :root .tm-topnav-links {
    order: 3;
    flex-basis: 100%;
    margin-left: 0;
  }

  :root .tm-topnav-tools {
    margin-left: auto;
  }

  :root .tm-topnav-link {
    flex: 1;
    text-align: center;
    padding: 8px;
  }

  .tm-workspace-heading h1 {
    font-size: 28px;
  }

  .tm-workspace-heading {
    flex-wrap: wrap;
  }

  .tm-workspace-heading p {
    font-size: 12px;
  }

  .tm-session-badge {
    display: none;
  }

  .tm-analysis-spot, .tm-analysis-ranges {
    grid-template-columns: minmax(0, 1fr);
  }

  .tm-analysis-insights {
    grid-column: auto;
    grid-row: auto;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: 340px 250px;
  }

  .tm-analysis-spot > .tm-panel {
    min-height: 420px;
  }

  .tm-analysis-ranges > .tm-panel .tm-panel-body {
    min-height: calc(100vw - 48px);
  }

  .tm-play-stage {
    gap: 12px;
  }

  .tm-table-stage {
    height: 410px;
  }

  .tm-table-stage .tm-felt {
    border-width: 6px;
    border-radius: 42%;
  }

  .tm-play-log {
    overflow-x: auto;
  }

  .tm-play-log > .tm-panel {
    min-width: 560px;
  }

  .tm-tools-popover > div {
    flex-wrap: wrap;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
     CONTAINERS - Nested box pattern
     ═══════════════════════════════════════════════════════════════════════ */

.tm-box {
  border-width: 1px;
  border-color: var(--tm-border);
  background-color: var(--tm-bg);
}

.tm-box-felt {
  /* Fixed paper styling for elements on felt - doesn't change in dark mode */
  background-color: var(--paper-felt);
  border-width: 1px;
  border-color: var(--card-black);
}

/* A module bolted to the chassis, not a card floating on a page. The
       face catches light along its top edge and loses it at the bottom;
       the cut line around it is a groove, not a border; and it throws a
       short cast shadow so you can tell it stands proud of the metal.
       `h-full` fills any height-constrained parent. Overflow stays visible
       so absolute-positioned children (histogram axis ticks, mean carets)
       can draw freely; per-component scrollers (tree, miller columns)
       handle their own clipping. */

.tm-panel {
  display: flex;
  height: 100%;
  flex-direction: column;
  min-width: 0;
  border: 1px solid var(--rig-line);
  border-radius: 2px;
  background: var(--rig-bezel);
}

/* Fixed height, never `min-h`. A header that can grow is a feedback
       loop: hover readouts appear, the header wraps, the body shrinks, the
       cursor falls off the cell it was over, the readout clears, the header
       shrinks back — the grid flickers at pointer-move frequency. Fixed
       height + `whitespace-nowrap` on `.tm-btn` makes hover purely a paint
       event, so nothing in the body can move under the cursor. */

.tm-panel-header {
  display: flex;
  height: 56px;
  flex-shrink: 0;
  align-items: center;
  overflow: hidden;
  padding: calc(var(--space-panel) / 2) var(--space-panel);
  font-family: var(--font-ui);
  /* A milled groove, not a rule: one dark line cut into the face and
           one light line on its lower lip, which is what an edge looks like
           under a light directly above it. */
  border-bottom: 1px solid var(--rig-line);
}

.tm-panel-body {
  min-height: 0px;
  flex: 1 1 0%;
  padding: var(--space-panel);
}

/* Flush body — no padding, lets children own the inner gutter (e.g.
       the GameLog miller columns that go edge-to-edge of the panel). */

.tm-panel-body-flush {
  min-height: 0px;
  flex: 1 1 0%;
}

/* ═══════════════════════════════════════════════════════════════════════
     RIG — chassis, wells, keys and lamps. The four physical primitives the
     rest of the sheet composes from.
     ═══════════════════════════════════════════════════════════════════════ */

/* The ground. A vertical light fall plus a fine vertical grain, fixed to
       the viewport so the metal stays still while the page scrolls over it —
       the grain moving with the content is what would give it away as
       wallpaper. */

.tm-chassis {
  background-color: var(--rig-chassis);
}

/* A recess milled into a module's face, for a readout to sit in. The
       inner shadow falls from the top lip and the outer highlight sits on
       the bottom one — exactly inverted from a key, which is the whole
       trick: same light, opposite geometry, so one reads as sunk and the
       other as proud without either needing an outline to say so. */

.tm-well {
  background: var(--rig-well);
  border: 1px solid var(--rig-line);
  border-radius: 2px;
}

/* Measurement grid behind a readout. Faint enough to read as etched
       into the well rather than drawn on top of the data. */

.tm-reticle {
  background-image:
            repeating-linear-gradient(0deg, var(--rig-reticle) 0 1px, transparent 1px 16px),
            repeating-linear-gradient(90deg, var(--rig-reticle) 0 1px, transparent 1px 16px);
}

/* A key, not a rectangle. `--face` is the cap colour and everything
       else is derived from it: the light fall across the cap, the catch
       on its top edge, and the skirt underneath in the cap's own darkened
       tone. Pressing collapses the skirt and drops the cap by its own
       height, so the travel is real displacement rather than a colour
       change. Anything that sets `--face` gets the whole treatment. */

.tm-key,
    .tm-btn,
    .tm-decision,
    .tm-decision-nav button {
  --face: var(--rig-key);
  position: relative;
  cursor: pointer;
  background: var(--face);
  border: 1px solid color-mix(in srgb, var(--face) 72%, var(--rig-line));
  border-radius: 2px;
  transition:
            transform 50ms linear,
            filter 90ms linear;
}

.tm-key:hover:not(:disabled),
    .tm-btn:hover:not(:disabled),
    .tm-decision:hover:not(:disabled),
    .tm-decision-nav button:hover:not(:disabled),
    .tm-spot-tools summary:hover:not(:disabled) {
  filter: brightness(1.14);
}

.tm-key:active:not(:disabled),
    .tm-btn:active:not(:disabled),
    .tm-decision:active:not(:disabled),
    .tm-decision-nav button:active:not(:disabled),
    .tm-spot-tools summary:active:not(:disabled) {
  transform: translateY(1px);
  filter: brightness(0.86);
}

.tm-key:disabled,
    .tm-btn:disabled,
    .tm-decision:disabled,
    .tm-decision-nav button:disabled,
    .tm-spot-tools summary:disabled {
  cursor: not-allowed;
  filter: saturate(0.15);
  opacity: 0.4;
  transform: none;
}

.tm-key:focus-visible,
    .tm-btn:focus-visible,
    .tm-decision:focus-visible,
    .tm-decision-nav button:focus-visible,
    .tm-spot-tools summary:focus-visible {
  outline: 2px solid var(--tm-accent);
  outline-offset: 2px;
}

/* Indicator lamp. Off is a dead lens flush with the face; on is a lit
       one, which means a bloom around it and not merely a brighter fill. */

.tm-lamp {
  display: inline-block;
  width: 6px;
  height: 6px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--rig-lamp-off);
}

.tm-lamp-on {
  background: var(--action-terminal);
  box-shadow: none;
}

/* Phosphor persistence. The curve a shuffle replaced does not cut — it
       decays, the way a trace does on a scope with the persistence turned
       up. Which is also the honest picture: the old distribution was real a
       moment ago, and watching it fade tells you how far the new bucket
       moved. */

@keyframes tm-phosphor-decay {
  from {
    opacity: 0.5;
  }

  to {
    opacity: 0;
  }
}

/* Rest state is invisible, not visible: the sheet kills every animation
       under `prefers-reduced-motion`, and a ghost whose only way of leaving
       is the decay would sit there at full strength forever. Off by default,
       lit by the animation — so reduced motion simply means no persistence. */

.tm-phosphor-ghost {
  opacity: 0;
  animation: tm-phosphor-decay 900ms ease-out forwards;
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════════════════
     BUTTONS - Tactile paper buttons with shadow + press
     ═══════════════════════════════════════════════════════════════════════ */

/* Geometry and voice only — the cap, its light, and its travel all come
       from the key rules above. An "active" button is the same key with a
       different cap colour, so the pressed state and the lit state are one
       mechanism instead of two. */

.tm-btn {
  white-space: nowrap;
  padding-left: 0.75rem;
  padding-right: 0.75rem;
  padding-top: 0.375rem;
  padding-bottom: 0.375rem;
  color: var(--tm-fg);
  font-family: var(--font-text);
  font-weight: 500;
}

.tm-btn-active {
  --face: var(--tm-accent);
  color: var(--tm-inverse);
}

.tm-btn-recall {
  box-shadow:
            inset 0 0 0 2px var(--tm-accent),
            2px 2px 0 var(--tm-shadow);
}

.tm-btn-sm {
  padding-left: 0.5rem;
  padding-right: 0.5rem;
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
}

/* Opt-in mono override for buttons carrying tabular data (bet sizes,
       timers, keychords, single-letter symbols). Default `.tm-btn` is
       serif so words read like names; this class is for cells you scan. */

/* ═══════════════════════════════════════════════════════════════════════
     TOP NAV — real site header (wordmark + primary nav + tools).
     Same height/density as the old TopStrip; shape upgraded to three
     slots (wordmark · nav · tools) for proper site navigation.
     ═══════════════════════════════════════════════════════════════════════ */

/* The rig's top rail — same face, same groove, same light as a module,
       so the chrome reads as part of the instrument and not as a website
       bolted above it. */

.tm-topnav {
  display: flex;
  width: 100%;
  flex-shrink: 0;
  align-items: center;
  gap: 1.5rem;
  padding: 0 32px;
  min-height: 72px;
  background: var(--rig-bezel);
  border-bottom: 1px solid var(--rig-line);
}

.tm-topnav-wordmark {
  color: var(--tm-fg);
  text-decoration-line: none;
}

.tm-topnav-links {
  display: flex;
  flex: 1 1 0%;
  align-items: center;
  gap: 0.25rem;
  margin-left: 32px;
}

.tm-topnav-tools {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.tm-topnav-link {
  border-width: 1px;
  border-color: transparent;
  padding-left: 1rem;
  padding-right: 1rem;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
  color: var(--tm-muted);
  text-decoration-line: none;
  font-family: var(--font-ui);
  font-weight: 600;
  border-radius: 7px;
}

.tm-topnav-link:hover {
  color: var(--tm-fg);
  background-color: var(--tm-hover);
}

.tm-topnav-link-active {
  color: var(--tm-accent);
  background-color: color-mix(in srgb, var(--tm-accent) 10%, transparent);
}

/* ═══════════════════════════════════════════════════════════════════════
     SIDEBAR — vertical stack of panels in the right column of Analysis.
     Cells inside scale with the sidebar width via container queries
     (see ANALYSIS LAYOUT block below).
     ═══════════════════════════════════════════════════════════════════════ */

/* Sidebar gives Observed a generous fixed minimum (so its 4 rows have
       breathing room) and lets Range claim the rest. Each panel centers
       its grid internally, so surplus vertical space lives as padding
       around the tile grids — not as a void between the panels. */

.tm-sidebar {
  display: grid;
  grid-template-rows: minmax(200px, auto) 1fr;
  gap: var(--space-panel);
  min-height: 0;
  min-width: 0;
}

.tm-sidebar > * {
  min-height: 0;
  min-width: 0;
}

/* ═══════════════════════════════════════════════════════════════════════
     TACTILE - Colored interactive elements with shadow + press
     ═══════════════════════════════════════════════════════════════════════ */

.tm-tactile {
  cursor: pointer;
  border-width: 1px;
  border-color: var(--tm-border);
  box-shadow: var(--shadow-sm);
}

.tm-tactile:hover {
  filter: brightness(0.92);
}

.tm-tactile:active {
  transform: translateY(var(--lift));
  box-shadow: var(--shadow-pressed);
}

/* Section name above a column or block inside a panel ("Subgame",
       "Choices"). Serif = "this is a name of something," matching the
       panel-title treatment. Pairs with mono data below. */

.tm-section-label {
  font-family: var(--font-text);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.2;
  color: var(--tm-fg);
}

/* Panel titles in HeaderTab. Same idiom: serif noun-of-identity sitting
       against the hard 1px panel border. Sized to fit the existing
       button-shaped header rail. */

.tm-btn-title {
  font-family: var(--font-text);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -0.005em;
}

/* ═══════════════════════════════════════════════════════════════════════
     GAME-TREE LANES - alternating column tints inside the Tree panel
     ═══════════════════════════════════════════════════════════════════════ */

/* Per-street backgrounds: community streets (flop/turn/river) sit on felt,
       preflop on a neutral grey to read as private. Spans the tree body between
       the actor-label header and the street-label footer. */

.tm-street-board {
  background-color: var(--felt);
}

.tm-street-settle {
  background-color: var(--street-settle);
}

.tm-street-private {
  background-color: var(--street-private);
}

.tm-tree-band-label {
  text-align: center;
  font-size: 10px;
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--tm-muted);
  font-family: var(--font-text);
}

/* ═══════════════════════════════════════════════════════════════════════
     CARDS & CARD-LIKE ELEMENTS - Shared styling for cards, chips, dealer button
     ═══════════════════════════════════════════════════════════════════════ */

/* Legacy aliases — kept so existing consumers keep working. New CSS
       should reference `var(--shadow-sm/md/lg)` directly. */

.tm-shadow {
  box-shadow: var(--shadow-sm);
}

.tm-panel-shadow {
  box-shadow: var(--shadow-md);
}

.tm-action-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  border-width: 2px;
  border-color: var(--tm-border);
  font-size: 0.75rem;
  line-height: 1rem;
  font-weight: 700;
  color: var(--tm-inverse);
}

.tm-card {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--card-white);
  border: 1px solid var(--rig-line);
  border-radius: 2px;
}

.tm-card-focus {
  outline: 2px solid var(--tm-accent);
  outline-offset: 1px;
  border-color: var(--tm-accent);
}

.tm-card-slot {
  border-width: 1px;
  border-style: dashed;
  border-color: var(--tm-border);
  border-radius: 4px;
}

/* Face-down card — light fill + diagonal hatch so it stays visible
       against both dark surfaces (green felt) and light. Distinct from
       `tm-card-slot` (undealt) and `tm-card` (face-up). */

/* Card back, Bicycle-wise. Three things make that deck read from across
       a room and all three survive at a 28px cell: the white margin, the
       crimson field, and a fine lattice that never resolves into a picture.
       The filigree does not, so it is two crossing hatches and a bloom at
       the centre where the rider would be — at this size the eye reads
       texture and colour and takes the rest on trust. */

.tm-card-back {
  border: 1px solid var(--rig-line);
  border-radius: 2px;
  background-color: var(--card-back-ink);
  background-image:
            repeating-linear-gradient(45deg, transparent 0 2px, rgba(255, 255, 255, 0.26) 2px 3px),
            repeating-linear-gradient(-45deg, transparent 0 2px, rgba(255, 255, 255, 0.26) 2px 3px),
            radial-gradient(ellipse at 50% 44%, rgba(255, 255, 255, 0.18) 0%, transparent 60%);
  box-shadow:
            inset 0 0 0 2px var(--card-white),
            inset 0 0 0 3px color-mix(in srgb, var(--card-back-ink) 80%, #000);
}

.tm-winner {
  box-shadow:
            0 0 0 3px var(--action-check),
            0 0 12px 2px var(--action-check),
            2px 2px 0 var(--tm-shadow);
  animation: tm-winner-pulse 1.5s ease-in-out infinite;
}

.tm-hero-seat {
  outline: 2px solid var(--tm-accent);
  outline-offset: -2px;
}

@keyframes tm-winner-pulse {
  0%, 100% {
    box-shadow:
                0 0 0 3px var(--action-check),
                0 0 12px 2px var(--action-check),
                2px 2px 0 var(--tm-shadow);
  }

  50% {
    box-shadow:
                0 0 0 3px var(--action-check),
                0 0 20px 6px var(--action-check),
                2px 2px 0 var(--tm-shadow);
  }
}

/* ═══════════════════════════════════════════════════════════════════════
     INPUTS
     ═══════════════════════════════════════════════════════════════════════ */

.tm-input {
  border-width: 1px;
  border-color: var(--tm-border);
  background-color: var(--tm-bg);
  padding-left: 0.75rem;
  padding-right: 0.75rem;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
  color: var(--tm-fg);
  border-radius: 6px;
}

.tm-input:focus {
  outline-style: solid;
  outline-width: 1px;
  outline-offset: 1px;
  outline-color: var(--tm-border);
}

/* ═══════════════════════════════════════════════════════════════════════
     FELT - Poker table surface (semantic color preserved)
     ═══════════════════════════════════════════════════════════════════════ */

.tm-felt {
  border-width: 1px;
  border-color: var(--tm-border);
  background-color: var(--felt);
}

/* ═══════════════════════════════════════════════════════════════════════
     GAME LOG - Level-based entry backgrounds
     ═══════════════════════════════════════════════════════════════════════ */

.tm-log-session {
  background-color: color-mix(in srgb, var(--tm-hover) 50%, transparent);
  border-left: 3px solid var(--tm-accent);
}

.tm-log-hand {
  background-color: color-mix(in srgb, var(--tm-hover) 20%, transparent);
  border-left: 3px solid var(--tm-border);
  margin-top: 4px;
  padding-top: 6px;
  border-top: 1px solid var(--tm-border);
}

.tm-log-chance {
  border-left: 3px solid var(--action-chance);
}

.tm-log-terminal {
  border-left: 3px solid var(--action-terminal);
  background-color: color-mix(in srgb, var(--action-terminal) 8%, transparent);
}

.tm-log-action {
  border-left: 3px solid var(--tm-border);
}

/* ═══════════════════════════════════════════════════════════════════════
     GRID LAYOUTS - CSS Grid templates (decoupled from Rust)
     ═══════════════════════════════════════════════════════════════════════ */

.tm-card-grid {
  display: grid;
  grid-template-columns: repeat(13, var(--lattice-cell));
  gap: 2px;
}

/* Felt band — the 13-column table strip in the middle of the Spot panel.
       Bleeds through `tm-panel-body`'s horizontal padding so the green reaches
       the panel's edges, then re-applies the inset so its card grid stays
       column-aligned with the deck grid above and the decisions below. Both
       long edges draw a border: the band is a seam between two surfaces now,
       not a rail welded to the panel's foot. */

.tm-felt-band {
  /* The felt is a dark surface in both registers, so the page's inks
           do not hold on it — paper's ochre gold and oxide red go muddy
           against green. Rebind the handful of semantic colours that
           actually appear here once, rather than patching each component
           that draws on the felt. */
  --accent-gold: #f2c14e;
  --action-terminal: #f2c14e;
  --action-allin: #f0736c;
  --tm-muted: rgba(255, 255, 255, 0.6);
  display: flex;
  flex-direction: column;
  align-items: center;
  background-color: var(--felt);
  gap: 3px;
  border-bottom: 1px solid var(--rig-line);
  margin: calc(-1 * var(--space-panel)) calc(-1 * var(--space-panel)) 0;
  padding: 10px var(--space-panel);
}

/* Stake marker. It was a white disc on green — the brightest object on
       the felt, for the least important number there. Dark field, light
       rim, light numerals: it now reads as a chip pushed out in front of a
       seat, and the cards are the brightest things again. */

.tm-felt-chip {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: var(--chip-field);
  border: 1px solid var(--chip-rim);
  font-family: var(--font-data);
  font-weight: 700;
}

/* One metadata rail on the felt band — a 4|5|4 split of the same 13
       columns, so labels sit over hole cards and the pot over the board. */

.tm-workspace .tm-felt-rail {
  --lattice-cell: calc((100cqw - 56px) / 13);
}

.tm-workspace .tm-felt-rail .w-7 {
  width: var(--lattice-cell);
  height: var(--lattice-cell);
}

.tm-workspace .tm-felt-rail .text-xl {
  font-size: clamp(12px, 4cqw, 20px);
}

.tm-felt-rail {
  display: grid;
  grid-template-columns: repeat(13, var(--lattice-cell));
  gap: 2px;
  align-items: center;
  font-family: var(--font-data);
  font-size: 10px;
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--card-white);
}

.tm-range-grid {
  display: grid;
  grid-template-columns: repeat(13, var(--lattice-cell));
  gap: 2px;
}

.tm-action-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(4, 1fr);
  gap: 4px;
}

.tm-raise-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: 1fr;
  gap: 4px;
}

/* ═══════════════════════════════════════════════════════════════════════
       ANALYSIS GRID — 2 cols × 3 rows, responsive
       Outer container is fluid up to 1680px. Cells are intrinsically sized:
       columns are equal 1fr (each ~700-800px on a wide screen), rows expand
       to fit content with a sensible minimum.
       ═══════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════
       ANALYSIS LAYOUT — see docs/active/frontend-analysis-redesign.md.
       Wide stage (default): PanelGrid (6/8) + Sidebar (2/8) side-by-side.
       Narrow stage: 2x2 collapses to 1x4 vertical stack, sidebar stays right.
       Tiny stage: sidebar moves below the stack as a full-width row.
       No horizontal scrollbars at any stage; vertical scroll only as last
       resort when even the tiny stage can't fit (browser zoom > ~180%).
       ═══════════════════════════════════════════════════════════════════════ */

/* Panels in the 2x2 grid use a fixed row height so vertical spacing
       stays consistent regardless of content. Width scales with viewport;
       the resulting aspect varies from roughly 5:4 (narrower viewports)
       to roughly 3:2 (wide viewports). */

.tm-panel-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: minmax(380px, auto);
  align-content: start;
  gap: var(--space-panel);
  min-width: 0;
}

.tm-panel-grid > * {
  min-width: 0;
}

/* Narrow stage: not enough horizontal room for 2x2 + sidebar. The
       2x2 collapses to a single column inside .tm-analysis-main's left
       cell. Sidebar still on the right. */

@media (max-width: 1100px) {
  .tm-panel-grid {
    grid-template-columns: 1fr;
  }
}

/* Tiny stage: sidebar moves below the stack as a full-width row. */

/* ModeGrid surface (Gameplay/History). Real CSS grid so GridCell's
       line-based `grid-column`/`grid-row` placement actually applies; the
       1px `gap-px` over a border-colored field draws the hairline dividers
       between panels. Callers pass their own template via `grid_class`. */

.tm-mode-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: minmax(380px, auto);
  align-content: start;
  min-width: 0;
  background-color: var(--tm-border);
}

/* ═══════════════════════════════════════════════════════════════════════
       HISTORY LAYOUT — the three read-out panels (P&L / AIVAT / Stats) stack
       in the main column; Matchup rides a full-height control rail on the
       right (it drives the query, the others render the result). Fluid up to
       a cap and centered, matching Analysis mode. 5fr/2fr columns × three
       uniform rows; Matchup's GridCell spans all three. 1fr keeps the rows
       equal, the 250px floor keeps the charts legible.
       ═══════════════════════════════════════════════════════════════════════ */

.tm-history-grid {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 2fr);
  grid-template-rows: repeat(3, minmax(250px, 1fr));
  align-items: stretch;
  gap: var(--space-panel);
  padding: var(--space-panel) var(--space-section);
  width: 100%;
  max-width: 1680px;
  margin-inline: auto;
}

/* The ring sits in a circular recess milled into the module face. */

.tm-policy-circle {
  width: 100%;
  height: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  background: var(--rig-well);
  box-shadow: inset 0 0 0 1px var(--rig-line);
}

.tm-tick-lg {
  background-color: var(--tm-fg);
  height: 14px;
  width: 2px;
}

.tm-tick-sm {
  background-color: var(--tm-fg);
  height: 8px;
  width: 2px;
}

/* ═══════════════════════════════════════════════════════════════════════
     DISABLED STATE
     ═══════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════
     GRID POSITIONING — column/row spans for sample panel and policy grid
     ═══════════════════════════════════════════════════════════════════════ */

.tm-col-span-2 {
  grid-column: 1 / 3;
}

.tm-row-6-10 {
  grid-row: 6 / 10;
}

.tm-row-span-2 {
  grid-row: span 2;
}

.tm-cell-span-2x2 {
  grid-row: span 2;
  grid-column: span 2;
}

/* ═══════════════════════════════════════════════════════════════════════
     CARD SUIT COLORS - Text colors for card suits
     ═══════════════════════════════════════════════════════════════════════ */

.tm-suit-red {
  color: var(--card-red);
}

.tm-suit-black {
  color: var(--card-black);
}

/* ═══════════════════════════════════════════════════════════════════════
     SVG RENDERING - Full coverage with visible overflow
     ═══════════════════════════════════════════════════════════════════════ */

.tm-svg-full {
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* ═══════════════════════════════════════════════════════════════════════
     HISTOGRAM TRANSITIONS - Opacity transitions for histogram elements
     ═══════════════════════════════════════════════════════════════════════ */

.tm-hist-transition {
  transition:
            opacity 400ms cubic-bezier(0.4, 0, 0.2, 1),
            d 400ms cubic-bezier(0.4, 0, 0.2, 1);
}

.tm-caret-transition {
  transition:
            left 400ms cubic-bezier(0.4, 0, 0.2, 1),
            opacity 400ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* ═══════════════════════════════════════════════════════════════════════
     LOADING VEIL - Overlay that blocks interactions during async operations
     ═══════════════════════════════════════════════════════════════════════ */

/* The original diagonal shimmer, kept. The accent-coloured sweep that
       replaced it read as a progress bar rather than as "busy", and a
       progress bar that is not measuring anything is a lie. The tint is
       now mixed from the panel face instead of a hardcoded rgb, so one
       rule covers both themes. */

.tm-loading-veil {
  position: absolute;
  inset: 0px;
  z-index: 50;
  cursor: wait;
  background: linear-gradient(
            135deg,
            color-mix(in srgb, var(--rig-bezel) 45%, transparent) 0%,
            color-mix(in srgb, var(--rig-bezel) 70%, transparent) 50%,
            color-mix(in srgb, var(--rig-bezel) 45%, transparent) 100%
        );
  background-size: 200% 200%;
  animation: tm-veil-shimmer 1.5s ease-in-out infinite;
}

@keyframes tm-veil-shimmer {
  0%,
        100% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
     INTERACTIVE ELEMENTS - Paper hover + click depression
     ═══════════════════════════════════════════════════════════════════════ */

/* The bucket id as a lit counter: amber digits sunk into the housing.
       It is a number the machine arrived at, not a token anyone placed, so
       it belongs in a recess rather than on a paper chip like the stakes
       riding on the felt. */

.tm-abs-readout {
  background: var(--rig-well);
  border: 1px solid var(--rig-line);
  border-radius: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-data);
  font-weight: 700;
  color: var(--action-terminal);
  cursor: pointer;
}

.tm-abs-prefix {
  color: var(--rig-etch);
}

.tm-abs-readout input {
  width: 2.6ch;
  background: transparent;
  border: 0;
  outline: none;
  color: inherit;
  font: inherit;
  text-align: center;
}

.tm-interactive {
  cursor: pointer;
}

.tm-interactive:hover {
  filter: brightness(0.96);
}

.tm-interactive:active {
  transform: translateY(var(--lift));
  box-shadow: var(--shadow-pressed);
}

/* ═══════════════════════════════════════════════════════════════════════
     MILLER COLUMNS - Hierarchical drill-down navigation
     ═══════════════════════════════════════════════════════════════════════ */

.tm-miller-col {
  display: flex;
  min-width: 0px;
  flex: 1 1 0%;
  flex-direction: column;
  border-right-width: 1px;
  border-color: var(--tm-border);
}

.tm-miller-col:last-child {
  border-right-width: 0px;
}

.tm-miller-footer {
  flex-shrink: 0;
  border-top-width: 1px;
  border-color: var(--tm-border);
  padding-left: 0.75rem;
  padding-right: 0.75rem;
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
}

.tm-miller-row {
  display: flex;
  cursor: pointer;
  align-items: baseline;
  justify-content: space-between;
  padding-left: 0.75rem;
  padding-right: 0.75rem;
  padding-top: 0.375rem;
  padding-bottom: 0.375rem;
  font-size: 0.75rem;
  line-height: 1rem;
}

.tm-miller-row:hover {
  background-color: var(--tm-hover);
}

.tm-miller-row-active {
  background-color: var(--tm-hover);
  font-weight: 600;
}

/* ═══════════════════════════════════════════════════════════════════════
     CARD HOVER - Thicker border on interactive cards
     ═══════════════════════════════════════════════════════════════════════ */

.tm-card.tm-interactive:hover {
  border-width: 2px;
}

/* ═══════════════════════════════════════════════════════════════════════
     LIST ROW - Flat row-style selector for dense vertical lists
     (Matchup hero/against columns, axis toggles). Shares the click
     surface of a button but drops the paper-shadow tactile so dense
     stacks read as a list, not a stack of stamps.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-list-row {
  width: 100%;
  cursor: pointer;
  border-width: 1px;
  background-color: var(--tm-bg);
  padding-left: 0.5rem;
  padding-right: 0.5rem;
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
  text-align: center;
  font-size: 0.75rem;
  line-height: 1rem;
  font-weight: 600;
  letter-spacing: 0.025em;
  color: var(--tm-fg);
  border-color: color-mix(in srgb, var(--tm-border) 40%, transparent);
  font-family: var(--font-data);
}

.tm-list-row:hover:not(.tm-list-row-active):not(.tm-disabled) {
  background-color: var(--tm-hover);
}

.tm-list-row:disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

/* ═══════════════════════════════════════════════════════════════════════
     JARGON - inline term with dotted underline + hover popover. Used to mark
     up unfamiliar acronyms (SPR, EV, Abs, etc.) so the reader can hover for
     a one-line definition without leaving the page.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-jargon {
  position: relative;
  display: inline-block;
  cursor: help;
}

.tm-jargon-label {
  border-bottom: 1px dotted var(--tm-muted);
}

.tm-jargon:hover .tm-jargon-label,
    .tm-jargon:focus .tm-jargon-label {
  border-bottom-color: var(--tm-accent);
  color: var(--tm-accent);
}

.tm-jargon-pop {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 70;
  min-width: 220px;
  max-width: 320px;
  padding: 8px 10px;
  background-color: var(--tm-bg);
  color: var(--tm-fg);
  border: 1px solid var(--tm-border);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-ui);
  font-size: 12px;
  line-height: 1.4;
  text-align: left;
  white-space: normal;
  opacity: 0;
  pointer-events: none;
  transition: opacity 120ms;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.tm-jargon:hover .tm-jargon-pop,
    .tm-jargon:focus .tm-jargon-pop {
  opacity: 1;
}

.tm-jargon-pop-title {
  font-weight: 700;
  font-family: var(--font-data);
}

.tm-jargon-pop-short {
  font-family: var(--font-text);
  color: var(--tm-muted);
}

/* ═══════════════════════════════════════════════════════════════════════
     PANEL SHADOW - shared floating-panel shadow used by modals, drawers,
     tour cards. Same offset as tm-shadow for the system's overall feel.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-panel-shadow {
  box-shadow: var(--shadow-lg);
}

/* ═══════════════════════════════════════════════════════════════════════
     HELP HINT CHIP - persistent "?" indicator in the TopStrip telling new
     visitors how to find shortcuts/help. Same shape as tm-btn-sm but more
     muted styling so it reads as informational rather than actionable.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-help-hint {
  display: flex;
  cursor: pointer;
  align-items: center;
  gap: 0.25rem;
  border-width: 1px;
  border-color: var(--tm-border);
  padding-left: 0.5rem;
  padding-right: 0.5rem;
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
  color: var(--tm-muted);
  font-family: var(--font-ui);
  font-size: 11px;
  background-color: var(--paper);
  border-radius: 6px;
}

.tm-help-hint:hover {
  color: var(--tm-fg);
  background-color: var(--tm-hover);
}

.tm-help-hint kbd {
  border-width: 1px;
  border-color: var(--tm-border);
  padding-left: 0.25rem;
  padding-right: 0.25rem;
  color: var(--tm-fg);
  font-family: var(--font-data);
  font-size: 10px;
  background-color: var(--tm-bg);
  line-height: 1;
}

/* Tiny accent dot used as a "new / unseen" indicator on chips like the
       TopNav Tour button. Vanishes once the user has run the tour. */

.tm-pip {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 9999px;
  background-color: var(--tm-accent);
}

/* ═══════════════════════════════════════════════════════════════════════
     SERIF MOMENTS — modal/drawer/tour-card titles, empty states. Anywhere
     the user is *reading*, we switch from mono (scanning) to serif
     (reading) per the makingsoftware split.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-overlay-title {
  font-family: var(--font-text);
  font-size: var(--text-h4);
  line-height: 1.15;
  font-weight: 500;
  letter-spacing: -0.005em;
  color: var(--tm-fg);
}

.tm-overlay-body {
  font-family: var(--font-text);
  font-size: var(--text-md);
  line-height: 1.6;
  color: var(--tm-fg);
}

/* Italic muted serif for empty-state coaching lines ("Hero is not to act
       here", "No equity data yet"). Reads as a soft narrator voice. */

.tm-empty-msg {
  font-family: var(--font-text);
  font-size: 14px;
  line-height: 1.5;
  font-style: italic;
  color: var(--tm-muted);
}

/* Term definitions in drawer/modal/jargon-popover + cheatsheet row
       descriptions. The right-hand "what this means" voice — serif, muted,
       comfortable line height. Pairs against mono labels/keys. */

.tm-term-def {
  font-family: var(--font-text);
  font-size: 14px;
  line-height: 1.55;
  color: var(--tm-muted);
}

/* ═══════════════════════════════════════════════════════════════════════
     WORDMARK — display font, used for the brand mark in the TopNav and
     in larger sizes on Home. Pixel/bitmap face (VT323 today; swap to
     Departure Mono via @font-face later). Uppercase by default to read
     as a logotype, not a sentence.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-wordmark {
  font-family: var(--font-display);
  font-size: var(--text-lead);
  line-height: 1;
  letter-spacing: -0.055em;
  font-weight: 800;
  color: var(--tm-fg);
  text-transform: lowercase;
  display: inline-block;
}

/* ═══════════════════════════════════════════════════════════════════════
     PROSE PAGES — Home, Blog, and future Learn surfaces. Centered column,
     serif body, mono captions, generous vertical rhythm. The container
     fills the viewport so the footer hugs the bottom of short pages.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-prose-page {
  margin-left: auto;
  margin-right: auto;
  display: flex;
  width: 100%;
  flex-direction: column;
  gap: 2.5rem;
  padding-left: 1.5rem;
  padding-right: 1.5rem;
  padding-top: 3rem;
  padding-bottom: 3rem;
  max-width: 720px;
}

.tm-prose-header {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.tm-prose-section {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.tm-prose-h1 {
  font-family: var(--font-text);
  font-size: var(--text-h1);
  line-height: 1.1;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--tm-fg);
}

.tm-prose-h2 {
  font-family: var(--font-text);
  font-size: var(--text-h2);
  line-height: 1.2;
  font-weight: 500;
  letter-spacing: -0.005em;
  color: var(--tm-fg);
}

.tm-prose-body {
  font-family: var(--font-text);
  font-size: var(--text-body);
  line-height: 1.75;
  color: var(--tm-fg);
}

.tm-prose-fade {
  font-family: var(--font-text);
  font-size: var(--text-body);
  line-height: 1.5;
  color: var(--tm-muted);
  font-style: italic;
}

.tm-caption {
  font-family: var(--font-data);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tm-muted);
}

/* ═══════════════════════════════════════════════════════════════════════
     HERO — Home page top block. Wordmark scaled way up; byline serif right.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-hero {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding-top: 2rem;
}

.tm-hero-word {
  font-family: var(--font-display);
  font-size: var(--text-hero);
  line-height: 0.9;
  letter-spacing: 0.02em;
  color: var(--tm-accent);
  text-transform: lowercase;
}

.tm-hero-byline {
  display: flex;
  max-width: 36rem;
  flex-direction: column;
  gap: 0.25rem;
}

.tm-hero-byline p:first-child {
  font-family: var(--font-text);
  font-size: var(--text-lead);
  line-height: 1.4;
  color: var(--tm-fg);
}

/* ═══════════════════════════════════════════════════════════════════════
     HALFTONE — decorative section divider mimicking makingsoftware's
     dot-pattern rule. Pure CSS, no asset.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-halftone {
  width: 100%;
  border-width: 0px;
  height: 8px;
  background-image: radial-gradient(circle, var(--tm-muted) 1px, transparent 1.2px);
  background-size: 6px 8px;
  background-repeat: repeat-x;
  background-position: center;
  opacity: 0.6;
}

/* ═══════════════════════════════════════════════════════════════════════
     SURFACE CARDS — Home page CTA grid (Play/Analysis/History/Blog).
     ═══════════════════════════════════════════════════════════════════════ */

.tm-surface-grid {
  display: grid;
  grid-template-columns: repeat(1, minmax(0, 1fr));
  gap: 0.75rem;
}

@media (min-width: 640px) {
  .tm-surface-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.tm-surface-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  border-width: 1px;
  border-color: var(--tm-border);
  padding: 1.25rem;
  text-decoration-line: none;
  background-color: var(--paper);
  box-shadow: var(--shadow-md);
  transition: transform 80ms;
}

.tm-surface-card:hover {
  transform: translate(calc(-1 * var(--lift)), calc(-1 * var(--lift)));
  box-shadow: var(--shadow-lg);
  border-color: var(--tm-accent);
}

.tm-surface-card-title {
  font-family: var(--font-text);
  font-size: var(--text-h3);
  line-height: 1.1;
  font-weight: 500;
  color: var(--tm-fg);
}

.tm-surface-card-body {
  font-family: var(--font-text);
  font-size: var(--text-md);
  line-height: 1.5;
  color: var(--tm-muted);
}

.tm-surface-card-arrow {
  position: absolute;
  top: 1rem;
  right: 1rem;
  color: var(--tm-muted);
  font-family: var(--font-data);
  font-size: 16px;
}

.tm-surface-card:hover .tm-surface-card-arrow {
  color: var(--tm-accent);
}

/* ═══════════════════════════════════════════════════════════════════════
     BREADCRUMB — small caps mono breadcrumb at the top of detail pages.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-breadcrumb {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-data);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tm-muted);
}

.tm-breadcrumb a {
  color: var(--tm-muted);
  text-decoration: none;
  border-bottom: 1px dotted var(--tm-muted);
}

.tm-breadcrumb a:hover {
  color: var(--tm-accent);
  border-bottom-color: var(--tm-accent);
}

.tm-breadcrumb-sep {
  opacity: 0.5;
}

/* ═══════════════════════════════════════════════════════════════════════
     BLOG POST LIST — index of posts on /blog.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-post-list {
  display: flex;
  list-style-type: none;
  flex-direction: column;
  gap: 0px;
  padding: 0px;
}

.tm-post-row {
  border-top-width: 1px;
  border-color: var(--tm-border);
}

.tm-post-row:last-child {
  border-bottom-width: 1px;
}

.tm-post-row-link {
  display: grid;
  gap: 0.5rem;
  padding-top: 1.25rem;
  padding-bottom: 1.25rem;
  text-decoration-line: none;
  grid-template-columns: 7rem 1fr;
  grid-template-rows: auto auto;
}

.tm-post-row-link:hover .tm-post-row-title {
  color: var(--tm-accent);
}

.tm-post-row-date {
  grid-column-start: 1;
  grid-row-start: 1;
  font-family: var(--font-data);
  font-size: 12px;
  color: var(--tm-muted);
  align-self: baseline;
}

.tm-post-row-title {
  grid-column-start: 2;
  grid-row-start: 1;
  font-family: var(--font-text);
  font-size: var(--text-lead);
  line-height: 1.3;
  font-weight: 500;
  color: var(--tm-fg);
}

.tm-post-row-blurb {
  grid-column-start: 2;
  grid-row-start: 2;
  font-family: var(--font-text);
  font-size: var(--text-md);
  line-height: 1.5;
  color: var(--tm-muted);
}

/* ═══════════════════════════════════════════════════════════════════════
     FOOTER — minimal site footer. Mono captions, hairline top border.
     ═══════════════════════════════════════════════════════════════════════ */

.tm-footer {
  width: 100%;
  flex-shrink: 0;
  border-top-width: 1px;
  border-color: var(--tm-border);
  padding-left: 1.5rem;
  padding-right: 1.5rem;
  padding-top: 1.5rem;
  padding-bottom: 1.5rem;
}

.tm-footer-row {
  margin-left: auto;
  margin-right: auto;
  display: flex;
  width: 100%;
  max-width: 80rem;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

.tm-footer-links {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.tm-footer-link {
  font-family: var(--font-data);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tm-muted);
  text-decoration: none;
}

.tm-footer-link:hover {
  color: var(--tm-accent);
}

.pointer-events-none {
  pointer-events: none;
}

.pointer-events-auto {
  pointer-events: auto;
}

.\!visible {
  visibility: visible !important;
}

.visible {
  visibility: visible;
}

.invisible {
  visibility: hidden;
}

.collapse {
  visibility: collapse;
}

.static {
  position: static;
}

.fixed {
  position: fixed;
}

.absolute {
  position: absolute;
}

.relative {
  position: relative;
}

.sticky {
  position: sticky;
}

.inset-0 {
  inset: 0px;
}

.inset-x-0 {
  left: 0px;
  right: 0px;
}

.bottom-0 {
  bottom: 0px;
}

.left-0 {
  left: 0px;
}

.right-0 {
  right: 0px;
}

.z-30 {
  z-index: 30;
}

.z-40 {
  z-index: 40;
}

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

.z-\[60\] {
  z-index: 60;
}

.col-span-2 {
  grid-column: span 2 / span 2;
}

.col-span-3 {
  grid-column: span 3 / span 3;
}

.col-span-4 {
  grid-column: span 4 / span 4;
}

.col-span-5 {
  grid-column: span 5 / span 5;
}

.m-auto {
  margin: auto;
}

.mx-1 {
  margin-left: 0.25rem;
  margin-right: 0.25rem;
}

.my-1 {
  margin-top: 0.25rem;
  margin-bottom: 0.25rem;
}

.mt-2 {
  margin-top: 0.5rem;
}

.block {
  display: block;
}

.inline {
  display: inline;
}

.flex {
  display: flex;
}

.inline-flex {
  display: inline-flex;
}

.table {
  display: table;
}

.grid {
  display: grid;
}

.hidden {
  display: none;
}

.aspect-square {
  aspect-ratio: 1 / 1;
}

.h-0 {
  height: 0px;
}

.h-0\.5 {
  height: 0.125rem;
}

.h-10 {
  height: 2.5rem;
}

.h-12 {
  height: 3rem;
}

.h-14 {
  height: 3.5rem;
}

.h-2 {
  height: 0.5rem;
}

.h-32 {
  height: 8rem;
}

.h-4 {
  height: 1rem;
}

.h-40 {
  height: 10rem;
}

.h-5 {
  height: 1.25rem;
}

.h-6 {
  height: 1.5rem;
}

.h-7 {
  height: 1.75rem;
}

.h-8 {
  height: 2rem;
}

.h-\[84px\] {
  height: 84px;
}

.h-full {
  height: 100%;
}

.max-h-\[80vh\] {
  max-height: 80vh;
}

.min-h-0 {
  min-height: 0px;
}

.min-h-full {
  min-height: 100%;
}

.min-h-screen {
  min-height: 100vh;
}

.w-14 {
  width: 3.5rem;
}

.w-2 {
  width: 0.5rem;
}

.w-2\/5 {
  width: 40%;
}

.w-20 {
  width: 5rem;
}

.w-4 {
  width: 1rem;
}

.w-40 {
  width: 10rem;
}

.w-5 {
  width: 1.25rem;
}

.w-6 {
  width: 1.5rem;
}

.w-7 {
  width: 1.75rem;
}

.w-8 {
  width: 2rem;
}

.w-96 {
  width: 24rem;
}

.w-\[1500px\] {
  width: 1500px;
}

.w-\[200px\] {
  width: 200px;
}

.w-\[2ch\] {
  width: 2ch;
}

.w-\[360px\] {
  width: 360px;
}

.w-\[420px\] {
  width: 420px;
}

.w-\[5ch\] {
  width: 5ch;
}

.w-\[640px\] {
  width: 640px;
}

.w-\[66px\] {
  width: 66px;
}

.w-full {
  width: 100%;
}

.w-px {
  width: 1px;
}

.min-w-0 {
  min-width: 0px;
}

.min-w-full {
  min-width: 100%;
}

.max-w-\[300px\] {
  max-width: 300px;
}

.max-w-full {
  max-width: 100%;
}

.flex-1 {
  flex: 1 1 0%;
}

.flex-\[2\] {
  flex: 2;
}

.shrink-0 {
  flex-shrink: 0;
}

.grow {
  flex-grow: 1;
}

.-translate-x-1\/2 {
  --tw-translate-x: -50%;
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.transform {
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

@keyframes pulse {
  50% {
    opacity: .5;
  }
}

.animate-pulse {
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

.cursor-default {
  cursor: default;
}

.cursor-help {
  cursor: help;
}

.cursor-not-allowed {
  cursor: not-allowed;
}

.cursor-pointer {
  cursor: pointer;
}

.select-none {
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

.resize {
  resize: both;
}

.list-disc {
  list-style-type: disc;
}

.grid-flow-col {
  grid-auto-flow: column;
}

.grid-cols-2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.grid-cols-4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.grid-cols-\[1fr_auto_1fr\] {
  grid-template-columns: 1fr auto 1fr;
}

.grid-rows-4 {
  grid-template-rows: repeat(4, minmax(0, 1fr));
}

.grid-rows-\[auto_1fr_auto\] {
  grid-template-rows: auto 1fr auto;
}

.flex-row {
  flex-direction: row;
}

.flex-row-reverse {
  flex-direction: row-reverse;
}

.flex-col {
  flex-direction: column;
}

.flex-wrap {
  flex-wrap: wrap;
}

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

.items-end {
  align-items: flex-end;
}

.items-center {
  align-items: center;
}

.items-baseline {
  align-items: baseline;
}

.items-stretch {
  align-items: stretch;
}

.justify-start {
  justify-content: flex-start;
}

.justify-end {
  justify-content: flex-end;
}

.justify-center {
  justify-content: center;
}

.justify-between {
  justify-content: space-between;
}

.gap-0 {
  gap: 0px;
}

.gap-0\.5 {
  gap: 0.125rem;
}

.gap-1 {
  gap: 0.25rem;
}

.gap-1\.5 {
  gap: 0.375rem;
}

.gap-2 {
  gap: 0.5rem;
}

.gap-3 {
  gap: 0.75rem;
}

.gap-4 {
  gap: 1rem;
}

.gap-5 {
  gap: 1.25rem;
}

.gap-8 {
  gap: 2rem;
}

.gap-px {
  gap: 1px;
}

.gap-x-2 {
  -moz-column-gap: 0.5rem;
       column-gap: 0.5rem;
}

.gap-x-4 {
  -moz-column-gap: 1rem;
       column-gap: 1rem;
}

.gap-y-1 {
  row-gap: 0.25rem;
}

.gap-y-3 {
  row-gap: 0.75rem;
}

.self-start {
  align-self: flex-start;
}

.overflow-hidden {
  overflow: hidden;
}

.overflow-visible {
  overflow: visible;
}

.overflow-x-auto {
  overflow-x: auto;
}

.overflow-y-auto {
  overflow-y: auto;
}

.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.whitespace-nowrap {
  white-space: nowrap;
}

.rounded-full {
  border-radius: 9999px;
}

.border {
  border-width: 1px;
}

.border-2 {
  border-width: 2px;
}

.border-b {
  border-bottom-width: 1px;
}

.border-l {
  border-left-width: 1px;
}

.border-r {
  border-right-width: 1px;
}

.border-t {
  border-top-width: 1px;
}

.border-dashed {
  border-style: dashed;
}

.border-tm-accent {
  border-color: var(--tm-accent);
}

.border-tm-border {
  border-color: var(--tm-border);
}

.bg-action-allin {
  background-color: var(--action-allin);
}

.bg-action-call {
  background-color: var(--action-call);
}

.bg-action-check {
  background-color: var(--action-check);
}

.bg-action-fold {
  background-color: var(--action-fold);
}

.bg-action-raise {
  background-color: var(--action-raise);
}

.bg-felt {
  background-color: var(--felt);
}

.bg-neutral-900 {
  --tw-bg-opacity: 1;
  background-color: rgb(23 23 23 / var(--tw-bg-opacity));
}

.bg-paper {
  background-color: var(--paper);
}

.bg-tm-accent {
  background-color: var(--tm-accent);
}

.bg-tm-bg {
  background-color: var(--tm-bg);
}

.bg-tm-fg {
  background-color: var(--tm-fg);
}

.bg-tm-hover {
  background-color: var(--tm-hover);
}

.bg-transparent {
  background-color: transparent;
}

.p-2 {
  padding: 0.5rem;
}

.p-3 {
  padding: 0.75rem;
}

.p-4 {
  padding: 1rem;
}

.p-6 {
  padding: 1.5rem;
}

.p-8 {
  padding: 2rem;
}

.px-1 {
  padding-left: 0.25rem;
  padding-right: 0.25rem;
}

.px-1\.5 {
  padding-left: 0.375rem;
  padding-right: 0.375rem;
}

.px-2 {
  padding-left: 0.5rem;
  padding-right: 0.5rem;
}

.px-3 {
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}

.px-4 {
  padding-left: 1rem;
  padding-right: 1rem;
}

.py-0 {
  padding-top: 0px;
  padding-bottom: 0px;
}

.py-0\.5 {
  padding-top: 0.125rem;
  padding-bottom: 0.125rem;
}

.py-1 {
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
}

.py-1\.5 {
  padding-top: 0.375rem;
  padding-bottom: 0.375rem;
}

.py-2 {
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.py-3 {
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}

.py-4 {
  padding-top: 1rem;
  padding-bottom: 1rem;
}

.pb-1 {
  padding-bottom: 0.25rem;
}

.pb-2 {
  padding-bottom: 0.5rem;
}

.pl-5 {
  padding-left: 1.25rem;
}

.pr-2 {
  padding-right: 0.5rem;
}

.pt-1 {
  padding-top: 0.25rem;
}

.pt-2 {
  padding-top: 0.5rem;
}

.pt-3 {
  padding-top: 0.75rem;
}

.pt-4 {
  padding-top: 1rem;
}

.text-left {
  text-align: left;
}

.text-center {
  text-align: center;
}

.text-right {
  text-align: right;
}

.font-mono {
  font-family: var(--font-data);
}

.font-serif {
  font-family: var(--font-text);
}

.text-2xl {
  font-size: 1.5rem;
  line-height: 2rem;
}

.text-3xl {
  font-size: 1.875rem;
  line-height: 2.25rem;
}

.text-base {
  font-size: 1rem;
  line-height: 1.5rem;
}

.text-lg {
  font-size: 1.125rem;
  line-height: 1.75rem;
}

.text-sm {
  font-size: 0.875rem;
  line-height: 1.25rem;
}

.text-xl {
  font-size: 1.25rem;
  line-height: 1.75rem;
}

.text-xs {
  font-size: 0.75rem;
  line-height: 1rem;
}

.text-xxs {
  font-size: 10px;
  line-height: 1.2;
}

.font-bold {
  font-weight: 700;
}

.font-medium {
  font-weight: 500;
}

.font-semibold {
  font-weight: 600;
}

.uppercase {
  text-transform: uppercase;
}

.tabular-nums {
  --tw-numeric-spacing: tabular-nums;
  font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction);
}

.leading-none {
  line-height: 1;
}

.leading-tight {
  line-height: 1.25;
}

.tracking-wide {
  letter-spacing: 0.025em;
}

.tracking-wider {
  letter-spacing: 0.05em;
}

.tracking-widest {
  letter-spacing: 0.1em;
}

.text-accent-gold {
  --tw-text-opacity: 1;
  color: rgb(217 119 6 / var(--tw-text-opacity));
}

.text-action-allin {
  color: var(--action-allin);
}

.text-action-call {
  color: var(--action-call);
}

.text-action-chance {
  color: var(--action-chance);
}

.text-action-check {
  color: var(--action-check);
}

.text-action-fold {
  color: var(--action-fold);
}

.text-action-raise {
  color: var(--action-raise);
}

.text-action-terminal {
  color: var(--action-terminal);
}

.text-card-red {
  --tw-text-opacity: 1;
  color: rgb(220 38 38 / var(--tw-text-opacity));
}

.text-tm-accent {
  color: var(--tm-accent);
}

.text-tm-fg {
  color: var(--tm-fg);
}

.text-tm-inverse {
  color: var(--tm-inverse);
}

.text-tm-muted {
  color: var(--tm-muted);
}

.underline {
  text-decoration-line: underline;
}

.opacity-100 {
  opacity: 1;
}

.opacity-40 {
  opacity: 0.4;
}

.opacity-50 {
  opacity: 0.5;
}

.opacity-60 {
  opacity: 0.6;
}

.opacity-80 {
  opacity: 0.8;
}

.shadow {
  --tw-shadow: 0 0 #0000;
  --tw-shadow-colored: 0 0 #0000;
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

.outline-none {
  outline: 2px solid transparent;
  outline-offset: 2px;
}

.outline {
  outline-style: solid;
}

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

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

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

.ring-tm-accent {
  --tw-ring-color: var(--tm-accent);
}

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

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

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

.transition {
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

.transition-all {
  transition-property: all;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

.duration-1000 {
  transition-duration: 1000ms;
}

.ease-linear {
  transition-timing-function: linear;
}

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

.tm-no-scrollbar::-webkit-scrollbar {
  display: none;
}

/* Workspace structure is shared by analysis and play. The lattice is
   container-sized so deck, board rail, and range cells stay aligned. */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   CSS CUSTOM PROPERTIES - Bridge between Tailwind config and Rust
   These are the SINGLE SOURCE OF TRUTH for colors used in inline styles/SVG
   ═══════════════════════════════════════════════════════════════════════════ */

.marker\:text-tm-muted *::marker {
  color: var(--tm-muted);
}

.marker\:text-tm-muted::marker {
  color: var(--tm-muted);
}

.last\:border-b-0:last-child {
  border-bottom-width: 0px;
}

.hover\:bg-tm-hover:hover {
  background-color: var(--tm-hover);
}

.hover\:text-tm-accent:hover {
  color: var(--tm-accent);
}

.hover\:text-tm-muted:hover {
  color: var(--tm-muted);
}

.active\:bg-tm-hover:active {
  background-color: var(--tm-hover);
}

.disabled\:cursor-wait:disabled {
  cursor: wait;
}

.disabled\:opacity-60:disabled {
  opacity: 0.6;
}

.\[\&\>\*\]\:max-w-full>* {
  max-width: 100%;
}

.\[\&\>\*\]\:truncate>* {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
