/* GENERATED by design-system/build.mjs — do not hand-edit. */

/* ============================================================
   AlphaBridge — Color tokens
   Extracted verbatim from the product (app/static/*.css).
   A warm-paper light UI wrapped around a felt-green card table.
   ============================================================ */

:root {
  /* ---- Surfaces & ink (the "paper" app chrome) ---- */
  --ab-page: #f5f4f0;        /* warm off-white app background           */
  --ab-panel: #fffefb;       /* card / panel surface                    */
  --ab-panel-soft: #f8f6ee;  /* inset / secondary panel                 */
  --ab-ink: #1c2622;         /* primary text (near-black green)         */
  --ab-muted: #6c7871;       /* secondary text                          */
  --ab-line: #e3e1da;        /* hairline borders / dividers             */
  --ab-code: #13211b;        /* dark code/terminal surface              */

  /* ---- Brand green (primary) ---- */
  --ab-green: #14735a;       /* primary action / brand                  */
  --ab-green-dark: #0b5443;  /* pressed / deep brand                    */
  --ab-green-soft: #e9f2ec;  /* tinted hover / selected wash            */

  /* ---- Felt (the playing table) ---- */
  --ab-felt: #0f6b55;        /* table felt base                         */
  --ab-felt-dark: #0b4a3c;   /* felt shadow / deep edge                 */
  --ab-felt-dark2: #0c5a46;  /* felt mid                                */
  --ab-felt-hi: #15875c;     /* felt highlight (radial top)             */
  --ab-accent-soft: #e3efe8; /* soft green chip background              */

  /* ---- Accents ---- */
  --ab-blue: #2e5f9e;        /* links, focus, "viewer" accent           */
  --ab-gold: #a07a22;        /* "your turn" / highlight                 */
  --ab-gold-bright: #eec05a; /* gold figure on dark "minted" chips (warm minted) */
  --ab-amber: #976a15;       /* warning text                            */
  --ab-red: #b3263a;         /* alerts / red suits / danger             */
  --ab-danger: #af2f3c;      /* destructive                             */

  /* ---- Score tones (HcpBadge `tone` figure color) ----
     Theme-independent: the chip is always a dark "minted" pill in both
     light and dark, so the numeral tone carries score meaning on its own. */
  --ab-score-pos: #25a37d;     /* @kind color */  /* MP > 50% · positive IMP */
  --ab-score-neg: #f06674;     /* @kind color */  /* MP < 50% · negative IMP */
  --ab-score-neutral: #abb7af; /* @kind color */  /* MP = 50% average · 0 IMP */

  /* ---- Card-suit palette (the four bid strains + calls) ---- */
  --ab-suit-clubs: #2f7d52;     /* ♣ green   */
  --ab-suit-diamonds: #d46c22;  /* ♦ orange  */
  --ab-suit-hearts: #c93444;    /* ♥ red     */
  --ab-suit-spades: #2b4d74;    /* ♠ navy    */
  --ab-suit-notrump: #38434f;   /* NT slate  */
  --ab-call-pass: #16835f;      /* Pass      */
  --ab-call-double: #b3263a;    /* Double    */
  --ab-call-redouble: #6e3ab2;  /* Redouble  */

  /* In-hand suit text: clubs/spades read black, hearts/diamonds red. */
  --ab-suit-black: #1c2622;
  --ab-suit-red: #b3263a;

  /* ---- Status washes ---- */
  --ab-note-bg: #fdf7e4;     /* amber note background      */
  --ab-note-text: #674806;   /* amber note text            */
  --ab-note-border: #e7d6a8; /* amber note border          */
  --ab-bad-bg: #fdeef0;      /* red note background        */
  --ab-bad-border: #e3b6bc;  /* red note border            */

  /* ============================================================
     Semantic aliases — prefer these in component CSS.
     ============================================================ */
  --ab-bg: var(--ab-page);
  --ab-surface: var(--ab-panel);
  --ab-surface-inset: var(--ab-panel-soft);
  --ab-text: var(--ab-ink);
  --ab-text-muted: var(--ab-muted);
  --ab-border: var(--ab-line);

  --ab-action: var(--ab-green);
  --ab-action-press: var(--ab-green-dark);
  --ab-action-wash: var(--ab-green-soft);

  --ab-focus-ring: var(--ab-blue);
  --ab-link: var(--ab-blue);

  /* Brand wordmark gradient (clipped to text). */
  --ab-brand-gradient: linear-gradient(95deg, var(--ab-green-dark) 10%, var(--ab-green) 55%, var(--ab-blue) 100%);

  /* Primary button gradient (top-lit green). */
  --ab-action-gradient: linear-gradient(180deg, #19836a, var(--ab-green) 55%, var(--ab-green-dark));

  /* The signature page background: four corner radial tints + a dot grid
     over warm paper. Apply to <body> with background-attachment: fixed. */
  --ab-page-backdrop:
    radial-gradient(900px 600px at 12% -6%, rgba(20, 115, 90, 0.10), transparent 60%),
    radial-gradient(820px 540px at 88% -10%, rgba(95, 140, 208, 0.09), transparent 60%),
    radial-gradient(720px 520px at 80% 80%, rgba(160, 122, 34, 0.07), transparent 65%),
    radial-gradient(640px 480px at 4% 72%, rgba(186, 105, 138, 0.05), transparent 65%),
    radial-gradient(rgba(28, 38, 34, 0.05) 1px, transparent 1px) 0 0 / 22px 22px,
    var(--ab-page);

  /* The felt table fill (radial green with a top sheen). */
  --ab-felt-fill:
    radial-gradient(120% 90% at 50% 22%, rgba(255, 255, 255, 0.10), transparent 58%),
    radial-gradient(130% 100% at 50% 30%, var(--ab-felt-hi) 0%, #0d6f44 50%, #07502c 100%);

  /* ---- Rail surface (left/right play drawers) ---- */
  --ab-rail: #fffefb;
  --ab-rail-panel: #f3f1e7;
  --ab-rail-panel-soft: #fbfaf4;
  --ab-rail-line: #e0ddd0;
  --ab-rail-text: #1c2622;
  --ab-rail-muted: #6c7871;
  --ab-rail-border: #ded9c8;
  --ab-rail-hover: #ebf1ea;
  --ab-rail-action-primary: #e3efe8;
  --ab-rail-action-accent: #0f6b55;
  --ab-rail-note-bg: #fdf7e4;
  --ab-rail-note-text: #694400;
  --ab-rail-note-border: #e7d6a8;
  --ab-rail-thought-bg: #eef2ec;
  --ab-rail-turn-bg: #fcf4df;
  --ab-rail-viewer-border: #2e5f9e;
  --ab-rail-shadow: 0 1px 2px rgba(28,40,34,0.05), 0 24px 48px -36px rgba(28,40,34,0.45);

  /* ---- Play-table surface tokens (theme-independent) ---- */
  --ab-white: #ffffff;
  --ab-cream: #f4f1e6;
  --ab-card-hi: #fffefb;
  --ab-card-face2: #f4f1e4;
  --ab-card-edge: #d9d3bf;
  --ab-card-label: #4d5a55;
  --ab-card-note: #26332f;
  --ab-card-muted: #6c7871;
  --ab-btn-hi: #17816a;
  --ab-stage-text: #694400;
  --ab-auction-vul: #d41010;
  --ab-auction-turn: #cfe9dd;
  --ab-auction-line: #9fb8b1;
  --ab-trickcard-face2: #f2efe2;
  --ab-scorebox-text: #f3ecd8;
  --ab-picture-face2: #f6f3e8;
  --ab-card-hover-border: #c4d3cc;
  --ab-card-legal-border: #b7d0eb;
  --ab-card-legal-bg: #edf6ff;
  --ab-card-legal-red-border: #edbec5;
  --ab-card-legal-red-bg: #fff0f2;
  --ab-cardback-hi: #15795f;
  --ab-cardback-mid: #0b4a3a;
  --ab-cardback-deep: #083f32;
  --ab-insight-edge: #b8c6c0;
  --ab-insight-edge-rail: #5d6661;
  --ab-insight-turn-bg: #fffaf0;
  --ab-pill-alert-bg-rail: #5a4721;
  --ab-pill-alert-text-rail: #ffe6a8;
  --ab-pill-alert-bg: #fff1d6;
  --ab-pill-alert-text: #6b4200;
  --ab-thought-bg: #f3f7f5;
  --ab-thought-text: #2c3d37;
  --ab-thought-strong: #14241f;
  --ab-auction-pass-bg: #eaf5f0;
  --ab-auction-pass-text: #11664b;
  --ab-alert-marker: #ffd24a;
  --ab-level-bg2: #efece0;
  --ab-level-border: #c9c2ab;
  --ab-level-disabled-bg: #eceadf;
  --ab-level-disabled-border: #ddd8c6;
  --ab-level-disabled-text: #9aa39d;
  --ab-stage-border: #e0cf9a;
  --ab-call-pass-border: #0d6548;
  --ab-call-double-border: #8e1f30;
  --ab-call-redouble-border: #56308a;
  --ab-suit-clubs-border: #23643f;
  --ab-suit-diamonds-border: #ad5418;
  --ab-suit-hearts-border: #a72737;
  --ab-suit-spades-border: #203a58;
  --ab-suit-notrump-border: #27313b;
  --ab-tour-grad2: #0b5b3a;
  --ab-tour-soft: #cfe2d2;
  --ab-tour-body: #e8efe6;
  --ab-wordmark-dk-mid: #bfe6d6;
  --ab-switch-track-dk: #3a443e;
  --ab-switch-track: #c7d0ca;
  --ab-mint: #8fd9c2;
  --ab-blue-bright: #8db9ff;

  /* ---- Translucent shadow / overlay tints ---- */
  --ab-black-a14: rgba(0, 0, 0, 0.14);
  --ab-black-a16: rgba(0, 0, 0, 0.16);
  --ab-black-a18: rgba(0,0,0,0.18);
  --ab-black-a22: rgba(0, 0, 0, 0.22);
  --ab-black-a28: rgba(0, 0, 0, 0.28);
  --ab-black-a30: rgba(0, 0, 0, 0.3);
  --ab-black-a35: rgba(0, 0, 0, 0.35);
  --ab-black-a40: rgba(0, 0, 0, 0.4);
  --ab-black-a45: rgba(0, 0, 0, 0.45);
  --ab-black-a50: rgba(0, 0, 0, 0.5);
  --ab-black-a55: rgba(0, 0, 0, 0.55);
  --ab-black-a6: rgba(0, 0, 0, 0.06);
  --ab-cream-a20: rgba(244, 241, 230, 0.2);
  --ab-cream-a28: rgba(244, 241, 230, 0.28);
  --ab-cream-a40: rgba(244, 241, 230, 0.4);
  --ab-cream-a45: rgba(244, 241, 230, 0.45);
  --ab-cream-a50: rgba(244, 241, 230, 0.5);
  --ab-cream-a85: rgba(244, 241, 230, 0.85);
  --ab-felt-a14: rgba(15, 107, 85, 0.14);
  --ab-felt-a16: rgba(15, 107, 85, 0.16);
  --ab-felt-a18: rgba(15, 107, 85, 0.18);
  --ab-felt-a35: rgba(15, 107, 85, 0.35);
  --ab-feltdeep-a35: rgba(8, 40, 30, 0.35);
  --ab-feltedge-a55: rgba(8, 56, 38, 0.55);
  --ab-feltedge-a60: rgba(8, 56, 38, 0.6);
  --ab-feltglow-a55: rgba(12, 90, 70, 0.55);
  --ab-goldglow-a45: rgba(240, 212, 137, 0.45);
  --ab-mint1-a88: rgba(12, 52, 38, 0.88);
  --ab-mint1-a92: rgba(12, 52, 38, 0.92);
  --ab-mint2-a94: rgba(7, 34, 24, 0.94);
  --ab-mint2-a96: rgba(7, 34, 24, 0.96);
  --ab-shadow-a10: rgba(28, 40, 34, 0.1);
  --ab-shadow-a18: rgba(28, 40, 34, 0.18);
  --ab-shadow-a24: rgba(28, 40, 34, 0.24);
  --ab-shadow-a35: rgba(28, 40, 34, 0.35);
  --ab-shadow-a4: rgba(28, 40, 34, 0.04);
  --ab-shadow-a50: rgba(28, 40, 34, 0.5);
  --ab-shadow-a55: rgba(28, 40, 34, 0.55);
  --ab-shadow-a6: rgba(28, 40, 34, 0.06);
  --ab-tourdim-a55: rgba(10, 30, 23, 0.55);
  --ab-white-a10: rgba(255, 255, 255, 0.1);
  --ab-white-a12: rgba(255, 255, 255, 0.12);
  --ab-white-a14: rgba(255, 255, 255, 0.14);
  --ab-white-a15: rgba(255,255,255,0.15);
  --ab-white-a18: rgba(255, 255, 255, 0.18);
  --ab-white-a20: rgba(255, 255, 255, 0.2);
  --ab-white-a25: rgba(255, 255, 255, 0.25);
  --ab-white-a50: rgba(255, 255, 255, 0.5);
  --ab-white-a60: rgba(255, 255, 255, 0.6);
  /* ---- Content-page chrome tints (index/assist/agreements) ---- */
  --ab-white-a22: rgba(255,255,255,0.22);
  --ab-green-a16: rgba(20,115,90,0.16);
  --ab-panel-a88: rgba(255,254,251,0.88);
  --ab-green-dark-a80: rgba(11,84,67,0.8);
  --ab-shadow-a20: rgba(28,40,34,0.2);
  --ab-green-dark-a55: rgba(11,84,67,0.55);
  --ab-green-a14: rgba(20,115,90,0.14);
  --ab-white-a16: rgba(255,255,255,0.16);
  --ab-green-a7: rgba(20,115,90,0.07);
  --ab-amber-a22: rgba(151,106,21,0.22);
  --ab-green-a12: rgba(20,115,90,0.12);
  --ab-green-a18: rgba(20,115,90,0.18);
  --ab-mist-a88: rgba(240,246,240,0.88);
  --ab-white-a28: rgba(255,255,255,0.28);
  --ab-danger-a22: rgba(175,47,60,0.22);
  --ab-blue-a18: rgba(46,95,158,0.18);
  --ab-edge-green: #c7d8cf;
  --ab-edge-warm: #cdc9b8;
  --ab-green-hi: #19836a;
  --ab-edge-green-strong: #bcd3c8;
  --ab-green-alt: #15745b;
  --ab-green-wash: #e9f4ec;
  --ab-inset-warm: #efeee6;
  --ab-muted-soft: #9aa49d;
  --ab-edge-green-soft: #c2d4ca;
  --ab-blue-wash: #ecf1f8;
  --ab-warn-bg: #fcf3dc;

}

[data-theme="dark"] {
  /* Dark-mode token layer — overrides the themed base + rail tokens.
     Flat play-surface tokens above stay constant (the felt and cards keep
     their color in dark mode; only the paper chrome and rails invert). */
  --ab-felt: #11725b;
  --ab-felt-dark: #8fd9c2;
  --ab-felt-dark2: #0b5644;
  --ab-ink: #f3f6f3;
  --ab-muted: #abb7af;
  --ab-line: #4b554f;
  --ab-panel: #1a201d;
  --ab-panel-soft: #222a26;
  --ab-panel-a88: rgba(26,32,29,0.88);  /* translucent app-bar surface (.ab-appbar) */
  --ab-page: #0d100f;
  --ab-red: #f06674;
  --ab-blue: #8db9ff;
  --ab-gold: #ecbe60;
  --ab-accent-soft: #22392f;

  /* Brand green: brighten so buttons/links pop on dark; keep gradient depth. */
  --ab-green: #1f9472;
  --ab-green-dark: #15765c;
  --ab-green-soft: #1d2c26;   /* control hover/selected wash (--ab-action-wash) */
  --ab-action-gradient: linear-gradient(180deg, #25a37d, #1f9472 55%, #15765c);

  /* Status washes — keep amber/red notes legible on dark instead of glaring. */
  --ab-note-bg: #2c2517;
  --ab-note-text: #ffe1a3;
  --ab-note-border: #5a471f;
  --ab-bad-bg: #2c1a1d;
  --ab-bad-border: #6a3940;

  /* ReasoningPanel summary text (was dark-on-dark). */
  --ab-thought-text: #d4ddd6;
  --ab-thought-strong: #f1f5f2;
  --ab-rail: #101412;
  --ab-rail-panel: #1d2320;
  --ab-rail-panel-soft: #161b18;
  --ab-rail-line: #2e3631;
  --ab-rail-text: #f2f5f2;
  --ab-rail-muted: #b4bfb8;
  --ab-rail-border: #232a26;
  --ab-rail-hover: #242b27;
  --ab-rail-action-primary: #21342c;
  --ab-rail-action-accent: #8fd9c2;
  --ab-rail-note-bg: #2c2517;
  --ab-rail-note-text: #ffe1a3;
  --ab-rail-note-border: #57441f;
  --ab-rail-thought-bg: #161c19;
  --ab-rail-turn-bg: #322c1f;
  --ab-rail-viewer-border: #79a7ff;
  --ab-rail-shadow: 0 1px 0 rgba(255,255,255,0.03), 0 14px 36px rgba(0,0,0,0.4);
}

/* ============================================================
   AlphaBridge — Typography tokens
   The product ships NO webfonts: it uses the native system-ui
   stack everywhere, with a "display" alias used for the wordmark,
   numbers, and large headings. Numbers use tabular figures.
   ============================================================ */

:root {
  /* ---- Families ---- */
  /* Body / UI: the platform system font. */
  --ab-font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  /* Display: same family family, used semantically for wordmark,
     big figures, headings (kept distinct so it can be re-themed). */
  --ab-font-display: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  /* Mono: for the dark output/console surface. */
  --ab-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* ---- Weights ---- */
  /* The brand leans heavy: UI labels sit at 750, buttons 700,
     figures/pills 800-850. Headings are 600 (display). */
  --ab-weight-regular: 500;
  --ab-weight-medium: 650;
  --ab-weight-label: 750;
  --ab-weight-strong: 800;
  --ab-weight-heavy: 850;
  --ab-weight-display: 600;

  /* ---- Type scale (px, matched to the product) ---- */
  --ab-text-hero: clamp(30px, 4vw, 50px); /* hero headline (display 600) */
  --ab-text-2xl: 26px;   /* page H1                    */
  --ab-text-xl: 22px;    /* compact H1 / rail title     */
  --ab-text-lg: 19px;    /* card title (display)        */
  --ab-text-md: 16px;    /* H2 / select value           */
  --ab-text-base: 14px;  /* body, buttons, nav          */
  --ab-text-sm: 13px;    /* secondary body, table       */
  --ab-text-xs: 12px;    /* pills, captions             */
  --ab-text-2xs: 11px;   /* uppercase labels            */
  --ab-text-3xs: 10px;   /* micro labels / units        */
  --ab-text-bigcall: 48px; /* assistant "big call" figure */

  /* ---- Line heights ---- */
  --ab-leading-tight: 1.05;
  --ab-leading-snug: 1.22;
  --ab-leading-normal: 1.45;
  --ab-leading-relaxed: 1.55;

  /* ---- Letter spacing ---- */
  --ab-tracking-display: -0.015em; /* large display headings    */
  --ab-tracking-tight: -0.01em;    /* H1                        */
  --ab-tracking-normal: 0;
  --ab-tracking-label: 0.06em;     /* uppercase UI labels       */
  --ab-tracking-eyebrow: 0.14em;   /* brand eyebrow / kicker    */

  /* Numbers (HCP, scores, seeds) always tabular. */
  --ab-numeric: tabular-nums; /* @kind font */
}

/* ============================================================
   AlphaBridge — Spacing, radii, shadows, motion
   ============================================================ */

:root {
  /* ---- Spacing scale (the product works on a 2/4px rhythm) ---- */
  --ab-space-1: 2px;
  --ab-space-2: 4px;
  --ab-space-3: 6px;
  --ab-space-4: 8px;
  --ab-space-5: 10px;
  --ab-space-6: 12px;
  --ab-space-7: 14px;
  --ab-space-8: 16px;
  --ab-space-10: 18px;
  --ab-space-12: 22px;
  --ab-space-16: 32px;

  /* ---- Radii ---- */
  --ab-radius-sm: 6px;     /* chips, small cards, thoughts        */
  --ab-radius-md: 10px;    /* buttons, inputs, status notes       */
  --ab-radius-lg: 12px;    /* rail sections, segmented controls   */
  --ab-radius-xl: 14px;    /* seat panels, popovers               */
  --ab-radius-2xl: 16px;   /* main panels / app cards             */
  --ab-radius-3xl: 20px;   /* hero surface                        */
  --ab-radius-pill: 999px; /* nav pills, toggles, badges          */

  /* ---- Borders ---- */
  --ab-border-width: 1px;
  --ab-border-accent: 4px; /* the colored left-edge on insight cards */

  /* ---- Control sizing (accessibility floors) ---- */
  --ab-control-min: 36px;  /* default button / input height       */
  --ab-control-pill: 40px; /* command-bar pills / toggles         */
  --ab-control-rail: 44px; /* rail rows (segmented / switch)       */

  /* ---- Shadows ---- */
  --ab-shadow-card: 0 1px 2px rgba(28, 40, 34, 0.05), 0 24px 48px -36px rgba(28, 40, 34, 0.45);
  --ab-shadow-lift: 0 2px 4px rgba(28, 40, 34, 0.07), 0 30px 60px -32px rgba(28, 40, 34, 0.5);
  --ab-shadow-pop: 0 24px 56px -16px rgba(0, 0, 0, 0.45); /* popovers/panels */
  --ab-shadow-felt:
    inset 0 0 0 1.5px rgba(244, 241, 230, 0.28),
    inset 0 0 90px rgba(0, 0, 0, 0.34),
    inset 0 2px 2px rgba(255, 255, 255, 0.12),
    0 24px 48px -20px rgba(8, 46, 31, 0.6);
  /* The button's inner top-highlight + drop, lit from above. */
  --ab-shadow-button: inset 0 1px 0 rgba(255, 255, 255, 0.22), 0 1px 2px rgba(28, 40, 34, 0.2);
  --ab-shadow-button-hover: inset 0 1px 0 rgba(255, 255, 255, 0.22), 0 6px 16px -6px rgba(11, 84, 67, 0.55);
  /* The "minted" dark pill (HCP badge, scorebox) with a gold figure. */
  --ab-shadow-chip: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 3px 10px rgba(0, 0, 0, 0.3);

  /* ---- Focus ring ---- */
  --ab-focus: 0 0 0 3px rgba(20, 115, 90, 0.14);

  /* ---- Motion ---- */
  --ab-ease-out: cubic-bezier(0.22, 1, 0.36, 1); /* @kind other */   /* entrances (rise-in) */
  --ab-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* @kind other */ /* pop-in / knob */
  --ab-dur-fast: 120ms; /* @kind other */
  --ab-dur-mid: 160ms; /* @kind other */
  --ab-dur-slow: 480ms; /* @kind other */
  --ab-dur-wave: 240ms; /* @kind other */ /* follow-the-mouse card hover swell */
}

/* ---- Button ---- */
.ab-btn {
    font-family: var(--ab-font-sans);
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    min-height: var(--ab-control-min);
    padding: 7px 14px;
    border-radius: var(--ab-radius-md);
    border: 1px solid var(--ab-green-dark);
    background: var(--ab-action-gradient);
    color: #fff; font-weight: var(--ab-weight-medium); font-size: var(--ab-text-base);
    cursor: pointer; white-space: nowrap;
    box-shadow: var(--ab-shadow-button);
    transition: filter var(--ab-dur-fast) ease, transform 80ms ease, box-shadow var(--ab-dur-fast) ease, background var(--ab-dur-fast) ease;
  }
  .ab-btn:hover:not(:disabled) { filter: brightness(1.07); box-shadow: var(--ab-shadow-button-hover); }
  .ab-btn:active:not(:disabled) { transform: translateY(1px); }
  .ab-btn:focus-visible { outline: 2px solid var(--ab-focus-ring); outline-offset: 2px; }
  .ab-btn:disabled { cursor: not-allowed; opacity: .48; box-shadow: none; }

  .ab-btn--secondary {
    background: var(--ab-panel); border-color: var(--ab-line); color: var(--ab-green-dark);
    box-shadow: 0 1px 2px rgba(28,40,34,.06); font-weight: var(--ab-weight-label);
  }
  .ab-btn--secondary:hover:not(:disabled) { filter: none; background: var(--ab-green-soft); border-color: #c7d8cf; box-shadow: 0 1px 2px rgba(28,40,34,.06); }

  .ab-btn--ghost {
    background: transparent; border-color: transparent; color: var(--ab-ink);
    border-radius: var(--ab-radius-pill); box-shadow: none; font-weight: var(--ab-weight-medium); padding: 8px 14px;
  }
  .ab-btn--ghost:hover:not(:disabled) { filter: none; background: var(--ab-green-soft); color: var(--ab-green-dark); box-shadow: none; }

  .ab-btn--sm { min-height: 30px; padding: 4px 10px; font-size: var(--ab-text-sm); }
  .ab-btn--lg { min-height: 44px; padding: 10px 20px; font-size: var(--ab-text-md); }
  .ab-btn--block { width: 100%; }

  /* Icon-only: a square, glyph-sized button (random-seed ↻, steppers). Compose
     with --secondary/--ghost for the surface, and always give it an aria-label
     since there is no text. */
  .ab-btn--icon { min-width: var(--ab-control-min); padding: 7px; gap: 0; font-size: 18px; line-height: 1; }
  .ab-btn--icon.ab-btn--sm { min-width: 30px; padding: 4px; font-size: 15px; }

/* ---- Pill ---- */
.ab-pill {
    display: inline-flex; align-items: center; gap: 6px;
    min-height: 24px; padding: 3px 10px;
    border-radius: var(--ab-radius-pill);
    border: 1px solid rgba(20,115,90,.16);
    background: var(--ab-green-soft); color: var(--ab-green-dark);
    font-family: var(--ab-font-sans); font-size: var(--ab-text-xs); font-weight: var(--ab-weight-label);
    white-space: nowrap;
  }
  .ab-pill--neutral { border-color: var(--ab-line); background: var(--ab-panel-soft); color: var(--ab-ink); }
  .ab-pill--warn { border-color: rgba(151,106,21,.22); background: #fcf3dc; color: var(--ab-amber); }
  .ab-pill--bad { border-color: rgba(175,47,60,.22); background: var(--ab-bad-bg); color: var(--ab-danger); }
  .ab-pill--gold { border-color: var(--ab-gold); background: var(--ab-note-bg); color: var(--ab-gold); }
  /* "Minted" dark chip with a gold figure — HCP badges, scoreboxes. */
  .ab-pill--minted {
    border: 1px solid rgba(244,241,230,.4);
    background: linear-gradient(180deg, rgba(12,52,38,.92), rgba(7,34,24,.96));
    color: var(--ab-gold-bright); box-shadow: var(--ab-shadow-chip);
    font-variant-numeric: var(--ab-numeric); font-weight: var(--ab-weight-heavy);
  }

/* ---- Panel ---- */
.ab-panel {
    background: var(--ab-panel); border: 1px solid var(--ab-line);
    border-radius: var(--ab-radius-2xl); padding: 18px; min-width: 0;
    box-shadow: var(--ab-shadow-card); color: var(--ab-ink);
    font-family: var(--ab-font-sans);
  }
  .ab-panel--soft { background: var(--ab-panel-soft); }
  /* Hover-lift is a NON-MOVING raise (border + shadow only): translating the
     hovered panel retreats its own bottom edge from under the cursor and the
     hover state oscillates — the hover-flicker loop. */
  .ab-panel--interactive { transition: box-shadow var(--ab-dur-mid) ease, border-color var(--ab-dur-mid) ease; }
  .ab-panel--interactive:hover { border-color: #bcd3c8; box-shadow: var(--ab-shadow-lift); }
  .ab-panel__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 12px; }
  .ab-panel__title { margin: 0; font-family: var(--ab-font-display); font-size: var(--ab-text-md); font-weight: var(--ab-weight-display); letter-spacing: -0.005em; }

/* ---- Toggle ---- */
.ab-toggle {
    position: relative; display: inline-flex; align-items: center; gap: 9px;
    min-height: var(--ab-control-pill); padding: 7px 12px;
    border: 1px solid var(--ab-line); border-radius: var(--ab-radius-pill);
    background: var(--ab-panel); color: var(--ab-ink);
    font-family: var(--ab-font-sans); font-size: var(--ab-text-sm); font-weight: var(--ab-weight-strong);
    cursor: pointer; white-space: nowrap; user-select: none;
  }
  .ab-toggle--block { width: 100%; justify-content: space-between; border-radius: var(--ab-radius-lg); min-height: var(--ab-control-rail); }
  .ab-toggle input { position: absolute; inset: 0; opacity: 0; cursor: pointer; margin: 0; }
  .ab-toggle:has(input:focus-visible) { outline: 2px solid var(--ab-focus-ring); outline-offset: 2px; }
  .ab-toggle:has(input:checked) { border-color: rgba(15,107,85,.35); color: var(--ab-felt-dark); }
  /* Layered toggle recipe — intensity L2, orange ON. The track is a
     grooved light pill; the knob is a two-disc (Circle B = ::after) raised button. */
  .ab-toggle__track {
    flex: none; position: relative; width: 52px; height: 26px;
    border-radius: var(--ab-radius-pill); background: #EBEBEB;
    box-shadow: 0 0 0 1.5px rgba(18,18,18,.08),
      inset 0 1.8px 4px rgba(18,18,18,.17),
      inset 0 1px 1px rgba(18,18,18,.07),
      inset 0 -1.5px 2px #fff;
  }
  .ab-toggle__state {
    position: absolute; top: 0; width: 26px; height: 100%;
    display: flex; align-items: center; justify-content: center;
    font-size: 8px; font-weight: var(--ab-weight-heavy); letter-spacing: .02em;
    line-height: 1; pointer-events: none;
  }
  .ab-toggle__state--on  { left: 2px;  color: #fff;    opacity: 0; }
  .ab-toggle__state--off { right: 2px; color: #5c665f; opacity: 1; }
  .ab-toggle__knob {
    position: absolute; top: 2px; left: 2px; width: 22px; height: 22px;
    border-radius: 50%; background: #fff;
    box-shadow: 0 1.9px 4.1px rgba(18,18,18,.16), 0 1px 1px rgba(18,18,18,.04),
      inset 0 0 0 1px rgba(18,18,18,.07), inset 0 -1px 2px rgba(18,18,18,.05),
      inset 0 1px 1px #fff;
  }
  .ab-toggle__knob::after {           /* Circle B — concentric inner disc */
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 18px; height: 18px; transform: translate(-50%,-50%);
    border-radius: 50%; background: #fff;
    box-shadow: inset 0 0 0 .9px rgba(18,18,18,.14), inset 0 1.6px 2.8px rgba(18,18,18,.09),
      inset 0 -1px 2px #fff, 0 1px 1px rgba(18,18,18,.03);
  }
  .ab-toggle input:checked ~ .ab-toggle__track { background: #FF7F1C; }
  .ab-toggle input:checked ~ .ab-toggle__track .ab-toggle__knob { transform: translateX(26px); }
  .ab-toggle input:checked ~ .ab-toggle__track .ab-toggle__state--on  { opacity: 1; }
  .ab-toggle input:checked ~ .ab-toggle__track .ab-toggle__state--off { opacity: 0; }
  [data-theme="dark"] .ab-toggle__track {     /* light rim + deeper groove on dark */
    background: #39433d;
    box-shadow: 0 0 0 1.5px rgba(255,255,255,.24),
      inset 0 1.8px 4px rgba(18,18,18,.37),
      inset 0 1px 1px rgba(18,18,18,.30),
      inset 0 -1.5px 2px rgba(255,255,255,.55);
  }
  [data-theme="dark"] .ab-toggle__knob::after { background: #f3f5f4; }
  @media (prefers-reduced-motion: no-preference) {
    .ab-toggle__track { transition: background 160ms ease; }
    .ab-toggle__knob { transition: transform 200ms var(--ab-ease-spring); }
    .ab-toggle__state { transition: opacity 140ms ease; }
  }

/* ---- Segmented ---- */
.ab-seg {
    display: flex; flex-wrap: wrap; gap: 3px; padding: 3px;
    border: 1px solid var(--ab-line); border-radius: var(--ab-radius-lg);
    background: var(--ab-panel); font-family: var(--ab-font-sans);
  }
  .ab-seg__opt {
    flex: 1 1 auto; min-width: 0; min-height: 40px; padding: 6px 11px;
    border: 1px solid transparent; border-radius: 9px;
    background: transparent; color: var(--ab-ink);
    font-size: var(--ab-text-md); font-weight: var(--ab-weight-label); white-space: nowrap;
    cursor: pointer; transition: background var(--ab-dur-fast) ease;
  }
  .ab-seg__opt:hover:not(.ab-seg__opt--on) { background: var(--ab-green-soft); }
  .ab-seg__opt:focus-visible { outline: 2px solid var(--ab-focus-ring); outline-offset: 2px; }
  .ab-seg__opt--on {
    background: var(--ab-accent-soft); border-color: rgba(15,107,85,.35); color: var(--ab-felt-dark);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.25);
  }

  /* Classic dropdown — the fallback for 3+ options (or long labels).
     A native <select> styled to the system so it stays accessible. */
  .ab-select {
    position: relative; display: inline-flex; align-items: center; font-family: var(--ab-font-sans);
  }
  .ab-select__field {
    appearance: none; -webkit-appearance: none;
    min-height: 40px; padding: 6px 34px 6px 13px;
    border: 1px solid var(--ab-line); border-radius: var(--ab-radius-lg);
    background: var(--ab-panel); color: var(--ab-ink);
    font-family: inherit; font-size: var(--ab-text-md); font-weight: var(--ab-weight-label);
    cursor: pointer; transition: border-color var(--ab-dur-fast) ease, box-shadow var(--ab-dur-fast) ease;
  }
  .ab-select__field:hover { border-color: rgba(15,107,85,.35); }
  .ab-select__field:focus-visible { outline: none; border-color: var(--ab-focus-ring); box-shadow: 0 0 0 3px rgba(46,95,158,.18); }
  /* Chevron */
  .ab-select::after {
    content: ""; position: absolute; right: 13px; top: 50%; width: 9px; height: 9px;
    transform: translateY(-65%) rotate(45deg); border-right: 2px solid var(--ab-muted); border-bottom: 2px solid var(--ab-muted);
    pointer-events: none;
  }

/* ---- StatusNote ---- */
.ab-status {
    display: flex; align-items: center;
    min-height: 40px; padding: 9px 13px;
    border: 1px solid var(--ab-note-border); border-radius: var(--ab-radius-md);
    background: var(--ab-note-bg); color: var(--ab-note-text);
    font-family: var(--ab-font-sans); font-size: var(--ab-text-base); font-weight: var(--ab-weight-medium);
    line-height: var(--ab-leading-normal);
  }
  .ab-status--error { border-color: var(--ab-bad-border); background: var(--ab-bad-bg); color: var(--ab-danger); }
  .ab-status--info { border-color: var(--ab-line); background: var(--ab-panel-soft); color: var(--ab-ink); }

/* ---- AppBar ---- */
/* The standard application top bar — IDENTICAL on every page. Brand (logo +
     wordmark) on the left, the same primary navigation pills on the right, in
     the same order, so a link never moves between pages. Only the active marker
     (.is-active / aria-current) changes. Page-specific actions live in the page
     body (a command bar / panel head), NEVER in this bar. */
  .ab-appbar {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: 10px 16px; padding: 12px 24px;
    background: var(--ab-panel-a88); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--ab-line);
    position: sticky; top: 0; z-index: 40;
  }
  .ab-appbar__brand { display: flex; align-items: center; gap: 12px; text-decoration: none; color: inherit; }
  .ab-appbar__logo {
    flex: none; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 13px;
    background:
      radial-gradient(120% 120% at 30% 20%, var(--ab-white-a22), transparent 60%),
      linear-gradient(150deg, var(--ab-green-hi), var(--ab-green-dark));
    color: var(--ab-cream); font-size: 20px; line-height: 1;
    box-shadow: inset 0 1px 0 var(--ab-white-a25), 0 8px 18px -10px var(--ab-green-dark-a80);
  }
  .ab-appbar__text { display: grid; gap: 2px; align-content: center; min-width: 0; }
  .ab-appbar__eyebrow {
    color: var(--ab-muted); font-size: var(--ab-text-xs); font-weight: var(--ab-weight-label);
    text-transform: uppercase; letter-spacing: 0.14em;
  }
  .ab-appbar__title {
    margin: 0; font-family: var(--ab-font-display); font-size: 24px; font-weight: var(--ab-weight-display);
    letter-spacing: -0.01em; line-height: 1.1;
    background: var(--ab-brand-gradient); -webkit-background-clip: text; background-clip: text; color: transparent;
  }
  .ab-appbar__nav { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
  .ab-appbar__link {
    min-height: 38px; display: inline-flex; align-items: center; justify-content: center;
    padding: 8px 14px; border: 1px solid transparent; border-radius: var(--ab-radius-pill);
    background: transparent; color: var(--ab-ink); font-weight: var(--ab-weight-strong);
    font-size: var(--ab-text-sm); text-decoration: none; cursor: pointer;
    transition: background var(--ab-dur-fast) ease, color var(--ab-dur-fast) ease, border-color var(--ab-dur-fast) ease;
  }
  .ab-appbar__link:hover { background: var(--ab-green-soft); color: var(--ab-green-dark); }
  .ab-appbar__link.is-active, .ab-appbar__link[aria-current="page"] {
    background: var(--ab-green-dark); border-color: var(--ab-green-dark); color: var(--ab-cream);
    box-shadow: inset 0 1px 0 var(--ab-white-a14);
  }
  .ab-appbar__link:focus-visible { outline: 2px solid var(--ab-focus-ring); outline-offset: 2px; }
  /* On a phone the brand + six pills wrap to several rows; pinning that over a
     scrolling list/browser eats too much of a short viewport, so the bar scrolls
     away with the page below this width (it stays sticky on desktop/tablet). */
  @media (max-width: 760px) { .ab-appbar { position: static; } }

/* ---- PlayingCard ---- */
.ab-card {
    display: inline-grid; place-items: center;
    min-width: 30px; min-height: 34px; padding: 3px 4px;
    border-radius: 7px; border: 1px solid var(--ab-line);
    background: var(--ab-panel); color: var(--ab-suit-black);
    font-family: var(--ab-font-sans); font-weight: var(--ab-weight-strong);
    font-size: 16px; font-variant-numeric: var(--ab-numeric);
    box-shadow: 0 1px 2px rgba(28,40,34,.1);
    transition: transform var(--ab-dur-fast) ease, box-shadow var(--ab-dur-fast) ease, background var(--ab-dur-fast) ease, filter var(--ab-dur-fast) ease;
  }
  .ab-card__suit { font-size: 13px; line-height: 1; }
  .ab-card--red { color: var(--ab-suit-red); }
  /* Mini playing-card "picture": corner rank index + a large centered suit pip. */
  .ab-card--picture {
    position: relative; display: block; place-items: initial;
    min-width: 46px; min-height: 64px; padding: 0;
    border-radius: 6px; background: linear-gradient(180deg, #fff 64%, #f6f3e8);
  }
  .ab-card--picture .ab-card__rank {
    position: absolute; top: 4px; left: 6px; font-size: 14px; font-weight: var(--ab-weight-heavy); line-height: 1;
  }
  .ab-card--picture .ab-card__suit {
    position: absolute; top: 52%; left: 50%; transform: translate(-50%, -50%);
    font-size: 27px; line-height: 1;
  }
  /* Interactive (legal-to-play) styling. Hover is a NON-MOVING raise (shadow +
     brightness): a hover style must never translate its own hit target, or the
     card slides out from under a cursor parked near the retreating edge and
     hover oscillates on/off — the classic hover-flicker loop. */
  .ab-card--legal { border-color: #b7d0eb; background: #edf6ff; color: var(--ab-blue); cursor: pointer; }
  .ab-card--legal.ab-card--red { border-color: #edbec5; background: #fff0f2; color: var(--ab-red); }
  .ab-card--legal:hover { filter: brightness(1.04); box-shadow: 0 6px 14px rgba(28,40,34,.24); }

  /* ---- A held hand: overlapping full cards with a hover WAVE ----
     The card under the cursor pops fully; its immediate and next-out
     neighbours ease up progressively less, and z-index brings the
     raised run to the front so nothing is clipped by the overlap. */
  .ab-card-hand { display: flex; align-items: flex-end; padding-top: 24px; }
  .ab-card-hand > .ab-card { position: relative; z-index: 1; }
  .ab-card-hand > .ab-card--picture + .ab-card--picture { margin-left: -24px; }
  @media (prefers-reduced-motion: no-preference) {
    .ab-card-hand > .ab-card { transition: transform var(--ab-dur-wave) var(--ab-ease-out), box-shadow var(--ab-dur-wave) var(--ab-ease-out); will-change: transform; }
    .ab-card-hand > .ab-card:hover { transform: translateY(-18px); z-index: 40; box-shadow: 0 16px 26px -8px rgba(28,40,34,.42); }
    .ab-card-hand > .ab-card:hover + .ab-card,
    .ab-card-hand > .ab-card:has(+ .ab-card:hover) { transform: translateY(-10px); z-index: 30; }
    .ab-card-hand > .ab-card:hover + .ab-card + .ab-card,
    .ab-card-hand > .ab-card:has(+ .ab-card + .ab-card:hover) { transform: translateY(-5px); z-index: 20; }
    .ab-card-hand > .ab-card:hover + .ab-card + .ab-card + .ab-card,
    .ab-card-hand > .ab-card:has(+ .ab-card + .ab-card + .ab-card:hover) { transform: translateY(-2px); z-index: 10; }
    /* Static hit area under the lifted card. The -18px pop vacates the card's
       own bottom strip; if that strip stops counting as "hovered" the card
       drops back onto the stationary cursor and oscillates (hover flicker).
       This pseudo-element keeps the rest-state footprint hoverable — hover
       detection stays static while only the visual moves (the group-hover
       fix without adding a wrapper). It covers only ground the card itself
       occupied at rest, so it can never shadow a neighbouring control. */
    .ab-card-hand > .ab-card:hover::after { content: ""; position: absolute; top: 100%; left: 0; right: 0; height: 18px; }
  }

/* ---- CardBack ---- */
.ab-cardback {
    flex: none; position: relative; z-index: 1; width: 32px; height: 44px; border-radius: 5px;
    border: 2px solid #f4f1e6;
    background:
      radial-gradient(120% 90% at 50% 36%, rgba(255,255,255,.18), transparent 60%),
      repeating-linear-gradient(45deg, rgba(244,241,230,.28) 0 1.5px, transparent 1.5px 5.5px),
      repeating-linear-gradient(-45deg, rgba(244,241,230,.2) 0 1.5px, transparent 1.5px 5.5px),
      linear-gradient(165deg, #15795f, #0b4a3a 70%, #083f32);
    box-shadow: 0 1px 2px rgba(28,40,34,.35), -2px 0 4px -1px rgba(8,40,30,.35);
  }
  .ab-cardback--landscape { width: 44px; height: 32px; }
  .ab-cardback-fan { display: flex; }
  .ab-cardback-fan .ab-cardback + .ab-cardback { margin-left: -20px; }
  .ab-cardback-fan--v { flex-direction: column; }
  .ab-cardback-fan--v .ab-cardback + .ab-cardback { margin-left: 0; margin-top: -20px; }
  /* Hover WAVE — only the back under the cursor pops fully; the immediate
     and next-out neighbours ease up progressively less, so moving across the
     hand reads as a smooth swell that follows the mouse. z-index lifts the
     raised run above the overlap. */
  @media (prefers-reduced-motion: no-preference) {
    .ab-cardback { transition: transform var(--ab-dur-wave) var(--ab-ease-out), box-shadow var(--ab-dur-wave) var(--ab-ease-out); will-change: transform; }

    /* Horizontal fan — pop up. */
    .ab-cardback-fan .ab-cardback:hover { transform: translateY(-14px); z-index: 40; box-shadow: 0 14px 22px rgba(8,40,30,.46), -2px 0 4px -1px rgba(8,40,30,.35); }
    .ab-cardback-fan .ab-cardback:hover + .ab-cardback,
    .ab-cardback-fan .ab-cardback:has(+ .ab-cardback:hover) { transform: translateY(-8px); z-index: 30; }
    .ab-cardback-fan .ab-cardback:hover + .ab-cardback + .ab-cardback,
    .ab-cardback-fan .ab-cardback:has(+ .ab-cardback + .ab-cardback:hover) { transform: translateY(-4px); z-index: 20; }
    .ab-cardback-fan .ab-cardback:hover + .ab-cardback + .ab-cardback + .ab-cardback,
    .ab-cardback-fan .ab-cardback:has(+ .ab-cardback + .ab-cardback + .ab-cardback:hover) { transform: translateY(-1.5px); z-index: 10; }
    /* Static hit area in the strip the pop vacates: without it the back slides
       out from under a cursor parked near the retreating edge, hover ends, it
       snaps back, and the swell flickers in place. The pseudo-element keeps the
       rest-state footprint hoverable (hover detection stays static, only the
       visual moves) and covers only ground the back itself occupied at rest. */
    .ab-cardback-fan .ab-cardback:hover::after { content: ""; position: absolute; top: 100%; left: 0; right: 0; height: 14px; }

    /* Vertical (E/W) fan — pop sideways instead (declared after, so it wins). */
    .ab-cardback-fan--v .ab-cardback:hover { transform: translateX(12px); }
    .ab-cardback-fan--v .ab-cardback:hover + .ab-cardback,
    .ab-cardback-fan--v .ab-cardback:has(+ .ab-cardback:hover) { transform: translateX(7px); }
    .ab-cardback-fan--v .ab-cardback:hover + .ab-cardback + .ab-cardback,
    .ab-cardback-fan--v .ab-cardback:has(+ .ab-cardback + .ab-cardback:hover) { transform: translateX(3px); }
    .ab-cardback-fan--v .ab-cardback:hover + .ab-cardback + .ab-cardback + .ab-cardback,
    .ab-cardback-fan--v .ab-cardback:has(+ .ab-cardback + .ab-cardback + .ab-cardback:hover) { transform: translateX(1px); }
    /* Sideways pop retreats from the LEFT edge — park the static hit strip there. */
    .ab-cardback-fan--v .ab-cardback:hover::after { top: 0; bottom: 0; height: auto; left: auto; right: 100%; width: 12px; }
  }

/* ---- BidCall ---- */
.ab-bidcall {
    min-width: 0; min-height: 38px; padding: 5px 10px;
    display: inline-grid; grid-auto-flow: column; justify-content: center; align-items: center; gap: 3px;
    border: 1px solid rgba(0,0,0,.16); border-radius: 8px;
    color: #fff; font-family: var(--ab-font-sans); font-size: 15px; font-weight: var(--ab-weight-heavy);
    text-shadow: 0 1px 1px rgba(0,0,0,.22);
    box-shadow: inset 0 -1px 0 rgba(0,0,0,.18); cursor: pointer;
    transition: filter var(--ab-dur-fast) ease, box-shadow var(--ab-dur-fast) ease, transform 80ms ease;
  }
  /* Hover NEVER recolors text or lightens the fill to where the call vanishes:
     a live bid only brightens + lifts; white text keeps its legibility shadow. */
  .ab-bidcall:hover:not(:disabled) { filter: brightness(1.08); box-shadow: inset 0 -1px 0 rgba(0,0,0,.18), 0 3px 9px -3px rgba(0,0,0,.34); }
  .ab-bidcall:active:not(:disabled) { transform: translateY(1px); filter: brightness(1.02); }
  .ab-bidcall:focus-visible { outline: 2px solid var(--ab-focus-ring); outline-offset: 2px; }
  .ab-bidcall__level { font-variant-numeric: var(--ab-numeric); }
  .ab-bidcall__strain { font-size: 16px; line-height: 1; }
  .ab-bidcall--clubs    { background: var(--ab-suit-clubs);    border-color: #23643f; }
  .ab-bidcall--diamonds { background: var(--ab-suit-diamonds); border-color: #ad5418; }
  .ab-bidcall--hearts   { background: var(--ab-suit-hearts);   border-color: #a72737; }
  .ab-bidcall--spades   { background: var(--ab-suit-spades);   border-color: #203a58; }
  .ab-bidcall--notrump  { background: var(--ab-suit-notrump);  border-color: #27313b; }
  .ab-bidcall--pass     { background: var(--ab-call-pass);     border-color: #0d6548; }
  .ab-bidcall--double   { background: var(--ab-call-double);   border-color: #8e1f30; }
  .ab-bidcall--redouble { background: var(--ab-call-redouble); border-color: #56308a; }
  .ab-bidcall--pending  { outline: 3px solid var(--ab-gold); outline-offset: 1px; }
  /* Disabled (illegal / not-yet-legal) call: muted text on green-soft, and it
     stays exactly that on hover — no brightness, no lift, never white-on-light. */
  .ab-bidcall:disabled  { background: var(--ab-green-soft); border-color: var(--ab-line); color: var(--ab-muted); text-shadow: none; box-shadow: none; opacity: 1; cursor: not-allowed; }
  .ab-bidcall:disabled:hover { filter: none; box-shadow: none; transform: none; }

/* ---- HcpBadge ---- */
.ab-hcp {
    flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 3px;
    min-height: 22px; padding: 2px 8px; border-radius: 7px;
    border: 1px solid rgba(244,241,230,.4);
    background: linear-gradient(180deg, rgba(12,52,38,.92), rgba(7,34,24,.96));
    color: var(--ab-gold-bright); font-family: var(--ab-font-sans); font-variant-numeric: var(--ab-numeric);
    box-shadow: var(--ab-shadow-chip);
  }
  .ab-hcp__value { font-size: 15px; font-weight: var(--ab-weight-heavy); line-height: 1; }
  .ab-hcp__unit { font-size: 15px; font-weight: var(--ab-weight-strong); letter-spacing: .08em; text-transform: uppercase; opacity: .82; line-height: 1; }
  /* Optional score tones — the figure (and its inherited unit) recolor to carry
     score meaning; the chip itself stays the dark "minted" pill. Theme-independent. */
  .ab-hcp--pos     { color: var(--ab-score-pos); }
  .ab-hcp--neg     { color: var(--ab-score-neg); }
  .ab-hcp--neutral { color: var(--ab-score-neutral); }

/* ---- BoardTile ---- */
.ab-boardtile {
    position: relative; flex: none; width: 66px; height: 66px; padding: 0;
    border: 2px solid rgba(28,38,34,.6); border-radius: 11px; overflow: hidden;
    background: var(--ab-card-hi); cursor: pointer; font-family: var(--ab-font-sans);
    box-shadow: 0 4px 12px -4px rgba(28,40,34,.20), inset 0 1px 0 rgba(255,255,255,.6);
    transition: box-shadow var(--ab-dur-fast) ease;
    /* Seat fills are theme-independent: the board is a card, so it keeps its
       light face in dark mode (vul seats turn red via the modifiers below). */
    --seat-n: var(--ab-card-hi); --seat-e: var(--ab-card-hi); --seat-s: var(--ab-card-hi); --seat-w: var(--ab-card-hi);
  }
  /* Hover is a shadow-only raise — a translate would retreat the tile's own
     bottom edge from under the cursor and flicker the hover state. */
  .ab-boardtile:hover { box-shadow: 0 7px 16px -5px rgba(28,40,34,.26), inset 0 1px 0 rgba(255,255,255,.6); }
  .ab-boardtile:focus-visible { outline: 2px solid var(--ab-focus-ring); outline-offset: 2px; }
  /* The four seats as a perspective frame: N up, E right, S down, W left.
     A seat's trapezoid turns red when that side is vulnerable. */
  .ab-boardtile::before {
    content: ""; position: absolute; inset: 0;
    background: conic-gradient(from -45deg,
      var(--seat-n) 0 90deg, var(--seat-e) 90deg 180deg, var(--seat-s) 180deg 270deg, var(--seat-w) 270deg 360deg);
  }
  /* Soft warm diagonals from each outer corner through the inner-square corners. */
  .ab-boardtile__x {
    position: absolute; top: 50%; left: 50%; width: 170%; height: 2px;
    background: rgba(28,38,34,.52); transform-origin: center;
  }
  .ab-boardtile__x--a { transform: translate(-50%, -50%) rotate(45deg); }
  .ab-boardtile__x--b { transform: translate(-50%, -50%) rotate(-45deg); }
  .ab-boardtile__center {
    position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    width: 50%; height: 50%; background: var(--ab-card-hi); border: 1.6px solid rgba(28,38,34,.5); border-radius: 5px;
    display: grid; place-items: center; align-content: center; gap: 1px; line-height: 1;
    box-shadow: 0 1px 3px rgba(28,40,34,.12);
    font-variant-numeric: var(--ab-numeric);
  }
  .ab-boardtile__center strong { font-size: 17px; font-weight: var(--ab-weight-heavy); color: var(--ab-card-note); }
  .ab-boardtile__center small { font-size: 9px; font-weight: var(--ab-weight-strong); color: var(--ab-card-muted); }
  .ab-boardtile--ns   { --seat-n: var(--ab-red); --seat-s: var(--ab-red); }
  .ab-boardtile--ew   { --seat-e: var(--ab-red); --seat-w: var(--ab-red); }
  .ab-boardtile--both { --seat-n: var(--ab-red); --seat-e: var(--ab-red); --seat-s: var(--ab-red); --seat-w: var(--ab-red); }
  /* Picked board in a board picker: a green border + soft ring around the card. */
  .ab-boardtile--selected { border-color: var(--ab-green); box-shadow: 0 0 0 3px var(--ab-green-a18), 0 4px 12px -4px rgba(28,40,34,.20); }
  .ab-boardtile--selected:hover { box-shadow: 0 0 0 3px var(--ab-green-a18), 0 7px 16px -5px rgba(28,40,34,.26); }

/* ---- Auction ---- */
.ab-auction {
    /* Columns floor at 0, not 54px, so the four seat columns shrink evenly to
       fit a container narrower than the component's default — instead of the
       4x54=216px track overflowing and overflow:hidden clipping the 4th seat
       column. min-width:232px keeps the natural/reference size unchanged; a
       consumer that places the grid in a tighter slot (e.g. a felt's auction
       lane) overrides min-width and the columns degrade gracefully. */
    display: inline-grid; grid-template-columns: repeat(4, minmax(0, 1fr));
    background: var(--ab-panel); border: 1px solid var(--ab-line); border-radius: var(--ab-radius-lg);
    overflow: hidden; font-family: var(--ab-font-sans); box-shadow: var(--ab-shadow-card);
    min-width: 232px;
  }
  .ab-auction__h {
    padding: 7px 4px; text-align: center; font-size: var(--ab-text-xs);
    font-weight: var(--ab-weight-label); text-transform: uppercase; letter-spacing: var(--ab-tracking-label);
    color: var(--ab-muted); background: var(--ab-panel-soft); border-bottom: 1px solid var(--ab-line);
  }
  .ab-auction__h--vul { color: var(--ab-red); }
  .ab-auction__c {
    min-height: 34px; padding: 6px 4px; display: flex; align-items: center; justify-content: center; gap: 2px;
    font-size: 15px; font-weight: var(--ab-weight-heavy); color: var(--ab-ink);
    font-variant-numeric: var(--ab-numeric); border-bottom: 1px solid var(--ab-line);
  }
  .ab-auction__c:nth-child(4n) { border-right: 0; }
  .ab-auction__row--last .ab-auction__c { border-bottom: 0; }
  .ab-auction__strain { font-size: 16px; line-height: 1; }
  .ab-auction__strain--clubs    { color: var(--ab-suit-clubs); }
  .ab-auction__strain--diamonds { color: var(--ab-suit-diamonds); }
  .ab-auction__strain--hearts   { color: var(--ab-suit-hearts); }
  .ab-auction__strain--spades   { color: var(--ab-suit-spades); }
  .ab-auction__strain--notrump  { color: var(--ab-suit-notrump); }
  .ab-auction__call--pass     { color: var(--ab-call-pass); font-weight: var(--ab-weight-strong); }
  .ab-auction__call--double   { color: var(--ab-call-double); }
  .ab-auction__call--redouble { color: var(--ab-call-redouble); }
  .ab-auction__c--pending { background: rgba(160,122,34,.12); box-shadow: inset 0 0 0 2px var(--ab-gold); border-radius: 4px; }
  .ab-auction__c--empty { color: var(--ab-line); }

/* ---- CallSequence ---- */
/* The bid-display standard for a *series of calls* shown inline — an auction
     or agreement sequence such as "P 1♥ X 1NT". This is the single contract for
     quoting bidding anywhere outside the live four-column .ab-auction grid: the
     agreement browser sequences, the assistant's recommended call, prose.

     One call (.ab-call) reads as:
       • the level digit in INK (never tinted — the level is not colored),
       • the strain as a SUIT-COLORED glyph (♣ green, ♦ orange, ♥ red, ♠ navy, NT slate),
       • a bare call (Pass / X / XX) in its call color.
     Calls in a sequence are separated by a thin .ab-callseq__sep ("·" or "–"). */
  .ab-callseq {
    display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px;
    font-family: var(--ab-font-sans); font-variant-numeric: var(--ab-numeric);
  }
  .ab-callseq__sep { color: var(--ab-muted); font-weight: var(--ab-weight-strong); user-select: none; }
  .ab-call {
    display: inline-flex; align-items: baseline; gap: 1px;
    color: var(--ab-ink); font-weight: var(--ab-weight-heavy); line-height: 1;
    white-space: nowrap;
  }
  .ab-call__level { color: var(--ab-ink); font-variant-numeric: var(--ab-numeric); }
  .ab-call__strain { font-size: 1.06em; line-height: 1; }
  .ab-call__strain--clubs    { color: var(--ab-suit-clubs); }
  .ab-call__strain--diamonds { color: var(--ab-suit-diamonds); }
  .ab-call__strain--hearts   { color: var(--ab-suit-hearts); }
  .ab-call__strain--spades   { color: var(--ab-suit-spades); }
  .ab-call__strain--notrump  { color: var(--ab-suit-notrump); }
  .ab-call--pass     { color: var(--ab-call-pass); }
  .ab-call--double   { color: var(--ab-call-double); }
  .ab-call--redouble { color: var(--ab-call-redouble); }
  /* Headline size — one call shown big (e.g. the assistant's recommendation).
     The display face + larger glyph; the level still stays in ink. */
  .ab-callseq--lg { gap: 10px; }
  .ab-call--lg { font-family: var(--ab-font-display); font-size: 44px; font-weight: var(--ab-weight-display); letter-spacing: -0.02em; }

/* ---- BiddingBox ---- */
.ab-biddingbox {
    display: inline-grid; gap: 6px; padding: 12px;
    background: var(--ab-panel); border: 1px solid var(--ab-line);
    border-radius: var(--ab-radius-xl); box-shadow: var(--ab-shadow-card);
    font-family: var(--ab-font-sans);
  }
  .ab-biddingbox__grid { display: grid; grid-template-columns: repeat(5, 44px); gap: 5px; }
  .ab-biddingbox__calls { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 5px; }
  .ab-biddingbox .ab-bidcall { width: 100%; min-height: 36px; padding: 5px 4px; }

/* ---- TrickArea ---- */
.ab-trickarea {
    position: relative; width: 236px; height: 236px; font-family: var(--ab-font-sans);
  }
  .ab-trickarea__seat { position: absolute; display: flex; align-items: center; gap: 4px; }
  .ab-trickarea__seat--n { top: 0; left: 50%; transform: translateX(-50%); flex-direction: column; }
  .ab-trickarea__seat--s { bottom: 0; left: 50%; transform: translateX(-50%); flex-direction: column-reverse; }
  .ab-trickarea__seat--w { left: 0; top: 50%; transform: translateY(-50%); flex-direction: row; }
  .ab-trickarea__seat--e { right: 0; top: 50%; transform: translateY(-50%); flex-direction: row-reverse; }
  .ab-trickarea__label {
    font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-label);
    text-transform: uppercase; letter-spacing: var(--ab-tracking-label); color: rgba(255,255,255,.62);
  }
  .ab-trickarea__empty {
    width: 46px; height: 64px; border-radius: 6px;
    border: 1.5px dashed rgba(244,241,230,.34); background: rgba(255,255,255,.04);
  }
  .ab-trickarea__seat--win .ab-card,
  .ab-trickarea__seat--win .ab-trickarea__empty { box-shadow: 0 0 0 2px var(--ab-gold), 0 8px 18px rgba(0,0,0,.4); border-radius: 6px; }
  .ab-trickarea__seat--act .ab-trickarea__label { color: var(--ab-gold); }
  .ab-trickarea__center { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); width: 7px; height: 7px; border-radius: 50%; background: rgba(244,241,230,.4); }

  /* ---- Minimal trick display: a compact, light-surface variant ----
     For inline board review (the History replay) rather than the dark felt. The
     full-size area is square (236²) so all four seats sit equidistant from the
     centre; the W/E seats are anchored to the left/right edges, so a wide-but-
     short area flings them outward. --mini keeps it near-square (140×132) so W/E
     stay as close to the centre dot as N/S. Slots are card-sized (30×40) to match
     the plain .ab-card chips this variant lays down — NOT the felt's 46×64
     picture cards — and labels/centre flip to ink-on-light tokens so they stay
     legible off the green felt. */
  .ab-trickarea--mini { width: 100%; max-width: 140px; height: 132px; }
  .ab-trickarea--mini .ab-trickarea__empty {
    width: 30px; height: 40px; min-width: 0; min-height: 0;
    border: 1px dashed var(--ab-line); background: transparent;
  }
  .ab-trickarea--mini .ab-trickarea__label { color: var(--ab-muted); }
  .ab-trickarea--mini .ab-trickarea__center { background: var(--ab-line); }

/* ---- ConfidenceBar ---- */
.ab-confidence { display: grid; gap: 5px; font-family: var(--ab-font-sans); min-width: 140px; }
  .ab-confidence__top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
  .ab-confidence__label { font-size: var(--ab-text-sm); font-weight: var(--ab-weight-label); color: var(--ab-ink); }
  .ab-confidence__value { font-size: var(--ab-text-sm); font-weight: var(--ab-weight-heavy); color: var(--ab-muted); font-variant-numeric: var(--ab-numeric); }
  .ab-confidence__track { position: relative; height: 8px; border-radius: 999px; background: var(--ab-panel-soft); box-shadow: inset 0 0 0 1px var(--ab-line); overflow: hidden; }
  .ab-confidence__fill { position: absolute; inset: 0 auto 0 0; border-radius: 999px; background: var(--ab-green); }
  .ab-confidence--sm .ab-confidence__track { height: 6px; }
  .ab-confidence--lg .ab-confidence__track { height: 11px; }
  .ab-confidence__fill--clubs    { background: var(--ab-suit-clubs); }
  .ab-confidence__fill--diamonds { background: var(--ab-suit-diamonds); }
  .ab-confidence__fill--hearts   { background: var(--ab-suit-hearts); }
  .ab-confidence__fill--spades   { background: var(--ab-suit-spades); }
  .ab-confidence__fill--notrump  { background: var(--ab-suit-notrump); }
  .ab-confidence__fill--gold     { background: var(--ab-gold); }
  .ab-confidence__fill--muted    { background: var(--ab-muted); }
  @media (prefers-reduced-motion: no-preference) {
    .ab-confidence__fill { transition: width var(--ab-dur-slow) var(--ab-ease-out); }
  }

/* ---- ReasoningPanel ---- */
.ab-reasoning {
    display: grid; gap: 14px; padding: 18px; max-width: 380px;
    background: var(--ab-panel); border: 1px solid var(--ab-line);
    border-left: var(--ab-border-accent) solid var(--ab-green);
    border-radius: var(--ab-radius-2xl); box-shadow: var(--ab-shadow-card);
    font-family: var(--ab-font-sans); color: var(--ab-ink);
  }
  .ab-reasoning__head { display: flex; align-items: center; gap: 12px; }
  .ab-reasoning__call { flex: none; }
  .ab-reasoning__headtext { display: grid; gap: 2px; }
  .ab-reasoning__eyebrow { font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-label); text-transform: uppercase; letter-spacing: var(--ab-tracking-label); color: var(--ab-muted); }
  .ab-reasoning__conf { display: flex; align-items: baseline; gap: 6px; }
  .ab-reasoning__conf b { font-family: var(--ab-font-display); font-size: 22px; font-weight: var(--ab-weight-display); font-variant-numeric: var(--ab-numeric); }
  .ab-reasoning__conf span { font-size: var(--ab-text-sm); color: var(--ab-muted); }
  .ab-reasoning__summary { margin: 0; font-size: var(--ab-text-md); line-height: var(--ab-leading-relaxed); color: var(--ab-text); }
  .ab-reasoning__section { font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-label); text-transform: uppercase; letter-spacing: var(--ab-tracking-label); color: var(--ab-muted); }
  .ab-reasoning__policy { display: grid; gap: 9px; padding-top: 2px; }
  .ab-reasoning__crow { display: grid; grid-template-columns: 34px 1fr; align-items: center; gap: 10px; }
  .ab-reasoning__chip { font-weight: var(--ab-weight-heavy); font-size: 14px; font-variant-numeric: var(--ab-numeric); color: var(--ab-ink); }
  .ab-reasoning__chip i { font-style: normal; }
  .ab-reasoning__chip--clubs    i { color: var(--ab-suit-clubs); }
  .ab-reasoning__chip--diamonds i { color: var(--ab-suit-diamonds); }
  .ab-reasoning__chip--hearts   i { color: var(--ab-suit-hearts); }
  .ab-reasoning__chip--spades   i { color: var(--ab-suit-spades); }

/* ---- TrickLog ---- */
/* BBO-style trick-by-trick replay log. Each row is one trick: the cards in
     play order (each prefixed with the seat that played it), the running NS/EW
     tally lives in the optional position header. The current trick is ribboned. */
  .ab-tricklog { display: grid; gap: 10px; font-family: var(--ab-font-sans); color: var(--ab-ink); }
  .ab-tricklog__pos {
    display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
    font-size: var(--ab-text-sm); color: var(--ab-ink); font-variant-numeric: var(--ab-numeric);
  }
  .ab-tricklog__tally { color: var(--ab-muted); font-weight: var(--ab-weight-label); }
  .ab-tricklog__tally b { color: var(--ab-ink); }
  .ab-tricklog__muted { color: var(--ab-muted); }
  .ab-tricklog__rows {
    max-height: 280px; overflow-y: auto;
    border: 1px solid var(--ab-line); border-radius: var(--ab-radius-lg); background: var(--ab-panel-soft);
  }
  .ab-tricklog__row {
    display: flex; align-items: center; gap: 8px; padding: 6px 10px;
    border-bottom: 1px solid var(--ab-line); font-size: var(--ab-text-sm); font-variant-numeric: var(--ab-numeric);
  }
  .ab-tricklog__row:last-child { border-bottom: 0; }
  .ab-tricklog__row--clickable { cursor: pointer; }
  .ab-tricklog__row--clickable:hover { background: var(--ab-green-soft); }
  .ab-tricklog__row--current { background: var(--ab-green-soft); box-shadow: inset 2px 0 0 var(--ab-green); }
  .ab-tricklog__num { width: 28px; flex: none; color: var(--ab-muted); font-weight: var(--ab-weight-label); }
  .ab-tricklog__cards { display: flex; gap: 8px; flex-wrap: wrap; flex: 1; }
  .ab-tricklog__card { display: inline-flex; align-items: center; gap: 2px; font-weight: var(--ab-weight-label); }
  .ab-tricklog__seat { color: var(--ab-muted); font-weight: var(--ab-weight-medium); font-size: var(--ab-text-2xs); margin-right: 1px; }
  .ab-tricklog__card--you .ab-card { box-shadow: 0 0 0 2px var(--ab-gold); }
  .ab-tricklog__win { flex: none; color: var(--ab-muted); }
  .ab-tricklog__win b { color: var(--ab-green-dark); }

/* ---- DoubleDummyTable ---- */
/* The double-dummy "makeable tricks" table: one row per strain, one column
     per seat, each cell the tricks that seat takes as declarer with both sides
     playing optimally. Strain row headers carry the four distinct strain colors.
     An optional par line summarizes the par contract + NS score. */
  .ab-ddtable { display: grid; gap: 10px; font-family: var(--ab-font-sans); color: var(--ab-ink); }
  .ab-ddtable__title {
    font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-label);
    text-transform: uppercase; letter-spacing: var(--ab-tracking-label); color: var(--ab-muted);
  }
  .ab-ddtable__table {
    width: 100%; border-collapse: collapse; font-variant-numeric: var(--ab-numeric);
    background: var(--ab-panel); border: 1px solid var(--ab-line);
    border-radius: var(--ab-radius-xl); overflow: hidden; box-shadow: var(--ab-shadow-card);
  }
  .ab-ddtable__table th, .ab-ddtable__table td {
    padding: 8px 12px; text-align: center; border-bottom: 1px solid var(--ab-line); font-size: var(--ab-text-sm);
  }
  .ab-ddtable__table thead th {
    background: var(--ab-panel-soft); color: var(--ab-muted);
    font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-label);
    text-transform: uppercase; letter-spacing: var(--ab-tracking-label);
  }
  .ab-ddtable__table tbody tr:last-child td { border-bottom: 0; }
  .ab-ddtable__table tbody tr:hover td { background: var(--ab-panel-soft); }
  .ab-ddtable__strain { display: inline-flex; align-items: center; gap: 5px; font-weight: var(--ab-weight-heavy); }
  .ab-ddtable__note { font-size: var(--ab-text-xs); color: var(--ab-muted); }
  .ab-ddtable__par {
    padding: 10px 12px; border-radius: var(--ab-radius-md);
    background: var(--ab-panel-soft); border: 1px solid var(--ab-line); font-size: var(--ab-text-sm);
  }
  .ab-ddtable__par-label { color: var(--ab-muted); }
  .ab-ddtable__par b { color: var(--ab-green-dark); }

/* ---- DoubleDummyHint ---- */
/* The "double-dummy from here" analysis card: how many tricks declarer makes
     from the current position, the seat-on-lead's optimal card(s) (green ring),
     the card actually played (gold ring) with a +/- verdict, and a per-card
     grid of declaring-side tricks after each legal card. */
  .ab-ddhint {
    display: grid; gap: 8px; padding: 12px 14px;
    border: 1px solid var(--ab-line); border-radius: var(--ab-radius-lg); background: var(--ab-panel-soft);
    font-family: var(--ab-font-sans); color: var(--ab-ink);
  }
  .ab-ddhint__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
  .ab-ddhint__make { font-size: var(--ab-text-sm); }
  .ab-ddhint__make b { font-size: var(--ab-text-md); color: var(--ab-green-dark); }
  .ab-ddhint__line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: var(--ab-text-sm); }
  .ab-ddhint__cards { display: flex; gap: 6px; flex-wrap: wrap; }
  .ab-ddhint__muted { color: var(--ab-muted); }
  .ab-ddhint__cards .ab-card.ab-ddhint__best { box-shadow: 0 0 0 2px var(--ab-green); }
  .ab-ddhint__cards .ab-card.ab-ddhint__played { box-shadow: 0 0 0 2px var(--ab-gold); }
  .ab-ddhint__ok { color: var(--ab-green-dark); font-weight: var(--ab-weight-strong); }
  .ab-ddhint__loss { color: var(--ab-red); font-weight: var(--ab-weight-strong); }
  .ab-ddhint__grid { display: flex; flex-wrap: wrap; gap: 6px; }
  .ab-ddhint__cell {
    display: inline-flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: var(--ab-radius-sm);
    border: 1px solid var(--ab-line); background: var(--ab-panel);
    font-size: var(--ab-text-xs); font-variant-numeric: var(--ab-numeric);
  }
  .ab-ddhint__cell b { color: var(--ab-ink); }
  .ab-ddhint__cell--best { border-color: var(--ab-green); background: var(--ab-green-soft); }
  .ab-ddhint__cell--best b { color: var(--ab-green-dark); }

/* ---- AgreementBundle ---- */
/* A bid "bundle" rendered as an always-expanded family tree: a header row
     showing the members' shared auction sequence — with the one varying
     position grouped in parentheses and pipe-separated as ( 1♣ | 1♦ | 1♥ | 1♠ )
     — above the member rows it expands into. Calls follow the bid-display
     standard (level in ink, strain in its suit color) via the Call component. */
  .ab-agbundle { display: grid; gap: 7px; font-family: var(--ab-font-sans); color: var(--ab-ink); }
  .ab-agbundle__head {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 11px 14px; background: var(--ab-panel-soft);
    border: 1px solid var(--ab-line); border-radius: var(--ab-radius-lg);
  }
  .ab-agbundle__auc {
    display: inline-flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
    font-weight: var(--ab-weight-heavy); font-size: var(--ab-text-md); color: var(--ab-ink);
  }
  .ab-agbundle__sep { color: var(--ab-muted); font-weight: var(--ab-weight-strong); }
  .ab-agbundle__alts { display: inline-flex; align-items: baseline; gap: 5px; }
  .ab-agbundle__paren, .ab-agbundle__or { color: var(--ab-muted); font-weight: var(--ab-weight-strong); }
  .ab-agbundle__label { margin-left: auto; font-size: var(--ab-text-xs); color: var(--ab-muted); }
  .ab-agbundle__group { display: grid; gap: 6px; }
  .ab-agbundle__listlabel {
    font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-label);
    text-transform: uppercase; letter-spacing: var(--ab-tracking-label); color: var(--ab-muted);
  }
  .ab-agbundle__list { display: grid; gap: 6px; }
  .ab-agbundle__member {
    display: grid; grid-template-columns: 30px auto 1fr auto; gap: 9px; align-items: center;
    padding: 8px 12px; background: var(--ab-panel);
    border: 1px solid var(--ab-line); border-radius: var(--ab-radius-md);
  }
  .ab-agbundle__member--active { background: var(--ab-green-soft); box-shadow: inset 0 0 0 1px var(--ab-green-a14); }
  .ab-agbundle__rank { font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-heavy); color: var(--ab-muted); font-variant-numeric: var(--ab-numeric); }
  .ab-agbundle__chip { display: inline-flex; align-items: baseline; font-weight: var(--ab-weight-heavy); }
  .ab-agbundle__main { min-width: 0; display: grid; gap: 3px; }
  .ab-agbundle__meaning { font-size: var(--ab-text-sm); color: var(--ab-ink); }
  .ab-agbundle__cond { font-size: var(--ab-text-xs); color: var(--ab-muted); overflow-wrap: anywhere; }
  .ab-agbundle__open { font-size: var(--ab-text-xs); color: var(--ab-green-dark); font-weight: var(--ab-weight-strong); }

/* ---- PlayShell ---- */
/* ============================================================
     Play UI shell + the Drawer standard.
     Every sidebar on the Play screen — Seat Views, Settings, the
     Assistant — is the SAME drawer: a titled panel that opens from
     a toolbar button and/or a felt edge-handle, closes on ×, Esc,
     or scrim-tap, persists per session, docks beside the felt at
     >=900px and becomes a scrim drawer below it. They differ only
     in side (left/right), mode (dock/overlay) and default state.
     ============================================================ */
  .ab-play {
    --ab-drawer-w: 320px; --ab-rail-w: 200px;
    position: relative; display: grid; grid-template-rows: auto minmax(0, 1fr);
    height: 100%; min-height: 0; background: var(--ab-panel); color: var(--ab-ink);
    font-family: var(--ab-font-sans); border-radius: var(--ab-radius-2xl);
    border: 1px solid var(--ab-line); box-shadow: var(--ab-shadow-card); overflow: hidden;
  }
  .ab-play__bar { display: flex; align-items: center; gap: 10px; padding: 9px 14px; border-bottom: 1px solid var(--ab-line); background: rgba(255,254,251,.92); backdrop-filter: blur(6px); }
  .ab-play__title { margin: 0; font-family: var(--ab-font-display); font-size: var(--ab-text-md); font-weight: var(--ab-weight-display); letter-spacing: -0.01em; }
  .ab-play__tools { margin-left: auto; display: flex; align-items: center; gap: 7px; }

  /* Main = [left drawers] · felt · [right drawers] */
  .ab-play__main { position: relative; display: flex; align-items: stretch; min-height: 0; min-width: 0; overflow: hidden; }
  .ab-play__felt { order: 0; flex: 1 1 auto; min-width: 0; position: relative; display: grid; gap: 10px; place-content: center; justify-items: center; padding: 18px; background: var(--ab-felt-fill); color: #fff; }
  .ab-play__felt .ab-play__regtag { color: rgba(255,255,255,.78); }
  .ab-play__regtag { font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-label); text-transform: uppercase; letter-spacing: var(--ab-tracking-label); color: var(--ab-muted); display: flex; align-items: center; gap: 6px; }

  /* ---- Drawer ---- */
  .ab-drawer { flex: none; align-self: stretch; background: var(--ab-panel); display: flex; flex-direction: column; overflow: hidden; z-index: 2; }
  .ab-drawer--left { order: -1; border-right: 1px solid var(--ab-line); }
  .ab-drawer--right { order: 1; border-left: 1px solid var(--ab-line); }
  .ab-drawer__inner { display: grid; gap: 11px; align-content: start; padding: 13px; overflow-y: auto; height: 100%; box-sizing: border-box; width: var(--w, var(--ab-drawer-w)); }
  .ab-drawer__head { display: flex; align-items: center; justify-content: space-between; }
  .ab-drawer__title { font-family: var(--ab-font-display); font-size: var(--ab-text-md); font-weight: var(--ab-weight-display); }
  .ab-drawer__close { width: 26px; height: 26px; border-radius: var(--ab-radius-sm); border: 1px solid var(--ab-line); background: var(--ab-panel); color: var(--ab-muted); display: grid; place-items: center; cursor: pointer; font-size: 15px; line-height: 1; }
  .ab-drawer__close:hover { background: var(--ab-panel-soft); color: var(--ab-ink); }

  /* dock: reflow the felt by animating width */
  .ab-drawer[data-ab-mode="dock"] { width: 0; }
  .ab-drawer[data-ab-mode="dock"][data-open="true"] { width: var(--w, var(--ab-drawer-w)); }

  /* overlay: slide in over a scrim at any width */
  .ab-drawer[data-ab-mode="overlay"] { position: absolute; top: 0; bottom: 0; width: var(--w, var(--ab-drawer-w)); max-width: 86vw; z-index: 50; box-shadow: var(--ab-shadow-pop); }
  .ab-drawer[data-ab-mode="overlay"].ab-drawer--left { left: 0; transform: translateX(-100%); }
  .ab-drawer[data-ab-mode="overlay"].ab-drawer--right { right: 0; transform: translateX(100%); }
  .ab-drawer[data-ab-mode="overlay"][data-open="true"] { transform: translateX(0); }
  .ab-drawer[data-ab-mode="overlay"] .ab-drawer__inner { width: 100%; }

  /* edge handle — the closed-state open affordance, on the felt */
  .ab-drawer-handle { position: absolute; top: 50%; transform: translateY(-50%); writing-mode: vertical-rl; display: inline-flex; align-items: center; gap: 6px; background: var(--ab-panel); border: 1px solid var(--ab-line); padding: 12px 5px; font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-heavy); letter-spacing: .06em; color: var(--ab-green-dark); cursor: pointer; box-shadow: var(--ab-shadow-card); z-index: 5; }
  .ab-drawer-handle--right { right: 0; border-right: 0; border-radius: 9px 0 0 9px; }
  .ab-drawer-handle--left { left: 0; border-left: 0; border-radius: 0 9px 9px 0; }
  .ab-drawer-handle:hover { background: var(--ab-accent-soft); }
  .ab-drawer-handle.is-hidden { opacity: 0; pointer-events: none; }

  /* scrim — drawn under overlay drawers (and under dock drawers on narrow) */
  .ab-drawer-scrim { position: absolute; inset: 0; background: rgba(8,40,30,.45); opacity: 0; visibility: hidden; z-index: 40; cursor: pointer; }
  .ab-play[data-overlay-open="true"] .ab-drawer-scrim { opacity: 1; visibility: visible; }

  @media (prefers-reduced-motion: no-preference) {
    .ab-drawer[data-ab-mode="dock"] { transition: width var(--ab-dur-mid, 240ms) var(--ab-ease-out, ease); }
    .ab-drawer[data-ab-mode="overlay"] { transition: transform var(--ab-dur-mid, 240ms) var(--ab-ease-out, ease); }
    .ab-drawer-handle { transition: opacity var(--ab-dur-fast) ease, background var(--ab-dur-fast) ease; }
    .ab-drawer-scrim { transition: opacity var(--ab-dur-fast) ease, visibility var(--ab-dur-fast) ease; }
  }

  /* Narrow (<900px): dock drawers also become scrim drawers */
  @media (max-width: 900px) {
    .ab-drawer[data-ab-mode="dock"] { position: absolute; top: 0; bottom: 0; width: min(86vw, 340px); z-index: 50; box-shadow: var(--ab-shadow-pop); }
    .ab-drawer[data-ab-mode="dock"].ab-drawer--left { left: 0; transform: translateX(-100%); }
    .ab-drawer[data-ab-mode="dock"].ab-drawer--right { right: 0; transform: translateX(100%); }
    .ab-drawer[data-ab-mode="dock"][data-open="true"] { transform: translateX(0); width: min(86vw, 340px); }
    .ab-drawer[data-ab-mode="dock"] .ab-drawer__inner { width: 100%; }
    .ab-play[data-dock-open="true"] .ab-drawer-scrim { opacity: 1; visibility: visible; }
    @media (prefers-reduced-motion: no-preference) { .ab-drawer[data-ab-mode="dock"] { transition: transform var(--ab-dur-mid, 240ms) var(--ab-ease-out, ease); } }
  }

  /* ---- Consumer-owned layout: bare shell + static drawer ----
     For a screen that owns its own page grid (e.g. a bespoke felt table grid)
     rather than the component's flex felt. .ab-play--bare uses .ab-play purely
     as the drawer JS hook + positioning context: it strips the card chrome so
     the shell never clips its rails or boxes the host layout (the default
     .ab-play keeps height:100% + an inner grid + overflow:hidden + border for
     the standalone card). The "static" drawer mode keeps each rail in-flow at
     every breakpoint — the host grid sizes it; no width animation, no <=900px
     off-canvas overlay. Default .ab-play / dock / overlay are unchanged. */
  .ab-play--bare {
    height: auto; min-height: 0; grid-template-rows: none;
    background: transparent; border: 0; border-radius: 0; box-shadow: none; overflow: visible;
  }
  .ab-drawer[data-ab-mode="static"] { position: static; width: auto; transform: none; z-index: auto; }

  /* Seat view (disclosed bot thought) — content of the Seat Views drawer. */
  .ab-seatview { background: var(--ab-panel); border: 1px solid var(--ab-line); border-radius: var(--ab-radius-sm); padding: 7px 8px; display: grid; gap: 3px; }
  .ab-seatview__name { font-size: var(--ab-text-xs); font-weight: var(--ab-weight-strong); color: var(--ab-ink); }
  .ab-seatview__detail { font-size: var(--ab-text-2xs); color: var(--ab-muted); line-height: 1.3; }
  .ab-seatview--turn { border-color: var(--ab-gold); box-shadow: 0 0 0 1px var(--ab-gold); }

/* ---- Stat ---- */
.ab-stat {
    display: grid; gap: 6px; padding: 16px 18px; min-width: 140px;
    background: var(--ab-panel); border: 1px solid var(--ab-line);
    border-radius: var(--ab-radius-xl); box-shadow: var(--ab-shadow-card);
    font-family: var(--ab-font-sans); color: var(--ab-ink);
  }
  .ab-stat__label { font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-label); text-transform: uppercase; letter-spacing: var(--ab-tracking-label); color: var(--ab-muted); }
  .ab-stat__valrow { display: flex; align-items: baseline; gap: 6px; }
  .ab-stat__value { font-family: var(--ab-font-display); font-size: 30px; font-weight: var(--ab-weight-display); letter-spacing: -0.02em; line-height: 1; font-variant-numeric: var(--ab-numeric); }
  .ab-stat__unit { font-size: var(--ab-text-sm); font-weight: var(--ab-weight-strong); color: var(--ab-muted); }
  .ab-stat__delta { display: inline-flex; align-items: center; gap: 4px; font-size: var(--ab-text-lg); font-weight: var(--ab-weight-heavy); font-variant-numeric: var(--ab-numeric); }
  .ab-stat__delta i { font-style: normal; font-size: 26px; line-height: 1; position: relative; top: 1px; }
  .ab-stat__delta--up   { color: var(--ab-green); }
  .ab-stat__delta--down { color: var(--ab-red); }
  .ab-stat__delta--flat { color: var(--ab-muted); }
  .ab-stat__hint { font-size: var(--ab-text-xs); color: var(--ab-muted); }
  .ab-stat--accent { border-left: var(--ab-border-accent) solid var(--ab-green); }

/* ---- Meter ---- */
.ab-meter { display: grid; gap: 6px; font-family: var(--ab-font-sans); min-width: 160px; }
  .ab-meter__top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
  .ab-meter__label { font-size: var(--ab-text-sm); font-weight: var(--ab-weight-label); color: var(--ab-ink); }
  .ab-meter__value { font-size: var(--ab-text-sm); font-weight: var(--ab-weight-heavy); color: var(--ab-muted); font-variant-numeric: var(--ab-numeric); }
  .ab-meter__track { position: relative; height: 10px; border-radius: 999px; background: var(--ab-panel-soft); box-shadow: inset 0 0 0 1px var(--ab-line); overflow: hidden; }
  .ab-meter__fill { position: absolute; inset: 0 auto 0 0; border-radius: 999px; background: linear-gradient(180deg, var(--ab-green), var(--ab-green-dark)); }
  .ab-meter__fill--gold { background: linear-gradient(180deg, #c79a3a, var(--ab-gold)); }
  .ab-meter__fill--red  { background: linear-gradient(180deg, #c4434f, var(--ab-red)); }
  .ab-meter__fill--running::after {
    content: ""; position: absolute; inset: 0;
    background: repeating-linear-gradient(45deg, rgba(255,255,255,.22) 0 8px, transparent 8px 16px);
  }
  @media (prefers-reduced-motion: no-preference) {
    .ab-meter__fill { transition: width var(--ab-dur-slow) var(--ab-ease-out); }
    .ab-meter__fill--running::after { animation: ab-meter-stripe 800ms linear infinite; }
    @keyframes ab-meter-stripe { from { background-position: 0 0; } to { background-position: 22px 0; } }
  }

/* ---- DataTable ---- */
.ab-datatable {
    width: 100%; border-collapse: collapse; font-family: var(--ab-font-sans);
    background: var(--ab-panel); border: 1px solid var(--ab-line);
    border-radius: var(--ab-radius-xl); overflow: hidden; box-shadow: var(--ab-shadow-card);
    color: var(--ab-ink); font-size: var(--ab-text-sm);
  }
  .ab-datatable thead th {
    text-align: left; padding: 10px 14px; background: var(--ab-panel-soft);
    font-size: var(--ab-text-2xs); font-weight: var(--ab-weight-label);
    text-transform: uppercase; letter-spacing: var(--ab-tracking-label); color: var(--ab-muted);
    border-bottom: 1px solid var(--ab-line);
  }
  .ab-datatable tbody td { padding: 10px 14px; border-bottom: 1px solid var(--ab-line); font-variant-numeric: var(--ab-numeric); }
  .ab-datatable tbody tr:last-child td { border-bottom: 0; }
  .ab-datatable tbody tr:hover td { background: var(--ab-panel-soft); }
  .ab-datatable__num { text-align: right; }
  .ab-datatable__center { text-align: center; }
  .ab-datatable th.ab-datatable__num, .ab-datatable th.ab-datatable__center { text-align: inherit; }
  .ab-datatable__row--hi td { background: var(--ab-accent-soft); }
  .ab-datatable__row--hi:hover td { background: var(--ab-accent-soft); }
  .ab-datatable__strong { font-weight: var(--ab-weight-heavy); }

/* ---- Sparkline ---- */
.ab-sparkline { display: inline-block; line-height: 0; font-family: var(--ab-font-sans); }
  .ab-sparkline svg { display: block; overflow: visible; }
  .ab-sparkline__line { fill: none; stroke: var(--ab-green); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
  .ab-sparkline__area { fill: var(--ab-green); opacity: .12; }
  .ab-sparkline__dot { fill: var(--ab-green); }
  .ab-sparkline--gold .ab-sparkline__line { stroke: var(--ab-gold); }
  .ab-sparkline--gold .ab-sparkline__area { fill: var(--ab-gold); }
  .ab-sparkline--gold .ab-sparkline__dot { fill: var(--ab-gold); }

.ab-app { font-family: var(--ab-font-sans); color: var(--ab-ink); background: var(--ab-page-backdrop); background-attachment: fixed; -webkit-font-smoothing: antialiased; }
.ab-card-surface { background: var(--ab-panel); border: 1px solid var(--ab-line); border-radius: var(--ab-radius-2xl); box-shadow: var(--ab-shadow-card); }
.ab-felt-surface { background: var(--ab-felt-fill); color: #fff; border: 1px solid rgba(8,56,38,.55); box-shadow: var(--ab-shadow-felt); border-radius: var(--ab-radius-3xl); }
.ab-wordmark { font-family: var(--ab-font-display); font-weight: var(--ab-weight-display); background: var(--ab-brand-gradient); -webkit-background-clip: text; background-clip: text; color: transparent; }
/* Native-control primitive. App-styled <button>/<select>/<input>/<table> opt into
   the system by carrying .ab-control (system font + border-box, no bespoke look);
   richer controls use the full .ab-btn / .ab-toggle / .ab-seg / .ab-select components. */
.ab-control { font: inherit; box-sizing: border-box; }
