/* specs.md MR11 "assets définitifs & polish visuel" — cards are still drawn
   in code (no external image pack, see docs/decisions.md for why), but now
   as an actual card face (corners + center rank, joker art + declared-value
   badge) instead of the MR5 placeholder box. Avatars: initiale + couleur,
   see avatars.js. */

/* Round 3 — playtest feedback "je voudrais un truc + graphique". Two
   directions were mocked up outside the repo (wood/felt "casino" look vs.
   flat cut-paper "board game" look) — the user picked the cut-paper one and
   explicitly flagged that the app-bar needs to follow the same treatment as
   the table, not stay in the old dark/glass style (see .app-bar below).
   This is a deliberate single-world commit (see artifact-design guidance on
   pages that commit to one visual identity): thick ink outlines, flat
   colour blocks, hard offset shadows instead of blur/glow, everywhere —
   not just on the table. No prefers-color-scheme split; the previous
   dark-navy identity is retired, not backgrounded. */
:root {
  color-scheme: light;
  --bg: #efe6d3; /* parchment page background */
  --bg-deep: #e3d7bb; /* recessed areas (felt surround, back-of-card) */
  --panel: #fffaf0; /* card-stock white — forms, panels */
  --panel-raised: #fff3dc;
  --panel-hover: #ffe9c2;
  --fg: #201a14; /* ink — text, outlines */
  --muted: #6b5d47;
  --accent: #2fa89a; /* felt teal — the one primary action colour */
  --accent-strong: #22867c;
  --on-accent: #fffaf0;
  --secondary: #6a4c93; /* plum */
  --attention: #f0b429; /* mustard — "this is winning / this matters" */
  --danger: #ff6b5e; /* coral */
  --border: var(--fg);
  --card-bg: #fffaf0;
  --card-fg: #201a14;
  /* Hard, un-blurred offset shadow — the one shadow language this identity
     uses everywhere instead of soft blur/glow, at three sizes. */
  --ink-shadow-sm: 2px 2px 0 var(--fg);
  --ink-shadow: 3px 3px 0 var(--fg);
  --ink-shadow-lg: 5px 6px 0 var(--fg);
}

* {
  box-sizing: border-box;
}

/* Real bug found in testing: several toggled containers (.home-menu__buttons,
   .bootstrap__form, .account-bar, .profile-switcher, ...) set their own
   `display` unconditionally (flex, for the row/column layouts). An author
   stylesheet's *normal*-priority rule always wins over the UA stylesheet's
   `[hidden] { display: none }` regardless of selector specificity — origin
   order (user-agent < author) trumps specificity in the cascade — so setting
   the `hidden` attribute on one of these did nothing visually: the login
   screen rendered stacked *under* the still-visible menu button list instead
   of replacing it. This one rule re-asserts `hidden` as the highest-priority
   author rule for every element in the app, whatever `display` its own class
   sets. */
[hidden] {
  display: none !important;
}

/* Playtest feedback: "peut-être une image en fond" — a flat solid color
   read as unfinished/placeholder-y. No external image asset (same call as
   the cards themselves, see docs/decisions.md): a warm paper-grain texture
   (SVG feTurbulence, generated, not downloaded) instead of the old navy
   vignette + scattered suit glyphs — the suits were always fictional
   decoration (PlayedCard never carries a suit, see decisions.md MR2) and
   read oddly once real card faces sat right next to them. Fixed to the
   viewport so it doesn't visibly tile or shift while scrolling. */
body {
  margin: 0;
  min-height: 100vh;
  background: radial-gradient(ellipse at 50% 0%, #f5eeda 0%, var(--bg) 60%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
  background-attachment: fixed;
  color: var(--fg);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
}

#app {
  max-width: 900px;
  margin: 0 auto;
  padding: 0 1rem 4rem;
}

h1 {
  color: inherit;
  margin: 0;
  font-size: 1.4rem;
  font-weight: 800;
}

h2 {
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin: 0 0 0.6rem;
}

