/* ==========================================================================
   Tarok - table, hand and cards
   ==========================================================================
   One deck, declared as data-card-art="classic" on .tk: photographs of a real
   Industrie und Glueck deck, shipped as web/images/tarok/cards/classic/*.webp.
   The JS drops one <img> into the card and every face part below sits it out.

   The CSS-drawn faces below are the FALLBACK, not a second look: they render
   when the photographs cannot be loaded at all (a deployment whose images never
   made it up - FTP deploys here ship code only). The reader-facing switch that
   used to choose between them is gone, along with its stored preference.

   Both share the same box: only the card's ASPECT differs (a real card is
   narrower than the CSS one), so hand, trick and talon layout is common to both
   and there is one set of geometry to reason about.

   Theme: uses the platform's semantic tokens from variables.css, so the table
   follows light/dark automatically.
   ========================================================================== */

.tk {
    /* Two layers on purpose. The -base pair is the size the reader picked; --tk-card-w/h is what
       cards actually use, so a descendant can restate it as a fraction of the base and rescale
       itself AND everything inside it (pips, numerals, figures are all shares of --tk-card-w).
       That is how .tk-card--mini shrinks with one rule instead of a second set of numbers.
       It has to be done with a separate base variable rather than a scale factor: var() inside
       a custom property is substituted where the property is DECLARED, so a scale set further
       down the tree would never reach a --tk-card-w declared up here. */
    --tk-card-w-base: 4.5rem;
    --tk-card-h-base: 6.6rem;
    --tk-card-w: var(--tk-card-w-base);
    --tk-card-h: var(--tk-card-h-base);
    --tk-radius: 0.5rem;
    --tk-felt: #1f6b4a;
    --tk-felt-edge: #17543a;
    /* The turn-clock and tournament-clock bars used to just borrow --tk-felt. Split out so a
       reader-chosen felt (see the [data-felt] palette below) never dulls the bar's own
       green-to-red "time is running out" signal. */
    --tk-clock-bar: #1f6b4a;
    /* Traditional two colours: clubs and spades black, hearts and diamonds red. */
    --tk-black: #1a1a1a;
    --tk-red: #c0392b;
    --tk-tarok: #8a6d1f;
    --tk-tarok-bg: #fdf6e3;
    /* Gold for anything sitting ON the felt or on a felt panel. Both of those are dark in
       BOTH themes, so this pair must NOT follow the theme the way --tk-tarok does: the light
       theme's #8a6d1f is a dark bronze that disappears against the plate. */
    --tk-felt-gold: #d9b551;
    --tk-felt-gold-text: #f4e3ad;
    /* Card face sizes, all expressed as a share of the card width so the reader's S/M/L control
       rescales them for free - no media queries, no second set of numbers.
       Face sizes are unitless RATIOS of the card width, multiplied at the point of use. They
       cannot be pre-multiplied lengths: var() inside a custom property is substituted where the
       property is declared, so a --tk-pip-size computed here would keep the full card's width
       and refuse to shrink inside .tk-card--mini. A bare number has no var() to bake. */
    --tk-pip-ratio: 0.26;
    /* The tarok numeral is the whole face of the card, so it gets room: 0.3 of the card width
       puts XIX at ~22px at size S and ~33px at size L. It also has to be this big for the font
       to work at all - see the note by .tk-card--tarok .tk-card__corner. */
    --tk-numeral-ratio: 0.3;
}

[data-theme="dark"] .tk {
    --tk-felt: #17402f;
    --tk-felt-edge: #0f2c20;
    --tk-clock-bar: #2f7d5a;
    --tk-tarok: #d9b551;
    --tk-tarok-bg: #2a2618;
    /* Cards stay white in both themes, so the suit colours barely change; the felt and
       the gold accents are what the theme drives. */
}

/* Reader-chosen felt colour (table-color header control). One rule per swatch, covering
   BOTH the table (.tk[data-felt]) and its own picker dot (.tk-felt-opt[data-felt]) so the
   hex values live in exactly one place, the way --tk-felt already did before this palette
   existed. "classic" restates the default pair so it is a real, selectable option rather
   than the absence of one. Every pair is kept dark enough that the white card faces, white
   seat text and --tk-felt-gold accents (never touched here) still read clearly - so no pale
   felt gets added to this list. --tk-clock-bar is deliberately NOT part of this palette
   (see the note above it): the clock bars always stay the true felt-green so their own
   low-time red flip keeps working under every choice below. Must come after the
   [data-theme="dark"] .tk block above: both are specificity 0,2,0, so source order decides
   in light mode; the dark variant below is 0,3,0 and wins on its own regardless. */
.tk[data-felt="classic"],
.tk-felt-opt[data-felt="classic"] {
    --tk-felt: #1f6b4a;
    --tk-felt-edge: #17543a;
}

[data-theme="dark"] .tk[data-felt="classic"] {
    --tk-felt: #17402f;
    --tk-felt-edge: #0f2c20;
}

.tk[data-felt="ocean"],
.tk-felt-opt[data-felt="ocean"] {
    --tk-felt: #1d4f7c;
    --tk-felt-edge: #143a5c;
}

[data-theme="dark"] .tk[data-felt="ocean"] {
    --tk-felt: #163c5e;
    --tk-felt-edge: #0d2740;
}

.tk[data-felt="midnight"],
.tk-felt-opt[data-felt="midnight"] {
    --tk-felt: #2b3556;
    --tk-felt-edge: #1c2440;
}

[data-theme="dark"] .tk[data-felt="midnight"] {
    --tk-felt: #1f2740;
    --tk-felt-edge: #131931;
}

.tk[data-felt="teal"],
.tk-felt-opt[data-felt="teal"] {
    --tk-felt: #1a5f63;
    --tk-felt-edge: #12474a;
}

[data-theme="dark"] .tk[data-felt="teal"] {
    --tk-felt: #14484b;
    --tk-felt-edge: #0d3235;
}

.tk[data-felt="burgundy"],
.tk-felt-opt[data-felt="burgundy"] {
    --tk-felt: #6d2233;
    --tk-felt-edge: #501824;
}

[data-theme="dark"] .tk[data-felt="burgundy"] {
    --tk-felt: #521a27;
    --tk-felt-edge: #38111a;
}

.tk[data-felt="plum"],
.tk-felt-opt[data-felt="plum"] {
    --tk-felt: #4d2a5c;
    --tk-felt-edge: #371e43;
}

[data-theme="dark"] .tk[data-felt="plum"] {
    --tk-felt: #3a2046;
    --tk-felt-edge: #281630;
}

.tk[data-felt="walnut"],
.tk-felt-opt[data-felt="walnut"] {
    --tk-felt: #6b452a;
    --tk-felt-edge: #4e321d;
}

[data-theme="dark"] .tk[data-felt="walnut"] {
    --tk-felt: #4f3420;
    --tk-felt-edge: #372316;
}

.tk[data-felt="charcoal"],
.tk-felt-opt[data-felt="charcoal"] {
    --tk-felt: #3a3f44;
    --tk-felt-edge: #26292d;
}

[data-theme="dark"] .tk[data-felt="charcoal"] {
    --tk-felt: #2a2e32;
    --tk-felt-edge: #1a1c1f;
}

/* The picker button itself: a bare colour chip that paints from --tk-felt, so it always
   shows whichever felt is currently active with no JS beyond toggling the menu open. */
.tk-felt-pick {
    position: relative;
}

.tk-felt-pick__btn {
    padding: 0.25rem;
}

.tk-felt-pick__chip,
.tk-felt-opt__dot {
    display: block;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
    background: radial-gradient(ellipse at 35% 30%, var(--tk-felt) 0%, var(--tk-felt-edge) 100%);
    border: 1px solid rgba(0, 0, 0, 0.15);
}

.tk-felt-pick__menu {
    position: absolute;
    top: calc(100% + 0.4rem);
    left: 0;
    z-index: 20;
    display: grid;
    grid-template-columns: repeat(4, auto);
    gap: 0.5rem;
    padding: 0.6rem;
    border-radius: 0.6rem;
    background: var(--bg-surface, #fff);
    border: 1px solid var(--bs-border-color, rgba(0, 0, 0, 0.15));
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.2);
}

.tk-felt-opt {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    padding: 0;
    border-radius: 50%;
    border: 2px solid transparent;
    background: transparent;
    cursor: pointer;
}

.tk-felt-opt:hover {
    border-color: var(--bs-border-color, rgba(0, 0, 0, 0.25));
}

.tk-felt-opt.active {
    border-color: var(--tk-tarok);
}

/* Reader-chosen card size (S/M/L header control). Each just rescales the two card
   variables, so every card - hand, trick, talon - follows. S is the comfortable baseline;
   M and L step up for anyone who finds the default hard to read. */
.tk[data-card-size="s"] {
    --tk-card-w-base: 4.5rem;
    --tk-card-h-base: 6.6rem;
}

.tk[data-card-size="m"] {
    --tk-card-w-base: 5.7rem;
    --tk-card-h-base: 8.35rem;
}

.tk[data-card-size="l"] {
    --tk-card-w-base: 6.9rem;
    --tk-card-h-base: 10.15rem;
}

/* A real card is narrower than the CSS one: the scans are 960x1620, so 0.593, against the
   0.68 of the box above. The reader picked a card HEIGHT with S/M/L, so derive the width from
   it and let the photo keep its true proportions - the other way round (same width, taller
   box) would grow the hand and the trick area vertically, which is exactly what a phone has
   none of. Must come after the [data-card-size] rules: same specificity, so order decides,
   and --tk-card-h-base still resolves from whichever size class is active. */
.tk[data-card-art="classic"] {
    --tk-card-w-base: calc(var(--tk-card-h-base) * 0.593);
}

.tk-size-btn.active {
    background: var(--tk-tarok);
    border-color: var(--tk-tarok);
    color: #1a1a1a;
}

/* --------------------------------------------------------------- your name */

/* The name badge sits inline with the page title, in the page's own text color - it is no
   longer pinned over the felt, so it should not carry the felt-overlay pill look. */
.tk-name-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    border: 1px solid var(--bs-border-color, rgba(0, 0, 0, 0.15));
    border-radius: 999px;
    padding: 0.2rem 0.5rem;
    font-size: 0.8rem;
}

.tk-name-badge__text {
    font-weight: 600;
    max-width: 8rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tk-name-badge__input {
    width: 8rem;
    max-width: 40vw;
    font-size: 0.8rem;
    font-weight: 600;
    padding: 0.1rem 0.4rem;
    line-height: 1.4;
}

.tk-name-edit {
    width: 1.6rem;
    height: 1.6rem;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
}

/* --------------------------------------------------------------- the table */

.tk-table {
    background: radial-gradient(ellipse at 50% 40%, var(--tk-felt) 0%, var(--tk-felt-edge) 100%);
    border-radius: 1rem;
    padding: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 1rem;
    position: relative;
    container-type: inline-size;
}

/* The watch strip: a spectator ribbon and/or a live "N watching" count, sitting at the
   very top of the felt above the contract banner. */
.tk-watch {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.75);
}

.tk-watch--spectator {
    color: #fff;
    background: rgba(0, 0, 0, 0.28);
    border: 1px solid var(--tk-tarok);
    border-radius: 999px;
    padding: 0.3rem 0.9rem;
    align-self: center;
}

.tk-watch__eye {
    font-size: 1rem;
    line-height: 1;
}

.tk-watch__label {
    font-weight: 600;
    letter-spacing: 0.02em;
}

.tk-watch__count {
    opacity: 0.85;
}

.tk-watch--spectator .tk-watch__count::before {
    content: "·";
    margin-right: 0.5rem;
    opacity: 0.6;
}

.tk-hand--empty {
    display: none;
}

/* A seat's radelci - open information at a real table, so shown on the seat. */
.tk-seat__radelc {
    display: block;
    color: var(--tk-felt-gold);
    font-size: 0.7rem;
    letter-spacing: 0.12em;
    line-height: 1;
    margin-top: 0.15rem;
    cursor: help;
}

/* Table chat. A drawer pinned to the right edge, sliding in over the page rather than
   beside it in the flow - so opening it never reflows the felt mid-trick, and the same
   rules give a phone a near-full-width panel.

   Lives outside the game container so a game re-render never wipes a half-typed message.

   `hidden` is reserved for "there is nobody to talk to". Open/closed is the --open class,
   because display:none would kill the transition it is supposed to animate. */
.tk-chat {
    position: fixed;
    top: 0;
    right: 0;
    /* Above .floating-widgets-stack (site.css, z-index 9998), which is emitted after this
       element in the layout and would otherwise win a tie. */
    z-index: 10000;
    width: min(23rem, 92vw);
    height: 100dvh;
    background: var(--bs-body-bg, #fff);
    border-left: 1px solid rgba(128, 128, 128, 0.3);
    box-shadow: -0.5rem 0 1.5rem rgba(0, 0, 0, 0.18);
    padding: 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    transform: translateX(100%);
    visibility: hidden;
    transition: transform 0.28s ease, visibility 0.28s;
}

.tk-chat--open {
    transform: none;
    visibility: visible;
}

.tk-chat[hidden] {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    .tk-chat {
        transition: none;
    }
}

/* Title row: the heading plus a close button. The drawer covers the header button that
   opened it on a narrow screen, so it needs its own way out. */
.tk-chat__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.tk-chat__title {
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--tk-tarok);
}

.tk-chat__close {
    flex: 0 0 auto;
    border: 0;
    background: none;
    color: inherit;
    opacity: 0.6;
    font-size: 1.1rem;
    line-height: 1;
    padding: 0.2rem 0.4rem;
    cursor: pointer;
}

.tk-chat__close:hover,
.tk-chat__close:focus-visible {
    opacity: 1;
}

/* Full height inside the drawer, unlike the old below-the-table panel which was capped. */
.tk-chat__list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    font-size: 0.85rem;
    scroll-behavior: smooth;
}

/* A short conversation sits at the BOTTOM of the tall drawer, next to the input, rather
   than stranded at the top. A flexible spacer does it; justify-content: flex-end would
   make the overflowing case unscrollable at the top in several browsers. Being a pseudo
   element it stays out of childNodes, so the DOM-trimming loop never sees it. */
.tk-chat__list::before {
    content: '';
    flex: 1 1 auto;
    min-height: 0;
}

/* Header toggle: the way into the drawer, with an unread count riding on it. */
.tk-chat-toggle {
    position: relative;
}