/* --- App bar ----------------------------------------------------------------
   Playtest feedback: "L'enfumette" et la barre "connecté" faisaient deux
   niveaux séparés, regroupées ici sur une seule ligne. Also home of the one
   persistent navigation button and the account dropdown — both real buttons,
   not text links ("pourri sur un tel").

   Round 3 fix: this used to stay in the old dark/glass panel style while the
   table got the full cut-paper treatment — "le header est pas dans le même
   style". It's now the same ink-outline + hard-shadow language as every
   other panel in the app.

   Round 4 correction: the first ink-bar pass (dark fill + mustard edge)
   was exactly the "doré / noir façon poker" combination the original
   design doc ruled out — "c'est hideux". Cream fill like every other
   panel/card, ink outline, plain ink shadow — no colour edge — so it
   reads as one more paper card sitting at the top of the page, not a
   casino marquee. */
.app-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 1rem 0;
  padding: 0.65rem 1rem;
  flex-wrap: wrap;
  background: var(--panel);
  color: var(--fg);
  border-radius: 14px;
  border: 2px solid var(--fg);
  box-shadow: var(--ink-shadow);
}

.app-bar h1 {
  color: var(--accent-strong);
}

.app-bar__left {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* Round 4: the profile switcher (profile <select> + "Oublier ce profil")
   used to be its own full-width row below the app-bar — "si ça pouvait
   être sur la même ligne ça allégerait". Moved into the DOM here (see
   index.html) so it shares this row with the account dropdown instead of
   adding a second one. */
.app-bar__right {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Playtest feedback: "je veux le bouton menu en haut, pas de lien texte" —
   one real button, always in the app bar, whose label/action changes with
   context (see app.js updateNavButton()): "← Retour" out of a sub-screen,
   "☰ Menu" from the table, "🂠 Retour à la partie" from the menu while a
   game is still active. Replaces the old per-screen "← Retour" text links
   entirely. */
.nav-btn {
  background: var(--bg);
  color: var(--fg);
  border: 2px solid var(--fg);
  box-shadow: var(--ink-shadow-sm);
  font-size: 0.85rem;
  padding: 0.45rem 0.85rem;
}

.nav-btn:hover {
  background: var(--attention);
}

/* --- Home menu (mode téléphone : un écran à la fois) --------------------- */

.home-menu__buttons {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  max-width: 320px;
  margin: 2.5rem auto 0;
}

.menu-btn {
  font-size: 1.05rem;
  padding: 0.85rem 1rem;
  text-align: center;
}

/* Design doc section 13 "Menu principal": one hero action (first/biggest —
   "JOUER"), one secondary action (same size), everything else discreet.
   "Créer une partie" is this app's "JOUER" — it's the action that actually
   starts something, unlike "Rejoindre"/"Classement"/"Se connecter" which are
   all just navigation. */
.menu-btn--primary {
  font-size: 1.15rem;
  padding: 1rem;
}

.menu-btn--secondary {
  background: var(--panel);
  color: var(--fg);
}

.menu-btn--secondary:hover {
  background: var(--panel-hover);
}

.menu-btn--tertiary {
  background: transparent;
  color: var(--muted);
  font-weight: 600;
  font-size: 0.95rem;
  border-color: transparent;
  box-shadow: none;
  padding: 0.6rem 1rem;
}

.menu-btn--tertiary:hover {
  background: rgba(32, 26, 20, 0.06);
  color: var(--fg);
  border-color: transparent;
  transform: none;
  box-shadow: none;
}

.home-screen {
  max-width: 420px;
  margin: 0 auto;
}

.bootstrap__form {
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 14px;
  box-shadow: var(--ink-shadow);
  padding: 1rem;
  margin-bottom: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.bootstrap__form label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.9rem;
  color: var(--muted);
}

.bootstrap__form input {
  padding: 0.5rem 0.6rem;
  border-radius: 8px;
  border: 2px solid var(--fg);
  background: var(--bg);
  color: var(--fg);
  font-size: 1rem;
}

/* Design doc section 14 "Boutons": assez gros pour le tactile, fortement
   arrondis. Round 3: hard ink outline + offset shadow that flattens on
   press instead of a soft colored glow — the "sticker" language used on
   every button, badge and card in this identity. */
button {
  cursor: pointer;
  border: 2px solid var(--fg);
  border-radius: 18px;
  padding: 0.55rem 1rem;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
  box-shadow: var(--ink-shadow);
  transition: transform 0.1s ease, box-shadow 0.1s ease, background 0.15s ease;
}

button:hover {
  background: var(--accent-strong);
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 var(--fg);
}

button:active {
  transform: translate(1px, 1px);
  box-shadow: 1px 1px 0 var(--fg);
}

/* Playtest feedback: "pas de lien texte, c'est pourri sur un tel" — despite
   the name (kept as-is, used in a lot of places already — renaming would
   just be file churn for no behavior change), this is a real secondary
   button now: cream fill, ink outline — same family as .nav-btn, just sized
   for inline use (invite/leave/end-game controls, the login↔register
   toggle, dialog buttons) rather than the app bar. */
.link-button {
  background: var(--panel);
  color: var(--fg);
  font-weight: 600;
}

.link-button:hover {
  background: var(--panel-hover);
}

/* --- Account dropdown / profile switcher / errors ------------------------- */

/* Playtest feedback: "Se déconnecter" was showing twice (top bar + menu
   button). Consolidated into one dropdown on the connected pseudo — also
   the natural home for account-level options added later (ex. "Détruire
   mon compte"), instead of the flat home-menu button list growing forever. */
.account-menu {
  position: relative;
}

.account-menu__toggle {
  background: var(--bg);
  color: var(--fg);
  border: 2px solid var(--fg);
  box-shadow: var(--ink-shadow-sm);
  font-size: 0.85rem;
  padding: 0.45rem 0.85rem;
}

.account-menu__toggle:hover {
  background: var(--attention);
}

.account-menu__panel {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 20;
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 10px;
  padding: 0.4rem;
  min-width: 180px;
  box-shadow: var(--ink-shadow);
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.account-menu__item {
  background: transparent;
  color: var(--fg);
  text-align: left;
  font-weight: 500;
  border: none;
  box-shadow: none;
  padding: 0.5rem 0.6rem;
  border-radius: 6px;
}

.account-menu__item:hover {
  background: rgba(47, 168, 154, 0.14);
  transform: none;
}

.account-menu__item--danger {
  color: #c73f2f;
}

/* Round 4: lives inside .app-bar__right now (see index.html) instead of
   its own full-width row — "si ça pouvait être sur la même ligne ça
   allégerait". */
.profile-switcher {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
}

.profile-switcher select {
  background: var(--bg);
  color: var(--fg);
  border: 2px solid var(--fg);
  border-radius: 8px;
  padding: 0.3rem 0.4rem;
  max-width: 11rem;
}

.profile-switcher .link-button {
  padding: 0.4rem 0.7rem;
  font-size: 0.8rem;
}

.error-banner {
  background: #ffe2dd;
  border: 2px solid var(--danger);
  color: #a5342a;
  padding: 0.6rem 0.8rem;
  border-radius: 10px;
  margin-bottom: 1rem;
  font-weight: 600;
}

/* --- Table toolbar / badges ------------------------------------------------ */

/* Playtest feedback: replaces the old `.table-header` (its own "L'enfumette"
   title + status badge + "Toi : X" line, all either duplicated the app-bar
   or stated the obvious). Just the actions row now. */
.table-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.link-button--danger {
  color: #a5342a;
  border-color: #a5342a;
}

.link-button--danger:hover {
  background: #ffe2dd;
  color: #a5342a;
}

/* --- Lobby / roster ---------------------------------------------------------- */

.lobby {
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 14px;
  box-shadow: var(--ink-shadow);
  padding: 1.25rem;
  margin-bottom: 1rem;
}

.roster-list {
  list-style: none;
  margin: 0 0 0.75rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.roster-row {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.4rem 0.6rem;
  border-radius: 8px;
}

.roster-row--me {
  background: rgba(47, 168, 154, 0.14);
  outline: 2px solid var(--accent);
}

.roster-row__status {
  color: var(--muted);
  font-size: 0.85rem;
}

.badge--host {
  background: var(--attention);
  color: var(--fg);
  border-color: var(--fg);
  margin-left: 0.4rem;
  font-weight: 800;
  padding: 0 0.4rem;
}

.lobby__hint {
  color: var(--muted);
  font-size: 0.9rem;
  margin: 0 0 0.75rem;
}

.lobby__start-btn {
  font-size: 1.05rem;
  padding: 0.6rem 1.5rem;
}

.lobby__start-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  background: var(--muted);
  box-shadow: none;
}

/* --- Score history ------------------------------------------------------------ */

.score-history {
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 14px;
  box-shadow: var(--ink-shadow);
  padding: 0.75rem 1rem;
  margin-top: 1rem;
}

.score-history summary {
  cursor: pointer;
  color: var(--muted);
  font-weight: 600;
}

.score-history__table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 0.75rem;
  font-size: 0.9rem;
}

.score-history__table th,
.score-history__table td {
  text-align: left;
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid var(--bg-deep);
}

.badge {
  display: inline-block;
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
  font-size: 0.8rem;
  font-weight: 600;
}

/* --- Player chip (avatar + name) — specs.md MR11 "Avatars joueurs : initiale
   + couleur" — used wherever a player is named on the table view; the raw
   text label (playerLabel()) is kept for the two spots an inline element
   doesn't fit: <select> options and score-history table headers. */

.player-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.player-chip__name {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

/* Round 3 tried an organic "sticker" blob (asymmetric radii) here. Round 4
   feedback: "on avait une lettre avec un cercle autour, le nom en dessous,
   le A/R et c'est tout" — back to a plain circle, ink-outlined like
   everything else in this identity, initial + colour is the whole point. */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  min-width: 1.6rem;
  border-radius: 50%;
  border: 2px solid var(--fg);
  color: var(--fg);
  font-weight: 800;
  font-size: 0.8rem;
  line-height: 1;
}

.lobby__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

.badge--bot {
  background: var(--bg);
  border-color: var(--fg);
  margin-left: 0.4rem;
  font-size: 0.75rem;
  text-transform: capitalize;
}

/* Playtest feedback: "une icône vert/orange/rouge pour la difficulté
   plutôt que le texte entre parenthèses" — replaces the " (Facile)" /
   " (Moyen)" name suffix (stripped for display, see
   stripBotLevelSuffix() in render.js) with a small coloured dot; colour
   itself comes from render.js's BOT_LEVEL_COLOR, this just sizes/shapes it. */
.bot-level-dot {
  display: inline-block;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  border: 1.5px solid var(--fg);
  flex: none;
}

/* Playtest feedback: "on a perdu le tag qui est le donneur" — a small
   ink-on-mustard tag, tilted a couple degrees like a post-it stuck on the
   avatar, rather than a flat inline badge easy to miss among the others. */
.badge--dealer {
  background: var(--attention);
  color: var(--fg);
  border-color: var(--fg);
  margin-left: 0.4rem;
  font-weight: 800;
  padding: 0 0.4rem;
  display: inline-block;
  transform: rotate(-3deg);
}

.empty-state,
.waiting-banner {
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 14px;
  box-shadow: var(--ink-shadow);
  padding: 1.5rem;
  text-align: center;
  color: var(--muted);
}

.waiting-banner__hint {
  font-size: 0.85rem;
}

/* --- Scoreboard ------------------------------------------------------------ */

.scoreboard {
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 14px;
  box-shadow: var(--ink-shadow);
  padding: 1rem;
  margin-bottom: 1rem;
}

.scoreboard ul,
/* Playtest feedback: "classement général" / "mon historique" were bare,
   class-less <ul><li>text</li></ul> lists ("pas mis en forme comme les
   autres tableaux") — they now get the .scoreboard class directly on their
   own <ul> (no separate wrapper section needed) rather than nested inside
   one, hence this rule matching both shapes. */
ul.scoreboard {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.scoreboard__row {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.4rem 0.6rem;
  border-radius: 8px;
}

.scoreboard__row--me {
  background: rgba(47, 168, 154, 0.14);
  outline: 2px solid var(--accent);
}

.scoreboard__value--total {
  color: var(--accent-strong);
  font-weight: 700;
}

/* specs.md MR11 "petites animations" — a slow ambient pulse on whoever's
   turn it is. Safe under the per-poll full-rebuild (see render.js header
   comment): restarting an infinite loop's phase every poll is imperceptible,
   unlike a one-shot entrance animation would be.

   Round 4: "on ne voit pas assez la personne en train de jouer" — a 2px
   accent outline on an otherwise identical cream seat was too subtle to
   register in the middle of an actual game. Filled background + a bigger
   pulse (scale + shadow together) instead of an outline alone. */
/* Playtest feedback: "le focus du joueur en cours ne fasse pas bouger toute
   l'interface" — this used to also pulse `transform: scale(...)`. Harmless
   in principle (transform doesn't reflow siblings), but this app rebuilds
   the whole #table subtree from scratch every poll (see render.js file
   header) — restarting the animation's phase on unrelated CSS is fine, but
   restarting a *scale* mid-cycle made the active seat visibly snap in
   size each rebuild, reading as the whole board shifting. Shadow/border
   only now — same emphasis, no size change to snap. */
@keyframes active-pulse {
  0%,
  100% {
    box-shadow: 3px 4px 0 var(--fg);
  }
  50% {
    box-shadow: 5px 7px 0 var(--fg);
  }
}

/* --- Table board (specs.md MR11 playtest feedback: "un système de table
   avec les cartes au milieu", reference belote-style UIs) -------------------
   Opponents around the top (bid/tricks won + their remaining cards —
   face-down, or revealed at the 1-card turn), the trick in progress in the
   middle, the player's own hand along the bottom.

   Round 4 correction (kept from the previous identity): a clearly framed
   felt table is what reads as "card game" at a glance — "je vois pas de
   table claire" when an earlier pass dropped it for a flat panel.

   Round 3 (this pass): the navy frame + inset glow is replaced by the same
   ink-outline + hard-shadow language as every other panel — the table is
   drawn as one more big "card" sitting on the page, not a separate framed
   object. */
.game-table {
  background: var(--accent);
  border: 3px solid var(--fg);
  border-radius: 26px;
  padding: 1.25rem;
  margin-bottom: 1.5rem;
  box-shadow: var(--ink-shadow-lg);
}

/* Playtest feedback: "Tour à X cartes — Jeu des plis" as a giant heading was
   jargon nobody asked for — down to just a small badge with the card count. */
.game-table__meta {
  display: flex;
  gap: 0.5rem;
  margin: 0 0 0.75rem;
}

.badge--turn-size {
  background: var(--panel);
  color: var(--fg);
  border-color: var(--fg);
}

/* Playtest feedback: "on peut pas intégrer ça à la table ?" — folds the
   score total into each player's own chip badges instead of a separate
   "SCORES" panel above the board. */
.badge--score {
  background: var(--attention);
  color: var(--fg);
  border-color: var(--fg);
  margin-left: 0.4rem;
  font-weight: 800;
}

.one-card-hint {
  color: #a5342a;
  font-size: 0.9rem;
  margin: -0.3rem 0 0.75rem;
  font-weight: 600;
}

/* Playtest feedback: "il faudrait que les joueurs soient positionnées en
   cercle autour de la table" — `justify-content: center` bunched every
   opponent together in the dead middle, reading as a plain list rather
   than seats around a table. Spread across the full width instead (render.js
   also nudges each seat's own vertical offset into a gentle arc). */
.game-table__opponents {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0 0.5rem;
  margin-bottom: 1.25rem;
}

/* Real bug found in testing: with only a `min-width`, each seat grew to fit
   its own longest unbroken line (name + level + 🤖 + score badge, e.g.
   "Camille (Facile) 🤖 0 pts") — fine for 2-3 opponents, but past that the
   row simply couldn't fit them all and wrapped into a disconnected 2-row
   grid, undoing the whole "seats around the table" arc (render.js's
   marginTop math only makes sense across one continuous row). A hard width
   forces the name/badges to wrap *inside* the seat instead of pushing the
   seat itself wider — up to 5 opponents (the spec max) now fit one row on
   anything wider than a small phone. */
.seat {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  background: var(--panel);
  border: 2.5px solid var(--fg);
  border-radius: 12px;
  box-shadow: var(--ink-shadow);
  padding: 0.6rem 0.4rem;
  width: 104px;
}

/* .game-table__own-row is flex — without this the fixed 104px width above
   would still get squeezed by a wide hand of cards on a narrow screen. */
.seat--self {
  flex: none;
}

/* Playtest feedback, comparing the shipped seat against the agreed design
   proposal: "tu trouves que c'est pareil toi ?" — it wasn't. A real ribbon
   tag instead of the inline "🎲" that had replaced it (too easy to miss —
   the exact "on a perdu le tag qui est le donneur" complaint from before).
   Pinned to the top-left corner rather than centered like the proposal so
   it never fights .seat--active's own centered "▶ à toi" tag when a seat
   is both the dealer's and the active one at once. */
.seat__dealer-tag {
  position: absolute;
  top: -0.6rem;
  left: 0.3rem;
  background: var(--fg);
  color: var(--panel);
  font-size: 0.58rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  padding: 0.1rem 0.4rem;
  border-radius: 4px;
  transform: rotate(-6deg);
  white-space: nowrap;
  z-index: 3;
}

/* Playtest feedback: "les noms > retour ligne... c'est pas tout pareil" —
   avatar+name used to sit side by side and only wrap onto two lines once a
   name was too long for the 104px seat, so short names (e.g. "Hugo") and
   long ones (e.g. "Léon") ended up laid out completely differently from
   seat to seat. Name always goes under the avatar now, regardless of its
   length — one consistent shape for every seat. */
.seat .player-chip {
  flex-direction: column;
  gap: 0.2rem;
}

/* Round 5: the face-down card fan (removed above — "ça sert à rien") used
   to fill out the seat's height; the avatar can afford to be bigger now
   that it's not sitting above a stack of card backs — closer to the design
   proposal's weight. Safe to grow without touching the 104px hard width
   cap that keeps 5 opponents on one row (see .seat above): the cap is on
   the seat, not on the avatar/name inside it. */
.seat .avatar {
  width: 2.1rem;
  height: 2.1rem;
  min-width: 2.1rem;
  font-size: 1rem;
  border-width: 2.5px;
}

.seat .player-chip__name {
  flex-wrap: wrap;
  justify-content: center;
  row-gap: 0.15rem;
  font-size: 0.9rem;
  font-weight: 700;
}

.seat .badge {
  font-size: 0.62rem;
  padding: 0.1rem 0.35rem;
}

/* Round 6: "vire le orange" — the solid mustard fill from round 4 is gone;
   the ribbon tag + pulse + a teal (the app's one accent colour, not a
   semantic "warning" one) border carry the "it's their turn" signal now. */
.seat--active {
  position: relative;
  border-color: var(--accent);
  border-width: 3px;
  animation: active-pulse 1.2s ease-in-out infinite;
  z-index: 2;
}

/* Small flag above the seat instead of relying on the fill/pulse alone —
   the fill colour by itself still reads as "just this player's seat" at a
   glance, the label removes any ambiguity. */
.seat--active::before {
  content: "▶ à toi";
  position: absolute;
  top: -0.8rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--fg);
  color: var(--panel);
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  white-space: nowrap;
}

/* Round 5: back to a boxed pill (as in the design proposal) instead of bare
   text — reads as a distinct piece of information ("this is the bid/tricks
   stat"), not a stray caption. */
.seat__bid {
  margin: 0;
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--fg);
  text-align: center;
  background: var(--bg);
  border: 1.5px solid var(--fg);
  border-radius: 999px;
  padding: 0.1rem 0.55rem;
}