.tk-chat-toggle__badge {
    position: absolute;
    top: -0.35rem;
    right: -0.35rem;
    min-width: 1.05rem;
    padding: 0 0.25rem;
    border-radius: 999px;
    background: var(--bs-danger, #dc3545);
    color: #fff;
    font-size: 0.65rem;
    font-weight: 700;
    line-height: 1.05rem;
    text-align: center;
}

.tk-chat-toggle__badge[hidden] {
    display: none;
}

.tk-chat__empty {
    opacity: 0.6;
    font-style: italic;
}

.tk-chat__msg {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    line-height: 1.35;
}

.tk-chat__who {
    font-weight: 600;
    white-space: nowrap;
}

.tk-chat__who::after {
    content: ":";
}

.tk-chat__msg--mine .tk-chat__who {
    color: var(--tk-tarok);
}

/* Messages that landed while the drawer was shut. The badge says how many; this says
   which. Cleared when the drawer closes again, so the mark never goes stale. */
.tk-chat__msg--new {
    background: rgba(217, 181, 81, 0.14);
    border-left: 2px solid var(--tk-tarok);
    border-radius: 0 var(--tk-radius) var(--tk-radius) 0;
    margin-left: -0.4rem;
    padding: 0.15rem 0.35rem 0.15rem 0.4rem;
}

/* The rule drawn above the first of them: "------ NEW ------". */
.tk-chat__newline {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0.2rem 0;
    color: var(--tk-tarok);
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
}

.tk-chat__newline::before,
.tk-chat__newline::after {
    content: '';
    flex: 1 1 auto;
    height: 1px;
    background: currentColor;
    opacity: 0.45;
}

/* Sits inside the name span, before its colon, so a watcher reads as "Ana (watching):". */
.tk-chat__tag {
    font-weight: 400;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.65;
    margin-left: 0.3rem;
}

.tk-chat__tag::before {
    content: "(";
}

.tk-chat__tag::after {
    content: ")";
}

.tk-chat__body {
    overflow-wrap: anywhere;
    flex: 1 1 8rem;
}

.tk-chat__form {
    display: flex;
    gap: 0.5rem;
}

.tk-chat__input {
    flex: 1 1 auto;
}

/* Send is drawn as a tarok card: white face, gold bar along the top edge, and the same
   lift-on-hover as a playable card. Mirrors .tk-card / .tk-card--tarok deliberately - the
   deck is this feature's whole visual identity, and a stock Bootstrap pill looked pasted on.
   Cards stay white in both themes (see the note by .tk-card--tarok), so does this. */
.tk-chat__send {
    flex: 0 0 auto;
    position: relative;
    padding: 0.55rem 0.9rem 0.45rem;
    border: 1px solid rgba(0, 0, 0, 0.25);
    border-radius: var(--tk-radius);
    background: #fff;
    color: #1a1a1a;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.02em;
    user-select: none;
    cursor: pointer;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.tk-chat__send::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: linear-gradient(90deg, var(--tk-tarok), #e3c273);
    border-radius: var(--tk-radius) var(--tk-radius) 0 0;
}

.tk-chat__send:hover,
.tk-chat__send:focus-visible {
    transform: translateY(-2px);
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.35);
    outline: none;
}

.tk-chat__send:active {
    transform: translateY(0);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}

@media (prefers-reduced-motion: reduce) {
    .tk-chat__send {
        transition: none;
    }

    .tk-chat__send:hover,
    .tk-chat__send:focus-visible {
        transform: none;
    }
}

.tk-chat__note {
    font-size: 0.8rem;
    opacity: 0.7;
}

/* ------------------------------------------------------------ side docks */

/* Card tracker (left) and stats & hints (right): read-only companions to the felt.
   Mobile-first: both start as the exact same slide-in drawer as #tk-chat (fixed,
   translateX, own close button), just on the opposite edges and without an audience
   gate - they are useful even in a solo game against bots, so nothing here is ever
   `hidden`. On a wide-enough screen (see .tk-dock--pinned below) JS adds a second
   class that turns the same box into a permanent, non-modal panel beside the felt. */
.tk-dock {
    position: fixed;
    top: 0;
    z-index: 10000;
    /* Narrower than chat (23rem) - these panels are read-only, no input row to fit. */
    width: min(20rem, 88vw);
    height: 100dvh;
    background: var(--bs-body-bg, #fff);
    padding: 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    overflow-y: auto;
    visibility: hidden;
    transition: transform 0.28s ease, visibility 0.28s;
}

.tk-dock--tracker {
    left: 0;
    border-right: 1px solid rgba(128, 128, 128, 0.3);
    box-shadow: 0.5rem 0 1.5rem rgba(0, 0, 0, 0.18);
    transform: translateX(-100%);
}

.tk-dock--hints {
    right: 0;
    border-left: 1px solid rgba(128, 128, 128, 0.3);
    box-shadow: -0.5rem 0 1.5rem rgba(0, 0, 0, 0.18);
    transform: translateX(100%);
}

.tk-dock--open {
    transform: none;
    visibility: visible;
}

.tk-dock[hidden] {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    .tk-dock {
        transition: none;
    }
}

.tk-dock__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.tk-dock__title {
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--tk-tarok);
}

.tk-dock__close {
    flex: 0 0 auto;
    border: 0;
    background: none;
    color: inherit;
    opacity: 0.6;
    font-size: 1.1rem;
    line-height: 1;
    padding: 0.2rem 0.4rem;
    cursor: pointer;
}

.tk-dock__close:hover,
.tk-dock__close:focus-visible {
    opacity: 1;
}

.tk-dock__empty {
    opacity: 0.6;
    font-style: italic;
    font-size: 0.85rem;
}

/* Pinned mode: on a screen wide enough that the centred .container (1320px max,
   Bootstrap's xxl cap - see header.css) leaves real margin on both sides, both docks
   sit in that margin instead of sliding over the felt. 1920px is where a 16rem dock +
   gap comfortably clears the container edge on both sides at once: half the container
   (660px) + a 1rem gap + a 16rem dock + a 1rem breathing margin from the viewport edge,
   doubled, rounds up to a full-HD-and-above breakpoint. Below it, or whenever fullscreen
   mode has removed the container's margins entirely (see body.tk-fullscreen below),
   JS never adds --pinned and the panel stays a normal drawer. */
:root {
    --tk-dock-w: 16rem;

    /* The three medals, defined once. Both shapes that wear them - the inline disc
       (.tk-medal) and the podium step on the results page - read these, so the gold on a
       tournament card is the same gold as the gold on the podium. They used to be two
       separate sets of hex values that had quietly drifted apart. */
    --tk-medal-gold: linear-gradient(180deg, #f7d55c, #e3b322);
    --tk-medal-silver: linear-gradient(180deg, #e2e6ea, #c3c9cf);
    --tk-medal-bronze: linear-gradient(180deg, #e0ac7e, #c98a55);
    /* Dark ink on every medal - all three are light metals, so the text colour does not
       change with the tone. */
    --tk-medal-ink: #3b2f00;
}

@media (min-width: 1920px) {
    .tk-dock--pinned {
        position: fixed;
        top: var(--dynamic-header-offset, calc(var(--header-height, 64px) + 1rem));
        width: var(--tk-dock-w);
        height: auto;
        max-height: calc(100vh - var(--dynamic-header-offset, calc(var(--header-height, 64px) + 1rem)) - 1rem);
        border-radius: 0.75rem;
        border: 1px solid rgba(128, 128, 128, 0.25);
        box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.12);
        transform: none;
        visibility: visible;
        transition: none;
    }

    .tk-dock--tracker.tk-dock--pinned {
        left: calc(50% - 660px - 1rem - var(--tk-dock-w));
        border-right-width: 1px;
    }

    .tk-dock--hints.tk-dock--pinned {
        right: calc(50% - 660px - 1rem - var(--tk-dock-w));
        border-left-width: 1px;
    }
}

/* Card tracker content: a stable chip grid so a card is always found in the same cell,
   whatever has been played - shape must never reshuffle mid-hand. */
/* The tracker's sections (four suit grids, the trump grid, the counts, the close button)
   stack as flex children with real breathing room between them - the panel was cramped
   when they butted straight up against each other. Scoped to the tracker so the hints
   panel keeps its own tight, dashed-separator row rhythm. */
.tk-dock--tracker .tk-dock__body {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.tk-tracker__group {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.tk-tracker__label {
    display: flex;
    align-items: center;
    font-size: 0.7rem;
    font-weight: 600;
    opacity: 0.7;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* The suit glyph / joker icon ahead of each group's name - full opacity and suit-tinted,
   so it reads at a glance even though the label text itself is muted. */
.tk-tracker__label-icon {
    margin-right: 0.35rem;
    font-size: 0.85rem;
    font-style: normal;
    opacity: 1;
}

.tk-tracker__label-icon--red {
    color: var(--tk-red);
}

.tk-tracker__label-icon--trump {
    color: var(--tk-tarok);
}

[data-theme="dark"] .tk-tracker__label-icon--red {
    color: #e8776a;
}

/* "(N left)" right after the group's name: how many are still out with the OTHER
   players. Kept in sentence case and lighter than the name so the row reads as
   "TRUMPS LEFT (13 left)" rather than one long shouted string. */
.tk-tracker__label-out {
    margin-left: 0.35rem;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    cursor: help;
}

/* The "left/total" count trailing each group's name - pushed to the far right of the
   title row, at full opacity/weight so it's readable at a glance against the muted
   uppercase label text next to it. */
.tk-tracker__label-count {
    margin-left: auto;
    padding-left: 0.5rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: none;
    opacity: 1;
}

.tk-tracker__grid {
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    gap: 0.2rem;
}

/* minmax(0, 1fr), not plain 1fr: a five-letter trump numeral (XVIII) has a min-content
   width wider than its share of the row, and plain 1fr would let that column swell and
   knock the whole grid out of alignment. minmax(0, ...) pins every column to an equal
   width and lets the numeral shrink to fit instead. */
.tk-tracker__grid--trump {
    grid-template-columns: repeat(11, minmax(0, 1fr));
}

/* Unlike .tk-card (real card art, deliberately white in both themes), these chips are a
   data readout, not a card face - they follow the site theme like the rest of the dock.
   Light mode: white squares, the same black/red the real cards use. Dark mode below pairs
   a dark square with LIGHT text - never reuse --tk-black on a dark chip, that pairing is
   what made clubs/spades invisible before this was theme-aware. */
.tk-tracker__chip {
    aspect-ratio: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    /* The box is sized by the grid column (aspect-ratio: 1), so the numeral can grow for
       legibility without nudging the chip's footprint. */
    font-size: 0.88rem;
    font-weight: 700;
    border-radius: 0.25rem;
    border: 1px solid rgba(0, 0, 0, 0.25);
    background: #fff;
    color: var(--tk-black);
}

.tk-tracker__chip--red {
    color: var(--tk-red);
}

.tk-tracker__chip--trump {
    color: var(--tk-tarok);
    border-color: var(--tk-tarok);
}

/* Trumps carry roman numerals up to five letters wide (XVIII) in an 11-across grid, so
   they can't take the big pip-numeral size - they get their own compact size and are
   kept on a single line (the minmax grid above guarantees the box width). */
.tk-tracker__grid--trump .tk-tracker__chip {
    font-size: 0.62rem;
    letter-spacing: -0.02em;
    white-space: nowrap;
    overflow: hidden;
}

[data-theme="dark"] .tk-tracker__chip {
    background: #262626;
    border-color: rgba(255, 255, 255, 0.15);
    color: #e6e6e6;
}

[data-theme="dark"] .tk-tracker__chip--red {
    color: #e8776a;
}

[data-theme="dark"] .tk-tracker__chip--trump {
    background: #262626;
    color: var(--tk-tarok);
    border-color: var(--tk-tarok);
}

.tk-tracker__chip-icon {
    font-size: 1.05rem;
    line-height: 1;
}

/* Gone, not just dimmed - the grid must keep its shape as the hand progresses (same slot,
   same suit row, forever), so a played card empties out into a hollow dashed outline with
   a bold cross over it rather than a merely greyed-out copy of itself. Suit/trump colour
   and the K/Q/V/J figure are hidden entirely (color: transparent, inherited by the icon
   too) - once a card is gone which one it was stops mattering at a glance; the tooltip
   still has the detail. Solid colours, not opacity, for the same dark-mode reason as
   .tk-card--muted: opacity fades a light mark toward invisible on a dark page. */
.tk-tracker__chip--played {
    position: relative;
    background: transparent;
    border: 1px dashed rgba(0, 0, 0, 0.3);
    color: transparent;
}

.tk-tracker__chip--played::after {
    content: '\2715';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.95rem;
    font-weight: 700;
    color: rgba(0, 0, 0, 0.4);
}

/* Restates color: transparent (not just border) - [data-theme="dark"] .tk-tracker__chip--red
   and --trump above are two-selector rules and would otherwise outrank the plain single-class
   .tk-tracker__chip--played and leave the old icon/numeral showing through in dark mode. */
[data-theme="dark"] .tk-tracker__chip--played {
    border-color: rgba(255, 255, 255, 0.3);
    color: transparent;
}

[data-theme="dark"] .tk-tracker__chip--played::after {
    color: rgba(255, 255, 255, 0.4);
}

/* The talon is shown face-up to the whole table once picked up - a card marked here is
   still live (could be played by anyone later) but no longer just "somewhere unseen".
   An inset ring rather than a new fill/border colour, so it layers over the suit/trump
   colouring instead of replacing it - the icon and its identity stay exactly as readable
   as any other unplayed card. Reuses --color-primary-500, the same token .tk-card--selected
   already uses for "flagged" cards elsewhere on this felt. */
.tk-tracker__chip--talon-seen {
    box-shadow: inset 0 0 0 2px var(--color-primary-500);
}

/* The cards still in your own hand - ringed just like the talon you took (same primary
   token, same inset ring) so your whole holding reads as one set and everything without a
   ring is, at a glance, still out with the opponents. A card that is both yours and part of
   the shown talon simply carries the one ring; the two rules paint the same colour. */
.tk-tracker__chip--mine {
    box-shadow: inset 0 0 0 2px var(--color-primary-500);
}

/* The "... left" tallies read as a curated summary panel, set apart from the card grids
   above by a hairline rule and a little inset padding rather than just sitting flush. */
.tk-tracker__counts {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    font-size: 0.82rem;
    margin: 0;
    padding-top: 0.85rem;
    border-top: 1px solid rgba(128, 128, 128, 0.22);
}

.tk-tracker__counts dt {
    opacity: 0.75;
    display: flex;
    align-items: center;
}

.tk-tracker__counts dd {
    font-weight: 700;
    display: inline;
    margin: 0 0 0 0.3rem;
    font-variant-numeric: tabular-nums;
}

.tk-tracker__counts > div {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* The suit glyph / joker / star ahead of each tally - full opacity and colour-keyed like
   the group headings, so a suit's count is instantly matchable to its grid above. */
.tk-tracker__count-icon {
    display: inline-flex;
    justify-content: center;
    width: 1.1rem;
    margin-right: 0.4rem;
    font-size: 0.9rem;
    font-style: normal;
    line-height: 1;
    opacity: 1;
}

.tk-tracker__count-icon--red {
    color: var(--tk-red);
}

.tk-tracker__count-icon--trump {
    color: var(--tk-tarok);
}

[data-theme="dark"] .tk-tracker__count-icon--red {
    color: #e8776a;
}

/* A full-width, thumb-sized way to dismiss the tracker from the bottom of the panel,
   where the reader ends up after scanning the tallies - the header × is small and easy
   to overshoot on a phone. */
.tk-tracker__close-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    width: 100%;
    margin-top: 0.25rem;
    padding: 0.65rem 1rem;
    border: 1px solid rgba(128, 128, 128, 0.3);
    border-radius: 0.5rem;
    background: rgba(128, 128, 128, 0.08);
    color: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.tk-tracker__close-btn:hover,
.tk-tracker__close-btn:focus-visible {
    background: rgba(128, 128, 128, 0.16);
    border-color: rgba(128, 128, 128, 0.45);
}

.tk-tracker__close-btn-icon {
    font-size: 1.2rem;
    line-height: 1;
    opacity: 0.8;
}

/* Stats & hints content. */
.tk-hints__stat {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: 0.85rem;
    padding: 0.2rem 0;
    border-bottom: 1px dashed rgba(128, 128, 128, 0.2);
}

.tk-hints__stat strong {
    font-variant-numeric: tabular-nums;
}

.tk-hints__note {
    font-size: 0.8rem;
    line-height: 1.4;
    padding: 0.4rem 0.5rem;
    border-left: 2px solid var(--tk-tarok);
    background: rgba(217, 181, 81, 0.1);
    border-radius: 0 0.4rem 0.4rem 0;
}

.tk-hints__note + .tk-hints__note {
    margin-top: 0.35rem;
}

/* ------------------------------------------------------- edge dock tabs */

/* The tracker and hints toggles are pulled out of the header and pinned to the screen
   edge their drawer slides in from - tracker on the left, hints on the right - vertically
   centred, so each tab reads as the door to its panel. z-index sits just under the dock's
   10000, so when a drawer opens it slides over (and hides) its own tab. `hidden` (set by
   table.js on a table with a real opponent) still wins via display:none. */
.tk-edge-toggle {
    position: fixed;
    top: 50%;
    z-index: 9998;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.4rem;
    height: 3.2rem;
    padding: 0;
    border: 1px solid rgba(128, 128, 128, 0.3);
    background: var(--bs-body-bg, #fff);
    color: var(--tk-tarok);
    font-size: 1.1rem;
    cursor: pointer;
    box-shadow: 0 0.25rem 0.9rem rgba(0, 0, 0, 0.18);
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

/* Same guard the docks use: display:flex above would otherwise beat the UA `hidden`
   attribute, so an explicit [hidden] rule keeps table.js's gating (no tools at a table
   with a real opponent) working regardless of the cascade. */
.tk-edge-toggle[hidden] {
    display: none;
}

.tk-edge-toggle--left {
    left: 0;
    /* Round only the outer (into-the-felt) corners, drop the flush edge border - it reads
       as a tab growing out of the screen edge rather than a floating button. */
    border-left: 0;
    border-radius: 0 0.7rem 0.7rem 0;
    transform: translateY(-50%);
}

.tk-edge-toggle--right {
    right: 0;
    border-right: 0;
    border-radius: 0.7rem 0 0 0.7rem;
    transform: translateY(-50%);
}

/* A small nudge out from the edge on hover/focus - the tab leans toward you. Keeps the
   vertical centring by restating translateY. */
.tk-edge-toggle--left:hover,
.tk-edge-toggle--left:focus-visible {
    background: var(--tk-tarok);
    border-color: var(--tk-tarok);
    color: #1a1a1a;
    transform: translateY(-50%) translateX(3px);
}

.tk-edge-toggle--right:hover,
.tk-edge-toggle--right:focus-visible {
    background: var(--tk-tarok);
    border-color: var(--tk-tarok);
    color: #1a1a1a;
    transform: translateY(-50%) translateX(-3px);
}

/* Drawer open: the tab is behind its own drawer on a narrow screen, but in pinned desktop
   mode (docks in the page margin) it stays visible, so give it the active gold fill. */
.tk-edge-toggle.active {
    background: var(--tk-tarok);
    border-color: var(--tk-tarok);
    color: #1a1a1a;
}

[data-theme="dark"] .tk-edge-toggle {
    background: #1f1f1f;
    border-color: rgba(255, 255, 255, 0.18);
}

@media (max-width: 576px) {
    .tk-edge-toggle {
        width: 2.1rem;
        height: 2.9rem;
        font-size: 1rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .tk-edge-toggle {
        transition: none;
    }
}

/* The platform's feedback/support floating heart (BugReport widget, bottom-left) is not
   wanted on the game surface - it crowds the tracker tab's left edge. This stylesheet only
   loads on the tarok views, so this hides it on tarok pages alone. */
#bugreport-widget {
    display: none !important;
}

/* Leaving the table gives up your seat, so it reads as neutral until you reach for it
   and turns red under the cursor - the one destructive control in the header. */
.tk-leave:hover,
.tk-leave:focus-visible {
    background-color: var(--bs-danger, #dc3545);
    border-color: var(--bs-danger, #dc3545);
    color: #fff;
}

/* ------------------------------------------------------------- fullscreen */

/* The website builder's expand mode, borrowed wholesale: a body class hides the site
   chrome and lifts the centered container's width cap so the felt gets the whole viewport.
   Body-scoped, and this stylesheet is only registered by the three tarok views, so nothing
   here can reach another page. The tarok view nests its own .container inside the layout's
   (views/layouts/main.php), hence both selectors. */
body.tk-fullscreen header,
body.tk-fullscreen footer,
body.tk-fullscreen .breadcrumb,
body.tk-fullscreen .language-switcher-floating,
body.tk-fullscreen #section-nav,
body.tk-fullscreen #mascot-container,
body.tk-fullscreen .floating-widgets-stack,
body.tk-fullscreen .my-section-nav-trigger,
body.tk-fullscreen .my-section-nav-backdrop,
body.tk-fullscreen .my-section-nav {
    /* MySectionNavWidget (the "Profile" pill) is mounted as a layout-level sibling
       of <header>, not inside it - position: fixed, so hiding header alone misses it. */
    display: none !important;
}

body.tk-fullscreen main {
    /* body.has-sticky-header pads main to clear the now-hidden header. */
    padding-top: 0 !important;
}

body.tk-fullscreen main > .container,
body.tk-fullscreen .tk.container {
    max-width: 100% !important;
}

body.tk-fullscreen .tk.container {
    /* The page's own py-4 survives main's padding-top: 0 above (it's the .tk element's
       own padding, not main's) - fullscreen has no header to clear, so trim it down to
       a little breathing room instead of the full 1.5rem. */
    padding-top: 0.5rem !important;
}

/* Fullscreen removes the container's side margins entirely, so a pinned dock would sit
   on top of the felt instead of beside it. table.js already avoids adding --pinned in
   this state; this is the CSS-side backstop in case the class briefly lags a resize. */
body.tk-fullscreen .tk-dock--pinned {
    position: fixed;
    top: 0;
    height: 100dvh;
    max-height: none;
    border-radius: 0;
    box-shadow: -0.5rem 0 1.5rem rgba(0, 0, 0, 0.18);
    transform: translateX(100%);
    visibility: hidden;
}

body.tk-fullscreen .tk-dock--tracker.tk-dock--pinned {
    left: 0;
    right: auto;
    box-shadow: 0.5rem 0 1.5rem rgba(0, 0, 0, 0.18);
    transform: translateX(-100%);
}

body.tk-fullscreen .tk-dock--pinned.tk-dock--open {
    transform: none;
    visibility: visible;
}

/* ==========================================================================
   Avatars - a round photo/initials/robot chip, reused across the felt, the
   waiting room, the score sheet, the lobby and the leaderboard. One class,
   sized down with --sm in the compact contexts (everywhere but the felt).
   margin-right + vertical-align so it drops cleanly into an inline/table
   context (a <th>/<td>, a plain name span) with no flex needed there; the
   few real flex rows that already space their children with `gap` cancel
   the margin back out (see their own rules further down this file). */
.tk-avatar {
    --tk-avatar-size: 2.25rem;
    width: var(--tk-avatar-size);
    height: var(--tk-avatar-size);
    border-radius: 50%;
    object-fit: cover;
    vertical-align: middle;
    margin-right: 0.4rem;
    flex: 0 0 auto;
    /* Always a flex container, even for a plain <img> (harmless there - nothing to align).
       Declared on the base class, not just --bot/--initials, so a more specific selector
       overriding `display` elsewhere (the felt rule below) only has to pick another flex
       value, never fall back to a non-flex one and silently break the centering below it. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.tk-avatar--sm {
    --tk-avatar-size: 1.6rem;
}

.tk-avatar--initials {
    color: #fff;
    font-weight: 600;
    font-size: calc(var(--tk-avatar-size) * 0.42);
    line-height: 1;
    user-select: none;
}

/* A fixed neutral gray rather than a translucent black: this chip sits on the dark felt
   in one context and a plain white card (leaderboard, waiting room) in another, and a
   35%-black overlay reads fine on the felt but washes out to a low-contrast pale gray on
   white - a solid tone keeps the white icon legible in both. */
.tk-avatar--bot {
    background: #6b7280;
    color: #fff;
    font-size: calc(var(--tk-avatar-size) * 0.5);
    line-height: 1;
}

/* The <i> glyph inherits a taller line-height from the page (not 1), so its own inline
   box is taller than the icon itself - flex centers that whole box, which reads as the
   glyph sitting high with extra empty room below it. Forcing line-height:1 here too (not
   just on the parent) is what actually centers the visible robot, not just its box. */
.tk-avatar--bot i {
    line-height: 1;
}

/* On the felt itself the chip sits centered above the name, not inline with it - `flex`
   (not `inline-flex`) is block-level, so a plain auto side-margin stacks it on its own
   line same as `display:block` would, but WITHOUT losing the flex centering that keeps
   the icon/initials in the middle of the circle (a bare `display:block` here previously
   beat .tk-avatar--bot/--initials's `inline-flex` on specificity alone - same class count
   as .tk-avatar's own base rule, but two classes vs one - which silently killed
   align-items/justify-content and left the icon pinned to the top of the circle). */
.tk-seat .tk-avatar {
    display: flex;
    margin: 0 auto 0.3rem;
}

/* A hint that this plate opens the block menu, without implying every seat is clickable -
   only seats carrying this class (a real, seated, non-bot opponent) get it. */
.tk-seat--blockable {
    cursor: pointer;
}

.tk-seat--blockable:hover {
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.35);
}

/* The tap-a-seat block/unblock popover. Fixed and positioned in JS against the tapped
   seat (openBlockMenu()/positionBlockMenu() in table.js) - not a modal, no backdrop, no
   modal library: this page's slim skin loads none on purpose. */
.tk-block-menu {
    position: fixed;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.65rem;
    border-radius: 0.5rem;
    background: var(--bg-primary);
    border: 1px solid var(--border-default);
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.25);
}

.tk-block-menu__name {
    font-weight: 600;
    font-size: 0.9rem;
    white-space: nowrap;
    max-width: 10rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tk-seats {
    display: flex;
    justify-content: space-around;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.tk-seat {
    color: #fff;
    text-align: center;
    padding: 0.45rem 0.85rem;
    border-radius: 0.5rem;
    background: rgba(0, 0, 0, 0.25);
    min-width: 7rem;
    font-size: 0.85rem;
    line-height: 1.3;
    transition: box-shadow 0.2s ease, background 0.2s ease;
}

.tk-seat--turn {
    background: rgba(255, 255, 255, 0.18);
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.55);
}

.tk-seat--you {
    font-weight: 600;
}

/* The seat playing the game, against everyone else at the table. */
.tk-seat--declarer {
    border: 1px solid var(--tk-felt-gold);
}

.tk-seat--declarer .tk-seat__name::before {
    content: '★ ';
    color: var(--tk-felt-gold);
}

/* The declarer's silent partner (4 players). Only ever styled once the engine has
   revealed the partnership - for opponents that is when the called king is played. */
.tk-seat--partner {
    border: 1px solid rgba(227, 194, 115, 0.6);
}

.tk-seat--partner .tk-seat__name::before {
    content: '🤝 ';
}

/* Who is sitting there is the first thing you read on a plate, and at 0.85rem it was losing
   to the score line under it. Sized up and given its own weight so the name leads and the
   tricks/points line reads as its caption. */
.tk-seat__name {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: 0.01em;
}

.tk-seat__meta {
    display: block;
    opacity: 0.8;
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}

/* What this seat called during the auction. */
.tk-seat__bid {
    display: inline-block;
    margin-top: 0.35rem;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.4;
}

/* A live bid - somebody has taken a game. */
.tk-seat__bid--bid {
    background: rgba(227, 194, 115, 0.2);
    color: var(--tk-felt-gold-text);
    border: 1px solid rgba(227, 194, 115, 0.45);
}

/* The current high bidder - the one everyone else has to beat. */
.tk-seat__bid--holder {
    background: var(--tk-felt-gold);
    color: #2a2205;
    border: 1px solid transparent;
}

/* Out of the auction. */
.tk-seat__bid--pass {
    background: rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.55);
    border: 1px solid rgba(255, 255, 255, 0.15);
}

/* Who took the game. In tarok the declarer plays alone against the rest, so this is
   the first thing you need to know when you look at the table. */
.tk-contract {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    color: #fff;
}

.tk-contract__game {
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.tk-contract__who {
    font-size: 0.8rem;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.3);
    color: var(--tk-tarok);
    border: 1px solid rgba(227, 194, 115, 0.5);
}

.tk-contract__who--you {
    background: rgba(227, 194, 115, 0.9);
    color: #2a2205;
    border-color: transparent;
    font-weight: 600;
}

/* The called king (4 players): a small label + the king's face, so everyone can see
   which king was named and watch for the partnership reveal. */
.tk-contract__king {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.tk-contract__king-label {
    font-size: 0.75rem;
    color: var(--tk-tarok);
    text-transform: lowercase;
}

.tk-contract__side {
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.85);
    font-style: italic;
}

/* --------------------------------------------- announcements + kontra chips */

/* A running read-out of what has been called and doubled, both on the felt banner and
   above the acting player's own controls. Public information, kept in view all hand. */
.tk-ann-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    align-items: center;
}

.tk-contract__ann {
    margin-left: 0.25rem;
}

.tk-ann-chip {
    font-size: 0.72rem;
    padding: 0.12rem 0.5rem;
    border-radius: 999px;
    white-space: nowrap;
    border: 1px solid transparent;
}

.tk-ann-chip--bonus {
    background: rgba(227, 194, 115, 0.9);
    color: #2a2205;
    font-weight: 600;
}

.tk-ann-chip--kontra {
    background: rgba(192, 57, 43, 0.85);
    color: #fff;
    text-transform: lowercase;
}

/* Declare step: the bonus toggles, select-then-confirm like the discard picker. */
.tk-ann-options {
    justify-content: center;
}

.tk-ann-opt--on {
    background: var(--tk-tarok);
    border-color: var(--tk-tarok);
    color: #2a2205;
    font-weight: 600;
}

/* Declare step: raising to colour valat is a different contract, not a bonus - a divider
   keeps it from reading as one more toggle in the row above. */
.tk-ann-raise {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.4rem;
    padding-top: 0.75rem;
    border-top: 1px dashed rgba(255, 255, 255, 0.18);
}

.tk-ann-raise__hint {
    font-size: 0.78rem;
    opacity: 0.75;
    text-align: center;
    max-width: 32rem;
}

/* The trick: a single centred row, cards in the order they were played. */
.tk-trick {
    display: flex;
    justify-content: center;
    align-items: flex-end;
    gap: 0.6rem;
    min-height: calc(var(--tk-card-h) + 1.5rem);
    flex-wrap: wrap;
}

.tk-trick--past .tk-card {
    opacity: 0.85;
}

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

.tk-trick__seat {
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.72rem;
    margin-bottom: 0.25rem;
    white-space: nowrap;
}

.tk-trick__empty {
    color: rgba(255, 255, 255, 0.55);
    font-size: 0.9rem;
    padding: 1rem;
}

/* ------------------------------------------------------- the klop vitamin (RULES.md 15.1)

   The talon card riding on each of the first six klop tricks. It is set apart from the
   played cards by a hairline divider and its own label so nobody mistakes it for someone's
   play, sits face down while the trick is live, and turns over as the trick is collected. */

.tk-trick__slot--vitamin {
    margin-left: 0.5rem;
    padding-left: 0.9rem;
    border-left: 1px dashed rgba(255, 255, 255, 0.3);
}

.tk-trick__slot--vitamin .tk-trick__seat {
    color: rgba(255, 255, 255, 0.6);
    font-style: italic;
}

/* The face-down back itself lives with the other .tk-card modifiers further down - it has
   to come AFTER the .tk-card base rule or that rule's white background wins on equal
   specificity and paints straight over it. */

/* --------------------------------------------------------------- the cards */

.tk-card {
    width: var(--tk-card-w);
    height: var(--tk-card-h);
    border-radius: var(--tk-radius);
    background: #fff;
    border: 1px solid rgba(0, 0, 0, 0.25);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
    display: inline-flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: center;
    padding: 0.3rem 0.25rem;
    font-weight: 600;
    line-height: 1;
    user-select: none;
    position: relative;
    flex: 0 0 auto;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

/* ----- the classic deck: one photograph, edge to edge -----
   The photo carries its own corner indices, pips and figures, so in art mode the card has a
   single child and none of the face parts below render at all. */

/* The scan is the whole card, so the white padding that frames a CSS face would read as a
   mount around a photograph. The second selector is not redundant: .tk-card--mini sets its own
   padding further down the file and would otherwise win on equal specificity, leaving the
   talon strip and the history rows framed while every full-size card was flush. */
.tk-card--art,
.tk-card--art.tk-card--mini {
    padding: 0;
}

.tk-card__art {
    display: block;
    width: 100%;
    height: 100%;
    /* Box and image are both 0.593 by construction, so this only absorbs sub-pixel rounding. */
    object-fit: cover;
    /* Rounds the IMAGE, which is also what hides the grey scan background left in the scans'
       own corner arcs. Deliberately not overflow: hidden on .tk-card - that clips the
       --selected tick badge, which overhangs the corner on purpose. inherit also picks up the
       smaller radius .tk-card--mini sets. */
    border-radius: inherit;
}

/* The gold bar reads as "this is a tarok" above a CSS face. Over a photograph it is a smudge,
   and the numeral it was flagging is printed on the card anyway. */
.tk-card--art.tk-card--tarok::before {
    display: none;
}

.tk-card__corner {
    align-self: flex-start;
    font-size: 0.8rem;
    /* The fan shows only the left strip of a card, so the corner must never wrap or
       spill - it is the only part of an overlapped card you can actually read. */
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
}

.tk-card__corner--bottom {
    align-self: flex-end;
    transform: rotate(180deg);
}

.tk-card__pip {
    font-size: 1.6rem;
}

/* An empty middle. A tarok carries its numeral only in the corners, so this is the spacer that
   keeps them pinned top and bottom - and the slot future tarok artwork drops into. */
.tk-card__mid {
    flex: 1 1 auto;
    align-self: stretch;
}

/* The pip field - the middle of a number card. It is the flex box's stretchy middle child,
   so it fills exactly the space between the two corner indices and a pip can never land
   under one. Positions come from PIP_LAYOUT in the JS and are percentages of THIS box, not
   of the card. */
.tk-card__pips {
    position: relative;
    flex: 1 1 auto;
    align-self: stretch;
    width: 100%;
}

.tk-card__pip-mark {
    position: absolute;
    transform: translate(-50%, -50%);
    font-size: calc(var(--tk-card-w) * var(--tk-pip-ratio));
    line-height: 1;
}

/* A real deck stands its lower-half pips on their heads - the reference photo of the 9 of
   clubs shows it plainly, stems down on top and stems up below. We can only honour that for
   clubs and diamonds. Unicode's heart and spade are very nearly each other's inverse: an
   upside-down spade has a heart's silhouette and an upside-down heart has a spade's, so
   rotating them would fill half of every spade card with black hearts and half of every
   heart card with red spades. In a game about following suit that is not cosmetic.
   Diamonds are symmetric, so the rotation there is free and costs nothing to keep uniform. */
.tk-card--clubs .tk-card__pip-mark--lower,
.tk-card--diamonds .tk-card__pip-mark--lower {
    transform: translate(-50%, -50%) rotate(180deg);
}

/* The red 1 is a single pip with the whole card to itself, and a real deck draws it large.
   Without this it would be the one rank that got SMALLER than the glyph it replaced. */
.tk-card__pips--single .tk-card__pip-mark {
    font-size: calc(var(--tk-card-w) * 0.44);
}

/* Figure cards. Font Awesome's chess set is already loaded by the layout and happens to be the
   tarok hierarchy exactly - King, Dame, Cavalier on horseback, Fant on foot - and Tabler's
   joker is the Skis, a jester's cap and bells. Being font glyphs they inherit colour, so one
   set of icons covers all sixteen courts: black for clubs and spades, red for hearts and
   diamonds, grey when muted, with no per-suit rules at all. The small pip below a court keeps
   clubs telling apart from spades; the Skis has no suit and so goes solo. */
.tk-card__figure {
    flex: 1 1 auto;
    align-self: stretch;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.05rem;
}

.tk-card__fig {
    font-size: calc(var(--tk-card-w) * 0.46);
    line-height: 1;
}

/* No suit pip underneath, so the figure can take the room it saves. */
.tk-card__figure--solo .tk-card__fig {
    font-size: calc(var(--tk-card-w) * 0.56);
}

.tk-card__figure-suit {
    font-size: calc(var(--tk-card-w) * 0.2);
    line-height: 1;
}

/* Two-colour deck: black suits and red suits. */
.tk-card--spades,
.tk-card--clubs { color: var(--tk-black); }

.tk-card--hearts,
.tk-card--diamonds { color: var(--tk-red); }

/* Taroks are white with black numerals like every other card - a real deck does not
   tint its trumps. They are marked instead by a gold bar along the top edge, which
   stays visible when the hand is fanned and the rest of the card is covered. */
.tk-card--tarok {
    background: #fff;
    color: #1a1a1a;
    border-color: rgba(0, 0, 0, 0.25);
}

.tk-card--tarok::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: linear-gradient(90deg, var(--tk-tarok), #e3c273);
    border-radius: var(--tk-radius) var(--tk-radius) 0 0;
}

/* Tarok numerals are the card. Bodoni Moda 700 is a true Didone - one thick stroke, one
   hairline, flat unbracketed serifs - which is what the real Industrie und Glueck deck uses
   and why its numerals read as straight letters rather than as decoration.
   The numeral lives in the corners only; the middle is left empty for artwork. */
.tk-card--tarok .tk-card__corner {
    font-family: var(--font-family-bodoni-moda);
    font-weight: 700;
    font-size: calc(var(--tk-card-w) * var(--tk-numeral-ratio));
    /* Optical sizing is left on AUTO deliberately, and it is doing real work here. Bodoni's
       opsz axis is its stroke-contrast dial, and contrast is a trap at small sizes: a hairline
       narrower than one device pixel antialiases to pale grey or vanishes, which is exactly how
       XIX ends up looking like X|X. `auto` sets opsz from the rendered size (~16 at card size S,
       ~25 at size L), so each card size gets as much contrast as its pixels can actually carry.
       Do NOT pin this with font-variation-settings: 'opsz' - a fixed high value looks right in a
       mockup and breaks the thin strokes on the real table. */
    font-optical-sizing: auto;
    /* Bodoni gives its I generous side bearings, which is right for words and wrong for Roman
       numerals: III came out as three separate strokes with air between them rather than one
       numeral. Pulled in until the strokes group without touching. */
    letter-spacing: -0.06em;
}

/* Long numerals step down so they never clip. VIII, XIII and XVII are four glyphs; XVIII is
   five, and Bodoni is a wide face. The tighter tracking above bought enough room to keep these
   close to full size, which matters: a smaller numeral has fewer pixels to render a hairline in. */
.tk-card--num4 .tk-card__corner { font-size: calc(var(--tk-card-w) * var(--tk-numeral-ratio) * 0.9); }
.tk-card--num5 .tk-card__corner { font-size: calc(var(--tk-card-w) * var(--tk-numeral-ratio) * 0.8); }

/* Skis, Mond and Pagat - the trula. Worth 5 each and worth spotting. */
.tk-card--honour {
    box-shadow: 0 0 0 2px var(--tk-tarok), 0 1px 4px rgba(0, 0, 0, 0.4);
}

/* A slightly reduced card for reference displays like the talon strip. It renders exactly the
   same content as a full card - pip field, court figure, corner numeral - so it stays readable;
   0.55 was small enough that a card became a suit glyph and nothing else. Every size inside it
   is a share of --tk-card-w, so scaling the box scales the contents with it. */
.tk-card--mini {
    --tk-card-w: calc(var(--tk-card-w-base) * 0.82);
    --tk-card-h: calc(var(--tk-card-h-base) * 0.82);
    padding: 0.2rem 0.2rem;
    border-radius: 0.4rem;
}

.tk-card--mini .tk-card__corner--bottom { display: none; }

/* -------------------------------------------------- the talon on the table */

/* A slim reference strip pinned at the top of the felt. Stays put whatever the trick
   area does below it. */
.tk-talon-strip {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    padding-bottom: 0.6rem;
    margin-bottom: 0.2rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.tk-talon-strip__label {
    color: rgba(255, 255, 255, 0.7);
    font-size: 0.75rem;
    font-weight: 600;
}

.tk-talon-strip__group {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    padding: 0.25rem;
    border-radius: 0.45rem;
    position: relative;
}

/* The group the declarer picked up - highlighted, and labelled with who took it. */
.tk-talon-strip__group--taken {
    background: rgba(227, 194, 115, 0.18);
    border: 1px solid rgba(227, 194, 115, 0.55);
}

/* The rest went to the opponents. */
.tk-talon-strip__group--rejected {
    opacity: 0.55;
    border: 1px solid transparent;
}

.tk-talon-strip__who {
    color: var(--tk-tarok);
    font-size: 0.65rem;
    font-weight: 600;
    white-space: nowrap;
    margin-left: 0.15rem;
}

/* On a phone the revealed talon must stay the small reference it is. The plain mini sizes off
   --tk-card-w-base, which skips the phone shrink applied to .tk, so the mini ends up BIGGER
   than the hand on mobile. Pin it small here (mobile only - desktop keeps the normal mini).
   Contents follow since they are shares of --tk-card-w. (0,2,0) beats .tk-card--mini (0,1,0). */
@media (max-width: 48rem) {
    .tk-talon-strip .tk-card {
        --tk-card-w: 2.7rem;
        --tk-card-h: 4rem;
    }

    /* Same pin, real-card aspect - 2.7rem wide at 4rem tall would squat a photograph. */
    .tk[data-card-art="classic"] .tk-talon-strip .tk-card {
        --tk-card-w: 2.4rem;
    }
}

/* ------------------------------------------------- match-end trick-by-trick reveal */

/* One block per hand played, inside the "Show cards" panel (renderTricksList). Same
   small-mini sizing as the talon strip above, for the same reason - a lot of cards in a
   small panel. */
.tk-trick-hand {
    margin-bottom: 1.1rem;
}

.tk-trick-hand__head {
    font-weight: 600;
    font-size: 0.85rem;
    margin-bottom: 0.5rem;
    color: var(--tk-tarok);
}

.tk-trick-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.3rem 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

/* Whose side took the trick, at a glance down the whole list - green for you (or your
   side, in a 4-player hand), red for the other side. Klop and spectating get neither (see
   handMySide() in table.js), so a row with no modifier is a deliberate "not applicable",
   not a missed case. */
.tk-trick-row--mine {
    background: rgba(76, 175, 80, 0.12);
    border-left: 3px solid rgba(76, 175, 80, 0.6);
    border-radius: 0.3rem;
    padding-left: 0.5rem;
}

.tk-trick-row--theirs {
    background: rgba(220, 53, 69, 0.1);
    border-left: 3px solid rgba(220, 53, 69, 0.55);
    border-radius: 0.3rem;
    padding-left: 0.5rem;
}

.tk-trick-row__no {
    flex: 0 0 auto;
    width: 1.4rem;
    color: rgba(255, 255, 255, 0.5);
    font-size: 0.75rem;
    text-align: right;
}

.tk-trick-row__cards {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.tk-trick-row__card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    padding: 0.2rem;
    border-radius: 0.4rem;
}

/* The card that took the trick - same highlight language as the talon strip's "taken"
   group, so a player already reads this as "this one won". */
.tk-trick-row__card--winner {
    background: rgba(227, 194, 115, 0.18);
    border: 1px solid rgba(227, 194, 115, 0.55);
}

.tk-trick-row__seat {
    font-size: 0.6rem;
    color: rgba(255, 255, 255, 0.6);
    white-space: nowrap;
}

@media (max-width: 48rem) {
    .tk-trick-row__card .tk-card {
        --tk-card-w: 2.7rem;
        --tk-card-h: 4rem;
    }

    .tk[data-card-art="classic"] .tk-trick-row__card .tk-card {
        --tk-card-w: 2.4rem;
    }
}

/* ------------------------------------------------------------- the card back

   A real deck's back: a white margin around a printed panel carrying a dense lattice that
   repeats in both directions, so no corner of it reads as "the top". Built from tiled
   gradients rather than an image so it scales with --tk-card-w and costs no request.

   Three layers on the panel, painted front to back:
     1. a small dot at every lattice crossing,
     2. + 3. two opposed diagonal hatches, which cross into a diamond grid.
   All three are locked to the same 8px cell so the crossings and the dots line up. */

.tk-card--facedown {
    /* The white frame is the card itself; the pattern is inset inside it. */
    background: #fff;
    overflow: hidden;
}

.tk-card--facedown::before {
    content: '';
    position: absolute;
    inset: 3px;
    border-radius: calc(var(--tk-radius) - 0.15rem);
    border: 1px solid rgba(255, 255, 255, 0.45);
    background-color: #7a1c28;
    background-image:
        radial-gradient(circle at 50% 50%,
            rgba(255, 255, 255, 0.55) 0, rgba(255, 255, 255, 0.55) 1px, transparent 1.2px),
        repeating-linear-gradient(45deg,
            rgba(255, 255, 255, 0.26) 0, rgba(255, 255, 255, 0.26) 1px,
            transparent 1px, transparent 8px),
        repeating-linear-gradient(-45deg,
            rgba(255, 255, 255, 0.26) 0, rgba(255, 255, 255, 0.26) 1px,
            transparent 1px, transparent 8px);
    background-size: 8px 8px, auto, auto;
    /* Half a cell in, so the dot grid sits in the middle of each diamond rather than
       clipping against the panel edge. */
    background-position: 4px 4px, 0 0, 0 0;
    box-shadow: inset 0 0 0.6rem rgba(0, 0, 0, 0.35);
}

/* The turn-over as the trick is collected. Kept short so it lands well inside HOLD_MS in
   web/js/tarok/table.js and the card is face up before it starts flying to the winner. */
.tk-card--flip {
    animation: tkCardFlip 0.34s ease-out both;
    backface-visibility: hidden;
}

@keyframes tkCardFlip {
    from { transform: rotateY(90deg); }
    to { transform: rotateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .tk-card--flip {
        animation: none;
    }
}

/* --------------------------------------------------- trick -> winner animation */

/* A completed trick is held on screen, then the cards fly to the seat that won it.
   Without this the bots resolve a whole trick inside one request and you never see
   what was played. The transform is set inline in JS from the winning seat's real
   position, so it works whatever the layout does. */
.tk-card--flying {
    /* Duration must match FLIGHT_MS in web/js/tarok/table.js. The fade is held back so
       the cards stay readable for most of the journey instead of vanishing at once. */
    transition: transform 0.7s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.7s ease-in 0.2s;
    opacity: 0;
    z-index: 20;
}

.tk-trick__slot--winner .tk-card {
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.85), 0 4px 10px rgba(0, 0, 0, 0.45);
}

/* --------------------------------------------------- card drop-in (a card played) */

/* When a card lands in the centre pile it drops onto the felt rather than teleporting
   in. Direction reads who played it: your own card rises from your hand below the felt;
   every opponent's falls in from the seat row above. Duration ~360ms - long enough to
   register, short enough to keep play brisk even when a solo table's bot replies cascade
   in (each later card gets an inline animation-delay from JS). */
.tk-card--drop {
    animation-duration: 0.42s;
    animation-timing-function: cubic-bezier(0.2, 0.7, 0.3, 1);
    animation-fill-mode: both;
    z-index: 15;
}

.tk-card--drop-self {
    animation-name: tk-drop-self;
}

.tk-card--drop-other {
    animation-name: tk-drop-other;
}

/* Your card travels a long way up from the hand at the bottom of the screen, so the rise
   is generous - it should clearly read as coming from your own cards. */
@keyframes tk-drop-self {
    from {
        opacity: 0;
        transform: translateY(90px) scale(1.18);
    }
    55% {
        opacity: 1;
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

/* Opponents' cards fall in from the seat row above the felt. */
@keyframes tk-drop-other {
    from {
        opacity: 0;
        transform: translateY(-80px) scale(1.18) rotate(-6deg);
    }
    55% {
        opacity: 1;
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1) rotate(0);
    }
}

/* Reduced motion: keep the reveal, drop the travel. The card still fades up in place so
   a new play is not silent, but nothing slides across the felt. */
@media (prefers-reduced-motion: reduce) {
    .tk-card--drop {
        animation-name: tk-drop-fade;
        animation-duration: 0.2s;
    }
}

@keyframes tk-drop-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

.tk-seat--collecting {
    background: rgba(255, 255, 255, 0.3);
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.8);
}

/* Skis is the one tarok that prints a WORD rather than a numeral (a real Skis carries no
   number), and a word needs to be small enough to fit. Deliberately scoped to --named and
   not --honour: Pagat and Mond are in the trula too, and they now print I and XXI, which
   must keep the full numeral size. */
.tk-card--named .tk-card__corner {
    font-size: calc(var(--tk-card-w) * var(--tk-numeral-ratio) * 0.62);
    letter-spacing: -0.02em;
}

/* --------------------------------------------------------------- your hand */

.tk-hand {
    display: flex;
    /* "safe" so a fanned hand that is wider than the screen falls back to flex-start instead
       of centring: plain "center" pushes the overflow off BOTH edges and the browser cannot
       scroll to the part that spills off the left, so the first cards become unreachable. */
    justify-content: safe center;
    /* overflow-y is hidden below (it must be, to pair with overflow-x: auto), so a
       lifted/selected card and its check badge would clip at the top. Reserve room:
       max lift is 1.1rem (selected + hover) plus the badge overhangs 0.55rem above
       the card, so ~1.9rem of headroom keeps both fully visible.
       The 1.5rem side padding gives the first/last cards breathing room from the screen
       edge so they are easy to tap (a scroll container honours end padding here). */
    padding: 1.9rem 1.5rem 1.25rem;
    min-height: calc(var(--tk-card-h) + 2rem);
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-padding-inline: 1.5rem;
    /* Break the hand out of the centred content column to the full viewport width, so the
       fanned cards (and their scroll room on a phone) get the whole screen. Standard
       full-bleed: 100vw wide, pulled back by half the gap between the column and the
       viewport edge on each side. */
    width: 100vw;
    max-width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
}

/* Fan the hand. 16 cards will not fit side by side on a phone, so they overlap
   and the hovered/focused card lifts clear.
   The overlap is 32%, not more, and that number is load-bearing: number cards carry no corner
   index any more, so the only way to read your own hand is to count pips. The left column sits
   at 25% of the card and the centre column at 50%, and it is the centre column that separates
   7 from 8 and 9 from 10 - hide it and half your hand becomes ambiguous. Showing 68% of each
   card clears the centre column with room to spare. */
/* Only while it is your turn does the scrub own the horizontal axis: let JS see the drag
   and auto-scroll the fan itself. On other turns the hand scrolls natively so you can still
   peek at your off-screen cards. Vertical drags always fall through to page scroll. */
.tk-hand--scrub {
    touch-action: pan-y;
}

.tk-hand .tk-card {
    margin-right: calc(var(--tk-card-w) * -0.22);
}

.tk-hand .tk-card:last-child {
    margin-right: 0;
}

/* A fan too wide for one row wraps into two instead of scrolling (finalizeHand() in
   table.js decides this from real layout - scrollWidth vs clientWidth). The second row
   sits physically below the first but drawn IN FRONT of it (row--bottom has the higher
   z-index and pulls up over row--top's bottom edge with a negative top margin) - so the
   second row stays fully readable and it is row--top's bottom edge that gets trimmed
   instead. The vertical overlap is deliberately kept well short of the 32% horizontal cap
   above: pips run from 13% to 87% of a card's height (see PIP_LAYOUT in table.js), so
   hiding much more than the outer edge risks the same "can't tell 7 from 8" problem the
   horizontal cap exists to avoid - here it's worse, because it's a whole edge of pips,
   not just one column. 18% keeps every rank's pip pattern legible at rest. */
.tk-hand--tworow {
    flex-direction: column;
    flex-wrap: nowrap;
    overflow-x: hidden;
    overflow-y: visible;
    touch-action: auto;
}

.tk-hand__row {
    display: flex;
    justify-content: safe center;
    flex-wrap: nowrap;
}

.tk-hand__row--top {
    position: relative;
    z-index: 0;
}

.tk-hand__row--bottom {
    position: relative;
    z-index: 1;
    margin-top: calc(var(--tk-card-h) * -0.18);
}

/* No cards left: collapse rather than leaving a card-height hole between the table and
   the score sheet. */
.tk-hand:empty {
    min-height: 0;
    padding: 0;
}

/* Live coaching line under the hand while it is your turn: "Pick a card..." then, once a
   card is armed, "Tap the highlighted card again to play it." Updated in step with a scrub
   without a full re-render (see updateHandHint). */
.tk-hand-hint {
    text-align: center;
    font-size: 0.8rem;
    color: var(--text-muted);
    padding: 0 1rem 0.5rem;
    margin-top: -0.5rem;
}

.tk-card--playable {
    cursor: pointer;
}

/* The hover lift is gated to real hovering pointers (a mouse). On touch, browsers emulate a
   sticky :hover on the last-touched card, so mid-scrub the card you started on would stay
   lifted while the card under your finger also lifts - two raised cards at once. Only the
   pick (.tk-card--selected) and keyboard focus lift on touch. */
@media (hover: hover) {
    .tk-card--playable:hover {
        transform: translateY(-0.9rem);
        box-shadow: 0 6px 14px rgba(0, 0, 0, 0.4);
        z-index: 5;
        outline: none;
    }
}

.tk-card--playable:focus-visible {
    transform: translateY(-0.9rem);
    box-shadow: 0 0 0 3px var(--color-primary-500), 0 6px 14px rgba(0, 0, 0, 0.4);
    z-index: 5;
    outline: none;
}

/* Not legal this trick: still readable, clearly not available. Showing them rather
   than hiding them is what lets a player learn the rules.
   Deliberately NOT opacity - a white card at 40% opacity over a dark page turns dark
   grey and becomes unreadable, and after a suit lead that is most of your hand. Dim
   the card's own colours instead so it stays a card. */
.tk-card--muted {
    background: #c8c8c8;
    border-color: rgba(0, 0, 0, 0.2);
    box-shadow: none;
    cursor: not-allowed;
}

/* Dimmed but still legible as black or red against the grey card. */
.tk-card--muted.tk-card--spades,
.tk-card--muted.tk-card--clubs { color: #4a4a4a; }

.tk-card--muted.tk-card--hearts,
.tk-card--muted.tk-card--diamonds { color: #9a6660; }

.tk-card--muted::before {
    opacity: 0.3;
}

.tk-card--muted.tk-card--honour {
    box-shadow: 0 0 0 2px rgba(138, 109, 31, 0.45);
}

/* --------------------------------------------------------------- prompts */

.tk-prompt {
    background: var(--bg-secondary);
    border: 1px solid var(--border-default);
    border-radius: 0.75rem;
    padding: 1rem;
}

.tk-prompt__title {
    font-weight: 600;
    margin-bottom: 0.15rem;
}

.tk-prompt__hint {
    color: var(--text-secondary);
    font-size: 0.875rem;
    margin-bottom: 0.75rem;
}

/* A prompt whose controls fit beside its title puts both on one line - the question on the
   left, what you do about it on the right (see the bury panel). Wraps rather than squeezes,
   so a narrow screen gets two centred rows instead of a cramped one. */
.tk-prompt__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem 0.9rem;
    text-align: left;
}

/* The 3-vs-4 players picker: two selectable cards (icon + title + description). The real
   radio is visually hidden; the label is the card, and :has(:checked) paints the choice. */
.tk-choice {
    display: flex;
    gap: 0.75rem;
}

/* Space-filler mode: the row grows to eat the leftover height in a shorter form, and its
   cards stretch with it (default align-items: stretch), so two side-by-side forms line up
   at the same bottom edge. */
.tk-choice--grow {
    flex: 1 1 auto;
}

.tk-choice__card {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 0;
    padding: 0.85rem 1rem;
    border: 1px solid var(--border-default);
    border-radius: 0.75rem;
    background: var(--bg-primary);
    cursor: pointer;
    transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

.tk-choice__input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.tk-choice__icon {
    flex: 0 0 auto;
    width: 2.5rem;
    height: 2.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 0.6rem;
    background: var(--bg-secondary);
    color: var(--text-secondary);
    font-size: 1.1rem;
    transition: background 0.15s ease, color 0.15s ease, transform 0.2s ease;
}

.tk-choice__body {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.tk-choice__title {
    font-weight: 600;
    line-height: 1.2;
}

.tk-choice__desc {
    font-size: 0.8rem;
    color: var(--text-secondary);
    line-height: 1.25;
}

.tk-choice__card:hover {
    border-color: var(--tk-tarok);
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
}

.tk-choice__card:hover .tk-choice__icon {
    transform: scale(1.08);
}

/* On phones a full-width form still leaves the two side-by-side choice cards too
   narrow (the title wraps to "3 / players"), so stack them vertically. */
@media (max-width: 480px) {
    .tk-choice {
        flex-direction: column;
    }
}

.tk-choice__card:has(.tk-choice__input:checked) {
    border-color: var(--tk-tarok);
    background: var(--tk-tarok-bg);
    box-shadow: inset 0 0 0 2px var(--tk-tarok);
}

.tk-choice__card:has(.tk-choice__input:checked) .tk-choice__icon {
    background: var(--tk-tarok);
    color: #fff;
}

/* The native radio is hidden, so surface keyboard focus on the card itself. */
.tk-choice__card:focus-within {
    outline: 2px solid var(--tk-tarok);
    outline-offset: 2px;
}

@media (max-width: 420px) {
    .tk-choice {
        flex-direction: column;
    }
}

.tk-choices {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* Picked for the discard but not yet committed. Deliberately loud - these cards are
   about to leave your hand, and the points you bury count toward your own pile. */
.tk-card--selected {
    transform: translateY(-0.75rem);
    box-shadow: 0 0 0 3px var(--color-primary-500), 0 8px 16px rgba(0, 0, 0, 0.45);
    z-index: 6;
}

.tk-card--selected::after {
    content: '✓';
    position: absolute;
    top: -0.55rem;
    right: -0.55rem;
    width: 1.4rem;
    height: 1.4rem;
    border-radius: 50%;
    background: var(--color-primary-500);
    color: #fff;
    font-size: 0.85rem;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}

@media (hover: hover) {
    .tk-card--playable.tk-card--selected:hover {
        transform: translateY(-1.1rem);
    }
}

.tk-confirm {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 1rem;
    padding-top: 0.85rem;
    border-top: 1px solid var(--border-default);
}

.tk-confirm__count {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--text-secondary);
}

/* Sitting inside a .tk-prompt__row rather than under the prompt body, so the divider and
   the space above it that separate a stacked confirm from its question are wrong here. */
.tk-confirm--inline {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
    flex-wrap: wrap;
}

.tk-confirm .btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* The discard grid wraps, so cards need breathing room for the lift and the tick. */
.tk-prompt .tk-choices .tk-card {
    margin: 0.6rem 0.15rem 0.2rem;
}

.tk-talon-group {
    display: flex;
    gap: 0.25rem;
    padding: 0.5rem;
    border: 2px solid var(--border-default);
    border-radius: 0.6rem;
    background: var(--bg-primary);
    cursor: pointer;
    transition: border-color 0.15s ease, transform 0.15s ease;
}

/* Talon-take: all groups on a single row whatever their size, so the whole talon reads
   at a glance. Cards are a touch larger than the default mini for readability; the row
   scrolls sideways rather than wrapping if a very narrow screen cannot hold all six. */
.tk-talon-take {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 0.85rem;
    padding: 0.35rem 0.1rem;
}

.tk-talon-take .tk-talon-group {
    flex: 0 0 auto;
    padding: 0.4rem;
}

/* On L/XL screens there is plenty of width to spare - widen the talon prompt past the
   normal 38rem prompt cap (see .tk-center--prompt .tk-prompt below) and force a genuine
   single row instead of relying on wrapping, so the whole talon always reads at a glance. */
@media (min-width: 992px) {
    .tk-prompt--talon .tk-talon-take {
        flex-wrap: nowrap;
        overflow-x: auto;
    }
}

.tk-talon-group:hover {
    border-color: var(--color-primary-500);
    transform: translateY(-2px);
}

/* --------------------------------------------------------------- log + score */

.tk-log {
    max-height: 12rem;
    overflow-y: auto;
    font-size: 0.85rem;
    color: var(--text-secondary);
}

.tk-log__line {
    padding: 0.15rem 0;
    border-bottom: 1px solid var(--border-muted);
}

/* --------------------------------------------------- end-of-hand result panel */

.tk-result__verdict {
    font-size: 1.15rem;
    font-weight: 700;
    margin: 0.4rem 0 0.15rem;
}

.tk-result__verdict--win { color: var(--color-success-600, #16a34a); }
.tk-result__verdict--lose { color: var(--color-danger-600, #dc2626); }
/* A watcher is on nobody's side, so the verdict states the fact without taking one. */
.tk-result__verdict--flat { color: var(--tk-tarok); }

.tk-result__note {
    color: var(--text-secondary);
    font-size: 0.9rem;
    margin-bottom: 0.3rem;
}

.tk-result__bars {
    margin: 0.85rem 0;
}

.tk-pts {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0.35rem 0;
}

.tk-pts__label {
    flex: 0 0 40%;
    font-size: 0.85rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tk-pts__bar {
    position: relative;
    flex: 1;
    height: 0.7rem;
    background: var(--bg-tertiary);
    border-radius: 999px;
    overflow: visible;
}

.tk-pts__fill {
    height: 100%;
    border-radius: 999px;
    background: var(--text-tertiary);
    transition: width 0.4s ease;
}

/* The declarer's own bar is the one you watch against the 36 line. */
.tk-pts__fill--decl {
    background: var(--color-primary-500);
}

.tk-pts__need {
    position: absolute;
    top: -0.2rem;
    bottom: -0.2rem;
    width: 2px;
    background: var(--tk-tarok);
}

.tk-pts__val {
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
    font-size: 0.85rem;
    font-weight: 600;
}

.tk-result__need-note {
    font-size: 0.78rem;
    color: var(--text-tertiary);
    margin-top: 0.3rem;
}

.tk-result__chips {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0.6rem 0;
}

.tk-result__chips-label {
    font-size: 0.85rem;
    color: var(--text-secondary);
}

.tk-chip {
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    font-size: 0.8rem;
    font-weight: 600;
    background: rgba(227, 194, 115, 0.18);
    color: var(--tk-tarok);
    border: 1px solid rgba(227, 194, 115, 0.4);
}

.tk-result__sheet-head {
    margin: 0.9rem 0 0.25rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-secondary);
}

.tk-result__you {
    font-weight: 700;
}

.tk-result__you::before {
    content: '▸ ';
    color: var(--tk-tarok);
}

.tk-sheet {
    width: 100%;
    font-variant-numeric: tabular-nums;
}

.tk-sheet td {
    padding: 0.25rem 0;
    border-bottom: 1px solid var(--border-muted);
}

.tk-sheet td:last-child {
    text-align: right;
    font-weight: 600;
}

/* The between-hands standings' name cell (renderStandings()) - avatar + name inline,
   spaced with `gap` so the avatar's own inline margin is zeroed here too. */
.tk-sheet__player {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.tk-sheet__player .tk-avatar {
    margin-right: 0;
}

/* Full score-sheet grid: every player score column (header + deltas + totals) is
   right-aligned so the numbers line up, not just the last one. */
.tk-sheet th.tk-num,
.tk-sheet td.tk-num {
    text-align: right;
}

.tk-sheet tr:last-child td {
    border-bottom: none;
    border-top: 2px solid var(--border-default);
    font-size: 1.05rem;
}

.tk-positive { color: var(--color-success-600, #16a34a); }
.tk-negative { color: var(--color-danger-600, #dc2626); }

/* --------------------------------------------------------------- responsive */

@container (max-width: 40rem) {
    .tk-seat {
        min-width: 5rem;
        font-size: 0.75rem;
        padding: 0.4rem 0.6rem;
    }

    /* Still a step above the caption under it - a narrow table shrinks the plate, it does
       not stop the name being the thing you are looking for. */
    .tk-seat__name {
        font-size: 0.95rem;
    }

    .tk-seat__meta,
    .tk-seat__bot {
        font-size: 0.72rem;
    }
}

@media (max-width: 36rem) {
    /* Shrink for the phone, but off the reader's S/M/L base rather than a fixed size, or the
       S/M/L control (which only moves --tk-card-w-base) would do nothing on mobile. S keeps
       the old 3.2rem look (4.5 * 0.71); M and L now step up here too. */
    .tk {
        --tk-card-w: calc(var(--tk-card-w-base) * 0.71);
        --tk-card-h: calc(var(--tk-card-h-base) * 0.71);
    }

    .tk-hand .tk-card {
        margin-right: calc(var(--tk-card-w) * -0.38);
    }

    .tk-table {
        padding: 0.75rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .tk-card,
    .tk-seat,
    .tk-talon-group {
        transition: none;
    }

    .tk-card--playable:hover {
        transform: none;
    }

    /* The trick is still HELD on screen - only the flight is removed. Skipping the
       pause as well would put the "you cannot see what was played" problem straight
       back for exactly the people least able to track fast movement. */
    .tk-card--flying {
        transition: opacity 0.2s ease;
        transform: none !important;
    }
}

/* --------------------------------------------------------- waiting room (M2) */

.tk-waiting {
    background: var(--bg-secondary);
    border: 1px solid var(--border-default);
    border-radius: 0.75rem;
    padding: 1.5rem;
    max-width: 32rem;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.tk-share {
    background: var(--bg-primary);
    border: 1px dashed var(--border-default);
    border-radius: 0.5rem;
    padding: 0.85rem 1rem;
}

.tk-share__label {
    color: var(--text-secondary);
    font-size: 0.85rem;
    margin-bottom: 0.35rem;
}

.tk-share__row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.tk-share__code {
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-size: 1.6rem;
    font-weight: 700;
    letter-spacing: 0.25em;
    color: var(--tk-tarok);
}

/* The direct-link row sits under the code, with its own "Or share this link" label. */
.tk-share__row + .tk-share__label {
    margin-top: 0.75rem;
}

.tk-share__link {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-size: 0.85rem;
    color: var(--text-secondary);
}

/* .tk-share__link--tap is gone with the tap-the-URL-to-share hack it styled: the waiting room
   now carries a real share row (.tk-share__sharebar below), so the link is back to being
   text you read rather than a button that did not look like one. */

.tk-share__row--link .btn {
    flex: 0 0 auto;
}

/* ------------------------------------------------------------------ the share row

   TarokShareWidget. Two faces of the same markup: on a phone (share.js adds --native) it is
   one Share button plus Copy link, and the platform row is gone; everywhere else it is the
   platform row plus Copy link and the Share button never appears. Both faces are always in
   the DOM - which one shows is decided client-side, so this survives page caching. */
.tk-sharebar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.7rem 0.9rem;
    border: 1px dashed var(--border-default);
    border-radius: 0.5rem;
    background: var(--bg-primary);
}

/* Inline variant for rows that already sit inside a card or a plate of their own. */
.tk-sharebar--compact {
    padding: 0;
    border: 0;
    background: none;
}

.tk-sharebar__label {
    color: var(--text-secondary);
    font-size: 0.85rem;
    margin-right: 0.15rem;
}

.tk-sharebar__platforms {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
}

/* Square by construction: the buttons carry an icon and nothing else, so without a floor
   the WhatsApp glyph and the envelope produce two different button widths and the row
   looks hand-set. */
.tk-sharebar__btn {
    min-width: 2.25rem;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
    line-height: 1.4;
}

/* On a device with a share sheet the buttons are noise - the sheet already offers every one
   of them, and more (Viber, Messages) besides. */
.tk-sharebar--native .tk-sharebar__platforms {
    display: none;
}

/* Brand colour on hover only: a permanently coloured row would shout louder than the page
   it is attached to, but a hover with no colour gives no hint of where the click goes. */
.tk-sharebar__btn--whatsapp:hover,
.tk-sharebar__btn--whatsapp:focus {
    background: #25d366;
    border-color: #25d366;
    color: #fff;
}

.tk-sharebar__btn--facebook:hover,
.tk-sharebar__btn--facebook:focus {
    background: #1877f2;
    border-color: #1877f2;
    color: #fff;
}

.tk-sharebar__btn--twitter:hover,
.tk-sharebar__btn--twitter:focus {
    background: #000;
    border-color: #000;
    color: #fff;
}

.tk-sharebar__btn--telegram:hover,
.tk-sharebar__btn--telegram:focus {
    background: #0088cc;
    border-color: #0088cc;
    color: #fff;
}

/* Confirmed state for Copy link. Colour rather than an icon swap so the button keeps its
   width and the row does not twitch when the label changes. */
.tk-sharebar__copy--done {
    color: var(--tk-tarok);
    border-color: var(--tk-tarok);
}

/* Phones: the label eats a whole line for one word, and the two remaining buttons want the
   room. Drop it and let them share the row. */
@media (max-width: 400px) {
    .tk-sharebar__label {
        display: none;
    }
}

/* The cloned copy inside the waiting room's share plate. Already inside a bordered box, so
   it wants nothing but the gap above it and a left edge that lines up with the code and the
   link above. */
.tk-share__sharebar {
    margin-top: 0.75rem;
}

.tk-share__sharebar .tk-sharebar {
    justify-content: flex-start;
}

.tk-waiting__sound-row {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
}

.tk-sound-toggle {
    padding: 0.3rem 0.55rem;
    line-height: 1;
}

.tk-sound-toggle.active {
    color: var(--tk-tarok);
    border-color: var(--tk-tarok);
}

.tk-waiting__sound-hint {
    color: var(--text-tertiary, var(--text-secondary, #888));
    font-size: 0.75rem;
    text-align: right;
}

.tk-waiting__seats {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.tk-waiting__seat {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.6rem 0.85rem;
    border: 1px solid var(--border-default);
    border-radius: 0.5rem;
    background: var(--bg-primary);
}

/* Already a flex row with its own `gap` - the avatar's usual inline margin-right would just
   double up the spacing here. */
.tk-waiting__seat .tk-avatar {
    margin-right: 0;
}

.tk-waiting__seat--you {
    border-color: var(--tk-tarok);
    box-shadow: inset 0 0 0 1px var(--tk-tarok);
}

.tk-waiting__seat--empty {
    border-style: dashed;
    color: var(--text-tertiary);
    background: transparent;
}

.tk-waiting__seat-name {
    font-weight: 600;
}

.tk-waiting__seat--empty .tk-waiting__seat-name {
    font-weight: 400;
    font-style: italic;
}

.tk-waiting__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
}

.tk-waiting__pulse {
    animation: tk-pulse 1.6s ease-in-out infinite;
}

@keyframes tk-pulse {
    0%, 100% { opacity: 0.55; }
    50% { opacity: 1; }
}

/* Presence: an absent player greys out at the table and in the waiting room. */
.tk-seat--away {
    opacity: 0.5;
}

.tk-seat__away {
    color: rgba(255, 255, 255, 0.62);
    font-size: 0.8rem;
    font-style: italic;
}

/* "Thinking" robot next to an away human - the computer is covering their turns.
   Reuses the tk-pulse opacity keyframe (reduced-motion guarded below). */
.tk-seat__robot {
    margin-left: 0.35rem;
    color: var(--tk-felt-gold);
    font-size: 0.85rem;
    cursor: help;
    animation: tk-pulse 1.6s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .tk-seat__robot {
        animation: none;
    }
}

/* Landing-page "a familiar player is at an open table" toast - rides inside a global
   Toastr notice (see lobby.js maybeToast(), and table.js's own join/back-online/live-stats
   notices), so it needs its own highlighted strip to read as distinct from the plain
   "a table is open" toast, which keeps Toastr's unstyled default look. */
.tk-toast-familiar {
    border-left: 3px solid var(--tk-tarok, #8a6d1f);
    padding-left: 0.6rem;
}

.tk-toast-familiar a {
    color: inherit;
    font-weight: 600;
    text-decoration: underline;
}

/* --------------------------------------------------------------- lobby (M2) */

.tk-lobby-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.tk-lobby-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.7rem 0.95rem;
    border: 1px solid var(--border-default);
    border-radius: 0.5rem;
    background: var(--bg-secondary);
}

/* Same reasoning as .tk-waiting__seat above: .tk-lobby-row already spaces its children
   with `gap`. */
.tk-lobby-row > .tk-avatar {
    margin-right: 0;
}

.tk-lobby-row__main {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.tk-lobby-row__host {
    font-weight: 600;
}

.tk-lobby-row__meta {
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.tk-lobby-row__join {
    margin: 0;
    flex: 0 0 auto;
}

@media (prefers-reduced-motion: reduce) {
    .tk-waiting__pulse {
        animation: none;
    }
}

/* Bot marker on a seat during play - so a computer player never passes for a human. */
/* Explicit white-alpha, not var(--text-tertiary): the plate is dark in both themes, and the
   light theme's tertiary grey all but vanished on it. */
.tk-seat__bot {
    color: rgba(255, 255, 255, 0.62);
    font-size: 0.8rem;
    font-weight: 500;
    text-transform: lowercase;
}

/* Wide screens spell it out; phones show just the robot icon (below). */
.tk-seat__bot-icon {
    display: none;
}

@media (max-width: 36rem) {
    .tk-seat__bot-text {
        display: none;
    }

    .tk-seat__bot-icon {
        display: inline;
    }
}

/* Your own rooms in the lobby - accented and badged so you spot them instantly. */
.tk-lobby-row--mine {
    border-color: var(--tk-tarok);
    box-shadow: inset 0 0 0 1px var(--tk-tarok);
}

.tk-lobby-row__badge {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--tk-tarok);
    border: 1px solid var(--tk-tarok);
    border-radius: 0.35rem;
    padding: 0.05rem 0.4rem;
    vertical-align: middle;
}

/* ------------------------------------------------------------------ leaderboard
   The ranking board and the "your rank" strip. --tk-tarok is the gold accent the
   light/dark themes already drive, so the board inherits the felt look for free. */
.tk-rank-me {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.35rem 1rem;
    padding: 0.85rem 1.15rem;
    border: 1px solid var(--tk-tarok);
    border-radius: var(--tk-radius);
    background: var(--tk-tarok-bg);
}

.tk-rank-me__label {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.75;
}

.tk-rank-me__value {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--tk-tarok);
}

.tk-rank-me__meta {
    font-size: 0.9rem;
    opacity: 0.85;
}

.tk-board {
    --bs-table-hover-bg: rgba(138, 109, 31, 0.08);
}

.tk-board__rank {
    width: 3rem;
    text-align: center;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Avatar + name, inline with the rest of the cell (badges, the "You" pill, the block
   button all follow on the same line) - so this is inline-flex, not a block row. */
/* The whole leaderboard "Player" cell (avatar, name, the "You" pill, the badge strip) -
   ALL of it, not just the avatar+name pair. One flex row with align-items:center is what
   actually keeps every child vertically centered against the others; splitting the pill
   and the badges out as independent inline siblings each relying on their own
   vertical-align was fragile - the moment one child's line-box height differed from the
   others (the badge icons vs. the name text), they visibly drifted apart. flex-wrap so a
   long badge list wraps onto its own line on a narrow screen instead of overflowing. */
.tk-board__player {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.tk-board__player .tk-avatar {
    margin-right: 0;
}

.tk-board__name {
    font-weight: 600;
}

/* The leaderboard row control. Icon-only in BOTH states on purpose - a Bootstrap button
   isn't a flex container by default, so a lone icon glyph just sits per normal line-box
   flow (off-center, closer to the top-left) rather than centered in the square; the
   Blocked-players-panel button reuses .tk-board__block for the shared click handler but
   stays a plain text "Unblock" button, so only the --icon modifier gets this treatment. */
.tk-board__block--icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    line-height: 1;
}

.tk-board__block--icon i {
    line-height: 1;
}

/* Currently blocked - same glyph, not swapped, just recolored (the whole point of the
   fix: one icon, two states, never a mix of icon and text). */
.tk-board__block--active {
    color: #fff;
    background: var(--color-danger-600, #dc3545);
    border-color: var(--color-danger-600, #dc3545);
}

/* The "Blocked players" panel at the bottom of the leaderboard - reuses the same row
   shape as the waiting room seats for visual consistency. */
.tk-blocklist {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.tk-blocklist__row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.85rem;
    border: 1px solid var(--border-default);
    border-radius: 0.5rem;
    background: var(--bg-secondary);
}

.tk-blocklist__row .tk-avatar {
    margin-right: 0;
}

.tk-blocklist__name {
    flex: 1 1 auto;
    font-weight: 600;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tk-board__rating {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--tk-tarok);
}

.tk-board__you {
    display: inline-block;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.05rem 0.4rem;
    border: 1px solid var(--tk-tarok);
    border-radius: 0.35rem;
    color: var(--tk-tarok);
}

.tk-board__row--me {
    background: var(--tk-tarok-bg);
}

.tk-board__row--me td {
    border-bottom-color: var(--tk-tarok);
}

/* ------------------------------------------------------------------ felt centre
   The middle of the felt now hosts whatever the hand asks of you: the bid/king/talon
   controls, a blinking "your turn" flag above the trick, or a quiet "waiting" line. */
.tk-center {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    min-height: calc(var(--tk-card-h) + 2.5rem);
    width: 100%;
}

/* When the felt centre is holding the decision controls, give the box a translucent
   panel so it reads over the green felt rather than the page background. */
.tk-center--prompt .tk-prompt {
    background: rgba(0, 0, 0, 0.34);
    border-color: rgba(255, 255, 255, 0.18);
    color: #fff;
    max-width: 38rem;
    text-align: center;
    backdrop-filter: blur(2px);
}

/* The talon-take prompt needs room for up to 6 full-size cards in a single row - the
   default 38rem cap above (fine for bidding/king/announce text) forces it to wrap well
   before it has to on a wide screen. */
@media (min-width: 992px) {
    .tk-center--prompt .tk-prompt--talon {
        max-width: none;
    }
}

.tk-center--prompt .tk-prompt__hint {
    color: rgba(255, 255, 255, 0.75);
}

.tk-center--prompt .tk-choices {
    justify-content: center;
}

/* ------------------------------------------------- controls on the felt panel

   The prompt panel is dark in BOTH themes (a translucent black plate over green felt), so
   the controls inside it cannot borrow the page's button colours: Bootstrap's light-theme
   outline-primary painted the bid ladder office-blue on green, and outline-secondary put
   near-black text on the black plate, which is what made "No bid" all but invisible.

   Everything here is therefore expressed against the plate, not against the theme, and the
   gold is the felt gold (bright in both themes) rather than var(--tk-tarok), which is a dark
   bronze in light mode and would be just as unreadable. */
.tk-center--prompt .tk-prompt .btn {
    min-height: 2.75rem;
    padding: 0.5rem 1.05rem;
    border-radius: 0.65rem;
    border: 1px solid rgba(255, 255, 255, 0.28);
    background: rgba(255, 255, 255, 0.07);
    color: #fff;
    font-weight: 600;
    line-height: 1.15;
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) inset;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease,
                transform 0.15s ease, box-shadow 0.15s ease;
}

.tk-center--prompt .tk-prompt .btn:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
    box-shadow: none;
}

.tk-center--prompt .tk-prompt .btn:not(:disabled):active {
    transform: translateY(1px);
}

/* A button that wraps a card (the king call) is a card first - it must not inherit the text
   button's padding or the card ends up floating in a huge chip. */
.tk-center--prompt .tk-prompt .btn:has(.tk-card) {
    min-height: 0;
    padding: 0.3rem;
    background: rgba(255, 255, 255, 0.06);
}

.tk-center--prompt .tk-prompt .btn:has(.tk-card):hover {
    background: rgba(217, 181, 81, 0.22);
    border-color: var(--tk-felt-gold);
    transform: translateY(-3px);
}

/* The offer you are meant to consider: bids, callable kings, bonus picks. Gold on the plate,
   filling solid on hover so the hit target is unmistakable. */
.tk-center--prompt .tk-prompt .btn-outline-primary {
    border-color: rgba(217, 181, 81, 0.55);
    background: rgba(217, 181, 81, 0.12);
    color: var(--tk-felt-gold-text);
}

.tk-center--prompt .tk-prompt .btn-outline-primary:not(:disabled):hover,
.tk-center--prompt .tk-prompt .btn-outline-primary:not(:disabled):focus {
    background: var(--tk-felt-gold);
    border-color: var(--tk-felt-gold);
    color: #241d05;
    transform: translateY(-2px);
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.35);
}

/* An announce pick that is already ON. Restated here because the base rule above outranks
   the plain .tk-ann-opt--on class and would otherwise wash the gold back out. */
.tk-center--prompt .tk-prompt .tk-ann-opt--on {
    background: var(--tk-felt-gold);
    border-color: var(--tk-felt-gold);
    color: #241d05;
    box-shadow: 0 0 12px rgba(217, 181, 81, 0.45);
}

/* The way out - pass, "do not double", undo. Deliberately quiet: it must read clearly but
   never compete with the offer above it. */
.tk-center--prompt .tk-prompt .btn-outline-secondary {
    border-color: rgba(255, 255, 255, 0.3);
    background: transparent;
    color: rgba(255, 255, 255, 0.82);
    font-weight: 500;
}

.tk-center--prompt .tk-prompt .btn-outline-secondary:not(:disabled):hover,
.tk-center--prompt .tk-prompt .btn-outline-secondary:not(:disabled):focus {
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(255, 255, 255, 0.6);
    color: #fff;
}

/* Committing an announcement. */
.tk-center--prompt .tk-prompt .btn-primary {
    background: linear-gradient(135deg, #f7dd8a, var(--tk-felt-gold));
    border-color: var(--tk-felt-gold);
    color: #241d05;
    font-weight: 700;
}

.tk-center--prompt .tk-prompt .btn-primary:not(:disabled):hover {
    filter: brightness(1.06);
    transform: translateY(-2px);
}

/* Kontra - the one aggressive move on the panel, so it keeps its red, brightened enough to
   carry on a dark plate. */
.tk-center--prompt .tk-prompt .btn-danger {
    background: rgba(200, 45, 60, 0.9);
    border-color: rgba(255, 138, 148, 0.85);
    color: #fff;
}

.tk-center--prompt .tk-prompt .btn-danger:not(:disabled):hover {
    background: #e0455a;
    border-color: #ffb3ba;
    transform: translateY(-2px);
}

/* The talon groups are pickable boxes, not buttons, but they sit on the same plate and were
   drawing their frame from the page theme - a pale card with a blue hover on green felt. */
.tk-center--prompt .tk-talon-group {
    border-color: rgba(255, 255, 255, 0.25);
    background: rgba(255, 255, 255, 0.06);
}

.tk-center--prompt .tk-talon-group:hover {
    border-color: var(--tk-felt-gold);
    transform: translateY(-3px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.35);
}

@media (prefers-reduced-motion: reduce) {
    .tk-center--prompt .tk-prompt .btn,
    .tk-center--prompt .tk-talon-group {
        transition: none;
    }

    .tk-center--prompt .tk-prompt .btn:hover,
    .tk-center--prompt .tk-prompt .btn:focus,
    .tk-center--prompt .tk-talon-group:hover {
        transform: none;
    }
}

/* ------------------------------------------------------------------ the auction

   Two decisions, not one list: the ladder of games you can take, and - set apart under a
   hairline - stepping out of the auction. */
.tk-prompt--bid .tk-bids {
    gap: 0.5rem 0.55rem;
    margin-top: 0.15rem;
}

/* Every rung the same size. The row was already centred - what read as crooked was that
   seven contracts whose names run from "Dve" to "Barvni valat" produced seven different
   button widths, so no two wrapped rows shared an edge and the ladder looked like a pile.
   A shared min-width (wide enough for the longest Slovenian label) plus the tightened side
   padding lands them all on one width, so the rows stack as a grid and a short last row
   centres under a full one. A longer label in another language still grows past it rather
   than being clipped - one wide rung is a far smaller price than a truncated bid name. */
.tk-prompt--bid .tk-bids .btn {
    flex: 0 1 auto;
    min-width: 11.5rem;
    padding-left: 0.85rem;
    padding-right: 0.85rem;
}

/* Centred, not baseline-aligned. The name is 0.95rem and the price is a 0.7rem pill with
   its own padding and line-height, so sharing a text baseline dropped every chip visibly
   below the label's optical centre - the ladder read as if the prices were sagging. The
   step-aside row next door has always used center; now the two halves of the auction panel
   agree. */
.tk-bid {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
}

.tk-bid__name {
    font-size: 0.95rem;
}

/* What the contract pays at this table. A chip rather than a parenthetical so the eye can
   scan the prices down the row without reading the names again. */
/* Fixed width as well as tabular figures: 20 and 250 have to make the same shape, or the
   price chips wobble down the ladder. */
.tk-bid__value {
    min-width: 2.5rem;
    padding: 0.05rem 0.4rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.16);
    font-size: 0.7rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.5;
    text-align: center;
}

.tk-center--prompt .tk-prompt .btn-outline-primary:hover .tk-bid__value,
.tk-center--prompt .tk-prompt .btn-outline-primary:focus .tk-bid__value {
    background: rgba(0, 0, 0, 0.18);
}

.tk-bid-out {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-top: 0.9rem;
    padding-top: 0.8rem;
    border-top: 1px solid rgba(255, 255, 255, 0.14);
}

.tk-bid-out__label {
    color: rgba(255, 255, 255, 0.6);
    font-size: 0.8rem;
}

/* Phones cannot spare 11.5rem a rung, and holding that width would put one bid per row.
   Drop the floor and let them grow into the row instead, so the ladder still fills the
   panel two-up rather than running off the bottom of the screen. Must stay AFTER the
   desktop rule above - same selector, so source order is what decides. */
@media (max-width: 575.98px) {
    .tk-prompt--bid .tk-bids .btn {
        flex: 1 1 auto;
        min-width: 8rem;
    }
}

/* The waiting line rewrites itself every few seconds (tickWaiting in table.js) and the lines
   run anywhere from "Waiting for luka..." to a full sentence, so reserve two lines of space up
   front: without it the trick below would hop up and down on every swap. */
.tk-center__waiting {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 2.6em;
    max-width: 26rem;
    padding: 0 0.75rem;
    color: rgba(255, 255, 255, 0.6);
    font-size: 0.9rem;
    font-style: italic;
    text-align: center;
    transition: opacity 0.25s ease;
}

/* Held for one beat while the text is replaced, so the line dissolves into the next one
   instead of snapping. */
.tk-wait-swap {
    opacity: 0;
}

.tk-waiting__pulse,
.tk-waiting__nudge {
    transition: opacity 0.25s ease;
}

/* The blinking call-to-act, small, sitting above the cards. */
.tk-turnflag {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 0.05rem;
    padding: 0.3rem 0.9rem;
    border: 1px solid var(--tk-tarok);
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.3);
    animation: tk-turnflag-blink 1.15s ease-in-out infinite;
}

.tk-turnflag__title {
    font-weight: 700;
    font-size: 0.9rem;
    color: var(--tk-tarok);
    letter-spacing: 0.02em;
}

.tk-turnflag__hint {
    font-size: 0.72rem;
    color: rgba(255, 255, 255, 0.7);
}

/* Watching somebody else's turn run down. Deliberately plain: it is a fact about another
   player, not a call to act, so it stays a quiet line rather than competing with the pill. */
.tk-turnflag__clock {
    margin-top: 0.4rem;
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
    color: rgba(255, 255, 255, 0.45);
    text-align: center;
}

/* Stacks the blinking "Your turn" flag and its clock without the pill inheriting the blink. */
.tk-turnzone {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 0.45rem;
}

/* ---------- The turn clock for whoever is on the clock ----------
   Structure and tokens lifted from .tk-tclock (the tournament chip), so being on the clock
   reads the same in an ordinary room as it does in a tournament: a pill, a draining track,
   and a number that turns red together with the bar in the last quarter. The difference is
   placement - the tournament parks its chip in the page header, while an ordinary room has
   the header free and wants the clock on the felt, next to the decision it belongs to. */
.tk-turnclock {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.4rem;
    padding: 0.25rem 0.6rem;
    border: 1px solid var(--border-default, rgba(128, 128, 128, 0.3));
    border-radius: 999px;
    background: var(--card-bg, #fff);
    font-size: 0.8125rem;
    line-height: 1;
    max-width: 100%;
    min-width: 0;
}

.tk-turnclock__track {
    position: relative;
    display: block;
    flex: 1 1 5rem;
    min-width: 3rem;
    max-width: 9rem;
    height: 0.375rem;
    border-radius: 999px;
    background: var(--bg-tertiary, rgba(128, 128, 128, 0.25));
    overflow: hidden;
}

.tk-turnclock__bar {
    display: block;
    height: 100%;
    width: 100%;
    border-radius: 999px;
    background: var(--tk-clock-bar);
    /* Matches the 1s tick in table.js so the bar glides instead of stepping. */
    transition: width 1s linear, background-color 0.3s ease;
}

.tk-turnclock__time {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--text-primary, #1a1a1a);
    white-space: nowrap;
}

.tk-turnclock.is-low .tk-turnclock__bar {
    background: var(--tk-red, #c0392b);
}

.tk-turnclock.is-low .tk-turnclock__time {
    color: var(--tk-red, #c0392b);
}

@media (prefers-reduced-motion: reduce) {
    .tk-turnclock__bar {
        transition: none;
    }
}

/* The room fuse: a full room deals itself, and this is the countdown saying so. Deliberately
   calm rather than alarming - it is good news (everyone is here), not a warning. */
.tk-waiting__countdown {
    margin: 0.5rem auto 0;
    padding: 0.35rem 0.9rem;
    border: 1px solid var(--tk-tarok);
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.25);
    color: var(--tk-tarok);
    font-weight: 600;
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.tk-waiting__pace {
    font-variant-numeric: tabular-nums;
}

@keyframes tk-turnflag-blink {
    0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(217, 181, 81, 0.0); }
    50% { opacity: 0.55; box-shadow: 0 0 12px 1px rgba(217, 181, 81, 0.35); }
}

@media (prefers-reduced-motion: reduce) {
    .tk-turnflag {
        animation: none;
        border-color: var(--tk-tarok);
    }
}

/* The end-of-hand scoresheet, framed on the felt like the bid controls: a translucent
   dark panel so the green shows through, with the muted greys lifted to stay legible. */
.tk-center--result {
    width: 100%;
}

.tk-center--result .tk-result {
    width: 100%;
    max-width: 34rem;
    text-align: left;
    color: #fff;
    background: rgba(10, 20, 15, 0.82);
    border-color: rgba(255, 255, 255, 0.16);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
    backdrop-filter: blur(3px);
}

.tk-center--result .tk-result__note,
.tk-center--result .tk-result__sheet-head,
.tk-center--result .tk-result__chips-label {
    color: rgba(255, 255, 255, 0.78);
}

.tk-center--result .tk-result__need-note {
    color: rgba(255, 255, 255, 0.55);
}

.tk-center--result .tk-pts__bar {
    background: rgba(255, 255, 255, 0.14);
}

.tk-center--result .tk-sheet td {
    border-bottom-color: rgba(255, 255, 255, 0.12);
}

.tk-center--result .tk-sheet tr:last-child td {
    border-top-color: rgba(255, 255, 255, 0.3);
}

/* Win/lose greens and reds pop brighter on the dark felt than the page defaults. */
.tk-center--result .tk-result__verdict--win,
.tk-center--result .tk-positive { color: #34d399; }
.tk-center--result .tk-result__verdict--lose,
.tk-center--result .tk-negative { color: #f87171; }

/* "Repeat" sits beside the solid "Next hand" on a practice table. Outline, so the primary
   action still reads first - but damped to the same weight as the prompt's outline buttons,
   since Bootstrap's near-white outline-light shouts on this dark panel. */
.tk-result__actions .btn-outline-light {
    border-color: rgba(255, 255, 255, 0.35);
    color: rgba(255, 255, 255, 0.85);
}

.tk-result__actions .btn-outline-light:hover,
.tk-result__actions .btn-outline-light:focus {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.6);
    color: #fff;
}

/* ---- "Wilder" discard on the felt: gold selection, springy hover, a live confirm ---- */
.tk-center--prompt .tk-card--selected {
    transform: translateY(-0.9rem) scale(1.04);
    box-shadow: 0 0 0 3px var(--tk-felt-gold),
                0 0 18px 2px rgba(217, 181, 81, 0.55),
                0 10px 20px rgba(0, 0, 0, 0.5);
}

.tk-center--prompt .tk-card--selected::after {
    background: linear-gradient(135deg, #f7dd8a, var(--tk-felt-gold));
    color: #1a1a1a;
    animation: tk-pick-pop 0.3s ease-out;
}

.tk-center--prompt .tk-card--playable:hover {
    transform: translateY(-0.55rem) rotate(-2deg);
    box-shadow: 0 0 14px 1px rgba(217, 181, 81, 0.4), 0 8px 16px rgba(0, 0, 0, 0.45);
}

.tk-center--prompt .tk-card--playable.tk-card--selected:hover {
    transform: translateY(-1.15rem) scale(1.05) rotate(-1deg);
}

@keyframes tk-pick-pop {
    0% { transform: scale(0) rotate(-30deg); }
    70% { transform: scale(1.35) rotate(8deg); }
    100% { transform: scale(1) rotate(0); }
}

/* The confirm button comes alive the instant the full set is chosen. */
.tk-center--prompt .tk-confirm {
    border-top-color: rgba(255, 255, 255, 0.18);
    justify-content: center;
}

.tk-center--prompt .tk-confirm__count {
    color: rgba(255, 255, 255, 0.85);
    font-size: 1.05rem;
}

.tk-center--prompt .tk-confirm .btn-primary:not(:disabled) {
    background: linear-gradient(135deg, #f7dd8a, var(--tk-felt-gold));
    border-color: var(--tk-felt-gold);
    color: #1a1a1a;
    font-weight: 700;
    animation: tk-confirm-pulse 1.1s ease-in-out infinite;
}

/* The undo sits beside the confirm on a dark translucent panel, where Bootstrap's own
   outline-secondary is close to invisible. Quiet on purpose - it must not compete with the
   confirm - but readable. */
.tk-center--prompt .tk-confirm .btn-outline-secondary {
    border-color: rgba(255, 255, 255, 0.35);
    color: rgba(255, 255, 255, 0.85);
}

.tk-center--prompt .tk-confirm .btn-outline-secondary:not(:disabled):hover {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.55);
    color: #fff;
}

@keyframes tk-confirm-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(217, 181, 81, 0); transform: translateY(0); }
    50% { box-shadow: 0 0 18px 4px rgba(217, 181, 81, 0.55); transform: translateY(-1px); }
}

@media (prefers-reduced-motion: reduce) {
    .tk-center--prompt .tk-card--selected::after,
    .tk-center--prompt .tk-confirm .btn-primary:not(:disabled) {
        animation: none;
    }
}

/* --------------------------------------------------- laying cards down (bury)

   One panel on the felt holds the whole decision: what is asked, how far along you are, the
   two controls, and the rule under them. The picking still happens in your own hand below -
   the fan keeps a single coaching line and nothing else. Splitting the panel in two (rule on
   the felt, count and confirm under the fan) meant five stacked lines that mostly repeated
   each other; merged, it still gets real padding and line spacing rather than reading as a
   cramped strip - there is plenty of felt around it to spend. */

.tk-center--prompt .tk-prompt--bury {
    padding: 1.1rem 1.4rem;
    text-align: left;
    /* A shade past the 38rem prompt cap: the point of this panel is that the question and
       both controls share one line, and a longer translation of either button label tips it
       over the default cap into a needless second row. */
    max-width: 46rem;
}

.tk-prompt--bury .tk-prompt__title {
    margin-bottom: 0;
    font-size: 1.05rem;
}

.tk-prompt--bury .tk-prompt__row {
    gap: 0.75rem 1.5rem;
}

.tk-prompt--bury .tk-prompt__hint {
    margin-bottom: 0;
    margin-top: 0.65rem;
    font-size: 0.85rem;
}

@media (min-width: 768px) {
    .tk-center--prompt .tk-prompt--bury {
        padding: 1.3rem 1.75rem;
    }

    .tk-prompt--bury .tk-prompt__row {
        gap: 0.75rem 2rem;
    }
}

/* Too narrow to put the question and its buttons side by side - centre both rows instead of
   leaving the buttons stranded against the right edge. */
@media (max-width: 575.98px) {
    .tk-center--prompt .tk-prompt--bury {
        text-align: center;
    }

    .tk-prompt--bury .tk-prompt__row {
        justify-content: center;
        text-align: center;
    }
}

/* A card the bury rules lock out is still clickable - clicking it explains why. renderCard
   only builds a <button> when it has a click handler, and a muted card only gets one while
   laying down, so this selector hits exactly those and never a dead card during play. */
.tk-hand button.tk-card--muted {
    cursor: help;
}

/* A card picked for the bury carries a tick (.tk-card--selected). While laying down, that
   tick is also the undo affordance, so it reads as a cross you can click rather than a
   decision already made - nothing has been sent to the server yet. */
.tk-card--undo::after {
    content: '✕';
    background: var(--color-error-500, #ef4444);
    transition: transform 0.12s ease;
}

@media (hover: hover) {
    .tk-card--undo:hover::after {
        transform: scale(1.15);
    }
}

/* The taroks the declarer buried face-up. Same shape as the talon strip it sits under,
   tinted with the tarok gold so it reads as "these are gone" rather than "these are in
   play". */
.tk-shown-strip .tk-talon-strip__group {
    background: rgba(227, 194, 115, 0.14);
    border: 1px dashed rgba(227, 194, 115, 0.5);
}

@media (prefers-reduced-motion: reduce) {
    .tk-card--undo::after {
        animation: none;
    }
}

/* ==========================================================================
   Standalone app (tarok.eventure.si) - slim skin + landing page
   ==========================================================================
   Chrome and landing styles for the standalone Tarok host. The game surfaces
   (.tk table/hub) are unchanged; these only dress the layouts/tarok.php shell
   and views/tarok/landing.php. All colours come from the platform semantic
   tokens so light/dark follows automatically. --tk-tarok is the gold accent
   already defined on .tk above.
   ========================================================================== */

.tarok-app {
    background: var(--bg-primary);
    color: var(--text-primary);
}

.tarok-app__header {
    padding: 0.4rem 0;
    background: var(--header-bg, var(--bg-secondary));
    border-bottom: 1px solid var(--header-border, var(--border-default));
}

/* Wordmark stacked over the live counter. The gap is the only thing separating them -
   the header keeps its own 0.4rem padding untouched, so this breathes the two lines
   apart without eating into the space below. */
.tarok-app__brand {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-width: 0;
}

/* Right group: everything on one inline row - language codes + user chip, then
   theme, leaderboard and log out. Below 480px it stacks into two right-aligned
   rows (language + user on top, controls beneath) so it never crowds on a phone. */
.tarok-app__nav {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.6rem;
}

@media (max-width: 480px) {
    .tarok-app__nav {
        flex-direction: column;
        align-items: flex-end;
        gap: 0.15rem;
    }
}

/* Top-right row: language codes + the signed-in user chip, kept compact. */
.tarok-app__brand-meta {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.6rem;
}

/* Tighter language codes here than the platform default (shared language.css). */
.tarok-app .tarok-app__brand-meta .language-text-toggle {
    gap: 0.1rem;
    padding: 0;
}

.tarok-app .tarok-app__brand-meta .language-toggle-link {
    padding: 0 0.15rem;
}

.tarok-app__wordmark {
    display: inline-flex;
    align-items: center;
    font-weight: 800;
    font-size: 1.25rem;
    letter-spacing: 0.01em;
    text-decoration: none;
    color: var(--text-primary);
}

.tarok-app__wordmark:hover {
    color: var(--tk-tarok);
}

/* The fancy logo: the "Tarok" word in the same italic Bodoni Moda Didone the card
   numerals use, so the wordmark echoes the deck. The heart stays sans/red. */
.tarok-app__wordmark-text {
    font-family: var(--font-family-bodoni-moda);
    font-style: italic;
    font-weight: 700;
    font-size: 1.5rem;
    letter-spacing: 0;
}

.tarok-app__wordmark .fa-heart {
    color: var(--tk-red, #c0392b);
}

.tarok-app__user {
    display: inline-flex;
    align-items: center;
    color: var(--text-secondary);
    font-size: 0.8rem;
    line-height: 1;
}

/* ----- Staff menu ---------------------------------------------------------- */

/* The staff menu is an ordinary nav button that happens to open a panel - same
   btn-outline-secondary btn-sm as Leaderboard and Tournaments beside it, so the header row
   reads identically whoever is looking. Bootstrap's dropdown plugin drives it (the layout
   registers BootstrapPluginAsset), so everything here is presentation - no show/hide state
   is managed in CSS. */

.tarok-app__menu {
    /* .dropdown already supplies position: relative; this is a styling hook only. */
    display: inline-flex;
}

.tarok-app__caret {
    font-size: 0.6rem;
    transition: transform 0.15s ease;
}

/* Bootstrap maintains aria-expanded, so there is no extra class to keep in sync. */
.tarok-app__menu-toggle[aria-expanded="true"] .tarok-app__caret {
    transform: rotate(180deg);
}

/* Same radius, border and shadow as .tarok-live__pop, so the header's two panels are
   visibly one family. */
.tarok-app__menu-panel {
    min-width: 15rem;
    padding: 0.5rem;
    border: 1px solid var(--border-default);
    border-radius: 0.6rem;
    background: var(--bg-primary);
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.18);
}

.tarok-app__menu-panel .dropdown-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.5rem;
    border-radius: 0.4rem;
    color: var(--text-primary);
    font-size: 0.85rem;
}

.tarok-app__menu-panel .dropdown-item:hover,
.tarok-app__menu-panel .dropdown-item:focus {
    background: var(--bg-secondary);
    color: var(--text-primary);
}

/* Fixed width so the icons line up in a column. */
.tarok-app__menu-icon {
    width: 1rem;
    text-align: center;
}

/* The logout form wraps a .dropdown-item; it must not add form margin inside the panel. */
.tarok-app__menu-form {
    margin: 0;
}

.tarok-app__menu-name {
    padding: 0.25rem 0.35rem 0.35rem;
}

.tarok-app__menu-label {
    display: block;
    margin-bottom: 0.25rem;
    color: var(--text-secondary);
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* Reserve the line so the panel does not jump when a message appears. */
.tarok-app__menu-msg {
    min-height: 1rem;
    margin-top: 0.25rem;
    color: var(--text-secondary);
    font-size: 0.72rem;
}

.tarok-app__menu-msg--ok {
    color: var(--bs-success, #198754);
}

.tarok-app__menu-msg--error {
    color: var(--tk-red, #c0392b);
}

@media (max-width: 480px) {
    .tarok-app__menu-panel {
        min-width: 13rem;
    }
}

/* Dark mode stays minimal: the layout sets data-bs-theme on <html>, so Bootstrap 5.3
   already recolours .dropdown-menu / .dropdown-item from its own tokens. Only the pieces
   restyled above need an override. */
[data-theme="dark"] .tarok-app__menu-panel {
    background: var(--bg-secondary);
    border-color: var(--border-default);
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.45);
}

[data-theme="dark"] .tarok-app__menu-panel .dropdown-item:hover,
[data-theme="dark"] .tarok-app__menu-panel .dropdown-item:focus {
    background: rgba(255, 255, 255, 0.06);
}

/* Keep the language + theme toggles vertically centred with the buttons. */
.tarok-app__toggle {
    display: inline-flex;
    align-items: center;
}

.tarok-app__footer {
    padding: 1.5rem 0;
    background: var(--footer-bg, var(--bg-secondary));
    border-top: 1px solid var(--footer-border, var(--border-default));
}

/* Centered, stacked blocks: pitch, modules, stats, link columns, rules. */
.tarok-app__footer-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 1.1rem;
}

.tarok-app__footer-pitch {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
}

.tarok-app__footer-pitch-text {
    margin: 0;
    max-width: 38rem;
    font-size: 0.9rem;
    color: var(--text-secondary);
}

.tarok-app__footer-cta {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem;
}

/* Module tiles: N per row (--tk-mod-cols set inline), tiles grow so a short last
   row stretches to the end and every row ends flush. */
.tarok-app__footer-modules {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    width: 100%;
    max-width: 52rem;
}

.tarok-app__footer-module {
    flex: 1 1 calc(100% / var(--tk-mod-cols, 4) - 0.5rem);
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 0.7rem;
    border: 1px solid var(--border-default);
    border-radius: 0.5rem;
    font-size: 0.8rem;
    text-align: left;
    color: var(--text-secondary);
    text-decoration: none;
}

.tarok-app__footer-module i {
    width: 1.1rem;
    text-align: center;
    color: var(--tk-tarok, #8a6d1f);
}

.tarok-app__footer-module:hover {
    color: var(--text-primary);
    border-color: var(--tk-tarok, #8a6d1f);
}

.tarok-app__footer-stats {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.3rem 1.4rem;
    font-size: 0.8rem;
    color: var(--text-secondary);
}

.tarok-app__footer-stat strong {
    color: var(--text-primary);
}

@media (max-width: 575.98px) {
    .tarok-app__footer-module {
        flex-basis: calc(50% - 0.5rem);
    }
}

.tarok-app__footer-left {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.4rem;
}

.tarok-app__footer-brand-line {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    white-space: nowrap;
}

.tarok-app__footer-heart {
    color: var(--tk-red, #c0392b);
    font-size: 0.85em;
}

.tarok-app__footer-mark {
    font-weight: 700;
    color: var(--text-primary);
}

.tarok-app__footer-dim {
    color: var(--text-secondary);
    font-size: 0.9rem;
}

/* The platform, emphasised - the one link that should stand out down here. */
.tarok-app__footer-brand {
    font-weight: 700;
    color: var(--tk-tarok, #8a6d1f);
    text-decoration: none;
}

.tarok-app__footer-brand:hover {
    text-decoration: underline;
}

.tarok-app__footer-links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 0.4rem 0.9rem;
    font-size: 0.85rem;
}

.tarok-app__footer-links a {
    color: var(--text-secondary);
    text-decoration: none;
}

.tarok-app__footer-links a:hover {
    color: var(--text-primary);
}

/* Thin separators between the discovery links. */
.tarok-app__footer-links > * + * {
    position: relative;
    padding-left: 0.9rem;
}

.tarok-app__footer-links > .tarok-app__footer-copy {
    font-weight: 600;
    color: var(--text-primary);
    margin-right: 0.9rem;
}

/* The copyright is set apart by space, not a separator. */
.tarok-app__footer-links > .tarok-app__footer-copy + a {
    padding-left: 0;
}

.tarok-app__footer-links > .tarok-app__footer-copy + a::before {
    display: none;
}

.tarok-app__footer-links > * + *::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    height: 0.8em;
    border-left: 1px solid var(--border-default);
}

/* The dedication - why this game exists. Meant to be found, not announced: small,
   muted, and the last row of the footer so it reads as a signature rather than copy. */
.tarok-app__footer-dedication {
    margin: 0;
    font-size: 0.8125rem;
    letter-spacing: 0.02em;
}

/* The sentence itself carries the muted/italic/faded treatment - kept off the paragraph
   so it does not also wash out the suit pips (opacity dims a whole subtree, not just color). */
.tarok-app__footer-dedication-text {
    font-style: italic;
    color: var(--text-muted, var(--text-secondary));
    opacity: 0.75;
}

/* Suit pips framing the dedication - hearts/diamonds red, spades/clubs a fixed black
   (same as card suits) in both themes, full opacity so they read at a glance rather
   than fading with the muted sentence. */
.tarok-app__footer-dedication-suit {
    font-style: normal;
    font-size: 1.3em;
    line-height: 1;
    vertical-align: -0.05em;
    opacity: 1;
}

/* --tk-red/--tk-black are declared on .tk (the card-table wrapper) - the footer sits
   outside it, so both need an explicit fallback or var() resolves to nothing here and
   silently falls back to the inherited muted text color instead of erroring loudly. */
.tarok-app__footer-dedication-suit--red {
    color: var(--tk-red, #c0392b);
}

[data-theme="dark"] .tarok-app__footer-dedication-suit--red {
    color: #e8776a;
}

/* Explicitly black in both themes - the card-suit black, not the theme-adaptive
   --text-primary, which would flip to near-white in dark mode. */
.tarok-app__footer-dedication-suit--black {
    color: var(--tk-black, #1a1a1a);
}

/* ----- Header live counter ------------------------------------------------ */

/* line-height 1 trims the Bodoni descender space under the wordmark, so the 2px gap on
   .tarok-app__brand is the real distance between the two lines rather than the leftover
   of a tall line box. The stacking itself lives on .tarok-app__brand above. */
.tarok-app__brand .tarok-app__wordmark {
    line-height: 1;
}

/* "N + M guests - K rooms", sitting quietly under the heart and the Tarok wordmark.
   Deliberately much smaller and dimmer than the wordmark above it: ambient reassurance
   that the game is alive, never a second title competing with it. */
.tarok-live {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.68rem;
    line-height: 1.2;
    letter-spacing: 0.01em;
    color: var(--text-secondary);
    cursor: default;
    border-radius: 999px;
    padding: 0 0 0 0.15rem;
    transition: color 0.25s ease;
}

.tarok-live[hidden] {
    display: none;
}

/* Exactly one mount is visible at a time. Normally that is the header one; in fullscreen
   the page header is gone, so the inline copy after the table code takes over. The
   [hidden] rules above still win until presence.js has data for either of them. */
.tarok-live--inline {
    display: none;
}

/* vertical-align: middle, not baseline: an inline-flex box takes its baseline from its
   first flex item, which on this smaller type sits noticeably high against the meta
   line. Middle centres the whole box against the text instead. */
body.tk-fullscreen .tarok-live--inline:not([hidden]) {
    display: inline-flex;
    margin-left: 0.5rem;
    vertical-align: middle;
}

/* The meta text itself is baseline-aligned inline content, so nudge the counter's own
   line box to sit centred rather than riding the cap height. */
.tarok-live--inline .tarok-live__part,
.tarok-live--inline .tarok-live__val {
    line-height: 1;
}

/* On a phone the meta line has no room left after the table code, so the counter drops
   to its own line underneath instead of crowding it. display:flex makes it block-level
   (hence the line break) while fit-content keeps the box - and the hover target - hugging
   the text rather than stretching the full width. */
@media (max-width: 578px) {
    body.tk-fullscreen .tarok-live--inline:not([hidden]) {
        display: flex;
        width: fit-content;
        margin-left: 0;
        margin-top: 0.15rem;
    }
}

/* The inline copy sits in a dim meta line - let it carry that line's own colour rather
   than competing with the table code it follows. */
.tarok-live--inline .tarok-live__dot {
    width: 0.3rem;
    height: 0.3rem;
}

.tarok-live:hover,
.tarok-live:focus-visible {
    color: var(--text-primary);
    outline: none;
}

/* The live dot - a slow, barely-there breath so the row reads as "now" without
   flickering in the corner of the eye. */
.tarok-live__dot {
    width: 0.34rem;
    height: 0.34rem;
    border-radius: 50%;
    background: var(--tk-live-dot, #2fae5e);
    box-shadow: 0 0 0 0 rgba(47, 174, 94, 0.5);
    animation: tk-live-breathe 3.2s ease-in-out infinite;
    flex: 0 0 auto;
}

@keyframes tk-live-breathe {
    0%, 100% { opacity: 0.55; }
    50% { opacity: 1; }
}

/* Resting state: the dot stops breathing and goes grey, and the empty rooms half
   collapses so no stray separator is left hanging. */
.tarok-live.is-idle .tarok-live__dot {
    background: var(--text-secondary);
    animation: none;
    opacity: 0.45;
}

.tarok-live.is-idle .tarok-live__sep {
    display: none;
}

/* Each value lives in its own clipped box so the outgoing copy can slide out of it. */
.tarok-live__part {
    position: relative;
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
    font-variant-numeric: tabular-nums;
    transition: color 0.6s ease;
}

.tarok-live__sep::before {
    content: "\00b7";
    opacity: 0.55;
}

.tarok-live__val {
    display: inline-block;
    white-space: nowrap;
}

/* Roll-up: the old value leaves through the top, the new one rises into its place. */
.tarok-live__val--out {
    position: absolute;
    left: 0;
    top: 0;
    animation: tk-live-roll-out 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

.tarok-live__val--in {
    animation: tk-live-roll-in 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

@keyframes tk-live-roll-out {
    to { transform: translateY(-110%); opacity: 0; }
}

@keyframes tk-live-roll-in {
    from { transform: translateY(110%); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}

/* Growth tint: the numbers flush green, then settle back to the ambient grey. */
.tarok-live.is-bump .tarok-live__part {
    color: var(--tk-live-up, #2fae5e);
    transition: color 0.1s ease;
}

.tarok-live.is-bump .tarok-live__dot {
    animation: tk-live-ping 0.9s ease-out;
}

@keyframes tk-live-ping {
    0% { box-shadow: 0 0 0 0 rgba(47, 174, 94, 0.55); opacity: 1; }
    70% { box-shadow: 0 0 0 0.5rem rgba(47, 174, 94, 0); opacity: 1; }
    100% { box-shadow: 0 0 0 0 rgba(47, 174, 94, 0); opacity: 1; }
}

/* Both hearts - header wordmark and footer brand line - thump twice when the live
   counter grows, so a new arrival registers wherever the reader is on the page. Two
   beats with a rest between them, the shape of a real pulse rather than a throb. */
.tarok-heart.is-beating {
    animation: tk-heartbeat 1s ease-in-out;
    transform-origin: center;
}

@keyframes tk-heartbeat {
    0% { transform: scale(1); }
    14% { transform: scale(1.32); }
    28% { transform: scale(1); }
    42% { transform: scale(1.24); }
    60%, 100% { transform: scale(1); }
}

/* ----- Live counter breakdown popover ------------------------------------- */

/* Hand-rolled on purpose: plain CSS hover/focus state - no JS show/hide, nothing to
   leak if the poller dies. (The layout does load Bootstrap's plugin bundle, which the
   staff menu above uses - but a passive hover readout needs none of it.) */
.tarok-live__pop {
    position: absolute;
    /* Opens downward and left-aligned: the counter now lives at the top-left of the
       viewport, so an upward/centered panel would clip off the top and the left edge. */
    top: calc(100% + 0.5rem);
    left: 0;
    transform: translateY(-0.25rem);
    z-index: 20;
    min-width: 13.5rem;
    padding: 0.7rem 0.8rem;
    border-radius: 0.6rem;
    border: 1px solid var(--border-default);
    background: var(--bg-primary);
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.18);
    text-align: left;
    font-size: 0.78rem;
    color: var(--text-primary);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
}

.tarok-live:hover .tarok-live__pop,
.tarok-live:focus-visible .tarok-live__pop,
.tarok-live:focus-within .tarok-live__pop {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

/* Little arrow tying the panel to the counter, pointing back up at it. */
.tarok-live__pop::after {
    content: "";
    position: absolute;
    bottom: 100%;
    left: 0.9rem;
    border: 0.35rem solid transparent;
    border-bottom-color: var(--bg-primary);
}

.tarok-live__pop-title {
    font-weight: 700;
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin-bottom: 0.3rem;
}

/* Every group after the first gets air and a hairline above it. */
.tarok-live__pop-title ~ .tarok-live__pop-title {
    margin-top: 0.6rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--border-default);
}

.tarok-live__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1.25rem;
    padding: 0.1rem 0;
}

.tarok-live__row-label {
    color: var(--text-secondary);
}

.tarok-live__row-value {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.tarok-live__pop-foot {
    margin-top: 0.55rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--border-default);
    font-size: 0.7rem;
    color: var(--text-secondary);
}

/* Motion here is pure decoration - the counts are already legible without it. */
@media (prefers-reduced-motion: reduce) {
    .tarok-live__dot,
    .tarok-live.is-bump .tarok-live__dot,
    .tarok-live__val--in,
    .tarok-live__val--out,
    .tarok-heart.is-beating {
        animation: none;
    }

    .tarok-live__val--out {
        display: none;
    }

    .tarok-live__pop {
        transition: none;
    }
}

/* ----- Landing ----------------------------------------------------------- */

.tarok-landing__hero {
    padding: clamp(3rem, 8vw, 6rem) 0 clamp(2rem, 5vw, 3.5rem);
    background:
        radial-gradient(120% 120% at 50% 0%, var(--tl-hero-glow, rgba(138, 109, 31, 0.12)), transparent 60%),
        var(--bg-primary);
}

.tarok-landing__title {
    font-family: var(--tl-font-heading, inherit);
    font-weight: var(--tl-title-weight, 800);
    font-size: clamp(2rem, 5vw, 3.25rem);
    margin-bottom: 0.75rem;
}

.tarok-landing__lead {
    max-width: 42rem;
    margin: 0 auto 1.75rem;
    font-size: clamp(1.05rem, 2vw, 1.25rem);
    color: var(--text-secondary);
}

/* Wraps the quick-start grid together with the Colour valat switch above it, so the switch
   is a sibling of the grid rather than an accidental 5th grid cell. A plain flex column
   centres correctly under the .text-center landing sections, and flows left inside the
   hub's non-centred .tk-prompt box like every other child already does there. */
.tarok-quickstart-panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
}

.tarok-quickstart-panel--compact {
    gap: 0.5rem;
}

/* Colour valat switch - not a form field of its own, see web/js/tarok/quickstart-valat.js
   for how its state reaches the hidden barvni_valat field inside each card's form. Off is
   quiet; on goes full rainbow-and-glow, since this is the one control telling a visitor
   "here be a game real tarok does not actually play" (games/tarok/RULES.md 8, open
   question 5). Same visually-hidden-input + sibling track/knob technique as .wb-rect-switch
   (web/css/wb-switch.css) and .theme-toggle-switch (web/css/theme.css) - neither file is
   loaded on tarok pages, so the structure is reused here rather than the class. */
.tk-valat-switch {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    cursor: pointer;
    user-select: none;
}

.tk-valat-switch__input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.tk-valat-switch__track {
    position: relative;
    display: inline-block;
    width: 3rem;
    height: 1.6rem;
    flex-shrink: 0;
    border-radius: 999px;
    background: var(--bg-tertiary, rgba(128, 128, 128, 0.25));
    border: 1px solid var(--border-default, rgba(128, 128, 128, 0.35));
    transition: background 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}

.tk-valat-switch__knob {
    position: absolute;
    top: 50%;
    left: 0.15rem;
    transform: translateY(-50%);
    width: 1.2rem;
    height: 1.2rem;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
    transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.tk-valat-switch__label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-secondary);
    transition: color 0.2s ease, text-shadow 0.2s ease;
}

.tk-valat-switch__input:checked ~ .tk-valat-switch__track .tk-valat-switch__knob {
    transform: translate(1.4rem, -50%);
}

/* The rainbow: same scrolling-gradient + hue-rotate recipe as .navbar-brand-beta:hover
   (web/css/header.css), given its own tk-scoped keyframes since that file is not loaded
   here - the technique is reused, not a cross-file class reference. */
.tk-valat-switch__input:checked ~ .tk-valat-switch__track {
    border-color: transparent;
    background: linear-gradient(120deg, #ff3d81, #ff8a3d, #ffd23d, #43e97b, #38b6ff, #b06bff, #ff3d81);
    background-size: 320% 320%;
    animation: tk-valat-switch-party 3s linear infinite, tk-valat-switch-glow 2.4s ease-in-out infinite;
}

.tk-valat-switch__input:checked ~ .tk-valat-switch__label {
    color: var(--tk-tarok, #8a6d1f);
    text-shadow: 0 0 6px rgba(255, 210, 61, 0.5);
}

.tk-valat-switch__input:focus-visible ~ .tk-valat-switch__track {
    outline: 2px solid var(--link-default, #3b82f6);
    outline-offset: 2px;
}

@keyframes tk-valat-switch-party {
    0%   { background-position: 0% 50%;   filter: hue-rotate(0deg); }
    100% { background-position: 320% 50%; filter: hue-rotate(360deg); }
}

@keyframes tk-valat-switch-glow {
    0%, 100% { box-shadow: 0 0 10px rgba(255, 61, 129, 0.45), 0 0 4px rgba(255, 255, 255, 0.35); }
    50%      { box-shadow: 0 0 16px rgba(255, 61, 129, 0.65), 0 0 7px rgba(255, 255, 255, 0.5); }
}

@media (prefers-reduced-motion: reduce) {
    .tk-valat-switch__input:checked ~ .tk-valat-switch__track {
        animation: none;
        box-shadow: 0 0 10px rgba(255, 61, 129, 0.45), 0 0 4px rgba(255, 255, 255, 0.35);
    }
    .tk-valat-switch__track,
    .tk-valat-switch__knob {
        transition: none;
    }
}

/* Quick-start: a symmetric 2x2 matrix of tappable cards. A guest gets the same four,
   with the two multiplayer ones in the locked state below. */
.tarok-quickstart {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.85rem;
    max-width: 30rem;
}

.tarok-quickstart__form {
    margin: 0;
    display: flex;
}

.tarok-quickstart__btn {
    position: relative; /* the locked badge hangs off the top-right corner */
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.3rem;
    width: 100%;
    padding: 1.25rem 1rem;
    border: 1px solid var(--card-border, var(--border-default));
    border-radius: var(--border-radius-lg, 0.9rem);
    background: var(--card-bg);
    color: var(--text-primary);
    box-shadow: var(--card-shadow, none);
    cursor: pointer;
    text-decoration: none; /* the locked cell is an <a>, the rest are <button>s */
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.tarok-quickstart__btn:hover {
    text-decoration: none;
}

.tarok-quickstart__btn:hover,
.tarok-quickstart__btn:focus-visible {
    transform: translateY(-3px);
    border-color: var(--tk-tarok, #8a6d1f);
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.14);
    outline: none;
}

.tarok-quickstart__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.6rem;
    height: 2.6rem;
    margin-bottom: 0.15rem;
    border-radius: 50%;
    font-size: 1.15rem;
}

/* A quiet colour cue so the two modes read apart without breaking symmetry. */
.tarok-quickstart__btn[data-mode="cpu"] .tarok-quickstart__icon {
    background: var(--tk-tarok-bg, #fdf6e3);
    color: var(--tk-tarok, #8a6d1f);
}

.tarok-quickstart__btn[data-mode="friends"] .tarok-quickstart__icon {
    background: var(--tl-friends-bg, rgba(59, 130, 246, 0.12));
    color: var(--tl-friends, #3b82f6);
}

/* Locked: the card a guest cannot use yet. Dimmed by draining its own colours rather than
   by a blanket opacity - the same call .tk-card--muted makes, and for the same reason (a
   card at 40% over a dark page stops being readable). It keeps the hover lift because it
   IS still a link: clicking it goes to the login form. */
.tarok-quickstart__btn--locked {
    border-style: dashed;
    background: var(--bg-secondary, var(--card-bg));
    box-shadow: none;
}

.tarok-quickstart__btn--locked .tarok-quickstart__title,
.tarok-quickstart__btn--locked .tarok-quickstart__count {
    color: var(--text-secondary);
}

.tarok-quickstart__btn--locked[data-mode="friends"] .tarok-quickstart__icon {
    background: var(--bg-subtle, rgba(128, 128, 128, 0.15));
    color: var(--text-secondary);
}

/* Corner ribbon saying why. Same shape as the .tk-status pill. */
.tarok-quickstart__badge {
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    padding: 0.05rem 0.45rem;
    border-radius: 999px;
    background: var(--bg-subtle, rgba(128, 128, 128, 0.15));
    color: var(--text-secondary, #6c757d);
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* The compact cells are short and left-aligned, so the ribbon would sit on top of the
   title - park it at the trailing edge, vertically centred, instead. */
.tarok-quickstart--compact .tarok-quickstart__badge {
    top: 50%;
    right: 0.5rem;
    transform: translateY(-50%);
}

[data-theme="dark"] .tarok-quickstart__badge,
[data-theme="dark"] .tarok-quickstart__btn--locked[data-mode="friends"] .tarok-quickstart__icon {
    background: rgba(255, 255, 255, 0.08);
}

.tarok-quickstart__title {
    font-weight: 700;
    font-size: 0.98rem;
    line-height: 1.2;
    text-align: center;
}

.tarok-quickstart__count {
    color: var(--text-secondary);
    font-size: 0.82rem;
}

/* Compact variant: the closing CTA repeats the same cells, but re-laid from tall stacked
   cards into short horizontal ones so it reads as a reminder rather than a second hero.
   Grid areas do the work, so the markup stays identical to the hero's. */
.tarok-quickstart--compact {
    max-width: 26rem;
    gap: 0.6rem;
}

/* "Bring friends, host a tournament" - the one-line progress teaser (_hosting-chip.php) on
   the lobby and landing pages. Same purple accent as .tk-status--valat, so the platform's
   two "here is something extra" pills read as one family without competing for attention. */
.tk-hosting-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.35rem 0.85rem;
    border-radius: 999px;
    border: 1px solid rgba(111, 66, 193, 0.3);
    background: rgba(111, 66, 193, 0.1);
    color: #6f42c1;
    font-size: 0.85rem;
    font-weight: 600;
    text-decoration: none;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.tk-hosting-chip:hover,
.tk-hosting-chip:focus-visible {
    color: #6f42c1;
    text-decoration: none;
    transform: translateY(-1px);
    box-shadow: 0 6px 16px rgba(111, 66, 193, 0.18);
}

.tk-hosting-chip--unlocked {
    border-color: rgba(25, 135, 84, 0.3);
    background: rgba(25, 135, 84, 0.1);
    color: #146c43;
}

.tk-hosting-chip--unlocked:hover,
.tk-hosting-chip--unlocked:focus-visible {
    color: #146c43;
    box-shadow: 0 6px 16px rgba(25, 135, 84, 0.18);
}

[data-theme="dark"] .tk-hosting-chip {
    border-color: rgba(111, 66, 193, 0.46);
    background: rgba(111, 66, 193, 0.22);
    color: #c9b3f0;
}

[data-theme="dark"] .tk-hosting-chip:hover,
[data-theme="dark"] .tk-hosting-chip:focus-visible {
    color: #c9b3f0;
}

[data-theme="dark"] .tk-hosting-chip--unlocked {
    border-color: rgba(25, 135, 84, 0.42);
    background: rgba(25, 135, 84, 0.22);
    color: #8fe0b5;
}

[data-theme="dark"] .tk-hosting-chip--unlocked:hover,
[data-theme="dark"] .tk-hosting-chip--unlocked:focus-visible {
    color: #8fe0b5;
}

/* The fuller progress panel on /my tournaments (_hosting-panel.php) - a plain card, so it
   needs no theme overrides of its own beyond what .card and .tk-share already carry. */
.tk-hosting-panel .progress {
    height: 0.6rem;
}

/* "Special offer: host a tournament for free" - the guest registration hook on the landing
   page (_guest-offer.php). Warm gold, the same --tk-tarok/--tk-tarok-bg pair the quickstart
   cpu-mode icon uses (:225 and around) - deliberately distinct from the blue .tk-formnote
   info box and the purple .tk-hosting-chip progress pill, so this reads as a celebratory
   highlight rather than either "here is a fact" or "here is your status". Both tokens
   already swap per theme on their own (defined once under :root and once under
   [data-theme="dark"] .tk near the top of this file), so no separate dark block is needed
   here. */
.tarok-guest-offer {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    max-width: 32rem;
    margin: 0 auto;
    padding: 1.5rem;
    border: 1px solid var(--tk-tarok);
    border-radius: var(--border-radius-lg, 0.9rem);
    background: var(--tk-tarok-bg);
    text-align: center;
}

.tarok-guest-offer__eyebrow {
    padding: 0.15rem 0.7rem;
    border-radius: 999px;
    background: var(--tk-tarok);
    color: var(--tk-tarok-bg);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.tarok-guest-offer__title {
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--tk-tarok);
}

.tarok-guest-offer__body {
    margin: 0;
    font-size: 0.9rem;
    color: var(--text-secondary);
}

.tarok-guest-offer__cta {
    margin-top: 0.35rem;
    background: var(--tk-tarok);
    border-color: var(--tk-tarok);
    color: var(--tk-tarok-bg);
}

.tarok-guest-offer__cta:hover,
.tarok-guest-offer__cta:focus-visible {
    background: var(--tk-tarok);
    border-color: var(--tk-tarok);
    color: var(--tk-tarok-bg);
    filter: brightness(1.08);
}

/* The compact one-liner repeated in the closing CTA - same family as .tk-hosting-chip, gold
   instead of purple/green so a guest never confuses "unlocked" with "here is an offer". */
.tarok-guest-offer--compact {
    display: inline-flex;
    /* Row, not the column the big banner above uses (it shares .tarok-guest-offer), and no
       32rem cap - the pill is one line: a big trophy, then the label. */
    flex-direction: row;
    max-width: 100%;
    margin: 0;
    white-space: nowrap;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 1.1rem 0.45rem 0.9rem;
    border-radius: 999px;
    border: 1px solid var(--tk-tarok);
    background: var(--tk-tarok-bg);
    color: var(--tk-tarok);
    font-size: 0.85rem;
    font-weight: 600;
    text-decoration: none;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.tarok-guest-offer--compact .fa-trophy,
.tarok-guest-offer--compact .fa-ranking-star {
    margin: 0 !important;
    font-size: 1.75rem;
    line-height: 1;
}

/* The two guest pills (offer + members-only leaderboard), one above the other, centred. */
.tarok-guest-offer__pills {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
}

/* The leaderboard pill: same family, filled accent so "members only" reads as the prize. */
.tarok-guest-offer--board,
.tarok-guest-offer--board:hover,
.tarok-guest-offer--board:focus-visible {
    background: var(--tk-tarok);
    color: var(--tk-tarok-bg);
}

/* The banner's leaderboard line (hero). */
.tarok-guest-offer__board {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--tk-tarok);
}

/* A phone cannot fit the whole label on one line - let it wrap beside the trophy there. */
@media (max-width: 575.98px) {
    .tarok-guest-offer--compact {
        white-space: normal;
        text-align: left;
    }
}

.tarok-guest-offer--compact:hover,
.tarok-guest-offer--compact:focus-visible {
    color: var(--tk-tarok);
    text-decoration: none;
    transform: translateY(-1px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
}

.tarok-quickstart--compact .tarok-quickstart__btn {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas:
        "icon title"
        "icon count";
    align-items: center;
    justify-items: start;
    column-gap: 0.6rem;
    padding: 0.7rem 0.85rem;
    text-align: left;
}

.tarok-quickstart--compact .tarok-quickstart__icon {
    grid-area: icon;
    width: 2rem;
    height: 2rem;
    margin-bottom: 0;
    font-size: 0.95rem;
}

.tarok-quickstart--compact .tarok-quickstart__title {
    grid-area: title;
    font-size: 0.88rem;
    text-align: left;
}

.tarok-quickstart--compact .tarok-quickstart__count {
    grid-area: count;
    font-size: 0.76rem;
}

@media (max-width: 400px) {
    .tarok-quickstart { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
    .tarok-quickstart__btn { transition: none; }
    .tarok-quickstart__btn:hover,
    .tarok-quickstart__btn:focus-visible { transform: none; }
}

.tarok-landing__rooms {
    padding: clamp(2rem, 5vw, 3.5rem) 0;
}

.tarok-landing__rooms-list {
    max-width: 34rem;
}

.tarok-landing__joincode {
    max-width: 26rem;
}

.tarok-landing__board {
    padding: clamp(2rem, 5vw, 3.5rem) 0;
    background: var(--bg-secondary);
}

.tarok-landing__board-list {
    max-width: 32rem;
    margin: 0 auto;
    padding: 0;
    list-style: none;
    counter-reset: tarok-rank;
}

.tarok-landing__board-row {
    counter-increment: tarok-rank;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.9rem;
    border-bottom: 1px solid var(--border-default);
}

.tarok-landing__board-row:last-child {
    border-bottom: 0;
}

.tarok-landing__board-row::before {
    content: counter(tarok-rank);
    flex: 0 0 1.6rem;
    font-weight: 700;
    color: var(--tk-tarok, #8a6d1f);
    text-align: center;
}

.tarok-landing__board-name {
    flex: 1 1 auto;
    font-weight: 600;
}

.tarok-landing__board-rating {
    color: var(--text-secondary);
    font-size: 0.9rem;
    white-space: nowrap;
}

.tarok-landing__outro {
    padding: clamp(2.5rem, 6vw, 4rem) 0;
}

/* The share row is the last thing on the page now that the dedication moved into the
   sitewide footer, so it takes no top padding of its own - the outro above it has
   already left plenty. */
.tarok-landing__share {
    padding: 0 0 clamp(1.5rem, 4vw, 2.5rem);
}

/* ----- Landing FAQ ------------------------------------------------------- */
.tarok-landing__faq {
    padding: clamp(2rem, 5vw, 3.5rem) 0;
    background: var(--bg-secondary);
}

.tarok-landing__faq-list {
    max-width: 44rem;
}

.tarok-landing__faq-item {
    border-bottom: 1px solid var(--border-default);
}

.tarok-landing__faq-q {
    margin: 0;
    font-size: 1rem;
}

.tarok-landing__faq-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    padding: 1rem 0.25rem;
    background: none;
    border: 0;
    text-align: left;
    font: inherit;
    font-weight: 600;
    color: var(--text-primary);
    cursor: pointer;
}

.tarok-landing__faq-icon {
    flex: 0 0 auto;
    font-size: 0.85rem;
    color: var(--text-secondary);
    transition: transform 0.2s ease;
}

.tarok-landing__faq-toggle:not(.collapsed) .tarok-landing__faq-icon {
    transform: rotate(180deg);
}

.tarok-landing__faq-a {
    padding: 0 0.25rem 1.1rem;
    color: var(--text-secondary);
    line-height: 1.6;
}

/* ------------------------------------------------------------------ badges
   The learner milestone ladder. Earned rungs take the gold accent the board already
   uses; unearned ones stay flat so the strip reads as progress, not decoration. */
.tk-badges__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.6rem;
}

.tk-badges__title {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.75;
}

.tk-badges__count {
    font-weight: 700;
    color: var(--tk-tarok);
    font-variant-numeric: tabular-nums;
}

.tk-badges__grid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.tk-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.65rem;
    border: 1px solid var(--border-color, rgba(128, 128, 128, 0.35));
    border-radius: 2rem;
    font-size: 0.82rem;
    opacity: 0.45;
    cursor: default;
}

.tk-badge--earned {
    opacity: 1;
    border-color: var(--tk-tarok);
    background: var(--tk-tarok-bg);
    color: var(--tk-tarok);
    font-weight: 600;
}

.tk-badge__icon {
    font-size: 0.9rem;
}

/* Earned-badge icons trailing a leaderboard name. */
.tk-board__badges {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

.tk-board__badge {
    font-size: 0.75rem;
    color: var(--tk-tarok);
    opacity: 0.85;
}

.tk-board__badge-more {
    font-size: 0.7rem;
    opacity: 0.6;
    font-variant-numeric: tabular-nums;
}

/* The badge glyph inside a toast - toastr renders our HTML, so this styles it there. */
.tk-toast-badge {
    display: inline-block;
    margin-right: 0.4rem;
}

/* A link inside a toast (the guest "keep your badges" signup nudge). Toastr's palette
   would leave it the same colour as the surrounding text - underline it so it reads as
   the way out, not as decoration. */
.tk-toast-link {
    color: inherit;
    text-decoration: underline;
}

/* The invite row on the hand-result screen. The shared label class carries a
   margin-bottom for its stacked waiting-room use; in this inline row it sits beside the
   buttons, so the margin would knock it off-centre. */
.tk-result__share .tk-share__label {
    margin-bottom: 0;
}

/* The guest's "keep your progress" card on a practice result. The result panel is always a
   dark translucent sheet over the felt (both themes), so the card is tuned for that surface. */
.tk-result__keep {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 0.9rem;
    border: 1px solid rgba(255, 193, 7, 0.45);
    border-radius: 0.6rem;
    background: rgba(255, 193, 7, 0.1);
}

.tk-result__keep-icon {
    color: #ffc107;
    font-size: 1.25rem;
}

.tk-result__keep-body {
    flex: 1 1 14rem;
    min-width: 0;
}

.tk-result__keep-title {
    font-weight: 600;
    line-height: 1.35;
}

.tk-result__keep-line {
    margin-top: 0.3rem;
    font-size: 0.9rem;
    opacity: 0.9;
}

.tk-result__keep-link {
    color: #ffd65a;
    text-decoration: underline;
}

.tk-result__keep-dot {
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    margin-right: 0.4rem;
    border-radius: 50%;
    background: #3ddc84;
    box-shadow: 0 0 0 0 rgba(61, 220, 132, 0.6);
    animation: tk-keep-pulse 2s infinite;
}

@keyframes tk-keep-pulse {
    70% { box-shadow: 0 0 0 0.45rem rgba(61, 220, 132, 0); }
    100% { box-shadow: 0 0 0 0 rgba(61, 220, 132, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .tk-result__keep-dot { animation: none; }
}

.tk-result__keep-cta {
    flex: 0 0 auto;
    font-weight: 600;
}

.tk-result__keep-warn {
    color: #ffd65a;
    font-weight: 600;
}

/* The guest daily-limit wall: same card, louder, CTAs stacked under the text. */
.tk-result__keep--wall {
    border-width: 2px;
    border-color: #ffc107;
    background: rgba(255, 193, 7, 0.16);
}

.tk-result__keep-wall {
    margin-bottom: 0.35rem;
    font-size: 1.05rem;
    font-weight: 700;
    color: #ffd65a;
}

.tk-result__keep-ctas {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
}

/* The daily-limit wall page (views/tarok/guest-limit.php). */
.tarok-limit {
    max-width: 38rem;
    margin: 0 auto;
}

.tarok-limit__icon {
    font-size: 3rem;
    color: var(--tk-tarok);
    margin-bottom: 1rem;
}

.tarok-limit__line {
    margin-bottom: 0.4rem;
    color: var(--text-secondary);
}

.tarok-limit__back {
    display: inline-block;
    margin-top: 1rem;
    color: var(--text-secondary);
}

/* ------------------------------------------------------------------ practice insights
   Operator-only dashboard. Deliberately plain: dense figures, no chart library, and
   every colour comes from the tokens the rest of the tarok pages already use. */
.tk-ins__tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}

.tk-ins__tiles--inline {
    margin-bottom: 0;
}

.tk-ins__tile {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.9rem 1rem;
    border: 1px solid var(--border-color, rgba(128, 128, 128, 0.25));
    border-radius: var(--tk-radius);
    background: var(--bg-secondary, rgba(128, 128, 128, 0.06));
}

.tk-ins__tile-value {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.1;
    color: var(--tk-tarok);
    font-variant-numeric: tabular-nums;
}

.tk-ins__tile-label {
    font-size: 0.82rem;
    opacity: 0.8;
}

.tk-ins__tile-hint {
    font-size: 0.75rem;
    opacity: 0.6;
}

.tk-ins__card {
    height: 100%;
    padding: 1.25rem;
    border: 1px solid var(--border-color, rgba(128, 128, 128, 0.25));
    border-radius: var(--tk-radius);
}

.tk-ins__card-title {
    font-size: 1.05rem;
    font-weight: 700;
    margin-bottom: 0.15rem;
}

.tk-ins__card-sub {
    font-size: 0.85rem;
    opacity: 0.7;
    margin-bottom: 1rem;
}

.tk-ins__note {
    font-size: 0.88rem;
    margin-bottom: 0.25rem;
}

.tk-ins__hint {
    font-size: 0.78rem;
    opacity: 0.65;
    margin-bottom: 0;
}

.tk-ins__rule {
    opacity: 0.25;
    margin: 1rem 0;
}

.tk-ins__bar {
    margin-bottom: 0.7rem;
}

.tk-ins__bar-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    font-size: 0.85rem;
    margin-bottom: 0.2rem;
}

.tk-ins__bar-value {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.tk-ins__bar-track {
    height: 0.5rem;
    border-radius: 0.25rem;
    background: rgba(128, 128, 128, 0.18);
    overflow: hidden;
}

.tk-ins__bar-fill {
    display: block;
    height: 100%;
    border-radius: 0.25rem;
    background: var(--tk-tarok);
}

.tk-ins__chart {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 8rem;
    padding-top: 0.5rem;
    overflow-x: auto;
}

.tk-ins__chart-col {
    display: flex;
    align-items: flex-end;
    gap: 1px;
    flex: 1 1 auto;
    min-width: 0.5rem;
    height: 100%;
}

.tk-ins__chart-bar {
    display: block;
    flex: 1 1 50%;
    min-height: 1px;
    border-radius: 1px 1px 0 0;
}

.tk-ins__chart-bar--tables {
    background: rgba(128, 128, 128, 0.5);
}

.tk-ins__chart-bar--hands {
    background: var(--tk-tarok);
}

.tk-ins__legend {
    display: flex;
    gap: 1rem;
    margin-top: 0.6rem;
    font-size: 0.78rem;
    opacity: 0.75;
}

.tk-ins__legend-item::before {
    content: '';
    display: inline-block;
    width: 0.65rem;
    height: 0.65rem;
    margin-right: 0.35rem;
    border-radius: 2px;
    vertical-align: middle;
}

.tk-ins__legend-item--tables::before {
    background: rgba(128, 128, 128, 0.5);
}

.tk-ins__legend-item--hands::before {
    background: var(--tk-tarok);
}

.tk-ins__table {
    font-size: 0.9rem;
}

.tk-ins__table td,
.tk-ins__table th {
    font-variant-numeric: tabular-nums;
}

/* ----- sortable columns ------------------------------------------------- */
/* The caret is driven entirely by aria-sort, so the accessible state and the visible
   state cannot drift apart - there is only one source of truth for both. */
.tk-ins__table--sortable th[data-sort-key] {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
    transition: background 0.12s ease;
}

.tk-ins__table--sortable th[data-sort-key]:hover,
.tk-ins__table--sortable th[data-sort-key]:focus-visible {
    background: rgba(128, 128, 128, 0.12);
}

.tk-ins__caret {
    display: inline-block;
    width: 0.9em;
    margin-left: 0.25rem;
    opacity: 0.35;
    font-size: 0.8em;
}

.tk-ins__caret::after {
    content: "\2195";
}

.tk-ins__table--sortable th[aria-sort="ascending"] .tk-ins__caret::after {
    content: "\2191";
}

.tk-ins__table--sortable th[aria-sort="descending"] .tk-ins__caret::after {
    content: "\2193";
}

.tk-ins__table--sortable th[aria-sort="ascending"],
.tk-ins__table--sortable th[aria-sort="descending"] {
    color: var(--tk-tarok);
}

.tk-ins__table--sortable th[aria-sort="ascending"] .tk-ins__caret,
.tk-ins__table--sortable th[aria-sort="descending"] .tk-ins__caret {
    opacity: 1;
}

/* ----- toolbar ---------------------------------------------------------- */
.tk-ins__toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
    margin-bottom: 0.75rem;
}

.tk-ins__toolbar-left,
.tk-ins__toolbar-right {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.tk-ins__search {
    position: relative;
}

.tk-ins__search-icon {
    position: absolute;
    top: 50%;
    left: 0.6rem;
    transform: translateY(-50%);
    font-size: 0.75rem;
    opacity: 0.5;
    pointer-events: none;
}

.tk-ins__search-input {
    width: 13rem;
    max-width: 100%;
    padding-left: 1.8rem;
    border-radius: var(--tk-radius);
}

.tk-ins__pills {
    display: inline-flex;
    gap: 0.25rem;
}

.tk-ins__pill {
    padding: 0.2rem 0.65rem;
    font-size: 0.8rem;
    line-height: 1.5;
    border: 1px solid var(--border-color, rgba(128, 128, 128, 0.25));
    border-radius: 999px;
    background: transparent;
    color: inherit;
}

.tk-ins__pill:hover {
    background: rgba(128, 128, 128, 0.12);
}

.tk-ins__pill--on {
    background: var(--tk-tarok);
    border-color: var(--tk-tarok);
    color: #fff;
}

.tk-ins__count {
    font-size: 0.78rem;
    opacity: 0.65;
}

.tk-ins__chip {
    padding: 0.15rem 0.6rem;
    font-size: 0.75rem;
    border: 1px dashed var(--border-color, rgba(128, 128, 128, 0.35));
    border-radius: 999px;
    background: transparent;
    color: inherit;
    opacity: 0.8;
}

.tk-ins__chip:hover {
    opacity: 1;
    border-style: solid;
}

.tk-ins__empty {
    padding: 1rem 0 0.25rem;
}

/* ----- learner button --------------------------------------------------- */
.tk-ins__learner {
    padding: 0;
    border: 0;
    background: none;
    color: var(--tk-tarok);
    font: inherit;
    text-align: left;
    cursor: pointer;
    border-bottom: 1px dotted currentColor;
}

.tk-ins__learner:hover {
    border-bottom-style: solid;
}

.tk-ins__learner--guest {
    color: inherit;
    opacity: 0.75;
}

/* The account a guest identity turned out to be - a quiet trailing note, never
   louder than the learner name it hangs off. */
.tk-ins__linked {
    margin-left: 0.4rem;
    font-size: 0.78rem;
    white-space: nowrap;
    color: var(--tk-tarok);
    opacity: 0.85;
}

/* ----- learner drawer --------------------------------------------------- */
.tk-ins__backdrop {
    position: fixed;
    inset: 0;
    z-index: 1040;
    background: rgba(0, 0, 0, 0.4);
    opacity: 0;
    transition: opacity 0.2s ease;
}

.tk-ins__backdrop--on {
    opacity: 1;
}

.tk-ins__drawer {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 1045;
    display: flex;
    flex-direction: column;
    width: min(26rem, 100vw);
    height: 100vh;
    border-left: 1px solid var(--border-color, rgba(128, 128, 128, 0.25));
    background: var(--bg-primary, #fff);
    box-shadow: -0.5rem 0 1.5rem rgba(0, 0, 0, 0.18);
    transform: translateX(100%);
    transition: transform 0.2s ease;
}

.tk-ins__drawer--open {
    transform: translateX(0);
}

.tk-ins__drawer:focus {
    outline: none;
}

.tk-ins__drawer-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 1rem 1.25rem 0.75rem;
    border-bottom: 1px solid var(--border-color, rgba(128, 128, 128, 0.25));
}

.tk-ins__drawer-title {
    font-size: 1.1rem;
    font-weight: 700;
    margin: 0;
}

.tk-ins__drawer-kind {
    font-size: 0.78rem;
    opacity: 0.6;
}

.tk-ins__drawer-close {
    padding: 0.15rem 0.45rem;
    border: 0;
    border-radius: var(--tk-radius);
    background: transparent;
    color: inherit;
    opacity: 0.6;
}

.tk-ins__drawer-close:hover {
    opacity: 1;
    background: rgba(128, 128, 128, 0.15);
}

.tk-ins__drawer-body {
    flex: 1;
    overflow-y: auto;
    padding: 1rem 1.25rem 2rem;
}

.tk-ins__drawer-section {
    font-size: 0.82rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.6;
    margin: 1.25rem 0 0.6rem;
}

.tk-ins__stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr));
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.tk-ins__stat-grid .tk-ins__pair {
    display: flex;
    flex-direction: column;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--border-color, rgba(128, 128, 128, 0.25));
    border-radius: var(--tk-radius);
}

.tk-ins__stat-grid .tk-ins__pair-value {
    order: -1;
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--tk-tarok);
    font-variant-numeric: tabular-nums;
}

.tk-ins__stat-grid .tk-ins__pair-label {
    font-size: 0.72rem;
    opacity: 0.7;
}

.tk-ins__pairs .tk-ins__pair {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.3rem 0;
    font-size: 0.85rem;
    border-bottom: 1px solid rgba(128, 128, 128, 0.15);
}

.tk-ins__pairs .tk-ins__pair-label {
    opacity: 0.7;
}

.tk-ins__pairs .tk-ins__pair-value {
    font-weight: 600;
    text-align: right;
}

.tk-ins__pairs .tk-ins__pair-hint {
    flex-basis: 100%;
    font-size: 0.72rem;
    opacity: 0.55;
}

.tk-ins__pairs--net {
    margin-top: 0.75rem;
}

.tk-ins__pairs--link {
    margin-top: 0.75rem;
    padding: 0.5rem 0.6rem;
    border-radius: 0.5rem;
    background: rgba(127, 127, 127, 0.1);
}

.tk-ins__badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.tk-ins__badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.2rem 0.55rem;
    font-size: 0.75rem;
    border: 1px solid var(--border-color, rgba(128, 128, 128, 0.25));
    border-radius: 999px;
}

.tk-ins__recent {
    list-style: none;
    padding: 0;
    margin: 0;
}

.tk-ins__recent-item {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.35rem 0;
    font-size: 0.8rem;
    border-bottom: 1px solid rgba(128, 128, 128, 0.15);
}

.tk-ins__recent-when {
    opacity: 0.6;
    font-variant-numeric: tabular-nums;
}

.tk-ins__recent-score {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.tk-ins__recent-score--won {
    color: #198754;
}

.tk-ins__recent-score--lost {
    color: #dc3545;
}

.tk-ins__recent-mode {
    font-size: 0.7rem;
    opacity: 0.5;
}

.tk-ins__drawer-link {
    display: inline-block;
    margin-top: 1.25rem;
}

@media (max-width: 575.98px) {
    .tk-ins__search-input {
        width: 100%;
    }

    .tk-ins__toolbar-left {
        width: 100%;
    }

    .tk-ins__drawer {
        width: 100vw;
    }
}

[data-theme="dark"] .tk-ins__tile,
[data-theme="dark"] .tk-ins__card,
[data-theme="dark"] .tk-ins__drawer,
[data-theme="dark"] .tk-ins__pill,
[data-theme="dark"] .tk-ins__badge,
[data-theme="dark"] .tk-ins__stat-grid .tk-ins__pair {
    border-color: rgba(255, 255, 255, 0.14);
}

[data-theme="dark"] .tk-ins__drawer {
    background: var(--bg-primary, #1a1d21);
}

[data-theme="dark"] .tk-ins__pill--on {
    border-color: var(--tk-tarok);
}

[data-theme="dark"] .tk-ins__tile {
    background: rgba(255, 255, 255, 0.04);
}

[data-theme="dark"] .tk-badge {
    border-color: rgba(255, 255, 255, 0.18);
}

/* ==========================================================================
   Tournaments - the compact deal clock and the standings strip
   ==========================================================================
   The clock is a chip in the page header, immediately after the player's name badge:
   deal counter, a progress track, and the seconds left, all on one line. It lives there
   rather than in a column beside the felt for two reasons - the felt keeps its full
   width, and the screen edges stay free for the card tracker and stats/hints docks,
   which pin into the container's outer margins above 1920px and slide in from those same
   edges below it. */

.tk-tclock {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0.6rem;
    border: 1px solid var(--border-default, rgba(128, 128, 128, 0.3));
    border-radius: 999px;
    background: var(--card-bg, #fff);
    font-size: 0.8125rem;
    line-height: 1;
    /* Never let the chip drive the header wider than the screen: the track absorbs the
       squeeze while the two numbers keep their natural size. */
    max-width: 100%;
    min-width: 0;
}

.tk-tclock__deal {
    font-variant-numeric: tabular-nums;
    color: var(--text-muted, #6c757d);
    white-space: nowrap;
}

.tk-tclock__track {
    position: relative;
    display: block;
    /* Grows into the space it is given and shrinks on a phone, with a floor so it stays
       readable as a bar rather than collapsing to a sliver. */
    flex: 1 1 7rem;
    min-width: 3.5rem;
    max-width: 14rem;
    height: 0.375rem;
    border-radius: 999px;
    background: var(--bg-tertiary, rgba(128, 128, 128, 0.25));
    overflow: hidden;
}

.tk-tclock__bar {
    display: block;
    height: 100%;
    width: 100%;
    border-radius: 999px;
    background: var(--tk-clock-bar);
    /* Matches the 1s interpolation tick in tournament.js so the bar glides. */
    transition: width 1s linear, background-color 0.3s ease;
}

.tk-tclock__time {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--text-primary, #1a1a1a);
    white-space: nowrap;
    /* Reserve the width of "0:00" so the header does not twitch every second. */
    min-width: 2.5rem;
    text-align: right;
}

/* Last quarter of the deal: bar and number turn together, one signal not two. */
.tk-tclock.is-low .tk-tclock__bar {
    background: var(--tk-red, #c0392b);
}

.tk-tclock.is-low .tk-tclock__time {
    color: var(--tk-red, #c0392b);
}

/* Warm-up: the deal exists but the clock is not spending anything yet, so the bar sits
   full and pulses gently instead of draining. Deliberately not the same red/green
   language as the running clock - "not started" is a third state, not a healthy one. */
.tk-tclock.is-warmup .tk-tclock__bar {
    background: var(--text-secondary, #6c757d);
    /* No width transition here: the bar is pinned at 100% and must not glide when the
       warm-up ends and the real countdown takes over. */
    transition: background-color 0.3s ease;
    animation: tk-tclock-warmup 1.4s ease-in-out infinite;
}

.tk-tclock.is-warmup .tk-tclock__time {
    color: var(--text-secondary, #6c757d);
    /* "Get ready" is wider than "0:00", and the reserved width would clip it. */
    min-width: 0;
}

@keyframes tk-tclock-warmup {
    0%, 100% { opacity: 0.45; }
    50% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .tk-tclock.is-warmup .tk-tclock__bar {
        animation: none;
    }
}

@media (max-width: 575.98px) {
    .tk-tclock {
        /* On a phone the chip takes the row under the name badge rather than fighting it
           for space - the header wrapper already wraps, this just makes the bar useful
           when it does. */
        flex: 1 1 100%;
        justify-content: space-between;
    }

    .tk-tclock__track {
        max-width: none;
    }
}

/* ---------- Standings, full width under the felt ---------- */

.tk-tournament {
    margin-top: 1rem;
    padding: 0.75rem;
    border: 1px solid var(--border-default, rgba(128, 128, 128, 0.3));
    border-radius: var(--tk-radius);
    background: var(--card-bg, #fff);
}

.tk-tournament__head {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 0.5rem;
}

.tk-tournament__title {
    font-weight: 600;
    color: var(--text-primary, #1a1a1a);
}

.tk-tournament__note {
    font-size: 0.8125rem;
    color: var(--text-secondary, #495057);
}

/* A responsive grid, not a list: on a wide screen the field reads as several columns of
   rows instead of one very long strip below the felt. */
.tk-tournament__board {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: 0.125rem 1rem;
    max-height: 14rem;
    overflow-y: auto;
}

.tk-tournament__row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.3125rem 0.25rem;
    border-bottom: 1px solid var(--border-muted, rgba(128, 128, 128, 0.18));
    font-size: 0.875rem;
}

.tk-tournament__row.is-you {
    background: var(--tk-tarok-bg);
    border-radius: var(--tk-radius);
    font-weight: 600;
}

.tk-tournament__row.is-dropped {
    opacity: 0.55;
}

.tk-tournament__rank {
    min-width: 1.5rem;
    color: var(--text-muted, #6c757d);
    font-variant-numeric: tabular-nums;
}

.tk-tournament__name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tk-tournament__you {
    color: var(--text-muted, #6c757d);
    font-weight: 400;
}

.tk-tournament__bot {
    font-size: 0.75rem;
    opacity: 0.7;
    cursor: help;
}

/* A player who left the field. Quiet on purpose: their points are real and their rank is
   earned, so this explains a deal count that stopped climbing rather than marking them down
   for it. Reads against the .is-dropped row dimming above rather than fighting it. */
.tk-tournament__dropped {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.05rem 0.35rem;
    border: 1px solid var(--border-default, rgba(128, 128, 128, 0.3));
    border-radius: 999px;
    color: var(--text-muted, #6c757d);
    white-space: nowrap;
}

.tk-tournament__points {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--text-primary, #1a1a1a);
}

.tk-tournament-card {
    border-color: var(--border-default, rgba(128, 128, 128, 0.3));
}

[data-theme="dark"] .tk-tclock,
[data-theme="dark"] .tk-turnclock,
[data-theme="dark"] .tk-tournament,
[data-theme="dark"] .tk-tournament-card {
    border-color: rgba(255, 255, 255, 0.14);
}

[data-theme="dark"] .tk-tournament__row {
    border-bottom-color: rgba(255, 255, 255, 0.08);
}

/* ==========================================================================
   Tournaments - the card
   ==========================================================================
   Used by the tournaments listing. Two columns inside the card body: what and
   when on the left, who is winning on the right.
   ========================================================================== */

.tk-tcard__facts li {
    display: flex;
    align-items: baseline;
    gap: 0.15rem;
    margin-bottom: 0.35rem;
}

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

/* The live "in 12 min". Filled by tournament-countdown.js, so it is empty (and
   invisible) for a reader with no JavaScript - the absolute date sits next to
   it and says everything that matters on its own. */
.tk-tcard__countdown:not(:empty) {
    margin-left: 0.4rem;
    padding: 0.05rem 0.4rem;
    border-radius: 999px;
    background: var(--bg-subtle, rgba(128, 128, 128, 0.12));
    font-variant-numeric: tabular-nums;
    font-size: 0.85em;
}

.tk-tcard__countdown.is-imminent:not(:empty) {
    background: rgba(217, 119, 6, 0.16);
    color: #b45309;
    font-weight: 600;
}

.tk-tcard__progress {
    height: 0.4rem;
    border-radius: 999px;
}

.tk-tcard__podium {
    height: 100%;
    padding: 0.6rem 0.7rem;
    border-radius: var(--tk-radius, 0.5rem);
    background: var(--bg-subtle, rgba(128, 128, 128, 0.08));
}

.tk-tcard__podium-title {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary, #6c757d);
    margin-bottom: 0.4rem;
}

.tk-tcard__podium-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.tk-tcard__podium-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.15rem 0;
    font-size: 0.875rem;
}

.tk-tcard__podium-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tk-tcard__podium-points {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.tk-tcard__podium-more {
    padding: 0.15rem 0;
    font-size: 0.8125rem;
    color: var(--text-secondary, #6c757d);
}

/* ==========================================================================
   Medal - gold, silver and bronze wherever a rank is shown
   ==========================================================================
   The inline shape. A rank number sitting in a coloured disc, used on the
   tournament cards, in both standings tables and on the live board beside the
   felt. The podium on the results page wears the same three gradients in a
   different shape - a step whose height carries the placing - and both read the
   --tk-medal-* variables at the top of this file, so there is one gold.

   The disc keeps the NUMBER rather than replacing it with an emoji: a medal
   answers "top three?" at a glance, the number answers "which?", and ranks below
   third need the number anyway. One shape for all of them beats two.
   ========================================================================== */

.tk-medal {
    flex: 0 0 1.375rem;
    width: 1.375rem;
    height: 1.375rem;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--tk-medal-ink, #3b2f00);
    background: var(--bg-subtle, rgba(128, 128, 128, 0.2));
    /* A lip along the bottom and a shadow under it - just enough to read as struck
       metal rather than a flat swatch. */
    box-shadow: inset 0 -1px 2px rgba(0, 0, 0, 0.18), 0 1px 2px rgba(0, 0, 0, 0.14);
}

.tk-medal--gold { background: var(--tk-medal-gold); }
.tk-medal--silver { background: var(--tk-medal-silver); }
.tk-medal--bronze { background: var(--tk-medal-bronze); }

/* In a table the medal replaces a bare number in a cell, so it needs the nudge
   that keeps it on the baseline of the row beside it. */
.tk-medal--cell {
    vertical-align: middle;
}

/* The live board beside the felt sizes its own rank column; the medal brings its
   own width, so drop the reserved one rather than padding the disc off-centre. */
.tk-tournament__rank.tk-medal {
    min-width: 0;
}

/* All three metals are light, so on a dark felt they need an edge rather than a
   drop shadow to sit down into the page. */
[data-theme="dark"] .tk-medal {
    box-shadow: inset 0 -1px 2px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(0, 0, 0, 0.35);
}

/* ==========================================================================
   Status pill - one badge for every tournament surface
   ==========================================================================
   There used to be two idioms for the same idea: Bootstrap's `badge bg-*` on the
   cards and tables, and a small grey uppercase pill on the landing rows. The same
   tournament therefore wore a green "Odprto za prijavo" on one page and a grey
   "ODPRI" on another, and a reader could not tell they meant the same thing.

   This is that one badge. The label and the tone both come from
   GameTournamentHelper::statusBadge(), so nothing here decides what a status is
   called - it only decides what the tone looks like.

   Deliberately NOT uppercase: the old pill shouted a single English word, but
   these labels are whole phrases in every language, and "ODPRTO ZA PRIJAVO" is
   both loud and hard to scan. Weight and colour do the work instead.
   ========================================================================== */

.tk-status {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    flex: 0 0 auto;
    padding: 0.12rem 0.55rem;
    border: 1px solid transparent;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.5;
    white-space: nowrap;
    background: var(--bg-subtle, rgba(128, 128, 128, 0.15));
    color: var(--text-secondary, #6c757d);
}

/* Green is reserved for the one status a visitor can act on. */
.tk-status--open {
    background: rgba(25, 135, 84, 0.15);
    color: #146c43;
    border-color: rgba(25, 135, 84, 0.3);
}

/* Red for what is happening right now - the same treatment the landing row's old
   is-live modifier had, and the reason it was the only colour on that row. */
.tk-status--live {
    background: rgba(220, 53, 69, 0.14);
    color: #b02a37;
    border-color: rgba(220, 53, 69, 0.28);
}

/* Over and settled: present, but it has stopped asking for attention. */
.tk-status--done {
    background: rgba(52, 58, 64, 0.12);
    color: #343a40;
    border-color: rgba(52, 58, 64, 0.22);
}

.tk-status--draft {
    background: var(--bg-subtle, rgba(128, 128, 128, 0.15));
    color: var(--text-secondary, #6c757d);
    border-color: rgba(128, 128, 128, 0.28);
}

/* Called off. Outlined rather than filled - it is the one status that describes
   something that will never happen, so it reads as struck through rather than lit. */
.tk-status--off {
    background: transparent;
    color: #b02a37;
    border-color: rgba(220, 53, 69, 0.35);
}

/* The two entrant markers on a standings row. Not statuses of the tournament, but
   the same pill so a row does not mix two badge shapes. */
.tk-status--info {
    background: rgba(13, 110, 253, 0.14);
    color: #0a58ca;
    border-color: rgba(13, 110, 253, 0.28);
}

.tk-status--muted {
    background: transparent;
    color: var(--text-secondary, #6c757d);
    border-color: var(--border-default, rgba(128, 128, 128, 0.35));
}

/* The one rules variant a room/tournament can opt into - violet so it never reads
   as a status (open/live/done) or as an entrant marker (info), the two families
   already covering green/red/grey/blue. */
.tk-status--valat {
    background: rgba(111, 66, 193, 0.14);
    color: #6f42c1;
    border-color: rgba(111, 66, 193, 0.3);
}

/* Denser variant for rows and inline markers, where the badge rides beside text
   rather than beside a heading. */
.tk-status--sm {
    padding: 0.05rem 0.45rem;
    font-size: 0.66rem;
    letter-spacing: 0.03em;
}

[data-theme="dark"] .tk-status {
    background: rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.72);
    border-color: rgba(255, 255, 255, 0.18);
}

[data-theme="dark"] .tk-status--open {
    background: rgba(25, 135, 84, 0.22);
    color: #75d1a4;
    border-color: rgba(25, 135, 84, 0.4);
}

[data-theme="dark"] .tk-status--live {
    background: rgba(220, 53, 69, 0.24);
    color: #f18b95;
    border-color: rgba(220, 53, 69, 0.42);
}

[data-theme="dark"] .tk-status--done {
    background: rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.78);
    border-color: rgba(255, 255, 255, 0.2);
}

[data-theme="dark"] .tk-status--off {
    background: transparent;
    color: #f18b95;
    border-color: rgba(220, 53, 69, 0.45);
}

[data-theme="dark"] .tk-status--info {
    background: rgba(13, 110, 253, 0.24);
    color: #8bb9ff;
    border-color: rgba(13, 110, 253, 0.42);
}

[data-theme="dark"] .tk-status--muted {
    background: transparent;
    color: rgba(255, 255, 255, 0.62);
    border-color: rgba(255, 255, 255, 0.22);
}

[data-theme="dark"] .tk-status--valat {
    background: rgba(111, 66, 193, 0.28);
    color: #c9b3f0;
    border-color: rgba(111, 66, 193, 0.46);
}

/* ==========================================================================
   Tournaments - the landing page panel
   ==========================================================================
   Compact rows rather than the full card: this is one narrow column under the
   open rooms, and cards three-across would fight the page for attention.
   ========================================================================== */

.tarok-landing__tournaments {
    padding: 1rem 0 2.5rem;
}

.tarok-landing__tournaments-lead {
    max-width: 42rem;
    margin-left: auto;
    margin-right: auto;
}

.tarok-landing__tournaments-list {
    max-width: 40rem;
}

.tk-tlist-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--border-default, rgba(128, 128, 128, 0.3));
    border-radius: var(--tk-radius, 0.5rem);
    background: var(--bg-surface, #fff);
    margin-bottom: 0.5rem;
}

.tk-tlist-row__main {
    flex: 1 1 auto;
    min-width: 0;
}

.tk-tlist-row__head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.15rem;
    /* The status labels are whole phrases ("Odprto za prijavo"), not the single word this
       row used to carry, so the name drops to a second line on a narrow column rather than
       the badge being squeezed out of legibility. */
    flex-wrap: wrap;
}

.tk-tlist-row__name {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tk-tlist-row__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.15rem 0.5rem;
    font-size: 0.825rem;
    color: var(--text-secondary, #6c757d);
}

.tk-tlist-row__leader {
    font-weight: 600;
}

.tk-tlist-row__cta {
    flex: 0 0 auto;
}

@media (max-width: 30rem) {
    .tk-tlist-row {
        flex-wrap: wrap;
    }

    .tk-tlist-row__cta {
        width: 100%;
    }
}

/* ==========================================================================
   Tournaments - the waiting room
   ========================================================================== */

.tk-tlobby__schedule {
    padding: 0.75rem 0.9rem;
    border-radius: var(--tk-radius, 0.5rem);
    background: var(--bg-subtle, rgba(128, 128, 128, 0.08));
    text-align: center;
}

.tk-tlobby__schedule-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary, #6c757d);
}

.tk-tlobby__schedule-when {
    font-weight: 600;
}

/* Big, because it is the one number anybody on this page is watching. */
.tk-tlobby__countdown {
    font-size: 1.75rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
    color: var(--text-primary, #1a1a1a);
}

.tk-tlobby__countdown.is-imminent {
    color: #b45309;
}

.tk-tlobby__schedule-note {
    font-size: 0.8rem;
    color: var(--text-secondary, #6c757d);
    margin-top: 0.25rem;
}

.tk-tlobby__note {
    margin-top: 0.75rem;
    font-weight: 600;
    text-align: center;
}

.tk-tlobby__you {
    color: var(--text-secondary, #6c757d);
    font-size: 0.875em;
}

/* --------------------------------------------------------------------------
   The entry CTA. It is the only thing on this page a visitor is meant to do,
   so it stops looking like the four other Bootstrap buttons in the sidebar:
   gold, its own size, a sheen that sweeps across on hover, and a short wobble
   every nine seconds for somebody who parked the tab and looked away.
   -------------------------------------------------------------------------- */

.tk-tlobby__cta {
    position: relative;
    overflow: hidden;                       /* clips the sheen to the button */
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.1rem;
    width: 100%;
    padding: 0.85rem 1rem;
    border: 0;
    border-radius: var(--tk-radius, 0.5rem);
    /* Explicit gold stops rather than --tk-tarok: the light-theme token (#8a6d1f) is dark
       enough to drop the small sub-line under 4.5:1 against the near-black ink. */
    background: linear-gradient(135deg, #f7dd8a, #c9a227);
    color: #1a1a1a;
    font-family: inherit;                   /* bare <button>, no .btn to normalise it */
    text-align: center;
    text-decoration: none;                  /* the guest variant is an <a> */
    cursor: pointer;
    box-shadow: 0 6px 18px rgba(138, 109, 31, 0.28);
    transition: transform .16s ease, box-shadow .16s ease, filter .16s ease;
    animation: tk-cta-nudge 9s ease-in-out infinite;
}

.tk-tlobby__cta-label {
    font-size: 1.1rem;
    font-weight: 700;
}

.tk-tlobby__cta-sub {
    font-size: 0.8rem;
    font-weight: 600;
    opacity: 0.82;
}

/* A slanted highlight parked off the left edge; it crosses the face on hover. */
.tk-tlobby__cta::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: -60%;
    width: 45%;
    background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.55), transparent);
    transform: skewX(-18deg);
    pointer-events: none;
}

.tk-tlobby__cta:hover,
.tk-tlobby__cta:focus-visible {
    transform: translateY(-2px) scale(1.015);
    box-shadow: 0 12px 26px rgba(138, 109, 31, 0.42);
    filter: saturate(1.08);
    color: #1a1a1a;
    animation: none;                        /* hovering IS the attention - stop nagging */
}

.tk-tlobby__cta:hover::after,
.tk-tlobby__cta:focus-visible::after {
    animation: tk-cta-sheen .7s ease-out;
}

.tk-tlobby__cta:focus-visible {
    outline: 3px solid rgba(138, 109, 31, 0.45);
    outline-offset: 2px;
}

.tk-tlobby__cta:active {
    transform: translateY(0) scale(0.995);
}

@keyframes tk-cta-sheen {
    from { left: -60%; }
    to { left: 115%; }
}

/* 9s cycle, idle for ~8.2s of it - a nudge, not a jitter. */
@keyframes tk-cta-nudge {
    0%, 86%, 100% { transform: none; }
    88% { transform: translateX(-3px) rotate(-1.2deg); }
    90% { transform: translateX(3px) rotate(1.2deg); }
    92% { transform: translateX(-2px) rotate(-0.8deg); }
    94% { transform: translateX(2px) rotate(0.8deg); }
    96% { transform: translateX(-1px); }
}

@media (prefers-reduced-motion: reduce) {
    .tk-tlobby__cta {
        animation: none;
        transition: none;
    }

    .tk-tlobby__cta:hover,
    .tk-tlobby__cta:focus-visible {
        transform: none;
    }

    .tk-tlobby__cta:hover::after,
    .tk-tlobby__cta:focus-visible::after {
        animation: none;
    }
}

[data-theme="dark"] .tk .tk-tlobby__cta {
    background: linear-gradient(135deg, #f3d573, var(--tk-tarok, #d9b551));
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
}

/* ==========================================================================
   Tournaments - the site-wide call-back bar
   ==========================================================================
   Pinned to the bottom on every tarok page except the table itself. Loud
   enough to catch someone mid-read, because a deal they are missing is being
   played by a bot on their behalf.
   ========================================================================== */

.tk-callback {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: 1rem;
    z-index: 1080;
    width: calc(100% - 2rem);
    max-width: 30rem;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--border-default, rgba(128, 128, 128, 0.3));
    border-radius: var(--tk-radius, 0.5rem);
    background: var(--bg-surface, #fff);
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.25);
    animation: tk-callback-in 0.25s ease-out;
}

@keyframes tk-callback-in {
    from { opacity: 0; transform: translate(-50%, 1rem); }
    to { opacity: 1; transform: translate(-50%, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .tk-callback { animation: none; }
}

.tk-callback__body {
    flex: 1 1 auto;
    min-width: 0;
}

.tk-callback__title {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-primary, #1a1a1a);
}

.tk-callback__meta {
    font-size: 0.825rem;
    color: var(--text-secondary, #6c757d);
}

.tk-callback__countdown {
    font-size: 0.825rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--tk-red, #c0392b);
}

.tk-callback__actions {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

@media (max-width: 30rem) {
    .tk-callback {
        flex-wrap: wrap;
    }

    .tk-callback__actions {
        flex-direction: row;
        width: 100%;
    }

    .tk-callback__actions .btn {
        flex: 1 1 0;
    }
}

/* ==========================================================================
   Tournaments - the scheduled-start chips
   ========================================================================== */

.tk-schedule__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 0.6rem;
}

/* Deliberately generous on a phone: these exist so an operator never has to
   fight a native date spinner for "in an hour". */
.tk-schedule__chip {
    flex: 1 1 auto;
    min-height: 2.5rem;
}

.tk-schedule__preview {
    margin-top: 0.5rem;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-primary, #1a1a1a);
}

.tk-schedule__preview.is-past {
    color: #b02a37;
}

/* ==========================================================================
   Tournaments - the deals field

   Chips for the counts a club night actually picks, a thumb-sized -/+ pair for
   everything else, and the length estimate underneath. The native number
   spinner is hidden on purpose: its arrows are unusable on a phone and having
   two ways to nudge the same value in the same control reads as a bug.
   ========================================================================== */

.tk-rounds__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 0.6rem;
}

.tk-rounds__chip {
    flex: 1 1 auto;
    min-height: 2.5rem;
}

.tk-rounds__stepper {
    display: flex;
    align-items: stretch;
    gap: 0.5rem;
}

.tk-rounds__step {
    flex: 0 0 3.25rem;
    font-size: 1.1rem;
}

.tk-rounds__input {
    text-align: center;
    font-size: 1.25rem;
    font-weight: 600;
    -moz-appearance: textfield;
}

.tk-rounds__input::-webkit-outer-spin-button,
.tk-rounds__input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.tk-rounds__estimate {
    margin-top: 0.5rem;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-primary, #1a1a1a);
}

/* A warning, never a block - the operator is allowed to re-deal, they just
   should not do it by accident. */
.tk-rounds__warn {
    margin-top: 0.5rem;
    padding: 0.4rem 0.6rem;
    border-radius: 0.375rem;
    background: rgba(255, 193, 7, 0.15);
    color: #8a6100;
    font-size: 0.875rem;
    font-weight: 600;
    animation: tk-rounds-pulse 1.6s ease-in-out infinite;
}

@keyframes tk-rounds-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.65; }
}

@media (prefers-reduced-motion: reduce) {
    .tk-rounds__warn {
        animation: none;
    }
}

[data-theme="dark"] .tk .tk-rounds__warn {
    background: rgba(255, 193, 7, 0.12);
    color: #ffce5a;
}

/* ==========================================================================
   Tournaments - the note above a form

   Orientation material, said before the first field instead of beside it. Quiet
   on purpose: it is context, not an alert, so it gets a rule and a tint rather
   than a full alert box competing with the form for attention.
   ========================================================================== */

.tk-formnote {
    padding: 0.75rem 0.9rem;
    border-left: 3px solid var(--tk-accent, #0d6efd);
    border-radius: 0 0.375rem 0.375rem 0;
    background: rgba(13, 110, 253, 0.05);
}

.tk-formnote__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
    font-weight: 600;
    font-size: 0.9375rem;
}

.tk-formnote__list {
    margin: 0;
    padding-left: 1.1rem;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--text-muted, #6c757d);
}

.tk-formnote__list li + li {
    margin-top: 0.2rem;
}

[data-theme="dark"] .tk .tk-formnote {
    background: rgba(110, 168, 254, 0.08);
}

/* The entry-link QR - big enough to scan across a table, never bigger. */
.tk-entryqr svg {
    display: block;
    width: 100%;
    max-width: 11rem;
    height: auto;
    margin: 0 auto 0.35rem;
    background: #fff;
    border-radius: 0.375rem;
    padding: 0.35rem;
}

/* ==========================================================================
   Tournaments - the results page
   ========================================================================== */

.tk-podium__trophy {
    font-size: 2.5rem;
    line-height: 1;
}

.tk-podium {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: 0.5rem;
    max-width: 34rem;
    margin: 0 auto;
}

.tk-podium__place {
    flex: 1 1 0;
    min-width: 0;
    text-align: center;
}

.tk-podium__name {
    font-weight: 600;
    font-size: 0.9rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tk-podium__points {
    font-variant-numeric: tabular-nums;
    font-size: 0.825rem;
    color: var(--text-secondary, #6c757d);
    margin-bottom: 0.35rem;
}

/* The step itself. Height carries the ranking, so the shape reads before any
   of the numbers do. */
.tk-podium__step {
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--tk-radius, 0.5rem) var(--tk-radius, 0.5rem) 0 0;
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--tk-medal-ink, #3b2f00);
}

/* The step is the other shape a medal takes. Only the height belongs to the podium -
   the metals come from the same three variables the inline .tk-medal disc reads. */
.tk-podium__place--gold .tk-podium__step {
    height: 6rem;
    background: var(--tk-medal-gold);
}

.tk-podium__place--silver .tk-podium__step {
    height: 4.5rem;
    background: var(--tk-medal-silver);
}

.tk-podium__place--bronze .tk-podium__step {
    height: 3.5rem;
    background: var(--tk-medal-bronze);
}

.tk-podium__stat-value {
    font-size: 1.4rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
}

.tk-podium__stat-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary, #6c757d);
}

.tk-podium__row-mine > td {
    background: rgba(13, 110, 253, 0.08);
}

[data-theme="dark"] .tk-tlist-row,
[data-theme="dark"] .tk-callback {
    border-color: rgba(255, 255, 255, 0.14);
    background: rgba(255, 255, 255, 0.03);
}

/* The floating bar needs a solid ground of its own - the translucent surface above
   would let the page show through a panel that is meant to interrupt. */
[data-theme="dark"] .tk-callback {
    background: #1f2225;
}

[data-theme="dark"] .tk-tcard__podium,
[data-theme="dark"] .tk-tlobby__schedule {
    background: rgba(255, 255, 255, 0.05);
}

[data-theme="dark"] .tk-tcard__countdown.is-imminent:not(:empty),
[data-theme="dark"] .tk-tlobby__countdown.is-imminent {
    color: #fbbf24;
}

[data-theme="dark"] .tk-podium__row-mine > td {
    background: rgba(13, 110, 253, 0.18);
}

/* ---- Lobby dock (views/tarok/_lobby-dock.php + web/js/tarok/lobby-dock.js) ---- */
.ldock { position: fixed; right: 1rem; bottom: 1rem; z-index: 1030; max-width: calc(100vw - 2rem); font-size: .9rem; color: var(--bs-body-color, #212529); }
@media (max-width: 767.98px) { .ldock--table { display: none; } }
.ldock__pill { display: inline-flex; align-items: center; gap: .5rem; border: 1px solid rgba(128, 128, 128, .45); border-radius: 999px; padding: .4rem .85rem; background: var(--bs-body-bg, #fff); color: inherit; box-shadow: 0 2px 10px rgba(0, 0, 0, .18); cursor: pointer; }
.ldock__dot { width: .6rem; height: .6rem; border-radius: 50%; background: #dc3545; display: none; }
.ldock--unread .ldock__dot, .ldock--msgunread .ldock__dot { display: inline-block; }
.ldock__panel { display: none; width: min(26rem, calc(100vw - 2rem)); max-height: calc(100dvh - 5rem); background: var(--bs-body-bg, #fff); border: 1px solid rgba(128, 128, 128, .45); border-radius: .75rem; box-shadow: 0 6px 24px rgba(0, 0, 0, .25); overflow-x: hidden; overflow-y: auto; }
.ldock--open .ldock__panel { display: block; }
.ldock--open .ldock__pill { display: none; }
.ldock__head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding: .5rem .75rem; border-bottom: 1px solid rgba(128, 128, 128, .3); }
.ldock__title { font-weight: 600; }
.ldock__close { border: 0; background: none; color: inherit; font-size: 1.2rem; line-height: 1; cursor: pointer; }
.ldock__tabs { display: flex; border-bottom: 1px solid rgba(128, 128, 128, .3); }
.ldock__tab { flex: 1 1 0; min-width: 0; display: inline-flex; align-items: center; justify-content: center; gap: .3rem; white-space: nowrap; font-size: .82rem; border: 0; background: none; color: inherit; padding: .5rem .2rem; cursor: pointer; opacity: .7; border-bottom: 2px solid transparent; }
@media (max-width: 380px) { .ldock__tablabel { display: none; } }
.ldock__heading { font-weight: 600; margin-bottom: .4rem; }
.ldock__tab--on { opacity: 1; border-bottom-color: var(--bs-primary, #0d6efd); }
.ldock__tab i { flex: 0 0 auto; }
.ldock__tablabel { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ldock__body { padding: .5rem .75rem .75rem; }
.ldock__rooms { display: flex; gap: .35rem; margin-bottom: .4rem; }
.ldock__log, .ldock__list { height: 15rem; overflow-y: auto; border: 1px solid rgba(128, 128, 128, .3); border-radius: .5rem; padding: .4rem .6rem; margin-bottom: .5rem; }
.ldock__line { display: flex; gap: .25rem; align-items: baseline; padding: .1rem 0; word-break: break-word; }
.ldock__line--system { font-style: italic; opacity: .7; }
.ldock__line--mine .ldock__who { opacity: .7; }
.ldock__text { flex: 1 1 auto; }
.ldock__x { border: 0; background: none; opacity: 0; line-height: 1; padding: 0 .25rem; color: inherit; cursor: pointer; }
.ldock__line:hover .ldock__x, .ldock__row:hover .ldock__x, .ldock__x:focus { opacity: .7; }
.ldock__row { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; padding: .25rem 0; border-bottom: 1px solid rgba(128, 128, 128, .15); }
.ldock__row-main { flex: 1 1 8rem; min-width: 0; word-break: break-word; }
.ldock__form { display: flex; gap: .4rem; margin-bottom: .3rem; }
.ldock__note { font-size: .8rem; opacity: .75; margin: .2rem 0; }
.ldock__status { font-size: .8rem; min-height: 1.1rem; color: #dc3545; }
.ldock__empty { opacity: .65; padding: .4rem 0; }

/* Slim-header message and notification links (views/layouts/tarok.php) */
.tarok-app__badge-link { position: relative; }
.tarok-app__badge { position: absolute; top: -.35rem; right: -.35rem; min-width: 1.05rem; height: 1.05rem; padding: 0 .25rem; border-radius: 999px; background: #dc3545; color: #fff; font-size: .65rem; line-height: 1.05rem; text-align: center; display: none; }
.tarok-app__badge--on { display: inline-block; }

/* Dock Messages tab */
.ldock__tab { position: relative; }
.ldock__tabdot { display: none; position: absolute; top: .3rem; right: .6rem; width: .5rem; height: .5rem; border-radius: 50%; background: #dc3545; }
.ldock--msgunread .ldock__tabdot { display: inline-block; }
.ldock__threadrow { width: 100%; text-align: left; background: none; border: 0; border-bottom: 1px solid rgba(128, 128, 128, .15); color: inherit; cursor: pointer; }
.ldock__threadrow--unread strong { color: var(--bs-primary, #0d6efd); }
.ldock__count { margin-left: .4rem; padding: 0 .4rem; border-radius: 999px; background: #dc3545; color: #fff; font-size: .7rem; }
.ldock__thread { min-height: 15rem; max-height: 22rem; overflow-y: auto; }
.ldock__thread .conv-messages { max-height: 13rem; overflow-y: auto; }
.ldock__back { padding-left: 0; }

/* Game header: notification dropdown */
.tarok-app__notif { position: relative; display: inline-block; }
.tarok-app__notif-panel { position: absolute; right: 0; top: calc(100% + .4rem); width: min(22rem, calc(100vw - 1.5rem)); max-height: 24rem; overflow-y: auto; z-index: 1040; background: var(--bs-body-bg, #fff); color: var(--bs-body-color, #212529); border: 1px solid rgba(128, 128, 128, .45); border-radius: .6rem; box-shadow: 0 6px 24px rgba(0, 0, 0, .25); display: none; }
.tarok-app__notif--open .tarok-app__notif-panel { display: block; }
.tarok-app__notif-head { display: flex; justify-content: space-between; align-items: center; padding: .4rem .75rem; border-bottom: 1px solid rgba(128, 128, 128, .3); font-weight: 600; }