.seat__cards {
  display: flex;
}

/* A fanned stack of face-down backs — playtest feedback: opponents' hands
   weren't shown at all outside the 1-card turn, making it hard to follow
   whose turn it was or how many cards were left. Shrunk relative to .card's
   base size (52x76) so a full fan of up to 5 still fits a seat's width. */
.seat__cards--fan .card {
  width: 28px;
  height: 40px;
  border-radius: 4px;
  border-width: 1.5px;
  box-shadow: 1px 1px 0 var(--fg);
  margin-left: -16px;
}

.seat__cards--fan .card:first-child {
  margin-left: 0;
}

.seat__cards--fan .card__back-mark {
  width: 1rem;
  height: 1rem;
  font-size: 0.6rem;
}

/* Round 4 removed the dashed drop-zone border here ("ça sert à rien... en
   couleur beige"), but kept a solid beige panel underneath — round 5:
   "je t'avais dit de virer le fond de couleur... la tu as remis un fond".
   The design proposal had the trick's cards sitting directly on the green
   felt, no boxed sub-panel at all — that's what this is now: no
   background, no border, just the cards and the table underneath. */
.game-table__felt {
  min-height: 96px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 0.5rem;
  padding: 1rem;
}

.game-table__felt--empty {
  color: var(--panel);
  text-shadow: 0 1px 2px rgba(32, 26, 20, 0.45);
  font-size: 0.9rem;
  font-weight: 700;
}

.game-table__felt-cards {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 1rem;
}

/* Playtest feedback: "on voit pas qui gagne le pli clairement" — names the
   card currently ahead (or, once the trick is full, the actual winner)
   instead of leaving everyone to compare values themselves. */
.game-table__trick-winner {
  margin: 0;
  font-size: 0.85rem;
  font-weight: 800;
  color: var(--fg);
  background: var(--attention);
  border: 2px solid var(--fg);
  border-radius: 999px;
  padding: 0.15rem 0.7rem;
}

.game-table__play {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
}

/* Round 5: "virer le fond de couleur" — no boxed panel here, the hand sits
   directly on the green felt like the design proposal. */
.game-table__own {
  position: relative;
  margin-top: 1rem;
  padding: 0 1rem;
}

/* Round 8: "on pourrait pas garder l'initiale + nom, mais peut-être sur un
   côté ? comme ça on peut focus comme les autres" — the player's own hand
   is laid out like an opponent's seat now: a `.seat--self` chip (avatar +
   "vous", see renderOwnHandRow() in render.js) beside the actual playable
   cards, instead of a text title above them. The active-turn highlight
   (teal border/pulse/ribbon) is `.seat--active` itself, reused as-is — no
   separate `--active` variant needed here any more. */
.game-table__own-row {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.game-table__own-row .hand__cards {
  flex: 1;
}

/* Round 6: "centrer les cartes du joueur" — was left-aligned by default. */
.hand__cards {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
}

/* Round 8: "A : 1 · R : 1 fait comme les autres, met le badge sous les
   cartes centré" — same `.seat__bid` pill opponents get, just centered
   under the whole row instead of living inside a fixed-width seat. */
.game-table__own-bid {
  margin: 0.6rem auto 0;
  width: fit-content;
}

/* Round 3: ink outline + hard offset shadow instead of a soft drop shadow —
   corner ranks kept as-is (see renderCard() in render.js: cards are
   deliberately suit-less, PlayedCard never carries a suit, so no pip glyph
   was invented here). */
.card {
  position: relative;
  width: 52px;
  height: 76px;
  background: var(--card-bg);
  color: var(--card-fg);
  border-radius: 8px;
  border: 2.5px solid var(--fg);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 3px 4px;
  font-weight: 800;
  box-shadow: var(--ink-shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.card--highlight {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  transform: translateY(-4px);
}

/* Playtest feedback: "on voit pas qui gagne le pli clairement" — a distinct
   treatment from the teal "playable" outline above (that one means "you can
   act on this"; this one means "this is currently winning"): the card lifts
   and tilts a couple degrees, mustard shadow instead of ink. */
.card--winning {
  outline: 2px solid var(--attention);
  outline-offset: 1px;
  transform: translateY(-4px) rotate(-2deg);
  box-shadow: 3px 5px 0 var(--attention);
}

/* Corner ranks — readable at a glance from either end of a fanned hand,
   like a real playing card, rather than one centered label. */
.card__corner {
  font-size: 0.7rem;
  line-height: 1;
  align-self: flex-start;
}

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

.card__pip {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.35rem;
  pointer-events: none;
}

.card--joker {
  background: #f3ecff;
}

.card__joker-face {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  pointer-events: none;
}

/* specs.md "aucun pack CC0 courant ne fournit de joker avec un badge de
   valeur déclarée" — small maison overlay, not a separate asset. */
.card__badge {
  position: absolute;
  top: -8px;
  right: -8px;
  min-width: 1.2rem;
  height: 1.2rem;
  padding: 0 0.25rem;
  border-radius: 999px;
  background: var(--attention);
  color: var(--fg);
  border: 2px solid var(--fg);
  font-size: 0.7rem;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: none;
}

/* Round 3: recolored diagonal-stripe back (teal/cream) to match the new
   palette instead of the old navy panel tones, ink circle stamp on top. */
.card--face-down {
  background: repeating-linear-gradient(45deg, var(--accent), var(--accent) 4px, var(--panel) 4px, var(--panel) 8px);
  align-items: center;
  justify-content: center;
}

.card__back-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  background: var(--panel);
  border: 1.5px solid var(--fg);
  color: var(--fg);
  font-weight: 800;
  font-size: 0.9rem;
}

.card--playable {
  cursor: grab;
}

.card--playable:hover,
.card--playable:focus-visible {
  transform: translateY(-6px);
  box-shadow: 3px 6px 0 var(--fg);
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.card--playable:active {
  cursor: grabbing;
}

/* --- Countdown -------------------------------------------------------------- */

.countdown {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 999px;
  box-shadow: var(--ink-shadow-sm);
  padding: 0.5rem 1rem;
  margin-bottom: 1rem;
  font-size: 0.9rem;
  color: var(--muted);
}

.countdown--urgent {
  animation: countdown-urgent 1s ease-in-out infinite;
}

@keyframes countdown-urgent {
  0%,
  100% {
    box-shadow: var(--ink-shadow-sm);
  }
  50% {
    box-shadow: 3px 4px 0 var(--danger);
  }
}

.countdown__resolve-btn {
  padding: 0.3rem 0.75rem;
  font-size: 0.85rem;
  background: var(--danger);
  color: var(--fg);
}

.countdown__resolve-btn:hover {
  background: #e2554f;
}

/* --- Bid controls ------------------------------------------------------------ */

.bid-controls {
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 14px;
  box-shadow: var(--ink-shadow);
  padding: 1rem;
  margin-bottom: 1.5rem;
}

.bid-controls__buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Playtest feedback: "faudrait annoncer le nombre total de plis annoncé...
   pour se rendre compte". */
.bid-controls__total {
  margin: -0.3rem 0 0.6rem;
  font-size: 0.85rem;
  color: var(--muted);
  font-weight: 600;
}

.bid-btn {
  min-width: 2.75rem;
  padding: 0.5rem;
  font-size: 1.1rem;
  border-radius: 50%;
  background: var(--panel);
  color: var(--fg);
}

.bid-btn:hover {
  background: var(--attention);
}

.bid-btn--forbidden {
  background: var(--bg-deep);
  color: var(--muted);
  border: 2px dashed var(--danger);
  box-shadow: none;
  opacity: 0.7;
  cursor: not-allowed;
}

.bid-btn--forbidden:hover {
  background: var(--bg-deep);
  transform: none;
  box-shadow: none;
}

.badge--turn {
  margin-left: 0.4rem;
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--fg);
}

/* --- Drag & drop / play zone --------------------------------------------------
   Round 4: "on n'a pas besoin des zones de déplacement et de dépôt des
   cartes" — dragging a card to play it still works (wireDropZone() in
   render.js), it just no longer gets its own dashed-outline/tinted-panel
   treatment; clicking a highlighted card is the primary way to play. */

.hand__cards--drag-over {
  outline: 2px solid var(--accent);
}

/* --- Joker declaration prompt ------------------------------------------------- */

.joker-prompt-overlay {
  position: fixed;
  inset: 0;
  background: rgba(32, 26, 20, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}

.joker-prompt {
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 14px;
  box-shadow: var(--ink-shadow-lg);
  padding: 1.5rem;
  text-align: center;
}

/* Playtest feedback: "continuer pas centré en fin de tour" — .joker-prompt
   has text-align: center, but that only affects inline content; this is
   itself a flex container, so its one button still sat at flex-start. */
.joker-prompt__buttons {
  display: flex;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 0.75rem;
}

.joker-prompt__buttons button {
  min-width: 4rem;
  font-size: 1.1rem;
}

.link-dialog__input {
  width: 100%;
  margin-top: 0.75rem;
  padding: 0.5rem 0.6rem;
  border-radius: 8px;
  border: 2px solid var(--fg);
  background: var(--bg);
  color: var(--fg);
  font-size: 0.9rem;
}

/* --- End of hand overlay (specs.md MR8) --------------------------------- */

.hand-end {
  min-width: 260px;
}

.hand-end__list {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.hand-end__row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.4rem 0.6rem;
  border-radius: 8px;
  text-align: left;
}

.hand-end__row--best {
  background: rgba(240, 180, 41, 0.22);
  outline: 2px solid var(--attention);
  font-weight: 700;
}

/* --- End of game screen (specs.md MR8) ----------------------------------- */

.game-end {
  background: var(--panel);
  border: 2px solid var(--fg);
  border-radius: 14px;
  box-shadow: var(--ink-shadow);
  padding: 1.25rem;
  margin-bottom: 1rem;
}

.game-end__hint {
  color: var(--muted);
  font-size: 0.9rem;
  margin: 0 0 0.75rem;
}

.game-end__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.game-end__row {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0.7rem;
  border-radius: 8px;
  font-size: 1.05rem;
}

.game-end__row--me {
  background: rgba(47, 168, 154, 0.16);
  outline: 2px solid var(--accent);
}

/* --- 1-card turn action ------------------------------------------------------- */

.one-card-actions {
  display: flex;
  gap: 0.6rem;
  margin-top: 0.75rem;
}
